add std.fs.Dir.openRead

This is progress towards file system APIs that encourage avoiding
Time Of Check, Time Of Use bugs.
This commit is contained in:
Andrew Kelley 2019-11-21 17:07:29 -05:00
parent 874b34a30f
commit cd37c1a377
No known key found for this signature in database
GPG Key ID: 7C5F548F728501A9
7 changed files with 1771 additions and 50 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

@ -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,

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,6 +60,7 @@ 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);
@ -89,6 +72,7 @@ pub const File = struct {
}
/// 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 +89,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,6 +99,7 @@ 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);
@ -124,6 +110,7 @@ pub const File = struct {
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 +133,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

@ -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;

File diff suppressed because it is too large Load Diff