| author | |
| committer | |
| log | 796687f1562bf0c9a73633b3fd828d25b7a11fac |
| tree | 9b6d2ca4e98f41f2410043e3ed74ad7cb5af5362 |
| parent | dfd604834b9bda7ba5cb8117a233ae51bcbc8c0f |
6 files changed, 185 insertions(+), 0 deletions(-)
lib/std/c.zig+2| ... | ... | @@ -147,6 +147,8 @@ pub extern "c" fn dup(fd: c.fd_t) c_int; |
| 147 | 147 | pub extern "c" fn dup2(old_fd: c.fd_t, new_fd: c.fd_t) c_int; |
| 148 | 148 | pub extern "c" fn readlink(noalias path: [*:0]const u8, noalias buf: [*]u8, bufsize: usize) isize; |
| 149 | 149 | pub extern "c" fn readlinkat(dirfd: c.fd_t, noalias path: [*:0]const u8, noalias buf: [*]u8, bufsize: usize) isize; |
| 150 | pub extern "c" fn fchmod(fd: c.fd_t, mode: c.mode_t) c_int; | |
| 151 | pub extern "c" fn fchown(fd: c.fd_t, owner: c.uid_t, group: c.gid_t) c_int; | |
| 150 | 152 | |
| 151 | 153 | pub extern "c" fn rmdir(path: [*:0]const u8) c_int; |
| 152 | 154 | pub extern "c" fn getenv(name: [*:0]const u8) ?[*:0]u8; |
lib/std/fs.zig+31| ... | ... | @@ -2178,6 +2178,37 @@ pub const Dir = struct { |
| 2178 | 2178 | }; |
| 2179 | 2179 | return file.stat(); |
| 2180 | 2180 | } |
| 2181 | ||
| 2182 | pub const ChmodError = File.ChmodError; | |
| 2183 | ||
| 2184 | /// Changes the mode of the directory. | |
| 2185 | /// The process must have the correct privileges in order to do this | |
| 2186 | /// successfully, or must have the effective user ID matching the owner | |
| 2187 | /// of the directory. Additionally, the directory must have been opened | |
| 2188 | /// with `OpenDirOptions{ .iterate = true }`. | |
| 2189 | pub fn chmod(self: Dir, new_mode: File.Mode) ChmodError!void { | |
| 2190 | const file: File = .{ | |
| 2191 | .handle = self.fd, | |
| 2192 | .capable_io_mode = .blocking, | |
| 2193 | }; | |
| 2194 | try file.chmod(new_mode); | |
| 2195 | } | |
| 2196 | ||
| 2197 | /// Changes the owner and group of the directory. | |
| 2198 | /// The process must have the correct privileges in order to do this | |
| 2199 | /// successfully. The group may be changed by the owner of the directory to | |
| 2200 | /// any group of which the owner is a member. Additionally, the directory | |
| 2201 | /// must have been opened with `OpenDirOptions{ .iterate = true }`. If the | |
| 2202 | /// owner or group is specified as `null`, the ID is not changed. | |
| 2203 | pub fn chown(self: Dir, owner: ?File.Uid, group: ?File.Gid) ChownError!void { | |
| 2204 | const file: File = .{ | |
| 2205 | .handle = self.fd, | |
| 2206 | .capable_io_mode = .blocking, | |
| 2207 | }; | |
| 2208 | try file.chown(owner, group); | |
| 2209 | } | |
| 2210 | ||
| 2211 | pub const ChownError = File.ChownError; | |
| 2181 | 2212 | }; |
| 2182 | 2213 | |
| 2183 | 2214 | /// Returns a handle to the current working directory. It is not opened with iteration capability. |
lib/std/fs/file.zig+23| ... | ... | @@ -31,6 +31,8 @@ pub const File = struct { |
| 31 | 31 | pub const Handle = os.fd_t; |
| 32 | 32 | pub const Mode = os.mode_t; |
| 33 | 33 | pub const INode = os.ino_t; |
| 34 | pub const Uid = os.uid_t; | |
| 35 | pub const Gid = os.gid_t; | |
| 34 | 36 | |
| 35 | 37 | pub const Kind = enum { |
| 36 | 38 | BlockDevice, |
| ... | ... | @@ -362,6 +364,27 @@ pub const File = struct { |
| 362 | 364 | }; |
| 363 | 365 | } |
| 364 | 366 | |
| 367 | pub const ChmodError = std.os.FChmodError; | |
| 368 | ||
| 369 | /// Changes the mode of the file. | |
| 370 | /// The process must have the correct privileges in order to do this | |
| 371 | /// successfully, or must have the effective user ID matching the owner | |
| 372 | /// of the file. | |
| 373 | pub fn chmod(self: File, new_mode: Mode) ChmodError!void { | |
| 374 | try os.fchmod(self.handle, new_mode); | |
| 375 | } | |
| 376 | ||
| 377 | pub const ChownError = std.os.FChownError; | |
| 378 | ||
| 379 | /// Changes the owner and group of the file. | |
| 380 | /// The process must have the correct privileges in order to do this | |
| 381 | /// successfully. The group may be changed by the owner of the file to | |
| 382 | /// any group of which the owner is a member. If the owner or group is | |
| 383 | /// specified as `null`, the ID is not changed. | |
| 384 | pub fn chown(self: File, owner: ?Uid, group: ?Gid) ChownError!void { | |
| 385 | try os.fchown(self.handle, owner, group); | |
| 386 | } | |
| 387 | ||
| 365 | 388 | pub const UpdateTimesError = os.FutimensError || windows.SetFileTimeError; |
| 366 | 389 | |
| 367 | 390 | /// The underlying file system may have a different granularity than nanoseconds, |
lib/std/fs/test.zig+40| ... | ... | @@ -1022,3 +1022,43 @@ test ". and .. in absolute functions" { |
| 1022 | 1022 | |
| 1023 | 1023 | try fs.deleteDirAbsolute(subdir_path); |
| 1024 | 1024 | } |
| 1025 | ||
| 1026 | test "chmod" { | |
| 1027 | if (builtin.os.tag == .windows or builtin.os.tag == .wasi) | |
| 1028 | return error.SkipZigTest; | |
| 1029 | ||
| 1030 | var tmp = tmpDir(.{}); | |
| 1031 | defer tmp.cleanup(); | |
| 1032 | ||
| 1033 | const file = try tmp.dir.createFile("test_file", .{ .mode = 0o600 }); | |
| 1034 | defer file.close(); | |
| 1035 | try testing.expect((try file.stat()).mode & 0o7777 == 0o600); | |
| 1036 | ||
| 1037 | try file.chmod(0o644); | |
| 1038 | try testing.expect((try file.stat()).mode & 0o7777 == 0o644); | |
| 1039 | ||
| 1040 | try tmp.dir.makeDir("test_dir"); | |
| 1041 | var dir = try tmp.dir.openDir("test_dir", .{ .iterate = true }); | |
| 1042 | defer dir.close(); | |
| 1043 | ||
| 1044 | try dir.chmod(0o700); | |
| 1045 | try testing.expect((try dir.stat()).mode & 0o7777 == 0o700); | |
| 1046 | } | |
| 1047 | ||
| 1048 | test "chown" { | |
| 1049 | if (builtin.os.tag == .windows or builtin.os.tag == .wasi) | |
| 1050 | return error.SkipZigTest; | |
| 1051 | ||
| 1052 | var tmp = tmpDir(.{}); | |
| 1053 | defer tmp.cleanup(); | |
| 1054 | ||
| 1055 | const file = try tmp.dir.createFile("test_file", .{}); | |
| 1056 | defer file.close(); | |
| 1057 | try file.chown(null, null); | |
| 1058 | ||
| 1059 | try tmp.dir.makeDir("test_dir"); | |
| 1060 | ||
| 1061 | var dir = try tmp.dir.openDir("test_dir", .{ .iterate = true }); | |
| 1062 | defer dir.close(); | |
| 1063 | try dir.chown(null, null); | |
| 1064 | } |
lib/std/os.zig+81| ... | ... | @@ -255,6 +255,87 @@ pub fn close(fd: fd_t) void { |
| 255 | 255 | } |
| 256 | 256 | } |
| 257 | 257 | |
| 258 | pub const FChmodError = error{ | |
| 259 | AccessDenied, | |
| 260 | InputOutput, | |
| 261 | SymLinkLoop, | |
| 262 | FileNotFound, | |
| 263 | SystemResources, | |
| 264 | ReadOnlyFileSystem, | |
| 265 | } || UnexpectedError; | |
| 266 | ||
| 267 | /// Changes the mode of the file referred to by the file descriptor. | |
| 268 | /// The process must have the correct privileges in order to do this | |
| 269 | /// successfully, or must have the effective user ID matching the owner | |
| 270 | /// of the file. | |
| 271 | pub fn fchmod(fd: fd_t, mode: mode_t) FChmodError!void { | |
| 272 | if (builtin.os.tag == .windows or builtin.os.tag == .wasi) | |
| 273 | @compileError("Unsupported OS"); | |
| 274 | ||
| 275 | while (true) { | |
| 276 | const res = system.fchmod(fd, mode); | |
| 277 | ||
| 278 | switch (system.getErrno(res)) { | |
| 279 | .SUCCESS => return, | |
| 280 | .INTR => continue, | |
| 281 | .BADF => unreachable, // Can be reached if the fd refers to a directory opened without `OpenDirOptions{ .iterate = true }` | |
| 282 | ||
| 283 | .FAULT => unreachable, | |
| 284 | .INVAL => unreachable, | |
| 285 | .ACCES => return error.AccessDenied, | |
| 286 | .IO => return error.InputOutput, | |
| 287 | .LOOP => return error.SymLinkLoop, | |
| 288 | .NOENT => return error.FileNotFound, | |
| 289 | .NOMEM => return error.SystemResources, | |
| 290 | .NOTDIR => return error.FileNotFound, | |
| 291 | .PERM => return error.AccessDenied, | |
| 292 | .ROFS => return error.ReadOnlyFileSystem, | |
| 293 | else => |err| return unexpectedErrno(err), | |
| 294 | } | |
| 295 | } | |
| 296 | } | |
| 297 | ||
| 298 | pub const FChownError = error{ | |
| 299 | AccessDenied, | |
| 300 | InputOutput, | |
| 301 | SymLinkLoop, | |
| 302 | FileNotFound, | |
| 303 | SystemResources, | |
| 304 | ReadOnlyFileSystem, | |
| 305 | } || UnexpectedError; | |
| 306 | ||
| 307 | /// Changes the owner and group of the file referred to by the file descriptor. | |
| 308 | /// The process must have the correct privileges in order to do this | |
| 309 | /// successfully. The group may be changed by the owner of the directory to | |
| 310 | /// any group of which the owner is a member. If the owner or group is | |
| 311 | /// specified as `null`, the ID is not changed. | |
| 312 | pub fn fchown(fd: fd_t, owner: ?uid_t, group: ?gid_t) FChownError!void { | |
| 313 | if (builtin.os.tag == .windows or builtin.os.tag == .wasi) | |
| 314 | @compileError("Unsupported OS"); | |
| 315 | ||
| 316 | while (true) { | |
| 317 | const res = system.fchown(fd, owner orelse @as(u32, 0) -% 1, group orelse @as(u32, 0) -% 1); | |
| 318 | ||
| 319 | switch (system.getErrno(res)) { | |
| 320 | .SUCCESS => return, | |
| 321 | .INTR => continue, | |
| 322 | .BADF => unreachable, // Can be reached if the fd refers to a directory opened without `OpenDirOptions{ .iterate = true }` | |
| 323 | ||
| 324 | .FAULT => unreachable, | |
| 325 | .INVAL => unreachable, | |
| 326 | .ACCES => return error.AccessDenied, | |
| 327 | .IO => return error.InputOutput, | |
| 328 | .LOOP => return error.SymLinkLoop, | |
| 329 | .NOENT => return error.FileNotFound, | |
| 330 | .NOMEM => return error.SystemResources, | |
| 331 | .NOTDIR => return error.FileNotFound, | |
| 332 | .PERM => return error.AccessDenied, | |
| 333 | .ROFS => return error.ReadOnlyFileSystem, | |
| 334 | else => |err| return unexpectedErrno(err), | |
| 335 | } | |
| 336 | } | |
| 337 | } | |
| 338 | ||
| 258 | 339 | pub const GetRandomError = OpenError; |
| 259 | 340 | |
| 260 | 341 | /// Obtain a series of random bytes. These bytes can be used to seed user-space |
lib/std/os/linux.zig+8| ... | ... | @@ -733,6 +733,14 @@ pub fn close(fd: i32) usize { |
| 733 | 733 | return syscall1(.close, @bitCast(usize, @as(isize, fd))); |
| 734 | 734 | } |
| 735 | 735 | |
| 736 | pub fn fchmod(fd: i32, mode: mode_t) usize { | |
| 737 | return syscall2(.fchmod, @bitCast(usize, @as(isize, fd)), mode); | |
| 738 | } | |
| 739 | ||
| 740 | pub fn fchown(fd: i32, owner: uid_t, group: gid_t) usize { | |
| 741 | return syscall3(.fchown, @bitCast(usize, @as(isize, fd)), owner, group); | |
| 742 | } | |
| 743 | ||
| 736 | 744 | /// Can only be called on 32 bit systems. For 64 bit see `lseek`. |
| 737 | 745 | pub fn llseek(fd: i32, offset: u64, result: ?*u64, whence: usize) usize { |
| 738 | 746 | // NOTE: The offset parameter splitting is independent from the target |