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:
parent
874b34a30f
commit
cd37c1a377
@ -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,
|
||||
};
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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
Loading…
x
Reference in New Issue
Block a user