From 03bec631bd493dc157d0c071363c967caf7f57ac Mon Sep 17 00:00:00 2001 From: Marc Tiehuis Date: Fri, 13 Apr 2018 21:27:09 +1200 Subject: [PATCH] Replace File.exists with File.access --- src-self-hosted/main.zig | 2 +- std/c/index.zig | 1 + std/os/darwin.zig | 9 +++++++++ std/os/file.zig | 43 +++++++++++++++++++++++++++++++++++----- std/os/linux/index.zig | 9 +++++++++ std/os/test.zig | 17 ++++++++++++++++ std/os/windows/index.zig | 2 ++ 7 files changed, 77 insertions(+), 6 deletions(-) diff --git a/src-self-hosted/main.zig b/src-self-hosted/main.zig index 825bf64a26..c1a6bbe99a 100644 --- a/src-self-hosted/main.zig +++ b/src-self-hosted/main.zig @@ -175,7 +175,7 @@ fn cmdBuild(allocator: &Allocator, args: []const []const u8) !void { const build_file_abs = try os.path.resolve(allocator, ".", build_file); defer allocator.free(build_file_abs); - const build_file_exists = os.File.exists(allocator, build_file_abs); + const build_file_exists = os.File.access(allocator, build_file_abs, os.default_file_mode) catch false; if (flags.present("init")) { if (build_file_exists) { diff --git a/std/c/index.zig b/std/c/index.zig index 369ea2b358..02321f1f34 100644 --- a/std/c/index.zig +++ b/std/c/index.zig @@ -28,6 +28,7 @@ pub extern "c" fn unlink(path: &const u8) c_int; pub extern "c" fn getcwd(buf: &u8, size: usize) ?&u8; pub extern "c" fn waitpid(pid: c_int, stat_loc: &c_int, options: c_int) c_int; pub extern "c" fn fork() c_int; +pub extern "c" fn access(path: &const u8, mode: c_uint) c_int; pub extern "c" fn pipe(fds: &c_int) c_int; pub extern "c" fn mkdir(path: &const u8, mode: c_uint) c_int; pub extern "c" fn symlink(existing: &const u8, new: &const u8) c_int; diff --git a/std/os/darwin.zig b/std/os/darwin.zig index 40da55315c..42b9917210 100644 --- a/std/os/darwin.zig +++ b/std/os/darwin.zig @@ -41,6 +41,11 @@ pub const SA_64REGSET = 0x0200; /// signal handler with SA_SIGINFO args with 64 pub const O_LARGEFILE = 0x0000; pub const O_PATH = 0x0000; +pub const F_OK = 0; +pub const X_OK = 1; +pub const W_OK = 2; +pub const R_OK = 4; + pub const O_RDONLY = 0x0000; /// open for reading only pub const O_WRONLY = 0x0001; /// open for writing only pub const O_RDWR = 0x0002; /// open for reading and writing @@ -209,6 +214,10 @@ pub fn fork() usize { return errnoWrap(c.fork()); } +pub fn access(path: &const u8, mode: u32) usize { + return errnoWrap(c.access(path, mode)); +} + pub fn pipe(fds: &[2]i32) usize { comptime assert(i32.bit_count == c_int.bit_count); return errnoWrap(c.pipe(@ptrCast(&c_int, fds))); diff --git a/std/os/file.zig b/std/os/file.zig index 94415a361d..7480ed3328 100644 --- a/std/os/file.zig +++ b/std/os/file.zig @@ -85,12 +85,45 @@ pub const File = struct { }; } - pub fn exists(allocator: &mem.Allocator, path: []const u8) bool { - if (openRead(allocator, path)) |*file| { - file.close(); + pub fn access(allocator: &mem.Allocator, path: []const u8, file_mode: os.FileMode) !bool { + const path_with_null = try std.cstr.addNullByte(allocator, path); + defer allocator.free(path_with_null); + + if (is_posix) { + // mode is ignored and is always F_OK for now + const result = posix.access(path_with_null.ptr, posix.F_OK); + const err = posix.getErrno(result); + if (err > 0) { + return switch (err) { + posix.EACCES => error.PermissionDenied, + posix.EROFS => error.PermissionDenied, + posix.ELOOP => error.PermissionDenied, + posix.ETXTBSY => error.PermissionDenied, + posix.ENOTDIR => error.NotFound, + posix.ENOENT => error.NotFound, + + posix.ENAMETOOLONG => error.NameTooLong, + posix.EINVAL => error.BadMode, + posix.EFAULT => error.BadPathName, + posix.EIO => error.Io, + posix.ENOMEM => error.SystemResources, + else => os.unexpectedErrorPosix(err), + }; + } return true; - } else |_| { - return false; + } else if (is_windows) { + if (os.windows.PathFileExists(path_with_null.ptr)) { + return true; + } + + const err = windows.GetLastError(); + return switch (err) { + windows.ERROR.FILE_NOT_FOUND => error.NotFound, + windows.ERROR.ACCESS_DENIED => error.PermissionDenied, + else => os.unexpectedErrorWindows(err), + }; + } else { + @compileError("TODO implement access for this OS"); } } diff --git a/std/os/linux/index.zig b/std/os/linux/index.zig index aa2a6d85da..e100af7733 100644 --- a/std/os/linux/index.zig +++ b/std/os/linux/index.zig @@ -38,6 +38,11 @@ pub const MAP_STACK = 0x20000; pub const MAP_HUGETLB = 0x40000; pub const MAP_FILE = 0; +pub const F_OK = 0; +pub const X_OK = 1; +pub const W_OK = 2; +pub const R_OK = 4; + pub const WNOHANG = 1; pub const WUNTRACED = 2; pub const WSTOPPED = 2; @@ -705,6 +710,10 @@ pub fn pread(fd: i32, buf: &u8, count: usize, offset: usize) usize { return syscall4(SYS_pread, usize(fd), @ptrToInt(buf), count, offset); } +pub fn access(path: &const u8, mode: u32) usize { + return syscall2(SYS_access, @ptrToInt(path), mode); +} + pub fn pipe(fd: &[2]i32) usize { return pipe2(fd, 0); } diff --git a/std/os/test.zig b/std/os/test.zig index 9c718d5b6b..718d1ce2c8 100644 --- a/std/os/test.zig +++ b/std/os/test.zig @@ -23,3 +23,20 @@ test "makePath, put some files in it, deleteTree" { assert(err == error.PathNotFound); } } + +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; + } else |err| { + assert(err == error.NotFound); + } + + try io.writeFile(a, "os_test_tmp/file.txt", ""); + assert((try os.File.access(a, "os_test_tmp/file.txt", os.default_file_mode)) == true); + try os.deleteTree(a, "os_test_tmp"); +} diff --git a/std/os/windows/index.zig b/std/os/windows/index.zig index 2709cf2a78..aa02c27f39 100644 --- a/std/os/windows/index.zig +++ b/std/os/windows/index.zig @@ -78,6 +78,8 @@ pub extern "kernel32" stdcallcc fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem pub extern "kernel32" stdcallcc fn MoveFileExA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR, dwFlags: DWORD) BOOL; +pub extern "kernel32" stdcallcc fn PathFileExists(pszPath: ?LPCTSTR) BOOL; + pub extern "kernel32" stdcallcc fn ReadFile(in_hFile: HANDLE, out_lpBuffer: &c_void, in_nNumberOfBytesToRead: DWORD, out_lpNumberOfBytesRead: &DWORD, in_out_lpOverlapped: ?&OVERLAPPED) BOOL;