Merge branch 'std.fs.Dir.openRead'

This commit is contained in:
Andrew Kelley 2019-11-21 20:41:30 -05:00
commit e3404e3c78
No known key found for this signature in database
GPG Key ID: 7C5F548F728501A9
12 changed files with 1809 additions and 67 deletions

View File

@ -1711,7 +1711,12 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u
const ofile_path = mem.toSliceConst(u8, di.strings.ptr + ofile.n_strx);
gop.kv.value = MachOFile{
.bytes = try std.io.readFileAllocAligned(di.ofiles.allocator, ofile_path, @alignOf(macho.mach_header_64)),
.bytes = try std.fs.Dir.cwd().readFileAllocAligned(
di.ofiles.allocator,
ofile_path,
maxInt(usize),
@alignOf(macho.mach_header_64),
),
.sect_debug_info = null,
.sect_debug_line = null,
};

View File

@ -415,7 +415,8 @@ pub fn openPosix(
pub fn openRead(loop: *Loop, path: []const u8) File.OpenError!fd_t {
switch (builtin.os) {
.macosx, .linux, .freebsd, .netbsd, .dragonfly => {
const flags = os.O_LARGEFILE | os.O_RDONLY | os.O_CLOEXEC;
const O_LARGEFILE = if (@hasDecl(os, "O_LARGEFILE")) os.O_LARGEFILE else 0;
const flags = O_LARGEFILE | os.O_RDONLY | os.O_CLOEXEC;
return openPosix(loop, path, flags, File.default_mode);
},
@ -448,7 +449,8 @@ pub fn openWriteMode(loop: *Loop, path: []const u8, mode: File.Mode) File.OpenEr
.netbsd,
.dragonfly,
=> {
const flags = os.O_LARGEFILE | os.O_WRONLY | os.O_CREAT | os.O_CLOEXEC | os.O_TRUNC;
const O_LARGEFILE = if (@hasDecl(os, "O_LARGEFILE")) os.O_LARGEFILE else 0;
const flags = O_LARGEFILE | os.O_WRONLY | os.O_CREAT | os.O_CLOEXEC | os.O_TRUNC;
return openPosix(loop, path, flags, File.default_mode);
},
.windows => return windows.CreateFile(
@ -472,7 +474,8 @@ pub fn openReadWrite(
) File.OpenError!fd_t {
switch (builtin.os) {
.macosx, .linux, .freebsd, .netbsd, .dragonfly => {
const flags = os.O_LARGEFILE | os.O_RDWR | os.O_CREAT | os.O_CLOEXEC;
const O_LARGEFILE = if (@hasDecl(os, "O_LARGEFILE")) os.O_LARGEFILE else 0;
const flags = O_LARGEFILE | os.O_RDWR | os.O_CREAT | os.O_CLOEXEC;
return openPosix(loop, path, flags, mode);
},

View File

@ -856,7 +856,8 @@ pub const Loop = struct {
},
.Close => |*msg| noasync os.close(msg.fd),
.WriteFile => |*msg| blk: {
const flags = os.O_LARGEFILE | os.O_WRONLY | os.O_CREAT |
const O_LARGEFILE = if (@hasDecl(os, "O_LARGEFILE")) os.O_LARGEFILE else 0;
const flags = O_LARGEFILE | os.O_WRONLY | os.O_CREAT |
os.O_CLOEXEC | os.O_TRUNC;
const fd = noasync os.openC(msg.path.ptr, flags, msg.mode) catch |err| {
msg.result = err;

View File

@ -6,6 +6,7 @@ const base64 = std.base64;
const crypto = std.crypto;
const Allocator = std.mem.Allocator;
const assert = std.debug.assert;
const math = std.math;
pub const path = @import("fs/path.zig");
pub const File = @import("fs/file.zig").File;
@ -698,17 +699,81 @@ pub const Dir = struct {
/// Call `File.close` on the result when done.
pub fn openRead(self: Dir, sub_path: []const u8) File.OpenError!File {
if (builtin.os == .windows) {
const path_w = try os.windows.sliceToPrefixedFileW(sub_path);
return self.openReadW(&path_w);
}
const path_c = try os.toPosixPath(sub_path);
return self.openReadC(&path_c);
}
/// Call `File.close` on the result when done.
pub fn openReadC(self: Dir, sub_path: [*]const u8) File.OpenError!File {
const flags = os.O_LARGEFILE | os.O_RDONLY | os.O_CLOEXEC;
if (builtin.os == .windows) {
const path_w = try os.windows.cStrToPrefixedFileW(sub_path);
return self.openReadW(&path_w);
}
const O_LARGEFILE = if (@hasDecl(os, "O_LARGEFILE")) os.O_LARGEFILE else 0;
const flags = O_LARGEFILE | os.O_RDONLY | os.O_CLOEXEC;
const fd = try os.openatC(self.fd, sub_path, flags, 0);
return File.openHandle(fd);
}
pub fn openReadW(self: Dir, sub_path_w: [*]const u16) File.OpenError!File {
const w = os.windows;
var result = File{ .handle = undefined };
const path_len_bytes = math.cast(u16, mem.toSliceConst(u16, sub_path_w).len * 2) catch |err| switch (err) {
error.Overflow => return error.NameTooLong,
};
var nt_name = w.UNICODE_STRING{
.Length = path_len_bytes,
.MaximumLength = path_len_bytes,
.Buffer = @intToPtr([*]u16, @ptrToInt(sub_path_w)),
};
var attr = w.OBJECT_ATTRIBUTES{
.Length = @sizeOf(w.OBJECT_ATTRIBUTES),
.RootDirectory = if (path.isAbsoluteW(sub_path_w)) null else self.fd,
.Attributes = 0, // Note we do not use OBJ_CASE_INSENSITIVE here.
.ObjectName = &nt_name,
.SecurityDescriptor = null,
.SecurityQualityOfService = null,
};
if (sub_path_w[0] == '.' and sub_path_w[1] == 0) {
return error.IsDir;
}
if (sub_path_w[0] == '.' and sub_path_w[1] == '.' and sub_path_w[2] == 0) {
return error.IsDir;
}
var io: w.IO_STATUS_BLOCK = undefined;
const rc = w.ntdll.NtCreateFile(
&result.handle,
w.GENERIC_READ | w.SYNCHRONIZE,
&attr,
&io,
null,
w.FILE_ATTRIBUTE_NORMAL,
w.FILE_SHARE_READ,
w.FILE_OPEN,
w.FILE_NON_DIRECTORY_FILE | w.FILE_SYNCHRONOUS_IO_NONALERT,
null,
0,
);
switch (rc) {
w.STATUS.SUCCESS => return result,
w.STATUS.OBJECT_NAME_INVALID => unreachable,
w.STATUS.OBJECT_NAME_NOT_FOUND => return error.FileNotFound,
w.STATUS.OBJECT_PATH_NOT_FOUND => return error.FileNotFound,
w.STATUS.INVALID_PARAMETER => unreachable,
w.STATUS.SHARING_VIOLATION => return error.SharingViolation,
w.STATUS.ACCESS_DENIED => return error.AccessDenied,
w.STATUS.PIPE_BUSY => return error.PipeBusy,
w.STATUS.OBJECT_PATH_SYNTAX_BAD => unreachable,
else => return w.unexpectedStatus(rc),
}
}
/// Call `close` on the result when done.
pub fn openDir(self: Dir, sub_path: []const u8) OpenError!Dir {
if (builtin.os == .windows) {
@ -866,6 +931,34 @@ pub const Dir = struct {
return os.readlinkatC(self.fd, sub_path_c, buffer);
}
/// On success, caller owns returned buffer.
/// If the file is larger than `max_bytes`, returns `error.FileTooBig`.
pub fn readFileAlloc(self: Dir, allocator: *mem.Allocator, file_path: []const u8, max_bytes: usize) ![]u8 {
return self.readFileAllocAligned(allocator, file_path, max_bytes, @alignOf(u8));
}
/// On success, caller owns returned buffer.
/// If the file is larger than `max_bytes`, returns `error.FileTooBig`.
pub fn readFileAllocAligned(
self: Dir,
allocator: *mem.Allocator,
file_path: []const u8,
max_bytes: usize,
comptime A: u29,
) ![]align(A) u8 {
var file = try self.openRead(file_path);
defer file.close();
const size = math.cast(usize, try file.getEndPos()) catch math.maxInt(usize);
if (size > max_bytes) return error.FileTooBig;
const buf = try allocator.alignedAlloc(u8, A, size);
errdefer allocator.free(buf);
try file.inStream().stream.readNoEof(buf);
return buf;
}
pub const DeleteTreeError = error{
AccessDenied,
FileTooBig,
@ -1150,9 +1243,9 @@ pub fn openSelfExe() OpenSelfExeError!File {
return File.openReadC(c"/proc/self/exe");
}
if (builtin.os == .windows) {
var buf: [os.windows.PATH_MAX_WIDE]u16 = undefined;
const wide_slice = try selfExePathW(&buf);
return File.openReadW(wide_slice.ptr);
const wide_slice = selfExePathW();
const prefixed_path_w = try os.windows.wToPrefixedFileW(wide_slice);
return Dir.cwd().openReadW(&prefixed_path_w);
}
var buf: [MAX_PATH_BYTES]u8 = undefined;
const self_exe_path = try selfExePath(&buf);
@ -1203,8 +1296,7 @@ pub fn selfExePath(out_buffer: *[MAX_PATH_BYTES]u8) SelfExePathError![]u8 {
return mem.toSlice(u8, out_buffer);
},
.windows => {
var utf16le_buf: [os.windows.PATH_MAX_WIDE]u16 = undefined;
const utf16le_slice = try selfExePathW(&utf16le_buf);
const utf16le_slice = selfExePathW();
// Trust that Windows gives us valid UTF-16LE.
const end_index = std.unicode.utf16leToUtf8(out_buffer, utf16le_slice) catch unreachable;
return out_buffer[0..end_index];
@ -1213,9 +1305,10 @@ pub fn selfExePath(out_buffer: *[MAX_PATH_BYTES]u8) SelfExePathError![]u8 {
}
}
/// Same as `selfExePath` except the result is UTF16LE-encoded.
pub fn selfExePathW(out_buffer: *[os.windows.PATH_MAX_WIDE]u16) SelfExePathError![]u16 {
return os.windows.GetModuleFileNameW(null, out_buffer, out_buffer.len);
/// The result is UTF16LE-encoded.
pub fn selfExePathW() []const u16 {
const image_path_name = &os.windows.peb().ProcessParameters.ImagePathName;
return mem.toSliceConst(u16, image_path_name.Buffer);
}
/// `selfExeDirPath` except allocates the result on the heap.

View File

@ -25,42 +25,23 @@ pub const File = struct {
pub const OpenError = windows.CreateFileError || os.OpenError;
/// Call close to clean up.
/// Deprecated; call `std.fs.Dir.openRead` directly.
pub fn openRead(path: []const u8) OpenError!File {
if (builtin.os == .windows) {
const path_w = try windows.sliceToPrefixedFileW(path);
return openReadW(&path_w);
}
const path_c = try os.toPosixPath(path);
return openReadC(&path_c);
return std.fs.Dir.cwd().openRead(path);
}
/// `openRead` except with a null terminated path
pub fn openReadC(path: [*]const u8) OpenError!File {
if (builtin.os == .windows) {
const path_w = try windows.cStrToPrefixedFileW(path);
return openReadW(&path_w);
}
const flags = os.O_LARGEFILE | os.O_RDONLY | os.O_CLOEXEC;
const fd = try os.openC(path, flags, 0);
return openHandle(fd);
/// Deprecated; call `std.fs.Dir.openReadC` directly.
pub fn openReadC(path_c: [*]const u8) OpenError!File {
return std.fs.Dir.cwd().openReadC(path_c);
}
/// `openRead` except with a null terminated UTF16LE encoded path
/// Deprecated; call `std.fs.Dir.openReadW` directly.
pub fn openReadW(path_w: [*]const u16) OpenError!File {
const handle = try windows.CreateFileW(
path_w,
windows.GENERIC_READ,
windows.FILE_SHARE_READ,
null,
windows.OPEN_EXISTING,
windows.FILE_ATTRIBUTE_NORMAL,
null,
);
return openHandle(handle);
return std.fs.Dir.cwd().openReadW(path_w);
}
/// Calls `openWriteMode` with `default_mode` for the mode.
/// TODO: deprecate this and move it to `std.fs.Dir`.
pub fn openWrite(path: []const u8) OpenError!File {
return openWriteMode(path, default_mode);
}
@ -68,6 +49,7 @@ pub const File = struct {
/// If the path does not exist it will be created.
/// If a file already exists in the destination it will be truncated.
/// Call close to clean up.
/// TODO: deprecate this and move it to `std.fs.Dir`.
pub fn openWriteMode(path: []const u8, file_mode: Mode) OpenError!File {
if (builtin.os == .windows) {
const path_w = try windows.sliceToPrefixedFileW(path);
@ -78,17 +60,20 @@ pub const File = struct {
}
/// Same as `openWriteMode` except `path` is null-terminated.
/// TODO: deprecate this and move it to `std.fs.Dir`.
pub fn openWriteModeC(path: [*]const u8, file_mode: Mode) OpenError!File {
if (builtin.os == .windows) {
const path_w = try windows.cStrToPrefixedFileW(path);
return openWriteModeW(&path_w, file_mode);
}
const flags = os.O_LARGEFILE | os.O_WRONLY | os.O_CREAT | os.O_CLOEXEC | os.O_TRUNC;
const O_LARGEFILE = if (@hasDecl(os, "O_LARGEFILE")) os.O_LARGEFILE else 0;
const flags = O_LARGEFILE | os.O_WRONLY | os.O_CREAT | os.O_CLOEXEC | os.O_TRUNC;
const fd = try os.openC(path, flags, file_mode);
return openHandle(fd);
}
/// Same as `openWriteMode` except `path` is null-terminated and UTF16LE encoded
/// TODO: deprecate this and move it to `std.fs.Dir`.
pub fn openWriteModeW(path_w: [*]const u16, file_mode: Mode) OpenError!File {
const handle = try windows.CreateFileW(
path_w,
@ -105,6 +90,7 @@ pub const File = struct {
/// If the path does not exist it will be created.
/// If a file already exists in the destination this returns OpenError.PathAlreadyExists
/// Call close to clean up.
/// TODO: deprecate this and move it to `std.fs.Dir`.
pub fn openWriteNoClobber(path: []const u8, file_mode: Mode) OpenError!File {
if (builtin.os == .windows) {
const path_w = try windows.sliceToPrefixedFileW(path);
@ -114,16 +100,19 @@ pub const File = struct {
return openWriteNoClobberC(&path_c, file_mode);
}
/// TODO: deprecate this and move it to `std.fs.Dir`.
pub fn openWriteNoClobberC(path: [*]const u8, file_mode: Mode) OpenError!File {
if (builtin.os == .windows) {
const path_w = try windows.cStrToPrefixedFileW(path);
return openWriteNoClobberW(&path_w, file_mode);
}
const flags = os.O_LARGEFILE | os.O_WRONLY | os.O_CREAT | os.O_CLOEXEC | os.O_EXCL;
const O_LARGEFILE = if (@hasDecl(os, "O_LARGEFILE")) os.O_LARGEFILE else 0;
const flags = O_LARGEFILE | os.O_WRONLY | os.O_CREAT | os.O_CLOEXEC | os.O_EXCL;
const fd = try os.openC(path, flags, file_mode);
return openHandle(fd);
}
/// TODO: deprecate this and move it to `std.fs.Dir`.
pub fn openWriteNoClobberW(path_w: [*]const u16, file_mode: Mode) OpenError!File {
const handle = try windows.CreateFileW(
path_w,
@ -146,16 +135,19 @@ pub const File = struct {
/// In general it is recommended to avoid this function. For example,
/// instead of testing if a file exists and then opening it, just
/// open it and handle the error for file not found.
/// TODO: deprecate this and move it to `std.fs.Dir`.
pub fn access(path: []const u8) !void {
return os.access(path, os.F_OK);
}
/// Same as `access` except the parameter is null-terminated.
/// TODO: deprecate this and move it to `std.fs.Dir`.
pub fn accessC(path: [*]const u8) !void {
return os.accessC(path, os.F_OK);
}
/// Same as `access` except the parameter is null-terminated UTF16LE-encoded.
/// TODO: deprecate this and move it to `std.fs.Dir`.
pub fn accessW(path: [*]const u16) !void {
return os.accessW(path, os.F_OK);
}

View File

@ -69,24 +69,9 @@ pub fn writeFile(path: []const u8, data: []const u8) !void {
}
/// On success, caller owns returned buffer.
/// TODO move this to `std.fs` and add a version to `std.fs.Dir`.
/// This function is deprecated; use `std.fs.Dir.readFileAlloc`.
pub fn readFileAlloc(allocator: *mem.Allocator, path: []const u8) ![]u8 {
return readFileAllocAligned(allocator, path, @alignOf(u8));
}
/// On success, caller owns returned buffer.
/// TODO move this to `std.fs` and add a version to `std.fs.Dir`.
pub fn readFileAllocAligned(allocator: *mem.Allocator, path: []const u8, comptime A: u29) ![]align(A) u8 {
var file = try File.openRead(path);
defer file.close();
const size = try math.cast(usize, try file.getEndPos());
const buf = try allocator.alignedAlloc(u8, A, size);
errdefer allocator.free(buf);
var adapter = file.inStream();
try adapter.stream.readNoEof(buf[0..size]);
return buf;
return fs.Dir.cwd().readFileAlloc(allocator, path, math.maxInt(usize));
}
pub fn BufferedInStream(comptime Error: type) type {

View File

@ -267,7 +267,6 @@ pub const SA_USERTRAMP = 0x0100;
/// signal handler with SA_SIGINFO args with 64bit regs information
pub const SA_64REGSET = 0x0200;
pub const O_LARGEFILE = 0x0000;
pub const O_PATH = 0x0000;
pub const F_OK = 0;

View File

@ -241,7 +241,6 @@ pub const KERN_MAXID = 37;
pub const HOST_NAME_MAX = 255;
pub const O_LARGEFILE = 0; // faked support
pub const O_RDONLY = 0;
pub const O_NDELAY = O_NONBLOCK;
pub const O_WRONLY = 1;

View File

@ -300,7 +300,6 @@ pub const O_CLOEXEC = 0x00100000;
pub const O_ASYNC = 0x0040;
pub const O_DIRECT = 0x00010000;
pub const O_LARGEFILE = 0;
pub const O_NOATIME = 0o1000000;
pub const O_PATH = 0o10000000;
pub const O_TMPFILE = 0o20200000;

View File

@ -292,7 +292,6 @@ pub const O_CLOEXEC = 0x00400000;
pub const O_ASYNC = 0x0040;
pub const O_DIRECT = 0x00080000;
pub const O_LARGEFILE = 0;
pub const O_NOATIME = 0;
pub const O_PATH = 0;
pub const O_TMPFILE = 0;

View File

@ -927,6 +927,24 @@ pub fn sliceToPrefixedFileW(s: []const u8) ![PATH_MAX_WIDE + 1]u16 {
return sliceToPrefixedSuffixedFileW(s, [_]u16{0});
}
/// Assumes an absolute path.
pub fn wToPrefixedFileW(s: []const u16) ![PATH_MAX_WIDE + 1]u16 {
// TODO https://github.com/ziglang/zig/issues/2765
var result: [PATH_MAX_WIDE + 1]u16 = undefined;
const start_index = if (mem.startsWith(u16, s, [_]u16{'\\', '?'})) 0 else blk: {
const prefix = [_]u16{ '\\', '?', '?', '\\' };
mem.copy(u16, result[0..], prefix);
break :blk prefix.len;
};
const end_index = start_index + s.len;
if (end_index + 1 > result.len) return error.NameTooLong;
mem.copy(u16, result[start_index..], s);
result[end_index] = 0;
return result;
}
pub fn sliceToPrefixedSuffixedFileW(s: []const u8, comptime suffix: []const u16) ![PATH_MAX_WIDE + suffix.len]u16 {
// TODO https://github.com/ziglang/zig/issues/2765
var result: [PATH_MAX_WIDE + suffix.len]u16 = undefined;
@ -948,7 +966,6 @@ pub fn sliceToPrefixedSuffixedFileW(s: []const u8, comptime suffix: []const u16)
break :blk prefix.len;
};
const end_index = start_index + try std.unicode.utf8ToUtf16Le(result[start_index..], s);
assert(end_index <= result.len);
if (end_index + suffix.len > result.len) return error.NameTooLong;
mem.copy(u16, result[end_index..], suffix);
return result;

File diff suppressed because it is too large Load Diff