| author | |
| committer | |
| log | d4215ffaa04b976400bd597cca0cca8182068bf6 |
| tree | b0047c72d94c145fc0abc2eb77c30a10247acfa8 |
| parent | 143127529b109971c931cce18cc7a328f6031df3 |
3 files changed, 70 insertions(+), 134 deletions(-)
lib/std/Io/Threaded.zig+69-1| ... | ... | @@ -190,7 +190,7 @@ pub fn io(t: *Threaded) Io { |
| 190 | 190 | }, |
| 191 | 191 | .dirCreateFile = switch (builtin.os.tag) { |
| 192 | 192 | .windows => @panic("TODO"), |
| 193 | .wasi => @panic("TODO"), | |
| 193 | .wasi => dirCreateFileWasi, | |
| 194 | 194 | else => dirCreateFilePosix, |
| 195 | 195 | }, |
| 196 | 196 | .dirOpenFile = dirOpenFile, |
| ... | ... | @@ -1378,6 +1378,74 @@ fn dirCreateFilePosix( |
| 1378 | 1378 | return .{ .handle = fd }; |
| 1379 | 1379 | } |
| 1380 | 1380 | |
| 1381 | fn dirCreateFileWasi( | |
| 1382 | userdata: ?*anyopaque, | |
| 1383 | dir: Io.Dir, | |
| 1384 | sub_path: []const u8, | |
| 1385 | flags: Io.File.CreateFlags, | |
| 1386 | ) Io.File.OpenError!Io.File { | |
| 1387 | const t: *Threaded = @ptrCast(@alignCast(userdata)); | |
| 1388 | const wasi = std.os.wasi; | |
| 1389 | const lookup_flags: wasi.lookupflags_t = .{}; | |
| 1390 | const oflags: wasi.oflags_t = .{ | |
| 1391 | .CREAT = true, | |
| 1392 | .TRUNC = flags.truncate, | |
| 1393 | .EXCL = flags.exclusive, | |
| 1394 | }; | |
| 1395 | const fdflags: wasi.fdflags_t = .{}; | |
| 1396 | const base: wasi.rights_t = .{ | |
| 1397 | .FD_READ = flags.read, | |
| 1398 | .FD_WRITE = true, | |
| 1399 | .FD_DATASYNC = true, | |
| 1400 | .FD_SEEK = true, | |
| 1401 | .FD_TELL = true, | |
| 1402 | .FD_FDSTAT_SET_FLAGS = true, | |
| 1403 | .FD_SYNC = true, | |
| 1404 | .FD_ALLOCATE = true, | |
| 1405 | .FD_ADVISE = true, | |
| 1406 | .FD_FILESTAT_SET_TIMES = true, | |
| 1407 | .FD_FILESTAT_SET_SIZE = true, | |
| 1408 | .FD_FILESTAT_GET = true, | |
| 1409 | // POLL_FD_READWRITE only grants extra rights if the corresponding FD_READ and/or | |
| 1410 | // FD_WRITE is also set. | |
| 1411 | .POLL_FD_READWRITE = true, | |
| 1412 | }; | |
| 1413 | const inheriting: wasi.rights_t = .{}; | |
| 1414 | var fd: posix.fd_t = undefined; | |
| 1415 | while (true) { | |
| 1416 | try t.checkCancel(); | |
| 1417 | switch (wasi.path_open(dir.handle, lookup_flags, sub_path.ptr, sub_path.len, oflags, base, inheriting, fdflags, &fd)) { | |
| 1418 | .SUCCESS => return .{ .handle = fd }, | |
| 1419 | .INTR => continue, | |
| 1420 | .CANCELED => return error.Canceled, | |
| 1421 | ||
| 1422 | .FAULT => |err| return errnoBug(err), | |
| 1423 | // Provides INVAL with a linux host on a bad path name, but NOENT on Windows | |
| 1424 | .INVAL => return error.BadPathName, | |
| 1425 | .BADF => |err| return errnoBug(err), | |
| 1426 | .ACCES => return error.AccessDenied, | |
| 1427 | .FBIG => return error.FileTooBig, | |
| 1428 | .OVERFLOW => return error.FileTooBig, | |
| 1429 | .ISDIR => return error.IsDir, | |
| 1430 | .LOOP => return error.SymLinkLoop, | |
| 1431 | .MFILE => return error.ProcessFdQuotaExceeded, | |
| 1432 | .NAMETOOLONG => return error.NameTooLong, | |
| 1433 | .NFILE => return error.SystemFdQuotaExceeded, | |
| 1434 | .NODEV => return error.NoDevice, | |
| 1435 | .NOENT => return error.FileNotFound, | |
| 1436 | .NOMEM => return error.SystemResources, | |
| 1437 | .NOSPC => return error.NoSpaceLeft, | |
| 1438 | .NOTDIR => return error.NotDir, | |
| 1439 | .PERM => return error.PermissionDenied, | |
| 1440 | .EXIST => return error.PathAlreadyExists, | |
| 1441 | .BUSY => return error.DeviceBusy, | |
| 1442 | .NOTCAPABLE => return error.AccessDenied, | |
| 1443 | .ILSEQ => return error.BadPathName, | |
| 1444 | else => |err| return posix.unexpectedErrno(err), | |
| 1445 | } | |
| 1446 | } | |
| 1447 | } | |
| 1448 | ||
| 1381 | 1449 | fn dirOpenFile( |
| 1382 | 1450 | userdata: ?*anyopaque, |
| 1383 | 1451 | dir: Io.Dir, |
lib/std/fs/Dir.zig-25| ... | ... | @@ -938,31 +938,6 @@ pub fn createFile(self: Dir, sub_path: []const u8, flags: File.CreateFlags) File |
| 938 | 938 | const path_w = try windows.sliceToPrefixedFileW(self.fd, sub_path); |
| 939 | 939 | return self.createFileW(path_w.span(), flags); |
| 940 | 940 | } |
| 941 | if (native_os == .wasi) { | |
| 942 | return .{ | |
| 943 | .handle = try posix.openatWasi(self.fd, sub_path, .{}, .{ | |
| 944 | .CREAT = true, | |
| 945 | .TRUNC = flags.truncate, | |
| 946 | .EXCL = flags.exclusive, | |
| 947 | }, .{}, .{ | |
| 948 | .FD_READ = flags.read, | |
| 949 | .FD_WRITE = true, | |
| 950 | .FD_DATASYNC = true, | |
| 951 | .FD_SEEK = true, | |
| 952 | .FD_TELL = true, | |
| 953 | .FD_FDSTAT_SET_FLAGS = true, | |
| 954 | .FD_SYNC = true, | |
| 955 | .FD_ALLOCATE = true, | |
| 956 | .FD_ADVISE = true, | |
| 957 | .FD_FILESTAT_SET_TIMES = true, | |
| 958 | .FD_FILESTAT_SET_SIZE = true, | |
| 959 | .FD_FILESTAT_GET = true, | |
| 960 | // POLL_FD_READWRITE only grants extra rights if the corresponding FD_READ and/or | |
| 961 | // FD_WRITE is also set. | |
| 962 | .POLL_FD_READWRITE = true, | |
| 963 | }, .{}), | |
| 964 | }; | |
| 965 | } | |
| 966 | 941 | var threaded: Io.Threaded = .init_single_threaded; |
| 967 | 942 | const io = threaded.io(); |
| 968 | 943 | const new_file = try Io.Dir.createFile(self.adaptToNewApi(), io, sub_path, flags); |
lib/std/posix.zig+1-108| ... | ... | @@ -1610,119 +1610,12 @@ pub fn openat(dir_fd: fd_t, file_path: []const u8, flags: O, mode: mode_t) OpenE |
| 1610 | 1610 | if (native_os == .windows) { |
| 1611 | 1611 | @compileError("Windows does not support POSIX; use Windows-specific API or cross-platform std.fs API"); |
| 1612 | 1612 | } else if (native_os == .wasi and !builtin.link_libc) { |
| 1613 | // `mode` is ignored on WASI, which does not support unix-style file permissions | |
| 1614 | const opts = try openOptionsFromFlagsWasi(flags); | |
| 1615 | const fd = try openatWasi( | |
| 1616 | dir_fd, | |
| 1617 | file_path, | |
| 1618 | opts.lookup_flags, | |
| 1619 | opts.oflags, | |
| 1620 | opts.fs_flags, | |
| 1621 | opts.fs_rights_base, | |
| 1622 | opts.fs_rights_inheriting, | |
| 1623 | ); | |
| 1624 | errdefer close(fd); | |
| 1625 | ||
| 1626 | if (flags.write) { | |
| 1627 | const info = try std.os.fstat_wasi(fd); | |
| 1628 | if (info.filetype == .DIRECTORY) | |
| 1629 | return error.IsDir; | |
| 1630 | } | |
| 1631 | ||
| 1632 | return fd; | |
| 1613 | @compileError("use std.Io instead"); | |
| 1633 | 1614 | } |
| 1634 | 1615 | const file_path_c = try toPosixPath(file_path); |
| 1635 | 1616 | return openatZ(dir_fd, &file_path_c, flags, mode); |
| 1636 | 1617 | } |
| 1637 | 1618 | |
| 1638 | /// Open and possibly create a file in WASI. | |
| 1639 | pub fn openatWasi( | |
| 1640 | dir_fd: fd_t, | |
| 1641 | file_path: []const u8, | |
| 1642 | lookup_flags: wasi.lookupflags_t, | |
| 1643 | oflags: wasi.oflags_t, | |
| 1644 | fdflags: wasi.fdflags_t, | |
| 1645 | base: wasi.rights_t, | |
| 1646 | inheriting: wasi.rights_t, | |
| 1647 | ) OpenError!fd_t { | |
| 1648 | while (true) { | |
| 1649 | var fd: fd_t = undefined; | |
| 1650 | switch (wasi.path_open(dir_fd, lookup_flags, file_path.ptr, file_path.len, oflags, base, inheriting, fdflags, &fd)) { | |
| 1651 | .SUCCESS => return fd, | |
| 1652 | .INTR => continue, | |
| 1653 | ||
| 1654 | .FAULT => unreachable, | |
| 1655 | // Provides INVAL with a linux host on a bad path name, but NOENT on Windows | |
| 1656 | .INVAL => return error.BadPathName, | |
| 1657 | .BADF => unreachable, | |
| 1658 | .ACCES => return error.AccessDenied, | |
| 1659 | .FBIG => return error.FileTooBig, | |
| 1660 | .OVERFLOW => return error.FileTooBig, | |
| 1661 | .ISDIR => return error.IsDir, | |
| 1662 | .LOOP => return error.SymLinkLoop, | |
| 1663 | .MFILE => return error.ProcessFdQuotaExceeded, | |
| 1664 | .NAMETOOLONG => return error.NameTooLong, | |
| 1665 | .NFILE => return error.SystemFdQuotaExceeded, | |
| 1666 | .NODEV => return error.NoDevice, | |
| 1667 | .NOENT => return error.FileNotFound, | |
| 1668 | .NOMEM => return error.SystemResources, | |
| 1669 | .NOSPC => return error.NoSpaceLeft, | |
| 1670 | .NOTDIR => return error.NotDir, | |
| 1671 | .PERM => return error.PermissionDenied, | |
| 1672 | .EXIST => return error.PathAlreadyExists, | |
| 1673 | .BUSY => return error.DeviceBusy, | |
| 1674 | .NOTCAPABLE => return error.AccessDenied, | |
| 1675 | .ILSEQ => return error.BadPathName, | |
| 1676 | else => |err| return unexpectedErrno(err), | |
| 1677 | } | |
| 1678 | } | |
| 1679 | } | |
| 1680 | ||
| 1681 | /// A struct to contain all lookup/rights flags accepted by `wasi.path_open` | |
| 1682 | const WasiOpenOptions = struct { | |
| 1683 | oflags: wasi.oflags_t, | |
| 1684 | lookup_flags: wasi.lookupflags_t, | |
| 1685 | fs_rights_base: wasi.rights_t, | |
| 1686 | fs_rights_inheriting: wasi.rights_t, | |
| 1687 | fs_flags: wasi.fdflags_t, | |
| 1688 | }; | |
| 1689 | ||
| 1690 | /// Compute rights + flags corresponding to the provided POSIX access mode. | |
| 1691 | fn openOptionsFromFlagsWasi(oflag: O) OpenError!WasiOpenOptions { | |
| 1692 | const w = std.os.wasi; | |
| 1693 | ||
| 1694 | // Next, calculate the read/write rights to request, depending on the | |
| 1695 | // provided POSIX access mode | |
| 1696 | var rights: w.rights_t = .{}; | |
| 1697 | if (oflag.read) { | |
| 1698 | rights.FD_READ = true; | |
| 1699 | rights.FD_READDIR = true; | |
| 1700 | } | |
| 1701 | if (oflag.write) { | |
| 1702 | rights.FD_DATASYNC = true; | |
| 1703 | rights.FD_WRITE = true; | |
| 1704 | rights.FD_ALLOCATE = true; | |
| 1705 | rights.FD_FILESTAT_SET_SIZE = true; | |
| 1706 | } | |
| 1707 | ||
| 1708 | // https://github.com/ziglang/zig/issues/18882 | |
| 1709 | const flag_bits: u32 = @bitCast(oflag); | |
| 1710 | const oflags_int: u16 = @as(u12, @truncate(flag_bits >> 12)); | |
| 1711 | const fs_flags_int: u16 = @as(u12, @truncate(flag_bits)); | |
| 1712 | ||
| 1713 | return .{ | |
| 1714 | // https://github.com/ziglang/zig/issues/18882 | |
| 1715 | .oflags = @bitCast(oflags_int), | |
| 1716 | .lookup_flags = .{ | |
| 1717 | .SYMLINK_FOLLOW = !oflag.NOFOLLOW, | |
| 1718 | }, | |
| 1719 | .fs_rights_base = rights, | |
| 1720 | .fs_rights_inheriting = rights, | |
| 1721 | // https://github.com/ziglang/zig/issues/18882 | |
| 1722 | .fs_flags = @bitCast(fs_flags_int), | |
| 1723 | }; | |
| 1724 | } | |
| 1725 | ||
| 1726 | 1619 | /// Open and possibly create a file. Keeps trying if it gets interrupted. |
| 1727 | 1620 | /// `file_path` is relative to the open directory handle `dir_fd`. |
| 1728 | 1621 | /// On Windows, `file_path` should be encoded as [WTF-8](https://wtf-8.codeberg.page/). |