mirror of
https://github.com/ziglang/zig.git
synced 2025-02-13 08:00:20 +00:00
Add chmod
and chown
This commit is contained in:
parent
dfd604834b
commit
796687f156
@ -147,6 +147,8 @@ pub extern "c" fn dup(fd: c.fd_t) c_int;
|
|||||||
pub extern "c" fn dup2(old_fd: c.fd_t, new_fd: c.fd_t) c_int;
|
pub extern "c" fn dup2(old_fd: c.fd_t, new_fd: c.fd_t) c_int;
|
||||||
pub extern "c" fn readlink(noalias path: [*:0]const u8, noalias buf: [*]u8, bufsize: usize) isize;
|
pub extern "c" fn readlink(noalias path: [*:0]const u8, noalias buf: [*]u8, bufsize: usize) isize;
|
||||||
pub extern "c" fn readlinkat(dirfd: c.fd_t, noalias path: [*:0]const u8, noalias buf: [*]u8, bufsize: usize) isize;
|
pub extern "c" fn readlinkat(dirfd: c.fd_t, noalias path: [*:0]const u8, noalias buf: [*]u8, bufsize: usize) isize;
|
||||||
|
pub extern "c" fn fchmod(fd: c.fd_t, mode: c.mode_t) c_int;
|
||||||
|
pub extern "c" fn fchown(fd: c.fd_t, owner: c.uid_t, group: c.gid_t) c_int;
|
||||||
|
|
||||||
pub extern "c" fn rmdir(path: [*:0]const u8) c_int;
|
pub extern "c" fn rmdir(path: [*:0]const u8) c_int;
|
||||||
pub extern "c" fn getenv(name: [*:0]const u8) ?[*:0]u8;
|
pub extern "c" fn getenv(name: [*:0]const u8) ?[*:0]u8;
|
||||||
|
@ -2178,6 +2178,37 @@ pub const Dir = struct {
|
|||||||
};
|
};
|
||||||
return file.stat();
|
return file.stat();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const ChmodError = File.ChmodError;
|
||||||
|
|
||||||
|
/// Changes the mode of the directory.
|
||||||
|
/// The process must have the correct privileges in order to do this
|
||||||
|
/// successfully, or must have the effective user ID matching the owner
|
||||||
|
/// of the directory. Additionally, the directory must have been opened
|
||||||
|
/// with `OpenDirOptions{ .iterate = true }`.
|
||||||
|
pub fn chmod(self: Dir, new_mode: File.Mode) ChmodError!void {
|
||||||
|
const file: File = .{
|
||||||
|
.handle = self.fd,
|
||||||
|
.capable_io_mode = .blocking,
|
||||||
|
};
|
||||||
|
try file.chmod(new_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Changes the owner and group of the directory.
|
||||||
|
/// The process must have the correct privileges in order to do this
|
||||||
|
/// successfully. The group may be changed by the owner of the directory to
|
||||||
|
/// any group of which the owner is a member. Additionally, the directory
|
||||||
|
/// must have been opened with `OpenDirOptions{ .iterate = true }`. If the
|
||||||
|
/// owner or group is specified as `null`, the ID is not changed.
|
||||||
|
pub fn chown(self: Dir, owner: ?File.Uid, group: ?File.Gid) ChownError!void {
|
||||||
|
const file: File = .{
|
||||||
|
.handle = self.fd,
|
||||||
|
.capable_io_mode = .blocking,
|
||||||
|
};
|
||||||
|
try file.chown(owner, group);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const ChownError = File.ChownError;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Returns a handle to the current working directory. It is not opened with iteration capability.
|
/// Returns a handle to the current working directory. It is not opened with iteration capability.
|
||||||
|
@ -31,6 +31,8 @@ pub const File = struct {
|
|||||||
pub const Handle = os.fd_t;
|
pub const Handle = os.fd_t;
|
||||||
pub const Mode = os.mode_t;
|
pub const Mode = os.mode_t;
|
||||||
pub const INode = os.ino_t;
|
pub const INode = os.ino_t;
|
||||||
|
pub const Uid = os.uid_t;
|
||||||
|
pub const Gid = os.gid_t;
|
||||||
|
|
||||||
pub const Kind = enum {
|
pub const Kind = enum {
|
||||||
BlockDevice,
|
BlockDevice,
|
||||||
@ -362,6 +364,27 @@ pub const File = struct {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const ChmodError = std.os.FChmodError;
|
||||||
|
|
||||||
|
/// Changes the mode of the file.
|
||||||
|
/// The process must have the correct privileges in order to do this
|
||||||
|
/// successfully, or must have the effective user ID matching the owner
|
||||||
|
/// of the file.
|
||||||
|
pub fn chmod(self: File, new_mode: Mode) ChmodError!void {
|
||||||
|
try os.fchmod(self.handle, new_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const ChownError = std.os.FChownError;
|
||||||
|
|
||||||
|
/// Changes the owner and group of the file.
|
||||||
|
/// The process must have the correct privileges in order to do this
|
||||||
|
/// successfully. The group may be changed by the owner of the file to
|
||||||
|
/// any group of which the owner is a member. If the owner or group is
|
||||||
|
/// specified as `null`, the ID is not changed.
|
||||||
|
pub fn chown(self: File, owner: ?Uid, group: ?Gid) ChownError!void {
|
||||||
|
try os.fchown(self.handle, owner, group);
|
||||||
|
}
|
||||||
|
|
||||||
pub const UpdateTimesError = os.FutimensError || windows.SetFileTimeError;
|
pub const UpdateTimesError = os.FutimensError || windows.SetFileTimeError;
|
||||||
|
|
||||||
/// The underlying file system may have a different granularity than nanoseconds,
|
/// The underlying file system may have a different granularity than nanoseconds,
|
||||||
|
@ -1022,3 +1022,43 @@ test ". and .. in absolute functions" {
|
|||||||
|
|
||||||
try fs.deleteDirAbsolute(subdir_path);
|
try fs.deleteDirAbsolute(subdir_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "chmod" {
|
||||||
|
if (builtin.os.tag == .windows or builtin.os.tag == .wasi)
|
||||||
|
return error.SkipZigTest;
|
||||||
|
|
||||||
|
var tmp = tmpDir(.{});
|
||||||
|
defer tmp.cleanup();
|
||||||
|
|
||||||
|
const file = try tmp.dir.createFile("test_file", .{ .mode = 0o600 });
|
||||||
|
defer file.close();
|
||||||
|
try testing.expect((try file.stat()).mode & 0o7777 == 0o600);
|
||||||
|
|
||||||
|
try file.chmod(0o644);
|
||||||
|
try testing.expect((try file.stat()).mode & 0o7777 == 0o644);
|
||||||
|
|
||||||
|
try tmp.dir.makeDir("test_dir");
|
||||||
|
var dir = try tmp.dir.openDir("test_dir", .{ .iterate = true });
|
||||||
|
defer dir.close();
|
||||||
|
|
||||||
|
try dir.chmod(0o700);
|
||||||
|
try testing.expect((try dir.stat()).mode & 0o7777 == 0o700);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "chown" {
|
||||||
|
if (builtin.os.tag == .windows or builtin.os.tag == .wasi)
|
||||||
|
return error.SkipZigTest;
|
||||||
|
|
||||||
|
var tmp = tmpDir(.{});
|
||||||
|
defer tmp.cleanup();
|
||||||
|
|
||||||
|
const file = try tmp.dir.createFile("test_file", .{});
|
||||||
|
defer file.close();
|
||||||
|
try file.chown(null, null);
|
||||||
|
|
||||||
|
try tmp.dir.makeDir("test_dir");
|
||||||
|
|
||||||
|
var dir = try tmp.dir.openDir("test_dir", .{ .iterate = true });
|
||||||
|
defer dir.close();
|
||||||
|
try dir.chown(null, null);
|
||||||
|
}
|
||||||
|
@ -255,6 +255,87 @@ pub fn close(fd: fd_t) void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const FChmodError = error{
|
||||||
|
AccessDenied,
|
||||||
|
InputOutput,
|
||||||
|
SymLinkLoop,
|
||||||
|
FileNotFound,
|
||||||
|
SystemResources,
|
||||||
|
ReadOnlyFileSystem,
|
||||||
|
} || UnexpectedError;
|
||||||
|
|
||||||
|
/// Changes the mode of the file referred to by the file descriptor.
|
||||||
|
/// The process must have the correct privileges in order to do this
|
||||||
|
/// successfully, or must have the effective user ID matching the owner
|
||||||
|
/// of the file.
|
||||||
|
pub fn fchmod(fd: fd_t, mode: mode_t) FChmodError!void {
|
||||||
|
if (builtin.os.tag == .windows or builtin.os.tag == .wasi)
|
||||||
|
@compileError("Unsupported OS");
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
const res = system.fchmod(fd, mode);
|
||||||
|
|
||||||
|
switch (system.getErrno(res)) {
|
||||||
|
.SUCCESS => return,
|
||||||
|
.INTR => continue,
|
||||||
|
.BADF => unreachable, // Can be reached if the fd refers to a directory opened without `OpenDirOptions{ .iterate = true }`
|
||||||
|
|
||||||
|
.FAULT => unreachable,
|
||||||
|
.INVAL => unreachable,
|
||||||
|
.ACCES => return error.AccessDenied,
|
||||||
|
.IO => return error.InputOutput,
|
||||||
|
.LOOP => return error.SymLinkLoop,
|
||||||
|
.NOENT => return error.FileNotFound,
|
||||||
|
.NOMEM => return error.SystemResources,
|
||||||
|
.NOTDIR => return error.FileNotFound,
|
||||||
|
.PERM => return error.AccessDenied,
|
||||||
|
.ROFS => return error.ReadOnlyFileSystem,
|
||||||
|
else => |err| return unexpectedErrno(err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const FChownError = error{
|
||||||
|
AccessDenied,
|
||||||
|
InputOutput,
|
||||||
|
SymLinkLoop,
|
||||||
|
FileNotFound,
|
||||||
|
SystemResources,
|
||||||
|
ReadOnlyFileSystem,
|
||||||
|
} || UnexpectedError;
|
||||||
|
|
||||||
|
/// Changes the owner and group of the file referred to by the file descriptor.
|
||||||
|
/// The process must have the correct privileges in order to do this
|
||||||
|
/// successfully. The group may be changed by the owner of the directory to
|
||||||
|
/// any group of which the owner is a member. If the owner or group is
|
||||||
|
/// specified as `null`, the ID is not changed.
|
||||||
|
pub fn fchown(fd: fd_t, owner: ?uid_t, group: ?gid_t) FChownError!void {
|
||||||
|
if (builtin.os.tag == .windows or builtin.os.tag == .wasi)
|
||||||
|
@compileError("Unsupported OS");
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
const res = system.fchown(fd, owner orelse @as(u32, 0) -% 1, group orelse @as(u32, 0) -% 1);
|
||||||
|
|
||||||
|
switch (system.getErrno(res)) {
|
||||||
|
.SUCCESS => return,
|
||||||
|
.INTR => continue,
|
||||||
|
.BADF => unreachable, // Can be reached if the fd refers to a directory opened without `OpenDirOptions{ .iterate = true }`
|
||||||
|
|
||||||
|
.FAULT => unreachable,
|
||||||
|
.INVAL => unreachable,
|
||||||
|
.ACCES => return error.AccessDenied,
|
||||||
|
.IO => return error.InputOutput,
|
||||||
|
.LOOP => return error.SymLinkLoop,
|
||||||
|
.NOENT => return error.FileNotFound,
|
||||||
|
.NOMEM => return error.SystemResources,
|
||||||
|
.NOTDIR => return error.FileNotFound,
|
||||||
|
.PERM => return error.AccessDenied,
|
||||||
|
.ROFS => return error.ReadOnlyFileSystem,
|
||||||
|
else => |err| return unexpectedErrno(err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub const GetRandomError = OpenError;
|
pub const GetRandomError = OpenError;
|
||||||
|
|
||||||
/// Obtain a series of random bytes. These bytes can be used to seed user-space
|
/// Obtain a series of random bytes. These bytes can be used to seed user-space
|
||||||
|
@ -733,6 +733,14 @@ pub fn close(fd: i32) usize {
|
|||||||
return syscall1(.close, @bitCast(usize, @as(isize, fd)));
|
return syscall1(.close, @bitCast(usize, @as(isize, fd)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn fchmod(fd: i32, mode: mode_t) usize {
|
||||||
|
return syscall2(.fchmod, @bitCast(usize, @as(isize, fd)), mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fchown(fd: i32, owner: uid_t, group: gid_t) usize {
|
||||||
|
return syscall3(.fchown, @bitCast(usize, @as(isize, fd)), owner, group);
|
||||||
|
}
|
||||||
|
|
||||||
/// Can only be called on 32 bit systems. For 64 bit see `lseek`.
|
/// Can only be called on 32 bit systems. For 64 bit see `lseek`.
|
||||||
pub fn llseek(fd: i32, offset: u64, result: ?*u64, whence: usize) usize {
|
pub fn llseek(fd: i32, offset: u64, result: ?*u64, whence: usize) usize {
|
||||||
// NOTE: The offset parameter splitting is independent from the target
|
// NOTE: The offset parameter splitting is independent from the target
|
||||||
|
Loading…
Reference in New Issue
Block a user