Commit 4843c3b4c3
Changed files (7)
lib/std/os/bits/dragonfly.zig
@@ -283,6 +283,8 @@ pub const F_LOCK = 1;
pub const F_TLOCK = 2;
pub const F_TEST = 3;
+pub const FD_CLOEXEC = 1;
+
pub const AT_FDCWD = -328243;
pub const AT_SYMLINK_NOFOLLOW = 1;
pub const AT_REMOVEDIR = 2;
lib/std/os/bits/freebsd.zig
@@ -355,6 +355,8 @@ pub const F_GETOWN_EX = 16;
pub const F_GETOWNER_UIDS = 17;
+pub const FD_CLOEXEC = 1;
+
pub const SEEK_SET = 0;
pub const SEEK_CUR = 1;
pub const SEEK_END = 2;
lib/std/os/bits/linux.zig
@@ -136,6 +136,8 @@ pub const MAP_FIXED_NOREPLACE = 0x100000;
/// For anonymous mmap, memory could be uninitialized
pub const MAP_UNINITIALIZED = 0x4000000;
+pub const FD_CLOEXEC = 1;
+
pub const F_OK = 0;
pub const X_OK = 1;
pub const W_OK = 2;
lib/std/os/bits/netbsd.zig
@@ -312,6 +312,8 @@ pub const F_GETLK = 7;
pub const F_SETLK = 8;
pub const F_SETLKW = 9;
+pub const FD_CLOEXEC = 1;
+
pub const SEEK_SET = 0;
pub const SEEK_CUR = 1;
pub const SEEK_END = 2;
lib/std/os/linux.zig
@@ -588,6 +588,10 @@ pub fn waitpid(pid: pid_t, status: *u32, flags: u32) usize {
return syscall4(SYS_wait4, @bitCast(usize, @as(isize, pid)), @ptrToInt(status), flags, 0);
}
+pub fn fcntl(fd: fd_t, cmd: i32, arg: usize) usize {
+ return syscall3(SYS_fcntl, @bitCast(usize, @as(isize, fd)), @bitCast(usize, @as(isize, cmd)), arg);
+}
+
var vdso_clock_gettime = @ptrCast(?*const c_void, init_vdso_clock_gettime);
// We must follow the C calling convention when we call into the VDSO
lib/std/os/test.zig
@@ -1,7 +1,8 @@
const std = @import("../std.zig");
const os = std.os;
const testing = std.testing;
-const expect = std.testing.expect;
+const expect = testing.expect;
+const expectEqual = testing.expectEqual;
const io = std.io;
const fs = std.fs;
const mem = std.mem;
@@ -446,3 +447,31 @@ test "getenv" {
expect(os.getenvZ("BOGUSDOESNOTEXISTENVVAR") == null);
}
}
+
+test "fcntl" {
+ if (builtin.os.tag == .windows)
+ return error.SkipZigTest;
+
+ const test_out_file = "os_tmp_test";
+
+ const file = try fs.cwd().createFile(test_out_file, .{});
+ defer file.close();
+
+ // Note: The test assumes createFile opens the file with O_CLOEXEC
+ {
+ const flags = try os.fcntl(file.handle, os.F_GETFD, 0);
+ expect((flags & os.FD_CLOEXEC) != 0);
+ }
+ {
+ _ = try os.fcntl(file.handle, os.F_SETFD, 0);
+ const flags = try os.fcntl(file.handle, os.F_GETFD, 0);
+ expect((flags & os.FD_CLOEXEC) == 0);
+ }
+ {
+ _ = try os.fcntl(file.handle, os.F_SETFD, os.FD_CLOEXEC);
+ const flags = try os.fcntl(file.handle, os.F_GETFD, 0);
+ expect((flags & os.FD_CLOEXEC) != 0);
+ }
+
+ try fs.cwd().deleteFile(test_out_file);
+}
lib/std/os.zig
@@ -3163,6 +3163,31 @@ pub fn lseek_CUR_get(fd: fd_t) SeekError!u64 {
}
}
+pub const FcntlError = error{
+ PermissionDenied,
+ FileBusy,
+ ProcessFdQuotaExceeded,
+ Locked,
+} || UnexpectedError;
+
+pub fn fcntl(fd: fd_t, cmd: i32, arg: usize) FcntlError!usize {
+ while (true) {
+ const rc = system.fcntl(fd, cmd, arg);
+ switch (errno(rc)) {
+ 0 => return @intCast(usize, rc),
+ EINTR => continue,
+ EACCES => return error.Locked,
+ EBADF => unreachable,
+ EBUSY => return error.FileBusy,
+ EINVAL => unreachable, // invalid parameters
+ EPERM => return error.PermissionDenied,
+ EMFILE => return error.ProcessFdQuotaExceeded,
+ ENOTDIR => unreachable, // invalid parameter
+ else => |err| return unexpectedErrno(err),
+ }
+ }
+}
+
pub const RealPathError = error{
FileNotFound,
AccessDenied,