wasip1: fix file open modes used by wasi-libc (#1421)
This extends wazero's interpretation of rights in wasi_snapshot_preview1.path_open to allow programs to open files in either read-only, write-only, or read-write mode. Signed-off-by: Achille Roussel <achille.roussel@gmail.com> Co-authored-by: Crypt Keeper <64215+codefromthecrypt@users.noreply.github.com>
This commit is contained in:
@@ -327,8 +327,8 @@ func TestRun(t *testing.T) {
|
||||
==> wasi_snapshot_preview1.fd_prestat_get(fd=4)
|
||||
<== (prestat=,errno=EBADF)
|
||||
==> wasi_snapshot_preview1.fd_fdstat_get(fd=3)
|
||||
<== (stat={filetype=DIRECTORY,fdflags=,fs_rights_base=,fs_rights_inheriting=},errno=ESUCCESS)
|
||||
==> wasi_snapshot_preview1.path_open(fd=3,dirflags=SYMLINK_FOLLOW,path=bear.txt,oflags=,fs_rights_base=,fs_rights_inheriting=,fdflags=)
|
||||
<== (stat={filetype=DIRECTORY,fdflags=,fs_rights_base=FD_DATASYNC|FDSTAT_SET_FLAGS|FD_SYNC|PATH_CREATE_DIRECTORY|PATH_CREATE_FILE|PATH_LINK_SOURCE|PATH_LINK_TARGET|PATH_OPEN|FD_READDIR|PATH_READLINK,fs_rights_inheriting=FD_DATASYNC|FD_READ|FD_SEEK|FDSTAT_SET_FLAGS|FD_SYNC|FD_TELL|FD_WRITE|FD_ADVISE|FD_ALLOCATE|PATH_CREATE_DIRECTORY|PATH_CREATE_FILE|PATH_LINK_SOURCE|PATH_LINK_TARGET|PATH_OPEN|FD_READDIR|PATH_READLINK},errno=ESUCCESS)
|
||||
==> wasi_snapshot_preview1.path_open(fd=3,dirflags=SYMLINK_FOLLOW,path=bear.txt,oflags=,fs_rights_base=FD_READ|FD_SEEK|FDSTAT_SET_FLAGS|FD_SYNC|FD_TELL|FD_ADVISE|PATH_CREATE_DIRECTORY|PATH_CREATE_FILE|PATH_LINK_SOURCE|PATH_LINK_TARGET|PATH_OPEN|FD_READDIR|PATH_READLINK|PATH_RENAME_SOURCE|PATH_RENAME_TARGET|PATH_FILESTAT_GET|PATH_FILESTAT_SET_SIZE|PATH_FILESTAT_SET_TIMES|FD_FILESTAT_GET|FD_FILESTAT_SET_TIMES|PATH_SYMLINK|PATH_REMOVE_DIRECTORY|PATH_UNLINK_FILE|POLL_FD_READWRITE,fs_rights_inheriting=FD_DATASYNC|FD_READ|FD_SEEK|FDSTAT_SET_FLAGS|FD_SYNC|FD_TELL|FD_WRITE|FD_ADVISE|FD_ALLOCATE|PATH_CREATE_DIRECTORY|PATH_CREATE_FILE|PATH_LINK_SOURCE|PATH_LINK_TARGET|PATH_OPEN|FD_READDIR|PATH_READLINK|PATH_RENAME_SOURCE|PATH_RENAME_TARGET|PATH_FILESTAT_GET|PATH_FILESTAT_SET_SIZE|PATH_FILESTAT_SET_TIMES|FD_FILESTAT_GET|FD_FILESTAT_SET_SIZE|FD_FILESTAT_SET_TIMES|PATH_SYMLINK|PATH_REMOVE_DIRECTORY|PATH_UNLINK_FILE|POLL_FD_READWRITE,fdflags=)
|
||||
<== (opened_fd=4,errno=ESUCCESS)
|
||||
==> wasi_snapshot_preview1.fd_filestat_get(fd=4)
|
||||
<== (filestat={filetype=REGULAR_FILE,size=5,mtim=%d},errno=ESUCCESS)
|
||||
|
||||
Binary file not shown.
@@ -222,24 +222,66 @@ func fdFdstatGetFn(_ context.Context, mod api.Module, params []uint64) syscall.E
|
||||
fdflags = wasip1.FD_APPEND
|
||||
}
|
||||
|
||||
filetype := getWasiFiletype(st.Mode)
|
||||
writeFdstat(buf, filetype, fdflags)
|
||||
var fsRightsBase uint32
|
||||
var fsRightsInheriting uint32
|
||||
fileType := getWasiFiletype(st.Mode)
|
||||
|
||||
switch fileType {
|
||||
case wasip1.FILETYPE_DIRECTORY:
|
||||
// To satisfy wasi-testsuite, we must advertise that directories cannot
|
||||
// be given seek permission (RIGHT_FD_SEEK).
|
||||
fsRightsBase = dirRightsBase
|
||||
fsRightsInheriting = fileRightsBase | dirRightsBase
|
||||
default:
|
||||
fsRightsBase = fileRightsBase
|
||||
}
|
||||
|
||||
writeFdstat(buf, fileType, fdflags, fsRightsBase, fsRightsInheriting)
|
||||
return 0
|
||||
}
|
||||
|
||||
var blockFdstat = []byte{
|
||||
wasip1.FILETYPE_BLOCK_DEVICE, 0, // filetype
|
||||
0, 0, 0, 0, 0, 0, // fdflags
|
||||
0, 0, 0, 0, 0, 0, 0, 0, // fs_rights_base
|
||||
0, 0, 0, 0, 0, 0, 0, 0, // fs_rights_inheriting
|
||||
}
|
||||
const fileRightsBase = wasip1.RIGHT_FD_DATASYNC |
|
||||
wasip1.RIGHT_FD_READ |
|
||||
wasip1.RIGHT_FD_SEEK |
|
||||
wasip1.RIGHT_FDSTAT_SET_FLAGS |
|
||||
wasip1.RIGHT_FD_SYNC |
|
||||
wasip1.RIGHT_FD_TELL |
|
||||
wasip1.RIGHT_FD_WRITE |
|
||||
wasip1.RIGHT_FD_ADVISE |
|
||||
wasip1.RIGHT_FD_ALLOCATE |
|
||||
wasip1.RIGHT_FD_FILESTAT_GET |
|
||||
wasip1.RIGHT_FD_FILESTAT_SET_SIZE |
|
||||
wasip1.RIGHT_FD_FILESTAT_SET_TIMES |
|
||||
wasip1.RIGHT_POLL_FD_READWRITE
|
||||
|
||||
func writeFdstat(buf []byte, filetype uint8, fdflags uint16) {
|
||||
// memory is re-used, so ensure the result is defaulted.
|
||||
copy(buf, blockFdstat)
|
||||
buf[0] = filetype
|
||||
buf[2] = byte(fdflags)
|
||||
const dirRightsBase = wasip1.RIGHT_FD_DATASYNC |
|
||||
wasip1.RIGHT_FDSTAT_SET_FLAGS |
|
||||
wasip1.RIGHT_FD_SYNC |
|
||||
wasip1.RIGHT_PATH_CREATE_DIRECTORY |
|
||||
wasip1.RIGHT_PATH_CREATE_FILE |
|
||||
wasip1.RIGHT_PATH_LINK_SOURCE |
|
||||
wasip1.RIGHT_PATH_LINK_TARGET |
|
||||
wasip1.RIGHT_PATH_OPEN |
|
||||
wasip1.RIGHT_FD_READDIR |
|
||||
wasip1.RIGHT_PATH_READLINK |
|
||||
wasip1.RIGHT_PATH_RENAME_SOURCE |
|
||||
wasip1.RIGHT_PATH_RENAME_TARGET |
|
||||
wasip1.RIGHT_PATH_FILESTAT_GET |
|
||||
wasip1.RIGHT_PATH_FILESTAT_SET_SIZE |
|
||||
wasip1.RIGHT_PATH_FILESTAT_SET_TIMES |
|
||||
wasip1.RIGHT_FD_FILESTAT_GET |
|
||||
wasip1.RIGHT_FD_FILESTAT_SET_TIMES |
|
||||
wasip1.RIGHT_PATH_SYMLINK |
|
||||
wasip1.RIGHT_PATH_REMOVE_DIRECTORY |
|
||||
wasip1.RIGHT_PATH_UNLINK_FILE
|
||||
|
||||
func writeFdstat(buf []byte, fileType uint8, fdflags uint16, fsRightsBase, fsRightsInheriting uint32) {
|
||||
b := (*[24]byte)(buf)
|
||||
le.PutUint16(b[0:], uint16(fileType))
|
||||
le.PutUint16(b[2:], fdflags)
|
||||
le.PutUint32(b[4:], 0)
|
||||
le.PutUint64(b[8:], uint64(fsRightsBase))
|
||||
le.PutUint64(b[16:], uint64(fsRightsInheriting))
|
||||
}
|
||||
|
||||
// fdFdstatSetFlags is the WASI function named FdFdstatSetFlagsName which
|
||||
@@ -1713,24 +1755,42 @@ func openFlags(dirflags, oflags, fdflags uint16, rights uint32) (openFlags int)
|
||||
} else if oflags&wasip1.O_EXCL != 0 {
|
||||
openFlags |= syscall.O_EXCL
|
||||
}
|
||||
// Because we don't implement rights, we paritally rely on the open flags
|
||||
// to determine the mode in which the file will be opened. This will create
|
||||
// divergeant behavior compared to WASI runtimes which have a more strict
|
||||
// interpretation of the WASI capabilities model; for example, a program
|
||||
// which sets O_CREAT but does not give read or write permissions will
|
||||
// successfully create a file when running with wazero, but might get a
|
||||
// permission denied error on other runtimes.
|
||||
defaultMode := syscall.O_RDONLY
|
||||
if oflags&wasip1.O_TRUNC != 0 {
|
||||
openFlags |= syscall.O_RDWR | syscall.O_TRUNC
|
||||
openFlags |= syscall.O_TRUNC
|
||||
defaultMode = syscall.O_RDWR
|
||||
}
|
||||
if oflags&wasip1.O_CREAT != 0 {
|
||||
openFlags |= syscall.O_RDWR | syscall.O_CREAT
|
||||
openFlags |= syscall.O_CREAT
|
||||
defaultMode = syscall.O_RDWR
|
||||
}
|
||||
if fdflags&wasip1.FD_APPEND != 0 {
|
||||
openFlags |= syscall.O_RDWR | syscall.O_APPEND
|
||||
openFlags |= syscall.O_APPEND
|
||||
defaultMode = syscall.O_RDWR
|
||||
}
|
||||
// Since rights were discontinued in wasi, we only interpret RIGHT_FD_WRITE
|
||||
// because it is the only way to know that we need to set write permissions
|
||||
// on a file if the application did not pass any of O_CREATE, O_APPEND, nor
|
||||
// O_TRUNC.
|
||||
if rights&wasip1.RIGHT_FD_WRITE != 0 {
|
||||
const r = wasip1.RIGHT_FD_READ
|
||||
const w = wasip1.RIGHT_FD_WRITE
|
||||
const rw = r | w
|
||||
switch {
|
||||
case (rights & rw) == rw:
|
||||
openFlags |= syscall.O_RDWR
|
||||
}
|
||||
if openFlags == 0 {
|
||||
openFlags = syscall.O_RDONLY
|
||||
case (rights & w) == w:
|
||||
openFlags |= syscall.O_WRONLY
|
||||
case (rights & r) == r:
|
||||
openFlags |= syscall.O_RDONLY
|
||||
default:
|
||||
openFlags |= defaultMode
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -248,12 +248,12 @@ func Test_fdFdstatGet(t *testing.T) {
|
||||
expectedMemory: []byte{
|
||||
1, 0, // fs_filetype
|
||||
0, 0, 0, 0, 0, 0, // fs_flags
|
||||
0, 0, 0, 0, 0, 0, 0, 0, // fs_rights_base
|
||||
0xff, 0x1, 0xe0, 0x8, 0x0, 0x0, 0x0, 0x0, // fs_rights_base
|
||||
0, 0, 0, 0, 0, 0, 0, 0, // fs_rights_inheriting
|
||||
},
|
||||
expectedLog: `
|
||||
==> wasi_snapshot_preview1.fd_fdstat_get(fd=0)
|
||||
<== (stat={filetype=BLOCK_DEVICE,fdflags=,fs_rights_base=,fs_rights_inheriting=},errno=ESUCCESS)
|
||||
<== (stat={filetype=BLOCK_DEVICE,fdflags=,fs_rights_base=FD_DATASYNC|FD_READ|FD_SEEK|FDSTAT_SET_FLAGS|FD_SYNC|FD_TELL|FD_WRITE|FD_ADVISE|FD_ALLOCATE,fs_rights_inheriting=},errno=ESUCCESS)
|
||||
`,
|
||||
},
|
||||
{
|
||||
@@ -262,12 +262,12 @@ func Test_fdFdstatGet(t *testing.T) {
|
||||
expectedMemory: []byte{
|
||||
1, 0, // fs_filetype
|
||||
1, 0, 0, 0, 0, 0, // fs_flags
|
||||
0, 0, 0, 0, 0, 0, 0, 0, // fs_rights_base
|
||||
0xff, 0x1, 0xe0, 0x8, 0x0, 0x0, 0x0, 0x0, // fs_rights_base
|
||||
0, 0, 0, 0, 0, 0, 0, 0, // fs_rights_inheriting
|
||||
},
|
||||
expectedLog: `
|
||||
==> wasi_snapshot_preview1.fd_fdstat_get(fd=1)
|
||||
<== (stat={filetype=BLOCK_DEVICE,fdflags=APPEND,fs_rights_base=,fs_rights_inheriting=},errno=ESUCCESS)
|
||||
<== (stat={filetype=BLOCK_DEVICE,fdflags=APPEND,fs_rights_base=FD_DATASYNC|FD_READ|FD_SEEK|FDSTAT_SET_FLAGS|FD_SYNC|FD_TELL|FD_WRITE|FD_ADVISE|FD_ALLOCATE,fs_rights_inheriting=},errno=ESUCCESS)
|
||||
`,
|
||||
},
|
||||
{
|
||||
@@ -276,12 +276,12 @@ func Test_fdFdstatGet(t *testing.T) {
|
||||
expectedMemory: []byte{
|
||||
1, 0, // fs_filetype
|
||||
1, 0, 0, 0, 0, 0, // fs_flags
|
||||
0, 0, 0, 0, 0, 0, 0, 0, // fs_rights_base
|
||||
0xff, 0x1, 0xe0, 0x8, 0x0, 0x0, 0x0, 0x0, // fs_rights_base
|
||||
0, 0, 0, 0, 0, 0, 0, 0, // fs_rights_inheriting
|
||||
},
|
||||
expectedLog: `
|
||||
==> wasi_snapshot_preview1.fd_fdstat_get(fd=2)
|
||||
<== (stat={filetype=BLOCK_DEVICE,fdflags=APPEND,fs_rights_base=,fs_rights_inheriting=},errno=ESUCCESS)
|
||||
<== (stat={filetype=BLOCK_DEVICE,fdflags=APPEND,fs_rights_base=FD_DATASYNC|FD_READ|FD_SEEK|FDSTAT_SET_FLAGS|FD_SYNC|FD_TELL|FD_WRITE|FD_ADVISE|FD_ALLOCATE,fs_rights_inheriting=},errno=ESUCCESS)
|
||||
`,
|
||||
},
|
||||
{
|
||||
@@ -290,12 +290,12 @@ func Test_fdFdstatGet(t *testing.T) {
|
||||
expectedMemory: []byte{
|
||||
3, 0, // fs_filetype
|
||||
0, 0, 0, 0, 0, 0, // fs_flags
|
||||
0, 0, 0, 0, 0, 0, 0, 0, // fs_rights_base
|
||||
0, 0, 0, 0, 0, 0, 0, 0, // fs_rights_inheriting
|
||||
0x19, 0xfe, 0xbf, 0x7, 0x0, 0x0, 0x0, 0x0, // fs_rights_base
|
||||
0xff, 0xff, 0xff, 0xf, 0x0, 0x0, 0x0, 0x0, // fs_rights_inheriting
|
||||
},
|
||||
expectedLog: `
|
||||
==> wasi_snapshot_preview1.fd_fdstat_get(fd=3)
|
||||
<== (stat={filetype=DIRECTORY,fdflags=,fs_rights_base=,fs_rights_inheriting=},errno=ESUCCESS)
|
||||
<== (stat={filetype=DIRECTORY,fdflags=,fs_rights_base=FD_DATASYNC|FDSTAT_SET_FLAGS|FD_SYNC|PATH_CREATE_DIRECTORY|PATH_CREATE_FILE|PATH_LINK_SOURCE|PATH_LINK_TARGET|PATH_OPEN|FD_READDIR|PATH_READLINK,fs_rights_inheriting=FD_DATASYNC|FD_READ|FD_SEEK|FDSTAT_SET_FLAGS|FD_SYNC|FD_TELL|FD_WRITE|FD_ADVISE|FD_ALLOCATE|PATH_CREATE_DIRECTORY|PATH_CREATE_FILE|PATH_LINK_SOURCE|PATH_LINK_TARGET|PATH_OPEN|FD_READDIR|PATH_READLINK},errno=ESUCCESS)
|
||||
`,
|
||||
},
|
||||
{
|
||||
@@ -304,12 +304,12 @@ func Test_fdFdstatGet(t *testing.T) {
|
||||
expectedMemory: []byte{
|
||||
4, 0, // fs_filetype
|
||||
0, 0, 0, 0, 0, 0, // fs_flags
|
||||
0, 0, 0, 0, 0, 0, 0, 0, // fs_rights_base
|
||||
0xff, 0x1, 0xe0, 0x8, 0x0, 0x0, 0x0, 0x0, // fs_rights_base
|
||||
0, 0, 0, 0, 0, 0, 0, 0, // fs_rights_inheriting
|
||||
},
|
||||
expectedLog: `
|
||||
==> wasi_snapshot_preview1.fd_fdstat_get(fd=4)
|
||||
<== (stat={filetype=REGULAR_FILE,fdflags=,fs_rights_base=,fs_rights_inheriting=},errno=ESUCCESS)
|
||||
<== (stat={filetype=REGULAR_FILE,fdflags=,fs_rights_base=FD_DATASYNC|FD_READ|FD_SEEK|FDSTAT_SET_FLAGS|FD_SYNC|FD_TELL|FD_WRITE|FD_ADVISE|FD_ALLOCATE,fs_rights_inheriting=},errno=ESUCCESS)
|
||||
`,
|
||||
},
|
||||
{
|
||||
@@ -318,12 +318,12 @@ func Test_fdFdstatGet(t *testing.T) {
|
||||
expectedMemory: []byte{
|
||||
3, 0, // fs_filetype
|
||||
0, 0, 0, 0, 0, 0, // fs_flags
|
||||
0, 0, 0, 0, 0, 0, 0, 0, // fs_rights_base
|
||||
0, 0, 0, 0, 0, 0, 0, 0, // fs_rights_inheriting
|
||||
0x19, 0xfe, 0xbf, 0x7, 0x0, 0x0, 0x0, 0x0, // fs_rights_base
|
||||
0xff, 0xff, 0xff, 0xf, 0x0, 0x0, 0x0, 0x0, // fs_rights_inheriting
|
||||
},
|
||||
expectedLog: `
|
||||
==> wasi_snapshot_preview1.fd_fdstat_get(fd=5)
|
||||
<== (stat={filetype=DIRECTORY,fdflags=,fs_rights_base=,fs_rights_inheriting=},errno=ESUCCESS)
|
||||
<== (stat={filetype=DIRECTORY,fdflags=,fs_rights_base=FD_DATASYNC|FDSTAT_SET_FLAGS|FD_SYNC|PATH_CREATE_DIRECTORY|PATH_CREATE_FILE|PATH_LINK_SOURCE|PATH_LINK_TARGET|PATH_OPEN|FD_READDIR|PATH_READLINK,fs_rights_inheriting=FD_DATASYNC|FD_READ|FD_SEEK|FDSTAT_SET_FLAGS|FD_SYNC|FD_TELL|FD_WRITE|FD_ADVISE|FD_ALLOCATE|PATH_CREATE_DIRECTORY|PATH_CREATE_FILE|PATH_LINK_SOURCE|PATH_LINK_TARGET|PATH_OPEN|FD_READDIR|PATH_READLINK},errno=ESUCCESS)
|
||||
`,
|
||||
},
|
||||
{
|
||||
@@ -3936,16 +3936,16 @@ func Test_pathOpen(t *testing.T) {
|
||||
`,
|
||||
},
|
||||
{
|
||||
name: "sysfs.DirFS RIGHT_FD_WRITE",
|
||||
name: "sysfs.DirFS RIGHT_FD_READ|RIGHT_FD_WRITE",
|
||||
fs: writeFS,
|
||||
path: func(*testing.T) string { return fileName },
|
||||
oflags: 0,
|
||||
rights: wasip1.RIGHT_FD_WRITE,
|
||||
rights: wasip1.RIGHT_FD_READ | wasip1.RIGHT_FD_WRITE,
|
||||
expected: func(t *testing.T, fsc *sys.FSContext) {
|
||||
requireContents(t, fsc, expectedOpenedFd, fileName, fileContents)
|
||||
},
|
||||
expectedLog: `
|
||||
==> wasi_snapshot_preview1.path_open(fd=3,dirflags=,path=file,oflags=,fs_rights_base=FD_WRITE,fs_rights_inheriting=,fdflags=)
|
||||
==> wasi_snapshot_preview1.path_open(fd=3,dirflags=,path=file,oflags=,fs_rights_base=FD_READ|FD_WRITE,fs_rights_inheriting=,fdflags=)
|
||||
<== (opened_fd=4,errno=ESUCCESS)
|
||||
`,
|
||||
},
|
||||
|
||||
@@ -413,9 +413,19 @@ func Test_openFlags(t *testing.T) {
|
||||
dirflags: wasip1.LOOKUP_SYMLINK_FOLLOW,
|
||||
expectedOpenFlags: syscall.O_RDONLY,
|
||||
},
|
||||
{
|
||||
name: "rights=FD_READ",
|
||||
rights: wasip1.RIGHT_FD_READ,
|
||||
expectedOpenFlags: platform.O_NOFOLLOW | syscall.O_RDONLY,
|
||||
},
|
||||
{
|
||||
name: "rights=FD_WRITE",
|
||||
rights: wasip1.RIGHT_FD_WRITE,
|
||||
expectedOpenFlags: platform.O_NOFOLLOW | syscall.O_WRONLY,
|
||||
},
|
||||
{
|
||||
name: "rights=FD_READ|FD_WRITE",
|
||||
rights: wasip1.RIGHT_FD_READ | wasip1.RIGHT_FD_WRITE,
|
||||
expectedOpenFlags: platform.O_NOFOLLOW | syscall.O_RDWR,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
@@ -70,6 +71,54 @@ void main_sleepmillis(int millis) {
|
||||
printf("OK\n");
|
||||
}
|
||||
|
||||
void main_open_rdonly() {
|
||||
const char *path = "zig-cc.rdonly.test";
|
||||
int fd;
|
||||
char buf[32];
|
||||
|
||||
fd = open(path, O_CREAT|O_TRUNC|O_RDONLY, 0644);
|
||||
if (fd < 0) {
|
||||
perror("ERR: open");
|
||||
goto cleanup;
|
||||
}
|
||||
if (write(fd, "hello world\n", 12) >= 0) {
|
||||
perror("ERR: write");
|
||||
goto cleanup;
|
||||
}
|
||||
if (read(fd, buf, sizeof(buf)) != 0) {
|
||||
perror("ERR: read");
|
||||
goto cleanup;
|
||||
}
|
||||
puts("OK");
|
||||
cleanup:
|
||||
close(fd);
|
||||
unlink(path);
|
||||
}
|
||||
|
||||
void main_open_wronly() {
|
||||
const char *path = "zig-cc.wronly.test";
|
||||
int fd;
|
||||
char buf[32];
|
||||
|
||||
fd = open(path, O_CREAT|O_TRUNC|O_WRONLY, 0644);
|
||||
if (fd < 0) {
|
||||
perror("ERR: open");
|
||||
goto cleanup;
|
||||
}
|
||||
if (write(fd, "hello world\n", 12) != 12) {
|
||||
perror("ERR: write");
|
||||
goto cleanup;
|
||||
}
|
||||
if (read(fd, buf, sizeof(buf)) >= 0) {
|
||||
perror("ERR: read");
|
||||
goto cleanup;
|
||||
}
|
||||
puts("OK");
|
||||
cleanup:
|
||||
close(fd);
|
||||
unlink(path);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (strcmp(argv[1],"ls")==0) {
|
||||
bool repeat = false;
|
||||
@@ -95,6 +144,11 @@ int main(int argc, char** argv) {
|
||||
timeout = atoi(argv[2]);
|
||||
}
|
||||
main_sleepmillis(timeout);
|
||||
} else if (strcmp(argv[1],"open-rdonly")==0) {
|
||||
main_open_rdonly();
|
||||
|
||||
} else if (strcmp(argv[1],"open-wronly")==0) {
|
||||
main_open_wronly();
|
||||
|
||||
} else {
|
||||
fprintf(stderr, "unknown command: %s\n", argv[1]);
|
||||
|
||||
Binary file not shown.
@@ -311,3 +311,35 @@ func Test_Sleep(t *testing.T) {
|
||||
require.True(t, time.Since(start) >= 100*time.Millisecond)
|
||||
require.Equal(t, "OK\n", console)
|
||||
}
|
||||
|
||||
func Test_open(t *testing.T) {
|
||||
for toolchain, bin := range map[string][]byte{
|
||||
"zig-cc": wasmZigCc,
|
||||
} {
|
||||
toolchain := toolchain
|
||||
bin := bin
|
||||
t.Run(toolchain, func(t *testing.T) {
|
||||
testOpenReadOnly(t, bin)
|
||||
testOpenWriteOnly(t, bin)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func testOpenReadOnly(t *testing.T, bin []byte) {
|
||||
testOpen(t, "rdonly", bin)
|
||||
}
|
||||
|
||||
func testOpenWriteOnly(t *testing.T, bin []byte) {
|
||||
testOpen(t, "wronly", bin)
|
||||
}
|
||||
|
||||
func testOpen(t *testing.T, cmd string, bin []byte) {
|
||||
t.Run(cmd, func(t *testing.T) {
|
||||
moduleConfig := wazero.NewModuleConfig().
|
||||
WithArgs("wasi", "open-"+cmd).
|
||||
WithFSConfig(wazero.NewFSConfig().WithDirMount(t.TempDir(), "/"))
|
||||
|
||||
console := compileAndRun(t, moduleConfig, bin)
|
||||
require.Equal(t, "OK", strings.TrimSpace(console))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -87,8 +87,14 @@ func isSymlink(path string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// The following is lifted from syscall_windows.go to add support for setting FILE_SHARE_DELETE.
|
||||
// https://github.com/golang/go/blob/go1.20/src/syscall/syscall_windows.go#L308-L379
|
||||
// # Differences from syscall.Open
|
||||
//
|
||||
// This code is based on syscall.Open from the below link with some differences
|
||||
// https://github.com/golang/go/blame/go1.20/src/syscall/syscall_windows.go#L308-L379
|
||||
//
|
||||
// - syscall.O_CREAT doesn't imply syscall.GENERIC_WRITE as that breaks
|
||||
// flag expectations in wasi.
|
||||
// - add support for setting FILE_SHARE_DELETE.
|
||||
func open(path string, mode int, perm uint32) (fd syscall.Handle, err error) {
|
||||
if len(path) == 0 {
|
||||
return syscall.InvalidHandle, syscall.ERROR_FILE_NOT_FOUND
|
||||
@@ -106,9 +112,6 @@ func open(path string, mode int, perm uint32) (fd syscall.Handle, err error) {
|
||||
case syscall.O_RDWR:
|
||||
access = syscall.GENERIC_READ | syscall.GENERIC_WRITE
|
||||
}
|
||||
if mode&syscall.O_CREAT != 0 {
|
||||
access |= syscall.GENERIC_WRITE
|
||||
}
|
||||
if mode&syscall.O_APPEND != 0 {
|
||||
access &^= syscall.GENERIC_WRITE
|
||||
access |= syscall.FILE_APPEND_DATA
|
||||
|
||||
Reference in New Issue
Block a user