aboutsummaryrefslogtreecommitdiff
path: root/std/os
diff options
context:
space:
mode:
authorAndrew Kelley <superjoe30@gmail.com>2018-06-14 18:27:59 -0400
committerAndrew Kelley <superjoe30@gmail.com>2018-06-14 18:27:59 -0400
commit32dd98b19fe3cc384df32704dac0ff3e377dbe0c (patch)
tree2eddf3618d80313bdd24c25bd589bd474f3d82fc /std/os
parentef7f69d14a017c6c2065e4a376bb8e1f05ace04b (diff)
parentf0697c28f80d64c544302aea576e41ebc443b41c (diff)
downloadzig-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.zig18
-rw-r--r--std/os/darwin.zig8
-rw-r--r--std/os/file.zig19
-rw-r--r--std/os/index.zig306
-rw-r--r--std/os/linux/vdso.zig10
-rw-r--r--std/os/path.zig74
-rw-r--r--std/os/test.zig9
-rw-r--r--std/os/time.zig6
-rw-r--r--std/os/windows/index.zig66
-rw-r--r--std/os/windows/util.zig43
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;
+}