diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2020-03-03 15:01:08 -0500 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2020-03-03 15:23:27 -0500 |
| commit | 4a67dd04c99954af2fd8e38b99704a1faea16267 (patch) | |
| tree | c9d66453e4e5bb0a9814db1f2ab5502bc3628207 /lib/std/os.zig | |
| parent | 1ca5f06762401d2e90c8119acb4837571696dd5e (diff) | |
| download | zig-4a67dd04c99954af2fd8e38b99704a1faea16267.tar.gz zig-4a67dd04c99954af2fd8e38b99704a1faea16267.zip | |
breaking changes to std.fs, std.os
* improve `std.fs.AtomicFile` to use sendfile()
- also fix AtomicFile cleanup not destroying tmp files under some
error conditions
* improve `std.fs.updateFile` to take advantage of the new `makePath`
which no longer needs an Allocator.
* rename std.fs.makeDir to std.fs.makeDirAbsolute
* rename std.fs.Dir.makeDirC to std.fs.Dir.makeDirZ
* add std.fs.Dir.makeDirW and provide Windows implementation of
std.os.mkdirat. std.os.windows.CreateDirectory is now implemented
by calling ntdll, supports an optional root directory handle,
and returns an open directory handle. Its error set has a few more
errors in it.
* rename std.fs.Dir.changeTo to std.fs.Dir.setAsCwd
* fix std.fs.File.writevAll and related functions when len 0 iovecs
supplied.
* introduce `std.fs.File.writeFileAll`, exposing a convenient
cross-platform API on top of sendfile().
* `NoDevice` added to std.os.MakeDirError error set.
* std.os.fchdir gets a smaller error set.
* std.os.windows.CloseHandle is implemented with ntdll call rather than
kernel32.
Diffstat (limited to 'lib/std/os.zig')
| -rw-r--r-- | lib/std/os.zig | 70 |
1 files changed, 46 insertions, 24 deletions
diff --git a/lib/std/os.zig b/lib/std/os.zig index 3ba810445a..b530ac94ab 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -1539,12 +1539,13 @@ pub const MakeDirError = error{ ReadOnlyFileSystem, InvalidUtf8, BadPathName, + NoDevice, } || UnexpectedError; pub fn mkdirat(dir_fd: fd_t, sub_dir_path: []const u8, mode: u32) MakeDirError!void { - if (builtin.os == .windows) { + if (builtin.os.tag == .windows) { const sub_dir_path_w = try windows.sliceToPrefixedFileW(sub_dir_path); - @compileError("TODO implement mkdirat for Windows"); + return mkdiratW(dir_fd, &sub_dir_path_w, mode); } else { const sub_dir_path_c = try toPosixPath(sub_dir_path); return mkdiratC(dir_fd, &sub_dir_path_c, mode); @@ -1552,9 +1553,9 @@ pub fn mkdirat(dir_fd: fd_t, sub_dir_path: []const u8, mode: u32) MakeDirError!v } pub fn mkdiratC(dir_fd: fd_t, sub_dir_path: [*:0]const u8, mode: u32) MakeDirError!void { - if (builtin.os == .windows) { + if (builtin.os.tag == .windows) { const sub_dir_path_w = try windows.cStrToPrefixedFileW(sub_dir_path); - @compileError("TODO implement mkdiratC for Windows"); + return mkdiratW(dir_fd, &sub_dir_path_w, mode); } switch (errno(system.mkdirat(dir_fd, sub_dir_path, mode))) { 0 => return, @@ -1576,23 +1577,31 @@ pub fn mkdiratC(dir_fd: fd_t, sub_dir_path: [*:0]const u8, mode: u32) MakeDirErr } } +pub fn mkdiratW(dir_fd: fd_t, sub_path_w: [*:0]const u16, mode: u32) MakeDirError!void { + const sub_dir_handle = try windows.CreateDirectoryW(dir_fd, sub_path_w, null); + windows.CloseHandle(sub_dir_handle); +} + /// Create a directory. /// `mode` is ignored on Windows. pub fn mkdir(dir_path: []const u8, mode: u32) MakeDirError!void { if (builtin.os.tag == .windows) { - const dir_path_w = try windows.sliceToPrefixedFileW(dir_path); - return windows.CreateDirectoryW(&dir_path_w, null); + const sub_dir_handle = try windows.CreateDirectory(null, dir_path, null); + windows.CloseHandle(sub_dir_handle); + return; } else { const dir_path_c = try toPosixPath(dir_path); - return mkdirC(&dir_path_c, mode); + return mkdirZ(&dir_path_c, mode); } } /// Same as `mkdir` but the parameter is a null-terminated UTF8-encoded string. -pub fn mkdirC(dir_path: [*:0]const u8, mode: u32) MakeDirError!void { +pub fn mkdirZ(dir_path: [*:0]const u8, mode: u32) MakeDirError!void { if (builtin.os.tag == .windows) { const dir_path_w = try windows.cStrToPrefixedFileW(dir_path); - return windows.CreateDirectoryW(&dir_path_w, null); + const sub_dir_handle = try windows.CreateDirectoryW(null, &dir_path_w, null); + windows.CloseHandle(sub_dir_handle); + return; } switch (errno(system.mkdir(dir_path, mode))) { 0 => return, @@ -1705,7 +1714,13 @@ pub fn chdirC(dir_path: [*:0]const u8) ChangeCurDirError!void { } } -pub fn fchdir(dirfd: fd_t) ChangeCurDirError!void { +pub const FchdirError = error{ + AccessDenied, + NotDir, + FileSystem, +} || UnexpectedError; + +pub fn fchdir(dirfd: fd_t) FchdirError!void { while (true) { switch (errno(system.fchdir(dirfd))) { 0 => return, @@ -3564,12 +3579,12 @@ fn count_iovec_bytes(iovs: []const iovec_const) usize { } /// Transfer data between file descriptors, with optional headers and trailers. -/// Returns the number of bytes written. This will be zero if `in_offset` falls beyond the end of the file. +/// Returns the number of bytes written, which can be zero. /// -/// The `sendfile` call copies `count` bytes from one file descriptor to another. When possible, +/// The `sendfile` call copies `in_len` bytes from one file descriptor to another. When possible, /// this is done within the operating system kernel, which can provide better performance /// characteristics than transferring data from kernel to user space and back, such as with -/// `read` and `write` calls. When `count` is `0`, it means to copy until the end of the input file has been +/// `read` and `write` calls. When `in_len` is `0`, it means to copy until the end of the input file has been /// reached. Note, however, that partial writes are still possible in this case. /// /// `in_fd` must be a file descriptor opened for reading, and `out_fd` must be a file descriptor @@ -3578,7 +3593,8 @@ fn count_iovec_bytes(iovs: []const iovec_const) usize { /// atomicity guarantees no longer apply. /// /// Copying begins reading at `in_offset`. The input file descriptor seek position is ignored and not updated. -/// If the output file descriptor has a seek position, it is updated as bytes are written. +/// If the output file descriptor has a seek position, it is updated as bytes are written. When +/// `in_offset` is past the end of the input file, it successfully reads 0 bytes. /// /// `flags` has different meanings per operating system; refer to the respective man pages. /// @@ -3599,7 +3615,7 @@ pub fn sendfile( out_fd: fd_t, in_fd: fd_t, in_offset: u64, - count: usize, + in_len: u64, headers: []const iovec_const, trailers: []const iovec_const, flags: u32, @@ -3608,9 +3624,15 @@ pub fn sendfile( var total_written: usize = 0; // Prevents EOVERFLOW. + const size_t = @Type(std.builtin.TypeInfo{ + .Int = .{ + .is_signed = false, + .bits = @typeInfo(usize).Int.bits - 1, + }, + }); const max_count = switch (std.Target.current.os.tag) { .linux => 0x7ffff000, - else => math.maxInt(isize), + else => math.maxInt(size_t), }; switch (std.Target.current.os.tag) { @@ -3630,7 +3652,7 @@ pub fn sendfile( } // Here we match BSD behavior, making a zero count value send as many bytes as possible. - const adjusted_count = if (count == 0) max_count else math.min(count, max_count); + const adjusted_count = if (in_len == 0) max_count else math.min(in_len, @as(size_t, max_count)); while (true) { var offset: off_t = @bitCast(off_t, in_offset); @@ -3639,10 +3661,10 @@ pub fn sendfile( 0 => { const amt = @bitCast(usize, rc); total_written += amt; - if (count == 0 and amt == 0) { + if (in_len == 0 and amt == 0) { // We have detected EOF from `in_fd`. break; - } else if (amt < count) { + } else if (amt < in_len) { return total_written; } else { break; @@ -3708,7 +3730,7 @@ pub fn sendfile( hdtr = &hdtr_data; } - const adjusted_count = math.min(count, max_count); + const adjusted_count = math.min(in_len, max_count); while (true) { var sbytes: off_t = undefined; @@ -3786,7 +3808,7 @@ pub fn sendfile( hdtr = &hdtr_data; } - const adjusted_count = math.min(count, @as(u63, max_count)); + const adjusted_count = math.min(in_len, @as(u63, max_count)); while (true) { var sbytes: off_t = adjusted_count; @@ -3840,10 +3862,10 @@ pub fn sendfile( rw: { var buf: [8 * 4096]u8 = undefined; // Here we match BSD behavior, making a zero count value send as many bytes as possible. - const adjusted_count = if (count == 0) buf.len else math.min(buf.len, count); + const adjusted_count = if (in_len == 0) buf.len else math.min(buf.len, in_len); const amt_read = try pread(in_fd, buf[0..adjusted_count], in_offset); if (amt_read == 0) { - if (count == 0) { + if (in_len == 0) { // We have detected EOF from `in_fd`. break :rw; } else { @@ -3852,7 +3874,7 @@ pub fn sendfile( } const amt_written = try write(out_fd, buf[0..amt_read]); total_written += amt_written; - if (amt_written < count or count == 0) return total_written; + if (amt_written < in_len or in_len == 0) return total_written; } if (trailers.len != 0) { |
