@@ -923,6 +923,7 @@ pub const Dir = struct {
923
923
pub const OpenError = error {
924
924
FileNotFound ,
925
925
NotDir ,
926
+ InvalidHandle ,
926
927
AccessDenied ,
927
928
SymLinkLoop ,
928
929
ProcessFdQuotaExceeded ,
@@ -981,6 +982,13 @@ pub const Dir = struct {
981
982
w .RIGHT .FD_FILESTAT_SET_TIMES |
982
983
w .RIGHT .FD_FILESTAT_SET_SIZE ;
983
984
}
985
+ if (self .fd == os .wasi .AT .FDCWD or path .isAbsolute (sub_path )) {
986
+ // Resolve absolute or CWD-relative paths to a path within a Preopen
987
+ var resolved_path_buf : [MAX_PATH_BYTES ]u8 = undefined ;
988
+ const resolved_path = try os .resolvePathWasi (sub_path , & resolved_path_buf );
989
+ const fd = try os .openatWasi (resolved_path .dir_fd , resolved_path .relative_path , 0x0 , 0x0 , fdflags , base , 0x0 );
990
+ return File { .handle = fd };
991
+ }
984
992
const fd = try os .openatWasi (self .fd , sub_path , 0x0 , 0x0 , fdflags , base , 0x0 );
985
993
return File { .handle = fd };
986
994
}
@@ -1145,6 +1153,13 @@ pub const Dir = struct {
1145
1153
if (flags .exclusive ) {
1146
1154
oflags |= w .O .EXCL ;
1147
1155
}
1156
+ if (self .fd == os .wasi .AT .FDCWD or path .isAbsolute (sub_path )) {
1157
+ // Resolve absolute or CWD-relative paths to a path within a Preopen
1158
+ var resolved_path_buf : [MAX_PATH_BYTES ]u8 = undefined ;
1159
+ const resolved_path = try os .resolvePathWasi (sub_path , & resolved_path_buf );
1160
+ const fd = try os .openatWasi (resolved_path .dir_fd , resolved_path .relative_path , 0x0 , oflags , 0x0 , base , 0x0 );
1161
+ return File { .handle = fd };
1162
+ }
1148
1163
const fd = try os .openatWasi (self .fd , sub_path , 0x0 , oflags , 0x0 , base , 0x0 );
1149
1164
return File { .handle = fd };
1150
1165
}
@@ -1330,7 +1345,19 @@ pub const Dir = struct {
1330
1345
/// See also `Dir.realpathZ`, `Dir.realpathW`, and `Dir.realpathAlloc`.
1331
1346
pub fn realpath (self : Dir , pathname : []const u8 , out_buffer : []u8 ) ! []u8 {
1332
1347
if (builtin .os .tag == .wasi ) {
1333
- @compileError ("realpath is unsupported in WASI" );
1348
+ if (self .fd == os .wasi .AT .FDCWD or path .isAbsolute (pathname )) {
1349
+ var buffer : [MAX_PATH_BYTES ]u8 = undefined ;
1350
+ const out_path = try os .realpath (pathname , & buffer );
1351
+ if (out_path .len > out_buffer .len ) {
1352
+ return error .NameTooLong ;
1353
+ }
1354
+ mem .copy (u8 , out_buffer , out_path );
1355
+ return out_buffer [0.. out_path .len ];
1356
+ } else {
1357
+ // Unfortunately, we have no ability to look up the path for an fd_t
1358
+ // on WASI, so we have to give up here.
1359
+ return error .InvalidHandle ;
1360
+ }
1334
1361
}
1335
1362
if (builtin .os .tag == .windows ) {
1336
1363
const pathname_w = try os .windows .sliceToPrefixedFileW (pathname );
@@ -1507,7 +1534,16 @@ pub const Dir = struct {
1507
1534
// TODO do we really need all the rights here?
1508
1535
const inheriting : w.rights_t = w .RIGHT .ALL ^ w .RIGHT .SOCK_SHUTDOWN ;
1509
1536
1510
- const result = os .openatWasi (self .fd , sub_path , symlink_flags , w .O .DIRECTORY , 0x0 , base , inheriting );
1537
+ const result = blk : {
1538
+ if (self .fd == os .wasi .AT .FDCWD or path .isAbsolute (sub_path )) {
1539
+ // Resolve absolute or CWD-relative paths to a path within a Preopen
1540
+ var resolved_path_buf : [MAX_PATH_BYTES ]u8 = undefined ;
1541
+ const resolved_path = try os .resolvePathWasi (sub_path , & resolved_path_buf );
1542
+ break :blk os .openatWasi (resolved_path .dir_fd , resolved_path .relative_path , symlink_flags , w .O .DIRECTORY , 0x0 , base , inheriting );
1543
+ } else {
1544
+ break :blk os .openatWasi (self .fd , sub_path , symlink_flags , w .O .DIRECTORY , 0x0 , base , inheriting );
1545
+ }
1546
+ };
1511
1547
const fd = result catch | err | switch (err ) {
1512
1548
error .FileTooBig = > unreachable , // can't happen for directories
1513
1549
error .IsDir = > unreachable , // we're providing O.DIRECTORY
@@ -1622,7 +1658,7 @@ pub const Dir = struct {
1622
1658
const sub_path_w = try os .windows .sliceToPrefixedFileW (sub_path );
1623
1659
return self .deleteFileW (sub_path_w .span ());
1624
1660
} else if (builtin .os .tag == .wasi and ! builtin .link_libc ) {
1625
- os .unlinkatWasi (self .fd , sub_path , 0 ) catch | err | switch (err ) {
1661
+ os .unlinkat (self .fd , sub_path , 0 ) catch | err | switch (err ) {
1626
1662
error .DirNotEmpty = > unreachable , // not passing AT.REMOVEDIR
1627
1663
else = > | e | return e ,
1628
1664
};
@@ -1761,7 +1797,7 @@ pub const Dir = struct {
1761
1797
sym_link_path : []const u8 ,
1762
1798
_ : SymLinkFlags ,
1763
1799
) ! void {
1764
- return os .symlinkatWasi (target_path , self .fd , sym_link_path );
1800
+ return os .symlinkat (target_path , self .fd , sym_link_path );
1765
1801
}
1766
1802
1767
1803
/// Same as `symLink`, except the pathname parameters are null-terminated.
@@ -1807,7 +1843,7 @@ pub const Dir = struct {
1807
1843
1808
1844
/// WASI-only. Same as `readLink` except targeting WASI.
1809
1845
pub fn readLinkWasi (self : Dir , sub_path : []const u8 , buffer : []u8 ) ! []u8 {
1810
- return os .readlinkatWasi (self .fd , sub_path , buffer );
1846
+ return os .readlinkat (self .fd , sub_path , buffer );
1811
1847
}
1812
1848
1813
1849
/// Same as `readLink`, except the `pathname` parameter is null-terminated.
@@ -1870,6 +1906,7 @@ pub const Dir = struct {
1870
1906
}
1871
1907
1872
1908
pub const DeleteTreeError = error {
1909
+ InvalidHandle ,
1873
1910
AccessDenied ,
1874
1911
FileTooBig ,
1875
1912
SymLinkLoop ,
@@ -1935,6 +1972,7 @@ pub const Dir = struct {
1935
1972
continue :start_over ;
1936
1973
},
1937
1974
1975
+ error .InvalidHandle ,
1938
1976
error .AccessDenied ,
1939
1977
error .SymLinkLoop ,
1940
1978
error .ProcessFdQuotaExceeded ,
@@ -2002,6 +2040,7 @@ pub const Dir = struct {
2002
2040
continue :scan_dir ;
2003
2041
},
2004
2042
2043
+ error .InvalidHandle ,
2005
2044
error .AccessDenied ,
2006
2045
error .SymLinkLoop ,
2007
2046
error .ProcessFdQuotaExceeded ,
@@ -2272,8 +2311,6 @@ pub const Dir = struct {
2272
2311
pub fn cwd () Dir {
2273
2312
if (builtin .os .tag == .windows ) {
2274
2313
return Dir { .fd = os .windows .peb ().ProcessParameters .CurrentDirectory .Handle };
2275
- } else if (builtin .os .tag == .wasi and ! builtin .link_libc ) {
2276
- @compileError ("WASI doesn't have a concept of cwd(); use std.fs.wasi.PreopenList to get available Dir handles instead" );
2277
2314
} else {
2278
2315
return Dir { .fd = os .AT .FDCWD };
2279
2316
}
@@ -2285,26 +2322,17 @@ pub fn cwd() Dir {
2285
2322
///
2286
2323
/// Asserts that the path parameter has no null bytes.
2287
2324
pub fn openDirAbsolute (absolute_path : []const u8 , flags : Dir.OpenDirOptions ) File.OpenError ! Dir {
2288
- if (builtin .os .tag == .wasi ) {
2289
- @compileError ("WASI doesn't have the concept of an absolute directory; use openDir instead for WASI." );
2290
- }
2291
2325
assert (path .isAbsolute (absolute_path ));
2292
2326
return cwd ().openDir (absolute_path , flags );
2293
2327
}
2294
2328
2295
2329
/// Same as `openDirAbsolute` but the path parameter is null-terminated.
2296
2330
pub fn openDirAbsoluteZ (absolute_path_c : [* :0 ]const u8 , flags : Dir.OpenDirOptions ) File.OpenError ! Dir {
2297
- if (builtin .os .tag == .wasi ) {
2298
- @compileError ("WASI doesn't have the concept of an absolute directory; use openDir instead for WASI." );
2299
- }
2300
2331
assert (path .isAbsoluteZ (absolute_path_c ));
2301
2332
return cwd ().openDirZ (absolute_path_c , flags );
2302
2333
}
2303
2334
/// Same as `openDirAbsolute` but the path parameter is null-terminated.
2304
2335
pub fn openDirAbsoluteW (absolute_path_c : [* :0 ]const u16 , flags : Dir.OpenDirOptions ) File.OpenError ! Dir {
2305
- if (builtin .os .tag == .wasi ) {
2306
- @compileError ("WASI doesn't have the concept of an absolute directory; use openDir instead for WASI." );
2307
- }
2308
2336
assert (path .isAbsoluteWindowsW (absolute_path_c ));
2309
2337
return cwd ().openDirW (absolute_path_c , flags );
2310
2338
}
@@ -2339,25 +2367,16 @@ pub fn openFileAbsoluteW(absolute_path_w: []const u16, flags: File.OpenFlags) Fi
2339
2367
/// open it and handle the error for file not found.
2340
2368
/// See `accessAbsoluteZ` for a function that accepts a null-terminated path.
2341
2369
pub fn accessAbsolute (absolute_path : []const u8 , flags : File.OpenFlags ) Dir.AccessError ! void {
2342
- if (builtin .os .tag == .wasi ) {
2343
- @compileError ("WASI doesn't have the concept of an absolute path; use access instead for WASI." );
2344
- }
2345
2370
assert (path .isAbsolute (absolute_path ));
2346
2371
try cwd ().access (absolute_path , flags );
2347
2372
}
2348
2373
/// Same as `accessAbsolute` but the path parameter is null-terminated.
2349
2374
pub fn accessAbsoluteZ (absolute_path : [* :0 ]const u8 , flags : File.OpenFlags ) Dir.AccessError ! void {
2350
- if (builtin .os .tag == .wasi ) {
2351
- @compileError ("WASI doesn't have the concept of an absolute path; use access instead for WASI." );
2352
- }
2353
2375
assert (path .isAbsoluteZ (absolute_path ));
2354
2376
try cwd ().accessZ (absolute_path , flags );
2355
2377
}
2356
2378
/// Same as `accessAbsolute` but the path parameter is WTF-16 encoded.
2357
2379
pub fn accessAbsoluteW (absolute_path : [* :0 ]const 16 , flags : File.OpenFlags ) Dir.AccessError ! void {
2358
- if (builtin .os .tag == .wasi ) {
2359
- @compileError ("WASI doesn't have the concept of an absolute path; use access instead for WASI." );
2360
- }
2361
2380
assert (path .isAbsoluteWindowsW (absolute_path ));
2362
2381
try cwd ().accessW (absolute_path , flags );
2363
2382
}
@@ -2458,9 +2477,6 @@ pub const SymLinkFlags = struct {
2458
2477
/// If `sym_link_path` exists, it will not be overwritten.
2459
2478
/// See also `symLinkAbsoluteZ` and `symLinkAbsoluteW`.
2460
2479
pub fn symLinkAbsolute (target_path : []const u8 , sym_link_path : []const u8 , flags : SymLinkFlags ) ! void {
2461
- if (builtin .os .tag == .wasi ) {
2462
- @compileError ("symLinkAbsolute is not supported in WASI; use Dir.symLinkWasi instead" );
2463
- }
2464
2480
assert (path .isAbsolute (target_path ));
2465
2481
assert (path .isAbsolute (sym_link_path ));
2466
2482
if (builtin .os .tag == .windows ) {
0 commit comments