diff options
| author | Andrew Kelley <superjoe30@gmail.com> | 2018-06-14 18:27:59 -0400 |
|---|---|---|
| committer | Andrew Kelley <superjoe30@gmail.com> | 2018-06-14 18:27:59 -0400 |
| commit | 32dd98b19fe3cc384df32704dac0ff3e377dbe0c (patch) | |
| tree | 2eddf3618d80313bdd24c25bd589bd474f3d82fc /std/os | |
| parent | ef7f69d14a017c6c2065e4a376bb8e1f05ace04b (diff) | |
| parent | f0697c28f80d64c544302aea576e41ebc443b41c (diff) | |
| download | zig-32dd98b19fe3cc384df32704dac0ff3e377dbe0c.tar.gz zig-32dd98b19fe3cc384df32704dac0ff3e377dbe0c.zip | |
Merge remote-tracking branch 'origin/master' into llvm7
Diffstat (limited to 'std/os')
| -rw-r--r-- | std/os/child_process.zig | 18 | ||||
| -rw-r--r-- | std/os/darwin.zig | 8 | ||||
| -rw-r--r-- | std/os/file.zig | 19 | ||||
| -rw-r--r-- | std/os/index.zig | 306 | ||||
| -rw-r--r-- | std/os/linux/vdso.zig | 10 | ||||
| -rw-r--r-- | std/os/path.zig | 74 | ||||
| -rw-r--r-- | std/os/test.zig | 9 | ||||
| -rw-r--r-- | std/os/time.zig | 6 | ||||
| -rw-r--r-- | std/os/windows/index.zig | 66 | ||||
| -rw-r--r-- | std/os/windows/util.zig | 43 |
10 files changed, 388 insertions, 171 deletions
diff --git a/std/os/child_process.zig b/std/os/child_process.zig index 822ade2eb8..1e3a732498 100644 --- a/std/os/child_process.zig +++ b/std/os/child_process.zig @@ -156,7 +156,7 @@ pub const ChildProcess = struct { }; } try self.waitUnwrappedWindows(); - return ??self.term; + return self.term.?; } pub fn killPosix(self: *ChildProcess) !Term { @@ -175,7 +175,7 @@ pub const ChildProcess = struct { }; } self.waitUnwrapped(); - return ??self.term; + return self.term.?; } /// Blocks until child process terminates and then cleans up all resources. @@ -212,8 +212,8 @@ pub const ChildProcess = struct { defer Buffer.deinit(&stdout); defer Buffer.deinit(&stderr); - var stdout_file_in_stream = io.FileInStream.init(&??child.stdout); - var stderr_file_in_stream = io.FileInStream.init(&??child.stderr); + var stdout_file_in_stream = io.FileInStream.init(&child.stdout.?); + var stderr_file_in_stream = io.FileInStream.init(&child.stderr.?); try stdout_file_in_stream.stream.readAllBuffer(&stdout, max_output_size); try stderr_file_in_stream.stream.readAllBuffer(&stderr, max_output_size); @@ -232,7 +232,7 @@ pub const ChildProcess = struct { } try self.waitUnwrappedWindows(); - return ??self.term; + return self.term.?; } fn waitPosix(self: *ChildProcess) !Term { @@ -242,7 +242,7 @@ pub const ChildProcess = struct { } self.waitUnwrapped(); - return ??self.term; + return self.term.?; } pub fn deinit(self: *ChildProcess) void { @@ -619,13 +619,13 @@ pub const ChildProcess = struct { self.term = null; if (self.stdin_behavior == StdIo.Pipe) { - os.close(??g_hChildStd_IN_Rd); + os.close(g_hChildStd_IN_Rd.?); } if (self.stderr_behavior == StdIo.Pipe) { - os.close(??g_hChildStd_ERR_Wr); + os.close(g_hChildStd_ERR_Wr.?); } if (self.stdout_behavior == StdIo.Pipe) { - os.close(??g_hChildStd_OUT_Wr); + os.close(g_hChildStd_OUT_Wr.?); } } diff --git a/std/os/darwin.zig b/std/os/darwin.zig index b8e18561cc..a835959103 100644 --- a/std/os/darwin.zig +++ b/std/os/darwin.zig @@ -327,7 +327,7 @@ pub fn raise(sig: i32) usize { } pub fn read(fd: i32, buf: [*]u8, nbyte: usize) usize { - return errnoWrap(c.read(fd, @ptrCast([*]c_void, buf), nbyte)); + return errnoWrap(c.read(fd, @ptrCast(*c_void, buf), nbyte)); } pub fn stat(noalias path: [*]const u8, noalias buf: *stat) usize { @@ -335,17 +335,17 @@ pub fn stat(noalias path: [*]const u8, noalias buf: *stat) usize { } pub fn write(fd: i32, buf: [*]const u8, nbyte: usize) usize { - return errnoWrap(c.write(fd, @ptrCast([*]const c_void, buf), nbyte)); + return errnoWrap(c.write(fd, @ptrCast(*const c_void, buf), nbyte)); } pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, offset: isize) usize { - const ptr_result = c.mmap(@ptrCast([*]c_void, address), length, @bitCast(c_int, c_uint(prot)), @bitCast(c_int, c_uint(flags)), fd, offset); + const ptr_result = c.mmap(@ptrCast(*c_void, address), length, @bitCast(c_int, c_uint(prot)), @bitCast(c_int, c_uint(flags)), fd, offset); const isize_result = @bitCast(isize, @ptrToInt(ptr_result)); return errnoWrap(isize_result); } pub fn munmap(address: usize, length: usize) usize { - return errnoWrap(c.munmap(@intToPtr([*]c_void, address), length)); + return errnoWrap(c.munmap(@intToPtr(*c_void, address), length)); } pub fn unlink(path: [*]const u8) usize { diff --git a/std/os/file.zig b/std/os/file.zig index 378782507b..56da4f73a6 100644 --- a/std/os/file.zig +++ b/std/os/file.zig @@ -96,7 +96,20 @@ pub const File = struct { return File{ .handle = handle }; } - pub fn access(allocator: *mem.Allocator, path: []const u8, file_mode: os.FileMode) !bool { + pub const AccessError = error{ + PermissionDenied, + NotFound, + NameTooLong, + BadMode, + BadPathName, + Io, + SystemResources, + OutOfMemory, + + Unexpected, + }; + + pub fn access(allocator: *mem.Allocator, path: []const u8, file_mode: os.FileMode) AccessError!bool { const path_with_null = try std.cstr.addNullByte(allocator, path); defer allocator.free(path_with_null); @@ -123,7 +136,7 @@ pub const File = struct { } return true; } else if (is_windows) { - if (os.windows.PathFileExists(path_with_null.ptr) == os.windows.TRUE) { + if (os.windows.GetFileAttributesA(path_with_null.ptr) != os.windows.INVALID_FILE_ATTRIBUTES) { return true; } @@ -334,7 +347,7 @@ pub const File = struct { while (index < buffer.len) { const want_read_count = windows.DWORD(math.min(windows.DWORD(@maxValue(windows.DWORD)), buffer.len - index)); var amt_read: windows.DWORD = undefined; - if (windows.ReadFile(self.handle, @ptrCast([*]c_void, buffer.ptr + index), want_read_count, &amt_read, null) == 0) { + if (windows.ReadFile(self.handle, @ptrCast(*c_void, buffer.ptr + index), want_read_count, &amt_read, null) == 0) { const err = windows.GetLastError(); return switch (err) { windows.ERROR.OPERATION_ABORTED => continue, diff --git a/std/os/index.zig b/std/os/index.zig index 6023929b04..62eeb7e43e 100644 --- a/std/os/index.zig +++ b/std/os/index.zig @@ -422,10 +422,10 @@ pub fn posixExecve(argv: []const []const u8, env_map: *const BufMap, allocator: const exe_path = argv[0]; if (mem.indexOfScalar(u8, exe_path, '/') != null) { - return posixExecveErrnoToErr(posix.getErrno(posix.execve(??argv_buf[0], argv_buf.ptr, envp_buf.ptr))); + return posixExecveErrnoToErr(posix.getErrno(posix.execve(argv_buf[0].?, argv_buf.ptr, envp_buf.ptr))); } - const PATH = getEnvPosix("PATH") ?? "/usr/local/bin:/bin/:/usr/bin"; + const PATH = getEnvPosix("PATH") orelse "/usr/local/bin:/bin/:/usr/bin"; // PATH.len because it is >= the largest search_path // +1 for the / to join the search path and exe_path // +1 for the null terminating byte @@ -490,7 +490,7 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap { errdefer result.deinit(); if (is_windows) { - const ptr = windows.GetEnvironmentStringsA() ?? return error.OutOfMemory; + const ptr = windows.GetEnvironmentStringsA() orelse return error.OutOfMemory; defer assert(windows.FreeEnvironmentStringsA(ptr) != 0); var i: usize = 0; @@ -573,7 +573,7 @@ pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) ![]u8 { return allocator.shrink(u8, buf, result); } } else { - const result = getEnvPosix(key) ?? return error.EnvironmentVariableNotFound; + const result = getEnvPosix(key) orelse return error.EnvironmentVariableNotFound; return mem.dupe(allocator, u8, result); } } @@ -714,7 +714,7 @@ pub fn atomicSymLink(allocator: *Allocator, existing_path: []const u8, new_path: else => return err, // TODO zig should know this set does not include PathAlreadyExists } - const dirname = os.path.dirname(new_path); + const dirname = os.path.dirname(new_path) orelse "."; var rand_buf: [12]u8 = undefined; const tmp_path = try allocator.alloc(u8, dirname.len + 1 + base64.Base64Encoder.calcSize(rand_buf.len)); @@ -734,7 +734,23 @@ pub fn atomicSymLink(allocator: *Allocator, existing_path: []const u8, new_path: } } -pub fn deleteFile(allocator: *Allocator, file_path: []const u8) !void { +pub const DeleteFileError = error{ + FileNotFound, + AccessDenied, + FileBusy, + FileSystem, + IsDir, + SymLinkLoop, + NameTooLong, + NotDir, + SystemResources, + ReadOnlyFileSystem, + OutOfMemory, + + Unexpected, +}; + +pub fn deleteFile(allocator: *Allocator, file_path: []const u8) DeleteFileError!void { if (builtin.os == Os.windows) { return deleteFileWindows(allocator, file_path); } else { @@ -844,14 +860,14 @@ pub const AtomicFile = struct { var rand_buf: [12]u8 = undefined; - const dirname_component_len = if (dirname.len == 0) 0 else dirname.len + 1; + const dirname_component_len = if (dirname) |d| d.len + 1 else 0; const tmp_path = try allocator.alloc(u8, dirname_component_len + base64.Base64Encoder.calcSize(rand_buf.len)); errdefer allocator.free(tmp_path); - if (dirname.len != 0) { - mem.copy(u8, tmp_path[0..], dirname); - tmp_path[dirname.len] = os.path.sep; + if (dirname) |dir| { + mem.copy(u8, tmp_path[0..], dir); + tmp_path[dir.len] = os.path.sep; } while (true) { @@ -1019,37 +1035,66 @@ pub fn makePath(allocator: *Allocator, full_path: []const u8) !void { } } +pub const DeleteDirError = error{ + AccessDenied, + FileBusy, + SymLinkLoop, + NameTooLong, + FileNotFound, + SystemResources, + NotDir, + DirNotEmpty, + ReadOnlyFileSystem, + OutOfMemory, + + Unexpected, +}; + /// Returns ::error.DirNotEmpty if the directory is not empty. /// To delete a directory recursively, see ::deleteTree -pub fn deleteDir(allocator: *Allocator, dir_path: []const u8) !void { +pub fn deleteDir(allocator: *Allocator, dir_path: []const u8) DeleteDirError!void { const path_buf = try allocator.alloc(u8, dir_path.len + 1); defer allocator.free(path_buf); mem.copy(u8, path_buf, dir_path); path_buf[dir_path.len] = 0; - const err = posix.getErrno(posix.rmdir(path_buf.ptr)); - if (err > 0) { - return switch (err) { - posix.EACCES, posix.EPERM => error.AccessDenied, - posix.EBUSY => error.FileBusy, - posix.EFAULT, posix.EINVAL => unreachable, - posix.ELOOP => error.SymLinkLoop, - posix.ENAMETOOLONG => error.NameTooLong, - posix.ENOENT => error.FileNotFound, - posix.ENOMEM => error.SystemResources, - posix.ENOTDIR => error.NotDir, - posix.EEXIST, posix.ENOTEMPTY => error.DirNotEmpty, - posix.EROFS => error.ReadOnlyFileSystem, - else => unexpectedErrorPosix(err), - }; + switch (builtin.os) { + Os.windows => { + if (windows.RemoveDirectoryA(path_buf.ptr) == 0) { + const err = windows.GetLastError(); + return switch (err) { + windows.ERROR.PATH_NOT_FOUND => error.FileNotFound, + windows.ERROR.DIR_NOT_EMPTY => error.DirNotEmpty, + else => unexpectedErrorWindows(err), + }; + } + }, + Os.linux, Os.macosx, Os.ios => { + const err = posix.getErrno(posix.rmdir(path_buf.ptr)); + if (err > 0) { + return switch (err) { + posix.EACCES, posix.EPERM => error.AccessDenied, + posix.EBUSY => error.FileBusy, + posix.EFAULT, posix.EINVAL => unreachable, + posix.ELOOP => error.SymLinkLoop, + posix.ENAMETOOLONG => error.NameTooLong, + posix.ENOENT => error.FileNotFound, + posix.ENOMEM => error.SystemResources, + posix.ENOTDIR => error.NotDir, + posix.EEXIST, posix.ENOTEMPTY => error.DirNotEmpty, + posix.EROFS => error.ReadOnlyFileSystem, + else => unexpectedErrorPosix(err), + }; + } + }, + else => @compileError("unimplemented"), } } /// Whether ::full_path describes a symlink, file, or directory, this function /// removes it. If it cannot be removed because it is a non-empty directory, /// this function recursively removes its entries and then tries again. -/// TODO non-recursive implementation const DeleteTreeError = error{ OutOfMemory, AccessDenied, @@ -1128,7 +1173,7 @@ pub fn deleteTree(allocator: *Allocator, full_path: []const u8) DeleteTreeError! try full_entry_buf.resize(full_path.len + entry.name.len + 1); const full_entry_path = full_entry_buf.toSlice(); mem.copy(u8, full_entry_path, full_path); - full_entry_path[full_path.len] = '/'; + full_entry_path[full_path.len] = path.sep; mem.copy(u8, full_entry_path[full_path.len + 1 ..], entry.name); try deleteTree(allocator, full_entry_path); @@ -1139,16 +1184,29 @@ pub fn deleteTree(allocator: *Allocator, full_path: []const u8) DeleteTreeError! } pub const Dir = struct { - fd: i32, - darwin_seek: darwin_seek_t, + handle: Handle, allocator: *Allocator, - buf: []u8, - index: usize, - end_index: usize, - const darwin_seek_t = switch (builtin.os) { - Os.macosx, Os.ios => i64, - else => void, + pub const Handle = switch (builtin.os) { + Os.macosx, Os.ios => struct { + fd: i32, + seek: i64, + buf: []u8, + index: usize, + end_index: usize, + }, + Os.linux => struct { + fd: i32, + buf: []u8, + index: usize, + end_index: usize, + }, + Os.windows => struct { + handle: windows.HANDLE, + find_file_data: windows.WIN32_FIND_DATAA, + first: bool, + }, + else => @compileError("unimplemented"), }; pub const Entry = struct { @@ -1168,81 +1226,122 @@ pub const Dir = struct { }; }; - pub fn open(allocator: *Allocator, dir_path: []const u8) !Dir { - const fd = switch (builtin.os) { - Os.windows => @compileError("TODO support Dir.open for windows"), - Os.linux => try posixOpen(allocator, dir_path, posix.O_RDONLY | posix.O_DIRECTORY | posix.O_CLOEXEC, 0), - Os.macosx, Os.ios => try posixOpen( - allocator, - dir_path, - posix.O_RDONLY | posix.O_NONBLOCK | posix.O_DIRECTORY | posix.O_CLOEXEC, - 0, - ), - else => @compileError("Dir.open is not supported for this platform"), - }; - const darwin_seek_init = switch (builtin.os) { - Os.macosx, Os.ios => 0, - else => {}, - }; + pub const OpenError = error{ + PathNotFound, + NotDir, + AccessDenied, + FileTooBig, + IsDir, + SymLinkLoop, + ProcessFdQuotaExceeded, + NameTooLong, + SystemFdQuotaExceeded, + NoDevice, + SystemResources, + NoSpaceLeft, + PathAlreadyExists, + OutOfMemory, + + Unexpected, + }; + + pub fn open(allocator: *Allocator, dir_path: []const u8) OpenError!Dir { return Dir{ .allocator = allocator, - .fd = fd, - .darwin_seek = darwin_seek_init, - .index = 0, - .end_index = 0, - .buf = []u8{}, + .handle = switch (builtin.os) { + Os.windows => blk: { + var find_file_data: windows.WIN32_FIND_DATAA = undefined; + const handle = try windows_util.windowsFindFirstFile(allocator, dir_path, &find_file_data); + break :blk Handle{ + .handle = handle, + .find_file_data = find_file_data, // TODO guaranteed copy elision + .first = true, + }; + }, + Os.macosx, Os.ios => Handle{ + .fd = try posixOpen( + allocator, + dir_path, + posix.O_RDONLY | posix.O_NONBLOCK | posix.O_DIRECTORY | posix.O_CLOEXEC, + 0, + ), + .seek = 0, + .index = 0, + .end_index = 0, + .buf = []u8{}, + }, + Os.linux => Handle{ + .fd = try posixOpen( + allocator, + dir_path, + posix.O_RDONLY | posix.O_DIRECTORY | posix.O_CLOEXEC, + 0, + ), + .index = 0, + .end_index = 0, + .buf = []u8{}, + }, + else => @compileError("unimplemented"), + }, }; } pub fn close(self: *Dir) void { - self.allocator.free(self.buf); - os.close(self.fd); + switch (builtin.os) { + Os.windows => { + _ = windows.FindClose(self.handle.handle); + }, + Os.macosx, Os.ios, Os.linux => { + self.allocator.free(self.handle.buf); + os.close(self.handle.fd); + }, + else => @compileError("unimplemented"), + } } /// Memory such as file names referenced in this returned entry becomes invalid - /// with subsequent calls to next, as well as when this ::Dir is deinitialized. + /// with subsequent calls to next, as well as when this `Dir` is deinitialized. pub fn next(self: *Dir) !?Entry { switch (builtin.os) { Os.linux => return self.nextLinux(), Os.macosx, Os.ios => return self.nextDarwin(), Os.windows => return self.nextWindows(), - else => @compileError("Dir.next not supported on " ++ @tagName(builtin.os)), + else => @compileError("unimplemented"), } } fn nextDarwin(self: *Dir) !?Entry { start_over: while (true) { - if (self.index >= self.end_index) { - if (self.buf.len == 0) { - self.buf = try self.allocator.alloc(u8, page_size); + if (self.handle.index >= self.handle.end_index) { + if (self.handle.buf.len == 0) { + self.handle.buf = try self.allocator.alloc(u8, page_size); } while (true) { - const result = posix.getdirentries64(self.fd, self.buf.ptr, self.buf.len, &self.darwin_seek); + const result = posix.getdirentries64(self.handle.fd, self.handle.buf.ptr, self.handle.buf.len, &self.handle.seek); const err = posix.getErrno(result); if (err > 0) { switch (err) { posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable, posix.EINVAL => { - self.buf = try self.allocator.realloc(u8, self.buf, self.buf.len * 2); + self.handle.buf = try self.allocator.realloc(u8, self.handle.buf, self.handle.buf.len * 2); continue; }, else => return unexpectedErrorPosix(err), } } if (result == 0) return null; - self.index = 0; - self.end_index = result; + self.handle.index = 0; + self.handle.end_index = result; break; } } - const darwin_entry = @ptrCast(*align(1) posix.dirent, &self.buf[self.index]); - const next_index = self.index + darwin_entry.d_reclen; - self.index = next_index; + const darwin_entry = @ptrCast(*align(1) posix.dirent, &self.handle.buf[self.handle.index]); + const next_index = self.handle.index + darwin_entry.d_reclen; + self.handle.index = next_index; const name = @ptrCast([*]u8, &darwin_entry.d_name)[0..darwin_entry.d_namlen]; - // skip . and .. entries if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) { continue :start_over; } @@ -1266,38 +1365,59 @@ pub const Dir = struct { } fn nextWindows(self: *Dir) !?Entry { - @compileError("TODO support Dir.next for windows"); + while (true) { + if (self.handle.first) { + self.handle.first = false; + } else { + if (!try windows_util.windowsFindNextFile(self.handle.handle, &self.handle.find_file_data)) + return null; + } + const name = std.cstr.toSlice(self.handle.find_file_data.cFileName[0..].ptr); + if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) + continue; + const kind = blk: { + const attrs = self.handle.find_file_data.dwFileAttributes; + if (attrs & windows.FILE_ATTRIBUTE_DIRECTORY != 0) break :blk Entry.Kind.Directory; + if (attrs & windows.FILE_ATTRIBUTE_REPARSE_POINT != 0) break :blk Entry.Kind.SymLink; + if (attrs & windows.FILE_ATTRIBUTE_NORMAL != 0) break :blk Entry.Kind.File; + break :blk Entry.Kind.Unknown; + }; + return Entry{ + .name = name, + .kind = kind, + }; + } } fn nextLinux(self: *Dir) !?Entry { start_over: while (true) { - if (self.index >= self.end_index) { - if (self.buf.len == 0) { - self.buf = try self.allocator.alloc(u8, page_size); + if (self.handle.index >= self.handle.end_index) { + if (self.handle.buf.len == 0) { + self.handle.buf = try self.allocator.alloc(u8, page_size); } while (true) { - const result = posix.getdents(self.fd, self.buf.ptr, self.buf.len); + const result = posix.getdents(self.handle.fd, self.handle.buf.ptr, self.handle.buf.len); const err = posix.getErrno(result); if (err > 0) { switch (err) { posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable, posix.EINVAL => { - self.buf = try self.allocator.realloc(u8, self.buf, self.buf.len * 2); + self.handle.buf = try self.allocator.realloc(u8, self.handle.buf, self.handle.buf.len * 2); continue; }, else => return unexpectedErrorPosix(err), } } if (result == 0) return null; - self.index = 0; - self.end_index = result; + self.handle.index = 0; + self.handle.end_index = result; break; } } - const linux_entry = @ptrCast(*align(1) posix.dirent, &self.buf[self.index]); - const next_index = self.index + linux_entry.d_reclen; - self.index = next_index; + const linux_entry = @ptrCast(*align(1) posix.dirent, &self.handle.buf[self.handle.index]); + const next_index = self.handle.index + linux_entry.d_reclen; + self.handle.index = next_index; const name = cstr.toSlice(@ptrCast([*]u8, &linux_entry.d_name)); @@ -1306,7 +1426,7 @@ pub const Dir = struct { continue :start_over; } - const type_char = self.buf[next_index - 1]; + const type_char = self.handle.buf[next_index - 1]; const entry_kind = switch (type_char) { posix.DT_BLK => Entry.Kind.BlockDevice, posix.DT_CHR => Entry.Kind.CharacterDevice, @@ -1641,7 +1761,7 @@ pub const ArgIterator = struct { if (builtin.os == Os.windows) { return self.inner.next(allocator); } else { - return mem.dupe(allocator, u8, self.inner.next() ?? return null); + return mem.dupe(allocator, u8, self.inner.next() orelse return null); } } @@ -1729,7 +1849,7 @@ test "windows arg parsing" { fn testWindowsCmdLine(input_cmd_line: [*]const u8, expected_args: []const []const u8) void { var it = ArgIteratorWindows.initWithCmdLine(input_cmd_line); for (expected_args) |expected_arg| { - const arg = ??it.next(debug.global_allocator) catch unreachable; + const arg = it.next(debug.global_allocator).? catch unreachable; assert(mem.eql(u8, arg, expected_arg)); } assert(it.next(debug.global_allocator) == null); @@ -1845,13 +1965,13 @@ pub fn selfExeDirPath(allocator: *mem.Allocator) ![]u8 { // the executable was in when it was run. const full_exe_path = try readLink(allocator, "/proc/self/exe"); errdefer allocator.free(full_exe_path); - const dir = path.dirname(full_exe_path); + const dir = path.dirname(full_exe_path) orelse "."; return allocator.shrink(u8, full_exe_path, dir.len); }, Os.windows, Os.macosx, Os.ios => { const self_exe_path = try selfExePath(allocator); errdefer allocator.free(self_exe_path); - const dirname = os.path.dirname(self_exe_path); + const dirname = os.path.dirname(self_exe_path) orelse "."; return allocator.shrink(u8, self_exe_path, dirname.len); }, else => @compileError("unimplemented: std.os.selfExeDirPath for " ++ @tagName(builtin.os)), @@ -2362,7 +2482,7 @@ pub const Thread = struct { }, builtin.Os.windows => struct { handle: windows.HANDLE, - alloc_start: [*]c_void, + alloc_start: *c_void, heap_handle: windows.HANDLE, }, else => @compileError("Unsupported OS"), @@ -2457,9 +2577,9 @@ pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!*Thread } }; - const heap_handle = windows.GetProcessHeap() ?? return SpawnThreadError.OutOfMemory; + const heap_handle = windows.GetProcessHeap() orelse return SpawnThreadError.OutOfMemory; const byte_count = @alignOf(WinThread.OuterContext) + @sizeOf(WinThread.OuterContext); - const bytes_ptr = windows.HeapAlloc(heap_handle, 0, byte_count) ?? return SpawnThreadError.OutOfMemory; + const bytes_ptr = windows.HeapAlloc(heap_handle, 0, byte_count) orelse return SpawnThreadError.OutOfMemory; errdefer assert(windows.HeapFree(heap_handle, 0, bytes_ptr) != 0); const bytes = @ptrCast([*]u8, bytes_ptr)[0..byte_count]; const outer_context = std.heap.FixedBufferAllocator.init(bytes).allocator.create(WinThread.OuterContext) catch unreachable; @@ -2468,7 +2588,7 @@ pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!*Thread outer_context.thread.data.alloc_start = bytes_ptr; const parameter = if (@sizeOf(Context) == 0) null else @ptrCast(*c_void, &outer_context.inner); - outer_context.thread.data.handle = windows.CreateThread(null, default_stack_size, WinThread.threadMain, parameter, 0, null) ?? { + outer_context.thread.data.handle = windows.CreateThread(null, default_stack_size, WinThread.threadMain, parameter, 0, null) orelse { const err = windows.GetLastError(); return switch (err) { else => os.unexpectedErrorWindows(err), @@ -2533,7 +2653,7 @@ pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!*Thread // align to page stack_end -= stack_end % os.page_size; - assert(c.pthread_attr_setstack(&attr, @intToPtr([*]c_void, stack_addr), stack_end - stack_addr) == 0); + assert(c.pthread_attr_setstack(&attr, @intToPtr(*c_void, stack_addr), stack_end - stack_addr) == 0); const err = c.pthread_create(&thread_ptr.data.handle, &attr, MainFuncs.posixThreadMain, @intToPtr(*c_void, arg)); switch (err) { diff --git a/std/os/linux/vdso.zig b/std/os/linux/vdso.zig index 2ab4d0cbc1..cbd0cd1df5 100644 --- a/std/os/linux/vdso.zig +++ b/std/os/linux/vdso.zig @@ -28,7 +28,7 @@ pub fn lookup(vername: []const u8, name: []const u8) usize { } } } - const dynv = maybe_dynv ?? return 0; + const dynv = maybe_dynv orelse return 0; if (base == @maxValue(usize)) return 0; var maybe_strings: ?[*]u8 = null; @@ -52,9 +52,9 @@ pub fn lookup(vername: []const u8, name: []const u8) usize { } } - const strings = maybe_strings ?? return 0; - const syms = maybe_syms ?? return 0; - const hashtab = maybe_hashtab ?? return 0; + const strings = maybe_strings orelse return 0; + const syms = maybe_syms orelse return 0; + const hashtab = maybe_hashtab orelse return 0; if (maybe_verdef == null) maybe_versym = null; const OK_TYPES = (1 << elf.STT_NOTYPE | 1 << elf.STT_OBJECT | 1 << elf.STT_FUNC | 1 << elf.STT_COMMON); @@ -67,7 +67,7 @@ pub fn lookup(vername: []const u8, name: []const u8) usize { if (0 == syms[i].st_shndx) continue; if (!mem.eql(u8, name, cstr.toSliceConst(strings + syms[i].st_name))) continue; if (maybe_versym) |versym| { - if (!checkver(??maybe_verdef, versym[i], vername, strings)) + if (!checkver(maybe_verdef.?, versym[i], vername, strings)) continue; } return base + syms[i].st_value; diff --git a/std/os/path.zig b/std/os/path.zig index 4df6179bf5..d3ab0c519f 100644 --- a/std/os/path.zig +++ b/std/os/path.zig @@ -182,8 +182,8 @@ pub fn windowsParsePath(path: []const u8) WindowsPath { } var it = mem.split(path, []u8{this_sep}); - _ = (it.next() ?? return relative_path); - _ = (it.next() ?? return relative_path); + _ = (it.next() orelse return relative_path); + _ = (it.next() orelse return relative_path); return WindowsPath{ .is_abs = isAbsoluteWindows(path), .kind = WindowsPath.Kind.NetworkShare, @@ -200,8 +200,8 @@ pub fn windowsParsePath(path: []const u8) WindowsPath { } var it = mem.split(path, []u8{this_sep}); - _ = (it.next() ?? return relative_path); - _ = (it.next() ?? return relative_path); + _ = (it.next() orelse return relative_path); + _ = (it.next() orelse return relative_path); return WindowsPath{ .is_abs = isAbsoluteWindows(path), .kind = WindowsPath.Kind.NetworkShare, @@ -265,7 +265,7 @@ fn networkShareServersEql(ns1: []const u8, ns2: []const u8) bool { var it2 = mem.split(ns2, []u8{sep2}); // TODO ASCII is wrong, we actually need full unicode support to compare paths. - return asciiEqlIgnoreCase(??it1.next(), ??it2.next()); + return asciiEqlIgnoreCase(it1.next().?, it2.next().?); } fn compareDiskDesignators(kind: WindowsPath.Kind, p1: []const u8, p2: []const u8) bool { @@ -286,7 +286,7 @@ fn compareDiskDesignators(kind: WindowsPath.Kind, p1: []const u8, p2: []const u8 var it2 = mem.split(p2, []u8{sep2}); // TODO ASCII is wrong, we actually need full unicode support to compare paths. - return asciiEqlIgnoreCase(??it1.next(), ??it2.next()) and asciiEqlIgnoreCase(??it1.next(), ??it2.next()); + return asciiEqlIgnoreCase(it1.next().?, it2.next().?) and asciiEqlIgnoreCase(it1.next().?, it2.next().?); }, } } @@ -414,8 +414,8 @@ pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 { WindowsPath.Kind.NetworkShare => { result = try allocator.alloc(u8, max_size); var it = mem.split(paths[first_index], "/\\"); - const server_name = ??it.next(); - const other_name = ??it.next(); + const server_name = it.next().?; + const other_name = it.next().?; result[result_index] = '\\'; result_index += 1; @@ -648,8 +648,8 @@ fn testResolvePosix(paths: []const []const u8) []u8 { } /// If the path is a file in the current directory (no directory component) -/// then the returned slice has .len = 0. -pub fn dirname(path: []const u8) []const u8 { +/// then returns null +pub fn dirname(path: []const u8) ?[]const u8 { if (is_windows) { return dirnameWindows(path); } else { @@ -657,9 +657,9 @@ pub fn dirname(path: []const u8) []const u8 { } } -pub fn dirnameWindows(path: []const u8) []const u8 { +pub fn dirnameWindows(path: []const u8) ?[]const u8 { if (path.len == 0) - return path[0..0]; + return null; const root_slice = diskDesignatorWindows(path); if (path.len == root_slice.len) @@ -671,13 +671,13 @@ pub fn dirnameWindows(path: []const u8) []const u8 { while ((path[end_index] == '/' or path[end_index] == '\\') and end_index > root_slice.len) { if (end_index == 0) - return path[0..0]; + return null; end_index -= 1; } while (path[end_index] != '/' and path[end_index] != '\\' and end_index > root_slice.len) { if (end_index == 0) - return path[0..0]; + return null; end_index -= 1; } @@ -685,12 +685,15 @@ pub fn dirnameWindows(path: []const u8) []const u8 { end_index += 1; } + if (end_index == 0) + return null; + return path[0..end_index]; } -pub fn dirnamePosix(path: []const u8) []const u8 { +pub fn dirnamePosix(path: []const u8) ?[]const u8 { if (path.len == 0) - return path[0..0]; + return null; var end_index: usize = path.len - 1; while (path[end_index] == '/') { @@ -701,13 +704,16 @@ pub fn dirnamePosix(path: []const u8) []const u8 { while (path[end_index] != '/') { if (end_index == 0) - return path[0..0]; + return null; end_index -= 1; } if (end_index == 0 and path[end_index] == '/') return path[0..1]; + if (end_index == 0) + return null; + return path[0..end_index]; } @@ -717,10 +723,10 @@ test "os.path.dirnamePosix" { testDirnamePosix("/a", "/"); testDirnamePosix("/", "/"); testDirnamePosix("////", "/"); - testDirnamePosix("", ""); - testDirnamePosix("a", ""); - testDirnamePosix("a/", ""); - testDirnamePosix("a//", ""); + testDirnamePosix("", null); + testDirnamePosix("a", null); + testDirnamePosix("a/", null); + testDirnamePosix("a//", null); } test "os.path.dirnameWindows" { @@ -742,7 +748,7 @@ test "os.path.dirnameWindows" { testDirnameWindows("c:foo\\bar", "c:foo"); testDirnameWindows("c:foo\\bar\\", "c:foo"); testDirnameWindows("c:foo\\bar\\baz", "c:foo\\bar"); - testDirnameWindows("file:stream", ""); + testDirnameWindows("file:stream", null); testDirnameWindows("dir\\file:stream", "dir"); testDirnameWindows("\\\\unc\\share", "\\\\unc\\share"); testDirnameWindows("\\\\unc\\share\\foo", "\\\\unc\\share\\"); @@ -753,18 +759,26 @@ test "os.path.dirnameWindows" { testDirnameWindows("/a/b/", "/a"); testDirnameWindows("/a/b", "/a"); testDirnameWindows("/a", "/"); - testDirnameWindows("", ""); + testDirnameWindows("", null); testDirnameWindows("/", "/"); testDirnameWindows("////", "/"); - testDirnameWindows("foo", ""); + testDirnameWindows("foo", null); } -fn testDirnamePosix(input: []const u8, expected_output: []const u8) void { - assert(mem.eql(u8, dirnamePosix(input), expected_output)); +fn testDirnamePosix(input: []const u8, expected_output: ?[]const u8) void { + if (dirnamePosix(input)) |output| { + assert(mem.eql(u8, output, expected_output.?)); + } else { + assert(expected_output == null); + } } -fn testDirnameWindows(input: []const u8, expected_output: []const u8) void { - assert(mem.eql(u8, dirnameWindows(input), expected_output)); +fn testDirnameWindows(input: []const u8, expected_output: ?[]const u8) void { + if (dirnameWindows(input)) |output| { + assert(mem.eql(u8, output, expected_output.?)); + } else { + assert(expected_output == null); + } } pub fn basename(path: []const u8) []const u8 { @@ -923,7 +937,7 @@ pub fn relativeWindows(allocator: *Allocator, from: []const u8, to: []const u8) var from_it = mem.split(resolved_from, "/\\"); var to_it = mem.split(resolved_to, "/\\"); while (true) { - const from_component = from_it.next() ?? return mem.dupe(allocator, u8, to_it.rest()); + const from_component = from_it.next() orelse return mem.dupe(allocator, u8, to_it.rest()); const to_rest = to_it.rest(); if (to_it.next()) |to_component| { // TODO ASCII is wrong, we actually need full unicode support to compare paths. @@ -974,7 +988,7 @@ pub fn relativePosix(allocator: *Allocator, from: []const u8, to: []const u8) ![ var from_it = mem.split(resolved_from, "/"); var to_it = mem.split(resolved_to, "/"); while (true) { - const from_component = from_it.next() ?? return mem.dupe(allocator, u8, to_it.rest()); + const from_component = from_it.next() orelse return mem.dupe(allocator, u8, to_it.rest()); const to_rest = to_it.rest(); if (to_it.next()) |to_component| { if (mem.eql(u8, from_component, to_component)) diff --git a/std/os/test.zig b/std/os/test.zig index 4aa3535829..5a977a569a 100644 --- a/std/os/test.zig +++ b/std/os/test.zig @@ -10,11 +10,6 @@ const AtomicRmwOp = builtin.AtomicRmwOp; const AtomicOrder = builtin.AtomicOrder; test "makePath, put some files in it, deleteTree" { - if (builtin.os == builtin.Os.windows) { - // TODO implement os.Dir for windows - // https://github.com/ziglang/zig/issues/709 - return; - } try os.makePath(a, "os_test_tmp/b/c"); try io.writeFile(a, "os_test_tmp/b/c/file.txt", "nonsense"); try io.writeFile(a, "os_test_tmp/b/file2.txt", "blah"); @@ -27,10 +22,6 @@ test "makePath, put some files in it, deleteTree" { } test "access file" { - if (builtin.os == builtin.Os.windows) { - return; - } - try os.makePath(a, "os_test_tmp"); if (os.File.access(a, "os_test_tmp/file.txt", os.default_file_mode)) |ok| { unreachable; diff --git a/std/os/time.zig b/std/os/time.zig index dd64df2156..ffb506cd7d 100644 --- a/std/os/time.zig +++ b/std/os/time.zig @@ -68,11 +68,13 @@ pub const milliTimestamp = switch (builtin.os) { fn milliTimestampWindows() u64 { //FileTime has a granularity of 100 nanoseconds // and uses the NTFS/Windows epoch - var ft: i64 = undefined; + var ft: windows.FILETIME = undefined; windows.GetSystemTimeAsFileTime(&ft); const hns_per_ms = (ns_per_s / 100) / ms_per_s; const epoch_adj = epoch.windows * ms_per_s; - return u64(@divFloor(ft, hns_per_ms) + epoch_adj); + + const ft64 = (u64(ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + return @divFloor(ft64, hns_per_ms) - -epoch_adj; } fn milliTimestampDarwin() u64 { diff --git a/std/os/windows/index.zig b/std/os/windows/index.zig index c491ae6538..d631c6adbf 100644 --- a/std/os/windows/index.zig +++ b/std/os/windows/index.zig @@ -1,3 +1,7 @@ +test "import" { + _ = @import("util.zig"); +} + pub const ERROR = @import("error.zig"); pub extern "advapi32" stdcallcc fn CryptAcquireContextA( @@ -61,6 +65,10 @@ pub extern "kernel32" stdcallcc fn DeleteFileA(lpFileName: LPCSTR) BOOL; pub extern "kernel32" stdcallcc fn ExitProcess(exit_code: UINT) noreturn; +pub extern "kernel32" stdcallcc fn FindFirstFileA(lpFileName: LPCSTR, lpFindFileData: *WIN32_FIND_DATAA) HANDLE; +pub extern "kernel32" stdcallcc fn FindClose(hFindFile: HANDLE) BOOL; +pub extern "kernel32" stdcallcc fn FindNextFileA(hFindFile: HANDLE, lpFindFileData: *WIN32_FIND_DATAA) BOOL; + pub extern "kernel32" stdcallcc fn FreeEnvironmentStringsA(penv: [*]u8) BOOL; pub extern "kernel32" stdcallcc fn GetCommandLineA() LPSTR; @@ -77,6 +85,8 @@ pub extern "kernel32" stdcallcc fn GetExitCodeProcess(hProcess: HANDLE, lpExitCo pub extern "kernel32" stdcallcc fn GetFileSizeEx(hFile: HANDLE, lpFileSize: *LARGE_INTEGER) BOOL; +pub extern "kernel32" stdcallcc fn GetFileAttributesA(lpFileName: LPCSTR) DWORD; + pub extern "kernel32" stdcallcc fn GetModuleFileNameA(hModule: ?HMODULE, lpFilename: LPSTR, nSize: DWORD) DWORD; pub extern "kernel32" stdcallcc fn GetLastError() DWORD; @@ -97,21 +107,21 @@ pub extern "kernel32" stdcallcc fn GetFinalPathNameByHandleA( pub extern "kernel32" stdcallcc fn GetProcessHeap() ?HANDLE; -pub extern "kernel32" stdcallcc fn GetSystemTimeAsFileTime(?*FILETIME) void; +pub extern "kernel32" stdcallcc fn GetSystemTimeAsFileTime(*FILETIME) void; pub extern "kernel32" stdcallcc fn HeapCreate(flOptions: DWORD, dwInitialSize: SIZE_T, dwMaximumSize: SIZE_T) ?HANDLE; pub extern "kernel32" stdcallcc fn HeapDestroy(hHeap: HANDLE) BOOL; -pub extern "kernel32" stdcallcc fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: [*]c_void, dwBytes: SIZE_T) ?[*]c_void; -pub extern "kernel32" stdcallcc fn HeapSize(hHeap: HANDLE, dwFlags: DWORD, lpMem: [*]const c_void) SIZE_T; -pub extern "kernel32" stdcallcc fn HeapValidate(hHeap: HANDLE, dwFlags: DWORD, lpMem: [*]const c_void) BOOL; +pub extern "kernel32" stdcallcc fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: *c_void, dwBytes: SIZE_T) ?*c_void; +pub extern "kernel32" stdcallcc fn HeapSize(hHeap: HANDLE, dwFlags: DWORD, lpMem: *const c_void) SIZE_T; +pub extern "kernel32" stdcallcc fn HeapValidate(hHeap: HANDLE, dwFlags: DWORD, lpMem: *const c_void) BOOL; pub extern "kernel32" stdcallcc fn HeapCompact(hHeap: HANDLE, dwFlags: DWORD) SIZE_T; pub extern "kernel32" stdcallcc fn HeapSummary(hHeap: HANDLE, dwFlags: DWORD, lpSummary: LPHEAP_SUMMARY) BOOL; pub extern "kernel32" stdcallcc fn GetStdHandle(in_nStdHandle: DWORD) ?HANDLE; -pub extern "kernel32" stdcallcc fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) ?[*]c_void; +pub extern "kernel32" stdcallcc fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) ?*c_void; -pub extern "kernel32" stdcallcc fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: [*]c_void) BOOL; +pub extern "kernel32" stdcallcc fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: *c_void) BOOL; pub extern "kernel32" stdcallcc fn MoveFileExA( lpExistingFileName: LPCSTR, @@ -123,16 +133,16 @@ pub extern "kernel32" stdcallcc fn QueryPerformanceCounter(lpPerformanceCount: * pub extern "kernel32" stdcallcc fn QueryPerformanceFrequency(lpFrequency: *LARGE_INTEGER) BOOL; -pub extern "kernel32" stdcallcc fn PathFileExists(pszPath: ?LPCTSTR) BOOL; - pub extern "kernel32" stdcallcc fn ReadFile( in_hFile: HANDLE, - out_lpBuffer: [*]c_void, + out_lpBuffer: *c_void, in_nNumberOfBytesToRead: DWORD, out_lpNumberOfBytesRead: *DWORD, in_out_lpOverlapped: ?*OVERLAPPED, ) BOOL; +pub extern "kernel32" stdcallcc fn RemoveDirectoryA(lpPathName: LPCSTR) BOOL; + pub extern "kernel32" stdcallcc fn SetFilePointerEx( in_fFile: HANDLE, in_liDistanceToMove: LARGE_INTEGER, @@ -150,7 +160,7 @@ pub extern "kernel32" stdcallcc fn WaitForSingleObject(hHandle: HANDLE, dwMillis pub extern "kernel32" stdcallcc fn WriteFile( in_hFile: HANDLE, - in_lpBuffer: [*]const c_void, + in_lpBuffer: *const c_void, in_nNumberOfBytesToWrite: DWORD, out_lpNumberOfBytesWritten: ?*DWORD, in_out_lpOverlapped: ?*OVERLAPPED, @@ -163,6 +173,8 @@ pub extern "kernel32" stdcallcc fn FreeLibrary(hModule: HMODULE) BOOL; pub extern "user32" stdcallcc fn MessageBoxA(hWnd: ?HANDLE, lpText: ?LPCTSTR, lpCaption: ?LPCTSTR, uType: UINT) c_int; +pub extern "shlwapi" stdcallcc fn PathFileExistsA(pszPath: ?LPCTSTR) BOOL; + pub const PROV_RSA_FULL = 1; pub const BOOL = c_int; @@ -196,7 +208,6 @@ pub const UNICODE = false; pub const WCHAR = u16; pub const WORD = u16; pub const LARGE_INTEGER = i64; -pub const FILETIME = i64; pub const TRUE = 1; pub const FALSE = 0; @@ -212,6 +223,8 @@ pub const STD_ERROR_HANDLE = @maxValue(DWORD) - 12 + 1; pub const INVALID_HANDLE_VALUE = @intToPtr(HANDLE, @maxValue(usize)); +pub const INVALID_FILE_ATTRIBUTES = DWORD(@maxValue(DWORD)); + pub const OVERLAPPED = extern struct { Internal: ULONG_PTR, InternalHigh: ULONG_PTR, @@ -293,13 +306,24 @@ pub const OPEN_EXISTING = 3; pub const TRUNCATE_EXISTING = 5; pub const FILE_ATTRIBUTE_ARCHIVE = 0x20; +pub const FILE_ATTRIBUTE_COMPRESSED = 0x800; +pub const FILE_ATTRIBUTE_DEVICE = 0x40; +pub const FILE_ATTRIBUTE_DIRECTORY = 0x10; pub const FILE_ATTRIBUTE_ENCRYPTED = 0x4000; pub const FILE_ATTRIBUTE_HIDDEN = 0x2; +pub const FILE_ATTRIBUTE_INTEGRITY_STREAM = 0x8000; pub const FILE_ATTRIBUTE_NORMAL = 0x80; +pub const FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x2000; +pub const FILE_ATTRIBUTE_NO_SCRUB_DATA = 0x20000; pub const FILE_ATTRIBUTE_OFFLINE = 0x1000; pub const FILE_ATTRIBUTE_READONLY = 0x1; +pub const FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS = 0x400000; +pub const FILE_ATTRIBUTE_RECALL_ON_OPEN = 0x40000; +pub const FILE_ATTRIBUTE_REPARSE_POINT = 0x400; +pub const FILE_ATTRIBUTE_SPARSE_FILE = 0x200; pub const FILE_ATTRIBUTE_SYSTEM = 0x4; pub const FILE_ATTRIBUTE_TEMPORARY = 0x100; +pub const FILE_ATTRIBUTE_VIRTUAL = 0x10000; pub const PROCESS_INFORMATION = extern struct { hProcess: HANDLE, @@ -372,6 +396,20 @@ pub const HEAP_NO_SERIALIZE = 0x00000001; pub const PTHREAD_START_ROUTINE = extern fn (LPVOID) DWORD; pub const LPTHREAD_START_ROUTINE = PTHREAD_START_ROUTINE; -test "import" { - _ = @import("util.zig"); -} +pub const WIN32_FIND_DATAA = extern struct { + dwFileAttributes: DWORD, + ftCreationTime: FILETIME, + ftLastAccessTime: FILETIME, + ftLastWriteTime: FILETIME, + nFileSizeHigh: DWORD, + nFileSizeLow: DWORD, + dwReserved0: DWORD, + dwReserved1: DWORD, + cFileName: [260]CHAR, + cAlternateFileName: [14]CHAR, +}; + +pub const FILETIME = extern struct { + dwLowDateTime: DWORD, + dwHighDateTime: DWORD, +}; diff --git a/std/os/windows/util.zig b/std/os/windows/util.zig index 5a40567310..88a9e7952e 100644 --- a/std/os/windows/util.zig +++ b/std/os/windows/util.zig @@ -42,7 +42,7 @@ pub const WriteError = error{ }; pub fn windowsWrite(handle: windows.HANDLE, bytes: []const u8) WriteError!void { - if (windows.WriteFile(handle, @ptrCast([*]const c_void, bytes.ptr), u32(bytes.len), null, null) == 0) { + if (windows.WriteFile(handle, @ptrCast(*const c_void, bytes.ptr), u32(bytes.len), null, null) == 0) { const err = windows.GetLastError(); return switch (err) { windows.ERROR.INVALID_USER_BUFFER => WriteError.SystemResources, @@ -153,7 +153,7 @@ pub fn createWindowsEnvBlock(allocator: *mem.Allocator, env_map: *const BufMap) pub fn windowsLoadDll(allocator: *mem.Allocator, dll_path: []const u8) !windows.HMODULE { const padded_buff = try cstr.addNullByte(allocator, dll_path); defer allocator.free(padded_buff); - return windows.LoadLibraryA(padded_buff.ptr) ?? error.DllNotFound; + return windows.LoadLibraryA(padded_buff.ptr) orelse error.DllNotFound; } pub fn windowsUnloadDll(hModule: windows.HMODULE) void { @@ -170,3 +170,42 @@ test "InvalidDll" { return; }; } + +pub fn windowsFindFirstFile( + allocator: *mem.Allocator, + dir_path: []const u8, + find_file_data: *windows.WIN32_FIND_DATAA, +) !windows.HANDLE { + const wild_and_null = []u8{ '\\', '*', 0 }; + const path_with_wild_and_null = try allocator.alloc(u8, dir_path.len + wild_and_null.len); + defer allocator.free(path_with_wild_and_null); + + mem.copy(u8, path_with_wild_and_null, dir_path); + mem.copy(u8, path_with_wild_and_null[dir_path.len..], wild_and_null); + + const handle = windows.FindFirstFileA(path_with_wild_and_null.ptr, find_file_data); + + if (handle == windows.INVALID_HANDLE_VALUE) { + const err = windows.GetLastError(); + switch (err) { + windows.ERROR.FILE_NOT_FOUND, + windows.ERROR.PATH_NOT_FOUND, + => return error.PathNotFound, + else => return os.unexpectedErrorWindows(err), + } + } + + return handle; +} + +/// Returns `true` if there was another file, `false` otherwise. +pub fn windowsFindNextFile(handle: windows.HANDLE, find_file_data: *windows.WIN32_FIND_DATAA) !bool { + if (windows.FindNextFileA(handle, find_file_data) == 0) { + const err = windows.GetLastError(); + return switch (err) { + windows.ERROR.NO_MORE_FILES => false, + else => os.unexpectedErrorWindows(err), + }; + } + return true; +} |
