| ... | @@ -167,7 +167,7 @@ pub fn io(t: *Threaded) Io { | ... | @@ -167,7 +167,7 @@ pub fn io(t: *Threaded) Io { |
| 167 | | 167 | |
| 168 | .dirMake = switch (builtin.os.tag) { | 168 | .dirMake = switch (builtin.os.tag) { |
| 169 | .windows => @panic("TODO"), | 169 | .windows => @panic("TODO"), |
| 170 | .wasi => @panic("TODO"), | 170 | .wasi => dirMakeWasi, |
| 171 | else => dirMakePosix, | 171 | else => dirMakePosix, |
| 172 | }, | 172 | }, |
| 173 | .dirStat = dirStat, | 173 | .dirStat = dirStat, |
| ... | @@ -906,6 +906,37 @@ fn dirMakePosix(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, mode: | ... | @@ -906,6 +906,37 @@ fn dirMakePosix(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, mode: |
| 906 | } | 906 | } |
| 907 | } | 907 | } |
| 908 | | 908 | |
| | 909 | fn dirMakeWasi(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, mode: Io.Dir.Mode) Io.Dir.MakeError!void { |
| | 910 | if (builtin.link_libc) return dirMakePosix(userdata, dir, sub_path, mode); |
| | 911 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| | 912 | while (true) { |
| | 913 | try t.checkCancel(); |
| | 914 | switch (std.os.wasi.path_create_directory(dir.handle, sub_path.ptr, sub_path.len)) { |
| | 915 | .SUCCESS => return, |
| | 916 | .INTR => continue, |
| | 917 | .CANCELED => return error.Canceled, |
| | 918 | |
| | 919 | .ACCES => return error.AccessDenied, |
| | 920 | .BADF => |err| return errnoBug(err), |
| | 921 | .PERM => return error.PermissionDenied, |
| | 922 | .DQUOT => return error.DiskQuota, |
| | 923 | .EXIST => return error.PathAlreadyExists, |
| | 924 | .FAULT => |err| return errnoBug(err), |
| | 925 | .LOOP => return error.SymLinkLoop, |
| | 926 | .MLINK => return error.LinkQuotaExceeded, |
| | 927 | .NAMETOOLONG => return error.NameTooLong, |
| | 928 | .NOENT => return error.FileNotFound, |
| | 929 | .NOMEM => return error.SystemResources, |
| | 930 | .NOSPC => return error.NoSpaceLeft, |
| | 931 | .NOTDIR => return error.NotDir, |
| | 932 | .ROFS => return error.ReadOnlyFileSystem, |
| | 933 | .NOTCAPABLE => return error.AccessDenied, |
| | 934 | .ILSEQ => return error.BadPathName, |
| | 935 | else => |err| return posix.unexpectedErrno(err), |
| | 936 | } |
| | 937 | } |
| | 938 | } |
| | 939 | |
| 909 | fn dirStat(userdata: ?*anyopaque, dir: Io.Dir) Io.Dir.StatError!Io.Dir.Stat { | 940 | fn dirStat(userdata: ?*anyopaque, dir: Io.Dir) Io.Dir.StatError!Io.Dir.Stat { |
| 910 | const t: *Threaded = @ptrCast(@alignCast(userdata)); | 941 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 911 | try t.checkCancel(); | 942 | try t.checkCancel(); |
| ... | @@ -1005,13 +1036,13 @@ fn dirStatPathWasi( | ... | @@ -1005,13 +1036,13 @@ fn dirStatPathWasi( |
| 1005 | const t: *Threaded = @ptrCast(@alignCast(userdata)); | 1036 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 1006 | const wasi = std.os.wasi; | 1037 | const wasi = std.os.wasi; |
| 1007 | const flags: wasi.lookupflags_t = .{ | 1038 | const flags: wasi.lookupflags_t = .{ |
| 1008 | .SYMLINK_FOLLOW = @intFromBool(options.follow_symlinks), | 1039 | .SYMLINK_FOLLOW = options.follow_symlinks, |
| 1009 | }; | 1040 | }; |
| 1010 | var stat: wasi.filestat_t = undefined; | 1041 | var stat: wasi.filestat_t = undefined; |
| 1011 | while (true) { | 1042 | while (true) { |
| 1012 | try t.checkCancel(); | 1043 | try t.checkCancel(); |
| 1013 | switch (wasi.path_filestat_get(dir.handle, flags, sub_path.ptr, sub_path.len, &stat)) { | 1044 | switch (wasi.path_filestat_get(dir.handle, flags, sub_path.ptr, sub_path.len, &stat)) { |
| 1014 | .SUCCESS => return statFromWasi(stat), | 1045 | .SUCCESS => return statFromWasi(&stat), |
| 1015 | .INTR => continue, | 1046 | .INTR => continue, |
| 1016 | .CANCELED => return error.Canceled, | 1047 | .CANCELED => return error.Canceled, |
| 1017 | | 1048 | |
| ... | @@ -1166,19 +1197,19 @@ fn dirAccessWasi( | ... | @@ -1166,19 +1197,19 @@ fn dirAccessWasi( |
| 1166 | userdata: ?*anyopaque, | 1197 | userdata: ?*anyopaque, |
| 1167 | dir: Io.Dir, | 1198 | dir: Io.Dir, |
| 1168 | sub_path: []const u8, | 1199 | sub_path: []const u8, |
| 1169 | options: Io.File.OpenFlags, | 1200 | options: Io.Dir.AccessOptions, |
| 1170 | ) Io.File.AccessError!void { | 1201 | ) Io.Dir.AccessError!void { |
| 1171 | if (builtin.link_libc) return dirAccessPosix(userdata, dir, sub_path, options); | 1202 | if (builtin.link_libc) return dirAccessPosix(userdata, dir, sub_path, options); |
| 1172 | const t: *Threaded = @ptrCast(@alignCast(userdata)); | 1203 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 1173 | const wasi = std.os.wasi; | 1204 | const wasi = std.os.wasi; |
| 1174 | const flags: wasi.lookupflags_t = .{ | 1205 | const flags: wasi.lookupflags_t = .{ |
| 1175 | .SYMLINK_FOLLOW = @intFromBool(options.follow_symlinks), | 1206 | .SYMLINK_FOLLOW = options.follow_symlinks, |
| 1176 | }; | 1207 | }; |
| 1177 | const stat = while (true) { | 1208 | var stat: wasi.filestat_t = undefined; |
| 1178 | var stat: wasi.filestat_t = undefined; | 1209 | while (true) { |
| 1179 | try t.checkCancel(); | 1210 | try t.checkCancel(); |
| 1180 | switch (wasi.path_filestat_get(dir.handle, flags, sub_path.ptr, sub_path.len, &stat)) { | 1211 | switch (wasi.path_filestat_get(dir.handle, flags, sub_path.ptr, sub_path.len, &stat)) { |
| 1181 | .SUCCESS => break statFromWasi(stat), | 1212 | .SUCCESS => break, |
| 1182 | .INTR => continue, | 1213 | .INTR => continue, |
| 1183 | .CANCELED => return error.Canceled, | 1214 | .CANCELED => return error.Canceled, |
| 1184 | | 1215 | |
| ... | @@ -1194,9 +1225,9 @@ fn dirAccessWasi( | ... | @@ -1194,9 +1225,9 @@ fn dirAccessWasi( |
| 1194 | .ILSEQ => return error.BadPathName, | 1225 | .ILSEQ => return error.BadPathName, |
| 1195 | else => |err| return posix.unexpectedErrno(err), | 1226 | else => |err| return posix.unexpectedErrno(err), |
| 1196 | } | 1227 | } |
| 1197 | }; | 1228 | } |
| 1198 | | 1229 | |
| 1199 | if (!options.mode.read and !options.mode.write and !options.mode.execute) | 1230 | if (!options.read and !options.write and !options.execute) |
| 1200 | return; | 1231 | return; |
| 1201 | | 1232 | |
| 1202 | var directory: wasi.fdstat_t = undefined; | 1233 | var directory: wasi.fdstat_t = undefined; |
| ... | @@ -1204,14 +1235,14 @@ fn dirAccessWasi( | ... | @@ -1204,14 +1235,14 @@ fn dirAccessWasi( |
| 1204 | return error.AccessDenied; | 1235 | return error.AccessDenied; |
| 1205 | | 1236 | |
| 1206 | var rights: wasi.rights_t = .{}; | 1237 | var rights: wasi.rights_t = .{}; |
| 1207 | if (options.mode.read) { | 1238 | if (options.read) { |
| 1208 | if (stat.filetype == .DIRECTORY) { | 1239 | if (stat.filetype == .DIRECTORY) { |
| 1209 | rights.FD_READDIR = true; | 1240 | rights.FD_READDIR = true; |
| 1210 | } else { | 1241 | } else { |
| 1211 | rights.FD_READ = true; | 1242 | rights.FD_READ = true; |
| 1212 | } | 1243 | } |
| 1213 | } | 1244 | } |
| 1214 | if (options.mode.write) | 1245 | if (options.write) |
| 1215 | rights.FD_WRITE = true; | 1246 | rights.FD_WRITE = true; |
| 1216 | | 1247 | |
| 1217 | // No validation for execution. | 1248 | // No validation for execution. |
| ... | @@ -3262,9 +3293,9 @@ fn statFromWasi(st: *const std.os.wasi.filestat_t) Io.File.Stat { | ... | @@ -3262,9 +3293,9 @@ fn statFromWasi(st: *const std.os.wasi.filestat_t) Io.File.Stat { |
| 3262 | .SOCKET_STREAM, .SOCKET_DGRAM => .unix_domain_socket, | 3293 | .SOCKET_STREAM, .SOCKET_DGRAM => .unix_domain_socket, |
| 3263 | else => .unknown, | 3294 | else => .unknown, |
| 3264 | }, | 3295 | }, |
| 3265 | .atime = st.atim, | 3296 | .atime = .fromNanoseconds(st.atim), |
| 3266 | .mtime = st.mtim, | 3297 | .mtime = .fromNanoseconds(st.mtim), |
| 3267 | .ctime = st.ctim, | 3298 | .ctime = .fromNanoseconds(st.ctim), |
| 3268 | }; | 3299 | }; |
| 3269 | } | 3300 | } |
| 3270 | | 3301 | |