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);
|
const ofile_path = mem.toSliceConst(u8, di.strings.ptr + ofile.n_strx);
|
||||||
|
|
||||||
gop.kv.value = MachOFile{
|
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_info = null,
|
||||||
.sect_debug_line = null,
|
.sect_debug_line = null,
|
||||||
};
|
};
|
||||||
|
@ -6,6 +6,7 @@ const base64 = std.base64;
|
|||||||
const crypto = std.crypto;
|
const crypto = std.crypto;
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
|
const math = std.math;
|
||||||
|
|
||||||
pub const path = @import("fs/path.zig");
|
pub const path = @import("fs/path.zig");
|
||||||
pub const File = @import("fs/file.zig").File;
|
pub const File = @import("fs/file.zig").File;
|
||||||
@ -698,17 +699,81 @@ pub const Dir = struct {
|
|||||||
|
|
||||||
/// Call `File.close` on the result when done.
|
/// Call `File.close` on the result when done.
|
||||||
pub fn openRead(self: Dir, sub_path: []const u8) File.OpenError!File {
|
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);
|
const path_c = try os.toPosixPath(sub_path);
|
||||||
return self.openReadC(&path_c);
|
return self.openReadC(&path_c);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Call `File.close` on the result when done.
|
/// Call `File.close` on the result when done.
|
||||||
pub fn openReadC(self: Dir, sub_path: [*]const u8) File.OpenError!File {
|
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);
|
const fd = try os.openatC(self.fd, sub_path, flags, 0);
|
||||||
return File.openHandle(fd);
|
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.
|
/// Call `close` on the result when done.
|
||||||
pub fn openDir(self: Dir, sub_path: []const u8) OpenError!Dir {
|
pub fn openDir(self: Dir, sub_path: []const u8) OpenError!Dir {
|
||||||
if (builtin.os == .windows) {
|
if (builtin.os == .windows) {
|
||||||
@ -866,6 +931,34 @@ pub const Dir = struct {
|
|||||||
return os.readlinkatC(self.fd, sub_path_c, buffer);
|
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{
|
pub const DeleteTreeError = error{
|
||||||
AccessDenied,
|
AccessDenied,
|
||||||
FileTooBig,
|
FileTooBig,
|
||||||
|
@ -25,42 +25,23 @@ pub const File = struct {
|
|||||||
|
|
||||||
pub const OpenError = windows.CreateFileError || os.OpenError;
|
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 {
|
pub fn openRead(path: []const u8) OpenError!File {
|
||||||
if (builtin.os == .windows) {
|
return std.fs.Dir.cwd().openRead(path);
|
||||||
const path_w = try windows.sliceToPrefixedFileW(path);
|
|
||||||
return openReadW(&path_w);
|
|
||||||
}
|
|
||||||
const path_c = try os.toPosixPath(path);
|
|
||||||
return openReadC(&path_c);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `openRead` except with a null terminated path
|
/// Deprecated; call `std.fs.Dir.openReadC` directly.
|
||||||
pub fn openReadC(path: [*]const u8) OpenError!File {
|
pub fn openReadC(path_c: [*]const u8) OpenError!File {
|
||||||
if (builtin.os == .windows) {
|
return std.fs.Dir.cwd().openReadC(path_c);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `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 {
|
pub fn openReadW(path_w: [*]const u16) OpenError!File {
|
||||||
const handle = try windows.CreateFileW(
|
return std.fs.Dir.cwd().openReadW(path_w);
|
||||||
path_w,
|
|
||||||
windows.GENERIC_READ,
|
|
||||||
windows.FILE_SHARE_READ,
|
|
||||||
null,
|
|
||||||
windows.OPEN_EXISTING,
|
|
||||||
windows.FILE_ATTRIBUTE_NORMAL,
|
|
||||||
null,
|
|
||||||
);
|
|
||||||
return openHandle(handle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calls `openWriteMode` with `default_mode` for the mode.
|
/// 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 {
|
pub fn openWrite(path: []const u8) OpenError!File {
|
||||||
return openWriteMode(path, default_mode);
|
return openWriteMode(path, default_mode);
|
||||||
}
|
}
|
||||||
@ -68,6 +49,7 @@ pub const File = struct {
|
|||||||
/// If the path does not exist it will be created.
|
/// If the path does not exist it will be created.
|
||||||
/// If a file already exists in the destination it will be truncated.
|
/// If a file already exists in the destination it will be truncated.
|
||||||
/// Call close to clean up.
|
/// 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 {
|
pub fn openWriteMode(path: []const u8, file_mode: Mode) OpenError!File {
|
||||||
if (builtin.os == .windows) {
|
if (builtin.os == .windows) {
|
||||||
const path_w = try windows.sliceToPrefixedFileW(path);
|
const path_w = try windows.sliceToPrefixedFileW(path);
|
||||||
@ -78,6 +60,7 @@ pub const File = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Same as `openWriteMode` except `path` is null-terminated.
|
/// 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 {
|
pub fn openWriteModeC(path: [*]const u8, file_mode: Mode) OpenError!File {
|
||||||
if (builtin.os == .windows) {
|
if (builtin.os == .windows) {
|
||||||
const path_w = try windows.cStrToPrefixedFileW(path);
|
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
|
/// 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 {
|
pub fn openWriteModeW(path_w: [*]const u16, file_mode: Mode) OpenError!File {
|
||||||
const handle = try windows.CreateFileW(
|
const handle = try windows.CreateFileW(
|
||||||
path_w,
|
path_w,
|
||||||
@ -105,6 +89,7 @@ pub const File = struct {
|
|||||||
/// If the path does not exist it will be created.
|
/// If the path does not exist it will be created.
|
||||||
/// If a file already exists in the destination this returns OpenError.PathAlreadyExists
|
/// If a file already exists in the destination this returns OpenError.PathAlreadyExists
|
||||||
/// Call close to clean up.
|
/// 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 {
|
pub fn openWriteNoClobber(path: []const u8, file_mode: Mode) OpenError!File {
|
||||||
if (builtin.os == .windows) {
|
if (builtin.os == .windows) {
|
||||||
const path_w = try windows.sliceToPrefixedFileW(path);
|
const path_w = try windows.sliceToPrefixedFileW(path);
|
||||||
@ -114,6 +99,7 @@ pub const File = struct {
|
|||||||
return openWriteNoClobberC(&path_c, file_mode);
|
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 {
|
pub fn openWriteNoClobberC(path: [*]const u8, file_mode: Mode) OpenError!File {
|
||||||
if (builtin.os == .windows) {
|
if (builtin.os == .windows) {
|
||||||
const path_w = try windows.cStrToPrefixedFileW(path);
|
const path_w = try windows.cStrToPrefixedFileW(path);
|
||||||
@ -124,6 +110,7 @@ pub const File = struct {
|
|||||||
return openHandle(fd);
|
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 {
|
pub fn openWriteNoClobberW(path_w: [*]const u16, file_mode: Mode) OpenError!File {
|
||||||
const handle = try windows.CreateFileW(
|
const handle = try windows.CreateFileW(
|
||||||
path_w,
|
path_w,
|
||||||
@ -146,16 +133,19 @@ pub const File = struct {
|
|||||||
/// In general it is recommended to avoid this function. For example,
|
/// In general it is recommended to avoid this function. For example,
|
||||||
/// instead of testing if a file exists and then opening it, just
|
/// instead of testing if a file exists and then opening it, just
|
||||||
/// open it and handle the error for file not found.
|
/// 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 {
|
pub fn access(path: []const u8) !void {
|
||||||
return os.access(path, os.F_OK);
|
return os.access(path, os.F_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Same as `access` except the parameter is null-terminated.
|
/// 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 {
|
pub fn accessC(path: [*]const u8) !void {
|
||||||
return os.accessC(path, os.F_OK);
|
return os.accessC(path, os.F_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Same as `access` except the parameter is null-terminated UTF16LE-encoded.
|
/// 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 {
|
pub fn accessW(path: [*]const u16) !void {
|
||||||
return os.accessW(path, os.F_OK);
|
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.
|
/// 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 {
|
pub fn readFileAlloc(allocator: *mem.Allocator, path: []const u8) ![]u8 {
|
||||||
return readFileAllocAligned(allocator, path, @alignOf(u8));
|
return fs.Dir.cwd().readFileAlloc(allocator, path, math.maxInt(usize));
|
||||||
}
|
|
||||||
|
|
||||||
/// 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn BufferedInStream(comptime Error: type) type {
|
pub fn BufferedInStream(comptime Error: type) type {
|
||||||
|
@ -241,7 +241,6 @@ pub const KERN_MAXID = 37;
|
|||||||
|
|
||||||
pub const HOST_NAME_MAX = 255;
|
pub const HOST_NAME_MAX = 255;
|
||||||
|
|
||||||
pub const O_LARGEFILE = 0; // faked support
|
|
||||||
pub const O_RDONLY = 0;
|
pub const O_RDONLY = 0;
|
||||||
pub const O_NDELAY = O_NONBLOCK;
|
pub const O_NDELAY = O_NONBLOCK;
|
||||||
pub const O_WRONLY = 1;
|
pub const O_WRONLY = 1;
|
||||||
|
@ -300,7 +300,6 @@ pub const O_CLOEXEC = 0x00100000;
|
|||||||
|
|
||||||
pub const O_ASYNC = 0x0040;
|
pub const O_ASYNC = 0x0040;
|
||||||
pub const O_DIRECT = 0x00010000;
|
pub const O_DIRECT = 0x00010000;
|
||||||
pub const O_LARGEFILE = 0;
|
|
||||||
pub const O_NOATIME = 0o1000000;
|
pub const O_NOATIME = 0o1000000;
|
||||||
pub const O_PATH = 0o10000000;
|
pub const O_PATH = 0o10000000;
|
||||||
pub const O_TMPFILE = 0o20200000;
|
pub const O_TMPFILE = 0o20200000;
|
||||||
|
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user