zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

blob d5451f64 (39845B) - Raw


      1 const std = @import("../std.zig");
      2 const os = std.os;
      3 const testing = std.testing;
      4 const expect = testing.expect;
      5 const expectEqual = testing.expectEqual;
      6 const expectError = testing.expectError;
      7 const io = std.io;
      8 const fs = std.fs;
      9 const mem = std.mem;
     10 const elf = std.elf;
     11 const File = std.fs.File;
     12 const Thread = std.Thread;
     13 
     14 const a = std.testing.allocator;
     15 
     16 const builtin = @import("builtin");
     17 const AtomicRmwOp = std.builtin.AtomicRmwOp;
     18 const AtomicOrder = std.builtin.AtomicOrder;
     19 const native_os = builtin.target.os.tag;
     20 const tmpDir = std.testing.tmpDir;
     21 const Dir = std.fs.Dir;
     22 const ArenaAllocator = std.heap.ArenaAllocator;
     23 
     24 test "chdir smoke test" {
     25     if (native_os == .wasi) return error.SkipZigTest;
     26 
     27     if (true) {
     28         // https://github.com/ziglang/zig/issues/14968
     29         return error.SkipZigTest;
     30     }
     31 
     32     // Get current working directory path
     33     var old_cwd_buf: [fs.MAX_PATH_BYTES]u8 = undefined;
     34     const old_cwd = try os.getcwd(old_cwd_buf[0..]);
     35 
     36     {
     37         // Firstly, changing to itself should have no effect
     38         try os.chdir(old_cwd);
     39         var new_cwd_buf: [fs.MAX_PATH_BYTES]u8 = undefined;
     40         const new_cwd = try os.getcwd(new_cwd_buf[0..]);
     41         try expect(mem.eql(u8, old_cwd, new_cwd));
     42     }
     43 
     44     // Next, change current working directory to one level above
     45     if (native_os != .wasi) { // WASI does not support navigating outside of Preopens
     46         const parent = fs.path.dirname(old_cwd) orelse unreachable; // old_cwd should be absolute
     47         try os.chdir(parent);
     48 
     49         // Restore cwd because process may have other tests that do not tolerate chdir.
     50         defer os.chdir(old_cwd) catch unreachable;
     51 
     52         var new_cwd_buf: [fs.MAX_PATH_BYTES]u8 = undefined;
     53         const new_cwd = try os.getcwd(new_cwd_buf[0..]);
     54         try expect(mem.eql(u8, parent, new_cwd));
     55     }
     56 
     57     // Next, change current working directory to a temp directory one level below
     58     {
     59         // Create a tmp directory
     60         var tmp_dir_buf: [fs.MAX_PATH_BYTES]u8 = undefined;
     61         var tmp_dir_path = path: {
     62             var allocator = std.heap.FixedBufferAllocator.init(&tmp_dir_buf);
     63             break :path try fs.path.resolve(allocator.allocator(), &[_][]const u8{ old_cwd, "zig-test-tmp" });
     64         };
     65         var tmp_dir = try fs.cwd().makeOpenPath("zig-test-tmp", .{});
     66 
     67         // Change current working directory to tmp directory
     68         try os.chdir("zig-test-tmp");
     69 
     70         var new_cwd_buf: [fs.MAX_PATH_BYTES]u8 = undefined;
     71         const new_cwd = try os.getcwd(new_cwd_buf[0..]);
     72 
     73         // On Windows, fs.path.resolve returns an uppercase drive letter, but the drive letter returned by getcwd may be lowercase
     74         var resolved_cwd_buf: [fs.MAX_PATH_BYTES]u8 = undefined;
     75         var resolved_cwd = path: {
     76             var allocator = std.heap.FixedBufferAllocator.init(&resolved_cwd_buf);
     77             break :path try fs.path.resolve(allocator.allocator(), &[_][]const u8{new_cwd});
     78         };
     79         try expect(mem.eql(u8, tmp_dir_path, resolved_cwd));
     80 
     81         // Restore cwd because process may have other tests that do not tolerate chdir.
     82         tmp_dir.close();
     83         os.chdir(old_cwd) catch unreachable;
     84         try fs.cwd().deleteDir("zig-test-tmp");
     85     }
     86 }
     87 
     88 test "open smoke test" {
     89     if (native_os == .wasi) return error.SkipZigTest;
     90 
     91     // TODO verify file attributes using `fstat`
     92 
     93     var tmp = tmpDir(.{});
     94     defer tmp.cleanup();
     95 
     96     // Get base abs path
     97     var arena = ArenaAllocator.init(testing.allocator);
     98     defer arena.deinit();
     99     const allocator = arena.allocator();
    100 
    101     const base_path = blk: {
    102         const relative_path = try fs.path.join(allocator, &[_][]const u8{ "zig-cache", "tmp", tmp.sub_path[0..] });
    103         break :blk try fs.realpathAlloc(allocator, relative_path);
    104     };
    105 
    106     var file_path: []u8 = undefined;
    107     var fd: os.fd_t = undefined;
    108     const mode: os.mode_t = if (native_os == .windows) 0 else 0o666;
    109 
    110     // Create some file using `open`.
    111     file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
    112     fd = try os.open(file_path, os.O.RDWR | os.O.CREAT | os.O.EXCL, mode);
    113     os.close(fd);
    114 
    115     // Try this again with the same flags. This op should fail with error.PathAlreadyExists.
    116     file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
    117     try expectError(error.PathAlreadyExists, os.open(file_path, os.O.RDWR | os.O.CREAT | os.O.EXCL, mode));
    118 
    119     // Try opening without `O.EXCL` flag.
    120     file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
    121     fd = try os.open(file_path, os.O.RDWR | os.O.CREAT, mode);
    122     os.close(fd);
    123 
    124     // Try opening as a directory which should fail.
    125     file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
    126     try expectError(error.NotDir, os.open(file_path, os.O.RDWR | os.O.DIRECTORY, mode));
    127 
    128     // Create some directory
    129     file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_dir" });
    130     try os.mkdir(file_path, mode);
    131 
    132     // Open dir using `open`
    133     file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_dir" });
    134     fd = try os.open(file_path, os.O.RDONLY | os.O.DIRECTORY, mode);
    135     os.close(fd);
    136 
    137     // Try opening as file which should fail.
    138     file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_dir" });
    139     try expectError(error.IsDir, os.open(file_path, os.O.RDWR, mode));
    140 }
    141 
    142 test "openat smoke test" {
    143     if (native_os == .wasi and builtin.link_libc) return error.SkipZigTest;
    144 
    145     // TODO verify file attributes using `fstatat`
    146 
    147     var tmp = tmpDir(.{});
    148     defer tmp.cleanup();
    149 
    150     var fd: os.fd_t = undefined;
    151     const mode: os.mode_t = if (native_os == .windows) 0 else 0o666;
    152 
    153     // Create some file using `openat`.
    154     fd = try os.openat(tmp.dir.fd, "some_file", os.O.RDWR | os.O.CREAT | os.O.EXCL, mode);
    155     os.close(fd);
    156 
    157     // Try this again with the same flags. This op should fail with error.PathAlreadyExists.
    158     try expectError(error.PathAlreadyExists, os.openat(tmp.dir.fd, "some_file", os.O.RDWR | os.O.CREAT | os.O.EXCL, mode));
    159 
    160     // Try opening without `O.EXCL` flag.
    161     fd = try os.openat(tmp.dir.fd, "some_file", os.O.RDWR | os.O.CREAT, mode);
    162     os.close(fd);
    163 
    164     // Try opening as a directory which should fail.
    165     try expectError(error.NotDir, os.openat(tmp.dir.fd, "some_file", os.O.RDWR | os.O.DIRECTORY, mode));
    166 
    167     // Create some directory
    168     try os.mkdirat(tmp.dir.fd, "some_dir", mode);
    169 
    170     // Open dir using `open`
    171     fd = try os.openat(tmp.dir.fd, "some_dir", os.O.RDONLY | os.O.DIRECTORY, mode);
    172     os.close(fd);
    173 
    174     // Try opening as file which should fail.
    175     try expectError(error.IsDir, os.openat(tmp.dir.fd, "some_dir", os.O.RDWR, mode));
    176 }
    177 
    178 test "symlink with relative paths" {
    179     if (native_os == .wasi and builtin.link_libc) return error.SkipZigTest;
    180 
    181     if (true) {
    182         // https://github.com/ziglang/zig/issues/14968
    183         return error.SkipZigTest;
    184     }
    185     const cwd = fs.cwd();
    186     cwd.deleteFile("file.txt") catch {};
    187     cwd.deleteFile("symlinked") catch {};
    188 
    189     // First, try relative paths in cwd
    190     try cwd.writeFile("file.txt", "nonsense");
    191 
    192     if (native_os == .windows) {
    193         os.windows.CreateSymbolicLink(
    194             cwd.fd,
    195             &[_]u16{ 's', 'y', 'm', 'l', 'i', 'n', 'k', 'e', 'd' },
    196             &[_]u16{ 'f', 'i', 'l', 'e', '.', 't', 'x', 't' },
    197             false,
    198         ) catch |err| switch (err) {
    199             // Symlink requires admin privileges on windows, so this test can legitimately fail.
    200             error.AccessDenied => {
    201                 try cwd.deleteFile("file.txt");
    202                 try cwd.deleteFile("symlinked");
    203                 return error.SkipZigTest;
    204             },
    205             else => return err,
    206         };
    207     } else {
    208         try os.symlink("file.txt", "symlinked");
    209     }
    210 
    211     var buffer: [fs.MAX_PATH_BYTES]u8 = undefined;
    212     const given = try os.readlink("symlinked", buffer[0..]);
    213     try expect(mem.eql(u8, "file.txt", given));
    214 
    215     try cwd.deleteFile("file.txt");
    216     try cwd.deleteFile("symlinked");
    217 }
    218 
    219 test "readlink on Windows" {
    220     if (native_os != .windows) return error.SkipZigTest;
    221 
    222     try testReadlink("C:\\ProgramData", "C:\\Users\\All Users");
    223     try testReadlink("C:\\Users\\Default", "C:\\Users\\Default User");
    224     try testReadlink("C:\\Users", "C:\\Documents and Settings");
    225 }
    226 
    227 fn testReadlink(target_path: []const u8, symlink_path: []const u8) !void {
    228     var buffer: [fs.MAX_PATH_BYTES]u8 = undefined;
    229     const given = try os.readlink(symlink_path, buffer[0..]);
    230     try expect(mem.eql(u8, target_path, given));
    231 }
    232 
    233 test "link with relative paths" {
    234     if (native_os == .wasi and builtin.link_libc) return error.SkipZigTest;
    235 
    236     switch (native_os) {
    237         .wasi, .linux, .solaris => {},
    238         else => return error.SkipZigTest,
    239     }
    240     if (true) {
    241         // https://github.com/ziglang/zig/issues/14968
    242         return error.SkipZigTest;
    243     }
    244     var cwd = fs.cwd();
    245 
    246     cwd.deleteFile("example.txt") catch {};
    247     cwd.deleteFile("new.txt") catch {};
    248 
    249     try cwd.writeFile("example.txt", "example");
    250     try os.link("example.txt", "new.txt", 0);
    251 
    252     const efd = try cwd.openFile("example.txt", .{});
    253     defer efd.close();
    254 
    255     const nfd = try cwd.openFile("new.txt", .{});
    256     defer nfd.close();
    257 
    258     {
    259         const estat = try os.fstat(efd.handle);
    260         const nstat = try os.fstat(nfd.handle);
    261 
    262         try testing.expectEqual(estat.ino, nstat.ino);
    263         try testing.expectEqual(@as(@TypeOf(nstat.nlink), 2), nstat.nlink);
    264     }
    265 
    266     try os.unlink("new.txt");
    267 
    268     {
    269         const estat = try os.fstat(efd.handle);
    270         try testing.expectEqual(@as(@TypeOf(estat.nlink), 1), estat.nlink);
    271     }
    272 
    273     try cwd.deleteFile("example.txt");
    274 }
    275 
    276 test "linkat with different directories" {
    277     if (native_os == .wasi and builtin.link_libc) return error.SkipZigTest;
    278 
    279     switch (native_os) {
    280         .wasi, .linux, .solaris => {},
    281         else => return error.SkipZigTest,
    282     }
    283     if (true) {
    284         // https://github.com/ziglang/zig/issues/14968
    285         return error.SkipZigTest;
    286     }
    287     var cwd = fs.cwd();
    288     var tmp = tmpDir(.{});
    289 
    290     cwd.deleteFile("example.txt") catch {};
    291     tmp.dir.deleteFile("new.txt") catch {};
    292 
    293     try cwd.writeFile("example.txt", "example");
    294     try os.linkat(cwd.fd, "example.txt", tmp.dir.fd, "new.txt", 0);
    295 
    296     const efd = try cwd.openFile("example.txt", .{});
    297     defer efd.close();
    298 
    299     const nfd = try tmp.dir.openFile("new.txt", .{});
    300 
    301     {
    302         defer nfd.close();
    303         const estat = try os.fstat(efd.handle);
    304         const nstat = try os.fstat(nfd.handle);
    305 
    306         try testing.expectEqual(estat.ino, nstat.ino);
    307         try testing.expectEqual(@as(@TypeOf(nstat.nlink), 2), nstat.nlink);
    308     }
    309 
    310     try os.unlinkat(tmp.dir.fd, "new.txt", 0);
    311 
    312     {
    313         const estat = try os.fstat(efd.handle);
    314         try testing.expectEqual(@as(@TypeOf(estat.nlink), 1), estat.nlink);
    315     }
    316 
    317     try cwd.deleteFile("example.txt");
    318 }
    319 
    320 test "fstatat" {
    321     // enable when `fstat` and `fstatat` are implemented on Windows
    322     if (native_os == .windows) return error.SkipZigTest;
    323 
    324     var tmp = tmpDir(.{});
    325     defer tmp.cleanup();
    326 
    327     // create dummy file
    328     const contents = "nonsense";
    329     try tmp.dir.writeFile("file.txt", contents);
    330 
    331     // fetch file's info on the opened fd directly
    332     const file = try tmp.dir.openFile("file.txt", .{});
    333     const stat = try os.fstat(file.handle);
    334     defer file.close();
    335 
    336     // now repeat but using `fstatat` instead
    337     const flags = if (native_os == .wasi) 0x0 else os.AT.SYMLINK_NOFOLLOW;
    338     const statat = try os.fstatat(tmp.dir.fd, "file.txt", flags);
    339     try expectEqual(stat, statat);
    340 }
    341 
    342 test "readlinkat" {
    343     var tmp = tmpDir(.{});
    344     defer tmp.cleanup();
    345 
    346     // create file
    347     try tmp.dir.writeFile("file.txt", "nonsense");
    348 
    349     // create a symbolic link
    350     if (native_os == .windows) {
    351         os.windows.CreateSymbolicLink(
    352             tmp.dir.fd,
    353             &[_]u16{ 'l', 'i', 'n', 'k' },
    354             &[_]u16{ 'f', 'i', 'l', 'e', '.', 't', 'x', 't' },
    355             false,
    356         ) catch |err| switch (err) {
    357             // Symlink requires admin privileges on windows, so this test can legitimately fail.
    358             error.AccessDenied => return error.SkipZigTest,
    359             else => return err,
    360         };
    361     } else {
    362         try os.symlinkat("file.txt", tmp.dir.fd, "link");
    363     }
    364 
    365     // read the link
    366     var buffer: [fs.MAX_PATH_BYTES]u8 = undefined;
    367     const read_link = try os.readlinkat(tmp.dir.fd, "link", buffer[0..]);
    368     try expect(mem.eql(u8, "file.txt", read_link));
    369 }
    370 
    371 fn testThreadIdFn(thread_id: *Thread.Id) void {
    372     thread_id.* = Thread.getCurrentId();
    373 }
    374 
    375 test "std.Thread.getCurrentId" {
    376     if (builtin.single_threaded) return error.SkipZigTest;
    377 
    378     var thread_current_id: Thread.Id = undefined;
    379     const thread = try Thread.spawn(.{}, testThreadIdFn, .{&thread_current_id});
    380     thread.join();
    381     try expect(Thread.getCurrentId() != thread_current_id);
    382 }
    383 
    384 test "spawn threads" {
    385     if (builtin.single_threaded) return error.SkipZigTest;
    386 
    387     var shared_ctx: i32 = 1;
    388 
    389     const thread1 = try Thread.spawn(.{}, start1, .{});
    390     const thread2 = try Thread.spawn(.{}, start2, .{&shared_ctx});
    391     const thread3 = try Thread.spawn(.{}, start2, .{&shared_ctx});
    392     const thread4 = try Thread.spawn(.{}, start2, .{&shared_ctx});
    393 
    394     thread1.join();
    395     thread2.join();
    396     thread3.join();
    397     thread4.join();
    398 
    399     try expect(shared_ctx == 4);
    400 }
    401 
    402 fn start1() u8 {
    403     return 0;
    404 }
    405 
    406 fn start2(ctx: *i32) u8 {
    407     _ = @atomicRmw(i32, ctx, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
    408     return 0;
    409 }
    410 
    411 test "cpu count" {
    412     if (native_os == .wasi) return error.SkipZigTest;
    413 
    414     const cpu_count = try Thread.getCpuCount();
    415     try expect(cpu_count >= 1);
    416 }
    417 
    418 test "thread local storage" {
    419     if (builtin.single_threaded) return error.SkipZigTest;
    420     const thread1 = try Thread.spawn(.{}, testTls, .{});
    421     const thread2 = try Thread.spawn(.{}, testTls, .{});
    422     try testTls();
    423     thread1.join();
    424     thread2.join();
    425 }
    426 
    427 threadlocal var x: i32 = 1234;
    428 fn testTls() !void {
    429     if (x != 1234) return error.TlsBadStartValue;
    430     x += 1;
    431     if (x != 1235) return error.TlsBadEndValue;
    432 }
    433 
    434 test "getrandom" {
    435     var buf_a: [50]u8 = undefined;
    436     var buf_b: [50]u8 = undefined;
    437     try os.getrandom(&buf_a);
    438     try os.getrandom(&buf_b);
    439     // If this test fails the chance is significantly higher that there is a bug than
    440     // that two sets of 50 bytes were equal.
    441     try expect(!mem.eql(u8, &buf_a, &buf_b));
    442 }
    443 
    444 test "getcwd" {
    445     // at least call it so it gets compiled
    446     var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
    447     _ = os.getcwd(&buf) catch undefined;
    448 }
    449 
    450 test "sigaltstack" {
    451     if (native_os == .windows or native_os == .wasi) return error.SkipZigTest;
    452 
    453     var st: os.stack_t = undefined;
    454     try os.sigaltstack(null, &st);
    455     // Setting a stack size less than MINSIGSTKSZ returns ENOMEM
    456     st.flags = 0;
    457     st.size = 1;
    458     try testing.expectError(error.SizeTooSmall, os.sigaltstack(&st, null));
    459 }
    460 
    461 // If the type is not available use void to avoid erroring out when `iter_fn` is
    462 // analyzed
    463 const dl_phdr_info = if (@hasDecl(os.system, "dl_phdr_info")) os.dl_phdr_info else anyopaque;
    464 
    465 const IterFnError = error{
    466     MissingPtLoadSegment,
    467     MissingLoad,
    468     BadElfMagic,
    469     FailedConsistencyCheck,
    470 };
    471 
    472 fn iter_fn(info: *dl_phdr_info, size: usize, counter: *usize) IterFnError!void {
    473     _ = size;
    474     // Count how many libraries are loaded
    475     counter.* += @as(usize, 1);
    476 
    477     // The image should contain at least a PT_LOAD segment
    478     if (info.dlpi_phnum < 1) return error.MissingPtLoadSegment;
    479 
    480     // Quick & dirty validation of the phdr pointers, make sure we're not
    481     // pointing to some random gibberish
    482     var i: usize = 0;
    483     var found_load = false;
    484     while (i < info.dlpi_phnum) : (i += 1) {
    485         const phdr = info.dlpi_phdr[i];
    486 
    487         if (phdr.p_type != elf.PT_LOAD) continue;
    488 
    489         const reloc_addr = info.dlpi_addr + phdr.p_vaddr;
    490         // Find the ELF header
    491         const elf_header = @as(*elf.Ehdr, @ptrFromInt(reloc_addr - phdr.p_offset));
    492         // Validate the magic
    493         if (!mem.eql(u8, elf_header.e_ident[0..4], elf.MAGIC)) return error.BadElfMagic;
    494         // Consistency check
    495         if (elf_header.e_phnum != info.dlpi_phnum) return error.FailedConsistencyCheck;
    496 
    497         found_load = true;
    498         break;
    499     }
    500 
    501     if (!found_load) return error.MissingLoad;
    502 }
    503 
    504 test "dl_iterate_phdr" {
    505     if (builtin.object_format != .elf) return error.SkipZigTest;
    506 
    507     var counter: usize = 0;
    508     try os.dl_iterate_phdr(&counter, IterFnError, iter_fn);
    509     try expect(counter != 0);
    510 }
    511 
    512 test "gethostname" {
    513     if (native_os == .windows or native_os == .wasi)
    514         return error.SkipZigTest;
    515 
    516     var buf: [os.HOST_NAME_MAX]u8 = undefined;
    517     const hostname = try os.gethostname(&buf);
    518     try expect(hostname.len != 0);
    519 }
    520 
    521 test "pipe" {
    522     if (native_os == .windows or native_os == .wasi)
    523         return error.SkipZigTest;
    524 
    525     var fds = try os.pipe();
    526     try expect((try os.write(fds[1], "hello")) == 5);
    527     var buf: [16]u8 = undefined;
    528     try expect((try os.read(fds[0], buf[0..])) == 5);
    529     try testing.expectEqualSlices(u8, buf[0..5], "hello");
    530     os.close(fds[1]);
    531     os.close(fds[0]);
    532 }
    533 
    534 test "argsAlloc" {
    535     var args = try std.process.argsAlloc(std.testing.allocator);
    536     std.process.argsFree(std.testing.allocator, args);
    537 }
    538 
    539 test "memfd_create" {
    540     // memfd_create is only supported by linux and freebsd.
    541     switch (native_os) {
    542         .linux => {},
    543         .freebsd => {
    544             if (comptime builtin.os.version_range.semver.max.order(.{ .major = 13, .minor = 0, .patch = 0 }) == .lt)
    545                 return error.SkipZigTest;
    546         },
    547         else => return error.SkipZigTest,
    548     }
    549 
    550     const fd = os.memfd_create("test", 0) catch |err| switch (err) {
    551         // Related: https://github.com/ziglang/zig/issues/4019
    552         error.SystemOutdated => return error.SkipZigTest,
    553         else => |e| return e,
    554     };
    555     defer os.close(fd);
    556     try expect((try os.write(fd, "test")) == 4);
    557     try os.lseek_SET(fd, 0);
    558 
    559     var buf: [10]u8 = undefined;
    560     const bytes_read = try os.read(fd, &buf);
    561     try expect(bytes_read == 4);
    562     try expect(mem.eql(u8, buf[0..4], "test"));
    563 }
    564 
    565 test "mmap" {
    566     if (native_os == .windows or native_os == .wasi)
    567         return error.SkipZigTest;
    568 
    569     var tmp = tmpDir(.{});
    570     defer tmp.cleanup();
    571 
    572     // Simple mmap() call with non page-aligned size
    573     {
    574         const data = try os.mmap(
    575             null,
    576             1234,
    577             os.PROT.READ | os.PROT.WRITE,
    578             os.MAP.ANONYMOUS | os.MAP.PRIVATE,
    579             -1,
    580             0,
    581         );
    582         defer os.munmap(data);
    583 
    584         try testing.expectEqual(@as(usize, 1234), data.len);
    585 
    586         // By definition the data returned by mmap is zero-filled
    587         try testing.expect(mem.eql(u8, data, &[_]u8{0x00} ** 1234));
    588 
    589         // Make sure the memory is writeable as requested
    590         @memset(data, 0x55);
    591         try testing.expect(mem.eql(u8, data, &[_]u8{0x55} ** 1234));
    592     }
    593 
    594     const test_out_file = "os_tmp_test";
    595     // Must be a multiple of 4096 so that the test works with mmap2
    596     const alloc_size = 8 * 4096;
    597 
    598     // Create a file used for testing mmap() calls with a file descriptor
    599     {
    600         const file = try tmp.dir.createFile(test_out_file, .{});
    601         defer file.close();
    602 
    603         const stream = file.writer();
    604 
    605         var i: u32 = 0;
    606         while (i < alloc_size / @sizeOf(u32)) : (i += 1) {
    607             try stream.writeIntNative(u32, i);
    608         }
    609     }
    610 
    611     // Map the whole file
    612     {
    613         const file = try tmp.dir.openFile(test_out_file, .{});
    614         defer file.close();
    615 
    616         const data = try os.mmap(
    617             null,
    618             alloc_size,
    619             os.PROT.READ,
    620             os.MAP.PRIVATE,
    621             file.handle,
    622             0,
    623         );
    624         defer os.munmap(data);
    625 
    626         var mem_stream = io.fixedBufferStream(data);
    627         const stream = mem_stream.reader();
    628 
    629         var i: u32 = 0;
    630         while (i < alloc_size / @sizeOf(u32)) : (i += 1) {
    631             try testing.expectEqual(i, try stream.readIntNative(u32));
    632         }
    633     }
    634 
    635     // Map the upper half of the file
    636     {
    637         const file = try tmp.dir.openFile(test_out_file, .{});
    638         defer file.close();
    639 
    640         const data = try os.mmap(
    641             null,
    642             alloc_size / 2,
    643             os.PROT.READ,
    644             os.MAP.PRIVATE,
    645             file.handle,
    646             alloc_size / 2,
    647         );
    648         defer os.munmap(data);
    649 
    650         var mem_stream = io.fixedBufferStream(data);
    651         const stream = mem_stream.reader();
    652 
    653         var i: u32 = alloc_size / 2 / @sizeOf(u32);
    654         while (i < alloc_size / @sizeOf(u32)) : (i += 1) {
    655             try testing.expectEqual(i, try stream.readIntNative(u32));
    656         }
    657     }
    658 
    659     try tmp.dir.deleteFile(test_out_file);
    660 }
    661 
    662 test "getenv" {
    663     if (native_os == .windows) {
    664         try expect(os.getenvW(&[_:0]u16{ 'B', 'O', 'G', 'U', 'S', 0x11, 0x22, 0x33, 0x44, 0x55 }) == null);
    665     } else {
    666         try expect(os.getenvZ("BOGUSDOESNOTEXISTENVVAR") == null);
    667     }
    668 }
    669 
    670 test "fcntl" {
    671     if (native_os == .windows or native_os == .wasi)
    672         return error.SkipZigTest;
    673 
    674     var tmp = tmpDir(.{});
    675     defer tmp.cleanup();
    676 
    677     const test_out_file = "os_tmp_test";
    678 
    679     const file = try tmp.dir.createFile(test_out_file, .{});
    680     defer {
    681         file.close();
    682         tmp.dir.deleteFile(test_out_file) catch {};
    683     }
    684 
    685     // Note: The test assumes createFile opens the file with O.CLOEXEC
    686     {
    687         const flags = try os.fcntl(file.handle, os.F.GETFD, 0);
    688         try expect((flags & os.FD_CLOEXEC) != 0);
    689     }
    690     {
    691         _ = try os.fcntl(file.handle, os.F.SETFD, 0);
    692         const flags = try os.fcntl(file.handle, os.F.GETFD, 0);
    693         try expect((flags & os.FD_CLOEXEC) == 0);
    694     }
    695     {
    696         _ = try os.fcntl(file.handle, os.F.SETFD, os.FD_CLOEXEC);
    697         const flags = try os.fcntl(file.handle, os.F.GETFD, 0);
    698         try expect((flags & os.FD_CLOEXEC) != 0);
    699     }
    700 }
    701 
    702 test "signalfd" {
    703     switch (native_os) {
    704         .linux, .solaris => {},
    705         else => return error.SkipZigTest,
    706     }
    707     _ = &os.signalfd;
    708 }
    709 
    710 test "sync" {
    711     if (native_os != .linux)
    712         return error.SkipZigTest;
    713 
    714     var tmp = tmpDir(.{});
    715     defer tmp.cleanup();
    716 
    717     const test_out_file = "os_tmp_test";
    718     const file = try tmp.dir.createFile(test_out_file, .{});
    719     defer {
    720         file.close();
    721         tmp.dir.deleteFile(test_out_file) catch {};
    722     }
    723 
    724     os.sync();
    725     try os.syncfs(file.handle);
    726 }
    727 
    728 test "fsync" {
    729     switch (native_os) {
    730         .linux, .windows, .solaris => {},
    731         else => return error.SkipZigTest,
    732     }
    733 
    734     var tmp = tmpDir(.{});
    735     defer tmp.cleanup();
    736 
    737     const test_out_file = "os_tmp_test";
    738     const file = try tmp.dir.createFile(test_out_file, .{});
    739     defer {
    740         file.close();
    741         tmp.dir.deleteFile(test_out_file) catch {};
    742     }
    743 
    744     try os.fsync(file.handle);
    745     try os.fdatasync(file.handle);
    746 }
    747 
    748 test "getrlimit and setrlimit" {
    749     if (!@hasDecl(os.system, "rlimit")) {
    750         return error.SkipZigTest;
    751     }
    752 
    753     inline for (std.meta.fields(os.rlimit_resource)) |field| {
    754         const resource = @as(os.rlimit_resource, @enumFromInt(field.value));
    755         const limit = try os.getrlimit(resource);
    756 
    757         // On 32 bit MIPS musl includes a fix which changes limits greater than -1UL/2 to RLIM_INFINITY.
    758         // See http://git.musl-libc.org/cgit/musl/commit/src/misc/getrlimit.c?id=8258014fd1e34e942a549c88c7e022a00445c352
    759         //
    760         // This happens for example if RLIMIT_MEMLOCK is bigger than ~2GiB.
    761         // In that case the following the limit would be RLIM_INFINITY and the following setrlimit fails with EPERM.
    762         if (comptime builtin.cpu.arch.isMIPS() and builtin.link_libc) {
    763             if (limit.cur != os.linux.RLIM.INFINITY) {
    764                 try os.setrlimit(resource, limit);
    765             }
    766         } else {
    767             try os.setrlimit(resource, limit);
    768         }
    769     }
    770 }
    771 
    772 test "shutdown socket" {
    773     if (native_os == .wasi)
    774         return error.SkipZigTest;
    775     if (native_os == .windows) {
    776         _ = try os.windows.WSAStartup(2, 2);
    777     }
    778     defer {
    779         if (native_os == .windows) {
    780             os.windows.WSACleanup() catch unreachable;
    781         }
    782     }
    783     const sock = try os.socket(os.AF.INET, os.SOCK.STREAM, 0);
    784     os.shutdown(sock, .both) catch |err| switch (err) {
    785         error.SocketNotConnected => {},
    786         else => |e| return e,
    787     };
    788     os.closeSocket(sock);
    789 }
    790 
    791 test "sigaction" {
    792     if (native_os == .wasi or native_os == .windows)
    793         return error.SkipZigTest;
    794 
    795     // https://github.com/ziglang/zig/issues/7427
    796     if (native_os == .linux and builtin.target.cpu.arch == .x86)
    797         return error.SkipZigTest;
    798 
    799     // https://github.com/ziglang/zig/issues/15381
    800     if (native_os == .macos and builtin.target.cpu.arch == .x86_64) {
    801         return error.SkipZigTest;
    802     }
    803 
    804     const S = struct {
    805         var handler_called_count: u32 = 0;
    806 
    807         fn handler(sig: i32, info: *const os.siginfo_t, ctx_ptr: ?*const anyopaque) callconv(.C) void {
    808             _ = ctx_ptr;
    809             // Check that we received the correct signal.
    810             switch (native_os) {
    811                 .netbsd => {
    812                     if (sig == os.SIG.USR1 and sig == info.info.signo)
    813                         handler_called_count += 1;
    814                 },
    815                 else => {
    816                     if (sig == os.SIG.USR1 and sig == info.signo)
    817                         handler_called_count += 1;
    818                 },
    819             }
    820         }
    821     };
    822 
    823     var sa = os.Sigaction{
    824         .handler = .{ .sigaction = &S.handler },
    825         .mask = os.empty_sigset,
    826         .flags = os.SA.SIGINFO | os.SA.RESETHAND,
    827     };
    828     var old_sa: os.Sigaction = undefined;
    829 
    830     // Install the new signal handler.
    831     try os.sigaction(os.SIG.USR1, &sa, null);
    832 
    833     // Check that we can read it back correctly.
    834     try os.sigaction(os.SIG.USR1, null, &old_sa);
    835     try testing.expectEqual(&S.handler, old_sa.handler.sigaction.?);
    836     try testing.expect((old_sa.flags & os.SA.SIGINFO) != 0);
    837 
    838     // Invoke the handler.
    839     try os.raise(os.SIG.USR1);
    840     try testing.expect(S.handler_called_count == 1);
    841 
    842     // Check if passing RESETHAND correctly reset the handler to SIG_DFL
    843     try os.sigaction(os.SIG.USR1, null, &old_sa);
    844     try testing.expectEqual(os.SIG.DFL, old_sa.handler.handler);
    845 
    846     // Reinstall the signal w/o RESETHAND and re-raise
    847     sa.flags = os.SA.SIGINFO;
    848     try os.sigaction(os.SIG.USR1, &sa, null);
    849     try os.raise(os.SIG.USR1);
    850     try testing.expect(S.handler_called_count == 2);
    851 
    852     // Now set the signal to ignored
    853     sa.handler = .{ .handler = os.SIG.IGN };
    854     sa.flags = 0;
    855     try os.sigaction(os.SIG.USR1, &sa, null);
    856 
    857     // Re-raise to ensure handler is actually ignored
    858     try os.raise(os.SIG.USR1);
    859     try testing.expect(S.handler_called_count == 2);
    860 
    861     // Ensure that ignored state is returned when querying
    862     try os.sigaction(os.SIG.USR1, null, &old_sa);
    863     try testing.expectEqual(os.SIG.IGN, old_sa.handler.handler.?);
    864 }
    865 
    866 test "dup & dup2" {
    867     switch (native_os) {
    868         .linux, .solaris => {},
    869         else => return error.SkipZigTest,
    870     }
    871 
    872     var tmp = tmpDir(.{});
    873     defer tmp.cleanup();
    874 
    875     {
    876         var file = try tmp.dir.createFile("os_dup_test", .{});
    877         defer file.close();
    878 
    879         var duped = std.fs.File{ .handle = try os.dup(file.handle) };
    880         defer duped.close();
    881         try duped.writeAll("dup");
    882 
    883         // Tests aren't run in parallel so using the next fd shouldn't be an issue.
    884         const new_fd = duped.handle + 1;
    885         try os.dup2(file.handle, new_fd);
    886         var dup2ed = std.fs.File{ .handle = new_fd };
    887         defer dup2ed.close();
    888         try dup2ed.writeAll("dup2");
    889     }
    890 
    891     var file = try tmp.dir.openFile("os_dup_test", .{});
    892     defer file.close();
    893 
    894     var buf: [7]u8 = undefined;
    895     try testing.expectEqualStrings("dupdup2", buf[0..try file.readAll(&buf)]);
    896 }
    897 
    898 test "writev longer than IOV_MAX" {
    899     if (native_os == .windows or native_os == .wasi) return error.SkipZigTest;
    900 
    901     var tmp = tmpDir(.{});
    902     defer tmp.cleanup();
    903 
    904     var file = try tmp.dir.createFile("pwritev", .{});
    905     defer file.close();
    906 
    907     const iovecs = [_]os.iovec_const{.{ .iov_base = "a", .iov_len = 1 }} ** (os.IOV_MAX + 1);
    908     const amt = try file.writev(&iovecs);
    909     try testing.expectEqual(@as(usize, os.IOV_MAX), amt);
    910 }
    911 
    912 test "POSIX file locking with fcntl" {
    913     if (native_os == .windows or native_os == .wasi) {
    914         // Not POSIX.
    915         return error.SkipZigTest;
    916     }
    917 
    918     if (true) {
    919         // https://github.com/ziglang/zig/issues/11074
    920         return error.SkipZigTest;
    921     }
    922 
    923     var tmp = std.testing.tmpDir(.{});
    924     defer tmp.cleanup();
    925 
    926     // Create a temporary lock file
    927     var file = try tmp.dir.createFile("lock", .{ .read = true });
    928     defer file.close();
    929     try file.setEndPos(2);
    930     const fd = file.handle;
    931 
    932     // Place an exclusive lock on the first byte, and a shared lock on the second byte:
    933     var struct_flock = std.mem.zeroInit(os.Flock, .{ .type = os.F.WRLCK });
    934     _ = try os.fcntl(fd, os.F.SETLK, @intFromPtr(&struct_flock));
    935     struct_flock.start = 1;
    936     struct_flock.type = os.F.RDLCK;
    937     _ = try os.fcntl(fd, os.F.SETLK, @intFromPtr(&struct_flock));
    938 
    939     // Check the locks in a child process:
    940     const pid = try os.fork();
    941     if (pid == 0) {
    942         // child expects be denied the exclusive lock:
    943         struct_flock.start = 0;
    944         struct_flock.type = os.F.WRLCK;
    945         try expectError(error.Locked, os.fcntl(fd, os.F.SETLK, @intFromPtr(&struct_flock)));
    946         // child expects to get the shared lock:
    947         struct_flock.start = 1;
    948         struct_flock.type = os.F.RDLCK;
    949         _ = try os.fcntl(fd, os.F.SETLK, @intFromPtr(&struct_flock));
    950         // child waits for the exclusive lock in order to test deadlock:
    951         struct_flock.start = 0;
    952         struct_flock.type = os.F.WRLCK;
    953         _ = try os.fcntl(fd, os.F.SETLKW, @intFromPtr(&struct_flock));
    954         // child exits without continuing:
    955         os.exit(0);
    956     } else {
    957         // parent waits for child to get shared lock:
    958         std.time.sleep(1 * std.time.ns_per_ms);
    959         // parent expects deadlock when attempting to upgrade the shared lock to exclusive:
    960         struct_flock.start = 1;
    961         struct_flock.type = os.F.WRLCK;
    962         try expectError(error.DeadLock, os.fcntl(fd, os.F.SETLKW, @intFromPtr(&struct_flock)));
    963         // parent releases exclusive lock:
    964         struct_flock.start = 0;
    965         struct_flock.type = os.F.UNLCK;
    966         _ = try os.fcntl(fd, os.F.SETLK, @intFromPtr(&struct_flock));
    967         // parent releases shared lock:
    968         struct_flock.start = 1;
    969         struct_flock.type = os.F.UNLCK;
    970         _ = try os.fcntl(fd, os.F.SETLK, @intFromPtr(&struct_flock));
    971         // parent waits for child:
    972         const result = os.waitpid(pid, 0);
    973         try expect(result.status == 0 * 256);
    974     }
    975 }
    976 
    977 test "rename smoke test" {
    978     if (native_os == .wasi) return error.SkipZigTest;
    979 
    980     var tmp = tmpDir(.{});
    981     defer tmp.cleanup();
    982 
    983     // Get base abs path
    984     var arena = ArenaAllocator.init(testing.allocator);
    985     defer arena.deinit();
    986     const allocator = arena.allocator();
    987 
    988     const base_path = blk: {
    989         const relative_path = try fs.path.join(allocator, &[_][]const u8{ "zig-cache", "tmp", tmp.sub_path[0..] });
    990         break :blk try fs.realpathAlloc(allocator, relative_path);
    991     };
    992 
    993     var file_path: []u8 = undefined;
    994     var fd: os.fd_t = undefined;
    995     const mode: os.mode_t = if (native_os == .windows) 0 else 0o666;
    996 
    997     // Create some file using `open`.
    998     file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
    999     fd = try os.open(file_path, os.O.RDWR | os.O.CREAT | os.O.EXCL, mode);
   1000     os.close(fd);
   1001 
   1002     // Rename the file
   1003     var new_file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_other_file" });
   1004     try os.rename(file_path, new_file_path);
   1005 
   1006     // Try opening renamed file
   1007     file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_other_file" });
   1008     fd = try os.open(file_path, os.O.RDWR, mode);
   1009     os.close(fd);
   1010 
   1011     // Try opening original file - should fail with error.FileNotFound
   1012     file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
   1013     try expectError(error.FileNotFound, os.open(file_path, os.O.RDWR, mode));
   1014 
   1015     // Create some directory
   1016     file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_dir" });
   1017     try os.mkdir(file_path, mode);
   1018 
   1019     // Rename the directory
   1020     new_file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_other_dir" });
   1021     try os.rename(file_path, new_file_path);
   1022 
   1023     // Try opening renamed directory
   1024     file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_other_dir" });
   1025     fd = try os.open(file_path, os.O.RDONLY | os.O.DIRECTORY, mode);
   1026     os.close(fd);
   1027 
   1028     // Try opening original directory - should fail with error.FileNotFound
   1029     file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_dir" });
   1030     try expectError(error.FileNotFound, os.open(file_path, os.O.RDONLY | os.O.DIRECTORY, mode));
   1031 }
   1032 
   1033 test "access smoke test" {
   1034     if (native_os == .wasi) return error.SkipZigTest;
   1035 
   1036     var tmp = tmpDir(.{});
   1037     defer tmp.cleanup();
   1038 
   1039     // Get base abs path
   1040     var arena = ArenaAllocator.init(testing.allocator);
   1041     defer arena.deinit();
   1042     const allocator = arena.allocator();
   1043 
   1044     const base_path = blk: {
   1045         const relative_path = try fs.path.join(allocator, &[_][]const u8{ "zig-cache", "tmp", tmp.sub_path[0..] });
   1046         break :blk try fs.realpathAlloc(allocator, relative_path);
   1047     };
   1048 
   1049     var file_path: []u8 = undefined;
   1050     var fd: os.fd_t = undefined;
   1051     const mode: os.mode_t = if (native_os == .windows) 0 else 0o666;
   1052 
   1053     // Create some file using `open`.
   1054     file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
   1055     fd = try os.open(file_path, os.O.RDWR | os.O.CREAT | os.O.EXCL, mode);
   1056     os.close(fd);
   1057 
   1058     // Try to access() the file
   1059     file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
   1060     if (builtin.os.tag == .windows) {
   1061         try os.access(file_path, os.F_OK);
   1062     } else {
   1063         try os.access(file_path, os.F_OK | os.W_OK | os.R_OK);
   1064     }
   1065 
   1066     // Try to access() a non-existent file - should fail with error.FileNotFound
   1067     file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_other_file" });
   1068     try expectError(error.FileNotFound, os.access(file_path, os.F_OK));
   1069 
   1070     // Create some directory
   1071     file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_dir" });
   1072     try os.mkdir(file_path, mode);
   1073 
   1074     // Try to access() the directory
   1075     file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_dir" });
   1076     try os.access(file_path, os.F_OK);
   1077 }
   1078 
   1079 test "timerfd" {
   1080     if (native_os != .linux)
   1081         return error.SkipZigTest;
   1082 
   1083     const linux = os.linux;
   1084     var tfd = try os.timerfd_create(linux.CLOCK.MONOTONIC, linux.TFD.CLOEXEC);
   1085     defer os.close(tfd);
   1086 
   1087     // Fire event 10_000_000ns = 10ms after the os.timerfd_settime call.
   1088     var sit: linux.itimerspec = .{ .it_interval = .{ .tv_sec = 0, .tv_nsec = 0 }, .it_value = .{ .tv_sec = 0, .tv_nsec = 10 * (1000 * 1000) } };
   1089     try os.timerfd_settime(tfd, 0, &sit, null);
   1090 
   1091     var fds: [1]os.pollfd = .{.{ .fd = tfd, .events = os.linux.POLL.IN, .revents = 0 }};
   1092     try expectEqual(@as(usize, 1), try os.poll(&fds, -1)); // -1 => infinite waiting
   1093 
   1094     var git = try os.timerfd_gettime(tfd);
   1095     var expect_disarmed_timer: linux.itimerspec = .{ .it_interval = .{ .tv_sec = 0, .tv_nsec = 0 }, .it_value = .{ .tv_sec = 0, .tv_nsec = 0 } };
   1096     try expectEqual(expect_disarmed_timer, git);
   1097 }
   1098 
   1099 test "isatty" {
   1100     var tmp = tmpDir(.{});
   1101     defer tmp.cleanup();
   1102 
   1103     var file = try tmp.dir.createFile("foo", .{});
   1104     defer file.close();
   1105 
   1106     try expectEqual(os.isatty(file.handle), false);
   1107 }
   1108 
   1109 test "read with empty buffer" {
   1110     if (native_os == .wasi) return error.SkipZigTest;
   1111 
   1112     var tmp = tmpDir(.{});
   1113     defer tmp.cleanup();
   1114 
   1115     var arena = ArenaAllocator.init(testing.allocator);
   1116     defer arena.deinit();
   1117     const allocator = arena.allocator();
   1118 
   1119     // Get base abs path
   1120     const base_path = blk: {
   1121         const relative_path = try fs.path.join(allocator, &[_][]const u8{ "zig-cache", "tmp", tmp.sub_path[0..] });
   1122         break :blk try fs.realpathAlloc(allocator, relative_path);
   1123     };
   1124 
   1125     var file_path: []u8 = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
   1126     var file = try fs.cwd().createFile(file_path, .{ .read = true });
   1127     defer file.close();
   1128 
   1129     var bytes = try allocator.alloc(u8, 0);
   1130 
   1131     _ = try os.read(file.handle, bytes);
   1132 }
   1133 
   1134 test "pread with empty buffer" {
   1135     if (native_os == .wasi) return error.SkipZigTest;
   1136 
   1137     var tmp = tmpDir(.{});
   1138     defer tmp.cleanup();
   1139 
   1140     var arena = ArenaAllocator.init(testing.allocator);
   1141     defer arena.deinit();
   1142     const allocator = arena.allocator();
   1143 
   1144     // Get base abs path
   1145     const base_path = blk: {
   1146         const relative_path = try fs.path.join(allocator, &[_][]const u8{ "zig-cache", "tmp", tmp.sub_path[0..] });
   1147         break :blk try fs.realpathAlloc(allocator, relative_path);
   1148     };
   1149 
   1150     var file_path: []u8 = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
   1151     var file = try fs.cwd().createFile(file_path, .{ .read = true });
   1152     defer file.close();
   1153 
   1154     var bytes = try allocator.alloc(u8, 0);
   1155 
   1156     _ = try os.pread(file.handle, bytes, 0);
   1157 }
   1158 
   1159 test "write with empty buffer" {
   1160     if (native_os == .wasi) return error.SkipZigTest;
   1161 
   1162     var tmp = tmpDir(.{});
   1163     defer tmp.cleanup();
   1164 
   1165     var arena = ArenaAllocator.init(testing.allocator);
   1166     defer arena.deinit();
   1167     const allocator = arena.allocator();
   1168 
   1169     // Get base abs path
   1170     const base_path = blk: {
   1171         const relative_path = try fs.path.join(allocator, &[_][]const u8{ "zig-cache", "tmp", tmp.sub_path[0..] });
   1172         break :blk try fs.realpathAlloc(allocator, relative_path);
   1173     };
   1174 
   1175     var file_path: []u8 = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
   1176     var file = try fs.cwd().createFile(file_path, .{});
   1177     defer file.close();
   1178 
   1179     var bytes = try allocator.alloc(u8, 0);
   1180 
   1181     _ = try os.write(file.handle, bytes);
   1182 }
   1183 
   1184 test "pwrite with empty buffer" {
   1185     if (native_os == .wasi) return error.SkipZigTest;
   1186 
   1187     var tmp = tmpDir(.{});
   1188     defer tmp.cleanup();
   1189 
   1190     var arena = ArenaAllocator.init(testing.allocator);
   1191     defer arena.deinit();
   1192     const allocator = arena.allocator();
   1193 
   1194     // Get base abs path
   1195     const base_path = blk: {
   1196         const relative_path = try fs.path.join(allocator, &[_][]const u8{ "zig-cache", "tmp", tmp.sub_path[0..] });
   1197         break :blk try fs.realpathAlloc(allocator, relative_path);
   1198     };
   1199 
   1200     var file_path: []u8 = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
   1201     var file = try fs.cwd().createFile(file_path, .{});
   1202     defer file.close();
   1203 
   1204     var bytes = try allocator.alloc(u8, 0);
   1205 
   1206     _ = try os.pwrite(file.handle, bytes, 0);
   1207 }
   1208 
   1209 test "fchmodat smoke test" {
   1210     if (!std.fs.has_executable_bit) return error.SkipZigTest;
   1211 
   1212     var tmp = tmpDir(.{});
   1213     defer tmp.cleanup();
   1214 
   1215     try expectError(error.FileNotFound, os.fchmodat(tmp.dir.fd, "foo.txt", 0o666, 0));
   1216     const fd = try os.openat(tmp.dir.fd, "foo.txt", os.O.RDWR | os.O.CREAT | os.O.EXCL, 0o666);
   1217     os.close(fd);
   1218     try os.fchmodat(tmp.dir.fd, "foo.txt", 0o755, 0);
   1219     const st = try os.fstatat(tmp.dir.fd, "foo.txt", 0);
   1220     try expectEqual(@as(os.mode_t, 0o755), st.mode & 0b111_111_111);
   1221 }