mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
added adapter to AnyWriter and GenericWriter to help bridge the gap
between old and new API
make std.testing.expectFmt work at compile-time
std.fmt no longer has a dependency on std.unicode. Formatted printing
was never properly unicode-aware. Now it no longer pretends to be.
Breakage/deprecations:
* std.fs.File.reader -> std.fs.File.deprecatedReader
* std.fs.File.writer -> std.fs.File.deprecatedWriter
* std.io.GenericReader -> std.io.Reader
* std.io.GenericWriter -> std.io.Writer
* std.io.AnyReader -> std.io.Reader
* std.io.AnyWriter -> std.io.Writer
* std.fmt.format -> std.fmt.deprecatedFormat
* std.fmt.fmtSliceEscapeLower -> std.ascii.hexEscape
* std.fmt.fmtSliceEscapeUpper -> std.ascii.hexEscape
* std.fmt.fmtSliceHexLower -> {x}
* std.fmt.fmtSliceHexUpper -> {X}
* std.fmt.fmtIntSizeDec -> {B}
* std.fmt.fmtIntSizeBin -> {Bi}
* std.fmt.fmtDuration -> {D}
* std.fmt.fmtDurationSigned -> {D}
* {} -> {f} when there is a format method
* format method signature
- anytype -> *std.io.Writer
- inferred error set -> error{WriteFailed}
- options -> (deleted)
* std.fmt.Formatted
- now takes context type explicitly
- no fmt string
384 lines
13 KiB
Zig
384 lines
13 KiB
Zig
const std = @import("std");
|
|
const uefi = std.os.uefi;
|
|
const io = std.io;
|
|
const Guid = uefi.Guid;
|
|
const Time = uefi.Time;
|
|
const Status = uefi.Status;
|
|
const cc = uefi.cc;
|
|
const Error = Status.Error;
|
|
|
|
pub const File = extern struct {
|
|
revision: u64,
|
|
_open: *const fn (*const File, **File, [*:0]const u16, OpenMode, Attributes) callconv(cc) Status,
|
|
_close: *const fn (*File) callconv(cc) Status,
|
|
_delete: *const fn (*File) callconv(cc) Status,
|
|
_read: *const fn (*File, *usize, [*]u8) callconv(cc) Status,
|
|
_write: *const fn (*File, *usize, [*]const u8) callconv(cc) Status,
|
|
_get_position: *const fn (*const File, *u64) callconv(cc) Status,
|
|
_set_position: *const fn (*File, u64) callconv(cc) Status,
|
|
_get_info: *const fn (*const File, *align(8) const Guid, *usize, ?[*]u8) callconv(cc) Status,
|
|
_set_info: *const fn (*File, *align(8) const Guid, usize, [*]const u8) callconv(cc) Status,
|
|
_flush: *const fn (*File) callconv(cc) Status,
|
|
|
|
pub const OpenError = uefi.UnexpectedError || error{
|
|
NotFound,
|
|
NoMedia,
|
|
MediaChanged,
|
|
DeviceError,
|
|
VolumeCorrupted,
|
|
WriteProtected,
|
|
AccessDenied,
|
|
OutOfResources,
|
|
VolumeFull,
|
|
InvalidParameter,
|
|
};
|
|
pub const CloseError = uefi.UnexpectedError;
|
|
pub const SeekError = uefi.UnexpectedError || error{
|
|
Unsupported,
|
|
DeviceError,
|
|
};
|
|
pub const ReadError = uefi.UnexpectedError || error{
|
|
NoMedia,
|
|
DeviceError,
|
|
VolumeCorrupted,
|
|
BufferTooSmall,
|
|
};
|
|
pub const WriteError = uefi.UnexpectedError || error{
|
|
Unsupported,
|
|
NoMedia,
|
|
DeviceError,
|
|
VolumeCorrupted,
|
|
WriteProtected,
|
|
AccessDenied,
|
|
VolumeFull,
|
|
};
|
|
pub const GetInfoSizeError = uefi.UnexpectedError || error{
|
|
Unsupported,
|
|
NoMedia,
|
|
DeviceError,
|
|
VolumeCorrupted,
|
|
};
|
|
pub const GetInfoError = GetInfoSizeError || error{
|
|
BufferTooSmall,
|
|
};
|
|
pub const SetInfoError = uefi.UnexpectedError || error{
|
|
Unsupported,
|
|
NoMedia,
|
|
DeviceError,
|
|
VolumeCorrupted,
|
|
WriteProtected,
|
|
AccessDenied,
|
|
VolumeFull,
|
|
BadBufferSize,
|
|
};
|
|
pub const FlushError = uefi.UnexpectedError || error{
|
|
DeviceError,
|
|
VolumeCorrupted,
|
|
WriteProtected,
|
|
AccessDenied,
|
|
VolumeFull,
|
|
};
|
|
|
|
pub fn open(
|
|
self: *const File,
|
|
file_name: [*:0]const u16,
|
|
mode: OpenMode,
|
|
create_attributes: Attributes,
|
|
) OpenError!*File {
|
|
var new: *File = undefined;
|
|
switch (self._open(
|
|
self,
|
|
&new,
|
|
file_name,
|
|
mode,
|
|
create_attributes,
|
|
)) {
|
|
.success => return new,
|
|
.not_found => return Error.NotFound,
|
|
.no_media => return Error.NoMedia,
|
|
.media_changed => return Error.MediaChanged,
|
|
.device_error => return Error.DeviceError,
|
|
.volume_corrupted => return Error.VolumeCorrupted,
|
|
.write_protected => return Error.WriteProtected,
|
|
.access_denied => return Error.AccessDenied,
|
|
.out_of_resources => return Error.OutOfResources,
|
|
.volume_full => return Error.VolumeFull,
|
|
.invalid_parameter => return Error.InvalidParameter,
|
|
else => |status| return uefi.unexpectedStatus(status),
|
|
}
|
|
}
|
|
|
|
pub fn close(self: *File) CloseError!void {
|
|
switch (self._close(self)) {
|
|
.success => {},
|
|
else => |status| return uefi.unexpectedStatus(status),
|
|
}
|
|
}
|
|
|
|
/// Delete the file.
|
|
///
|
|
/// Returns true if the file was deleted, false if the file was not deleted, which is a warning
|
|
/// according to the UEFI specification.
|
|
pub fn delete(self: *File) uefi.UnexpectedError!bool {
|
|
switch (self._delete(self)) {
|
|
.success => return true,
|
|
.warn_delete_failure => return false,
|
|
else => |status| return uefi.unexpectedStatus(status),
|
|
}
|
|
}
|
|
|
|
pub fn read(self: *File, buffer: []u8) ReadError!usize {
|
|
var size: usize = buffer.len;
|
|
switch (self._read(self, &size, buffer.ptr)) {
|
|
.success => return size,
|
|
.no_media => return Error.NoMedia,
|
|
.device_error => return Error.DeviceError,
|
|
.volume_corrupted => return Error.VolumeCorrupted,
|
|
.buffer_too_small => return Error.BufferTooSmall,
|
|
else => |status| return uefi.unexpectedStatus(status),
|
|
}
|
|
}
|
|
|
|
pub fn write(self: *File, buffer: []const u8) WriteError!usize {
|
|
var size: usize = buffer.len;
|
|
switch (self._write(self, &size, buffer.ptr)) {
|
|
.success => return size,
|
|
.unsupported => return Error.Unsupported,
|
|
.no_media => return Error.NoMedia,
|
|
.device_error => return Error.DeviceError,
|
|
.volume_corrupted => return Error.VolumeCorrupted,
|
|
.write_protected => return Error.WriteProtected,
|
|
.access_denied => return Error.AccessDenied,
|
|
.volume_full => return Error.VolumeFull,
|
|
else => |status| return uefi.unexpectedStatus(status),
|
|
}
|
|
}
|
|
|
|
pub fn getPosition(self: *const File) SeekError!u64 {
|
|
var position: u64 = undefined;
|
|
switch (self._get_position(self, &position)) {
|
|
.success => return position,
|
|
.unsupported => return Error.Unsupported,
|
|
.device_error => return Error.DeviceError,
|
|
else => |status| return uefi.unexpectedStatus(status),
|
|
}
|
|
}
|
|
|
|
fn getEndPos(self: *File) SeekError!u64 {
|
|
const start_pos = try self.getPosition();
|
|
// ignore error
|
|
defer self.setPosition(start_pos) catch {};
|
|
|
|
try self.setPosition(end_of_file);
|
|
return self.getPosition();
|
|
}
|
|
|
|
pub fn setPosition(self: *File, position: u64) SeekError!void {
|
|
switch (self._set_position(self, position)) {
|
|
.success => {},
|
|
.unsupported => return Error.Unsupported,
|
|
.device_error => return Error.DeviceError,
|
|
else => |status| return uefi.unexpectedStatus(status),
|
|
}
|
|
}
|
|
|
|
fn seekBy(self: *File, offset: i64) SeekError!void {
|
|
var pos = try self.getPosition();
|
|
const seek_back = offset < 0;
|
|
const amt = @abs(offset);
|
|
if (seek_back) {
|
|
pos += amt;
|
|
} else {
|
|
pos -= amt;
|
|
}
|
|
try self.setPosition(pos);
|
|
}
|
|
|
|
pub fn getInfoSize(self: *const File, comptime info: std.meta.Tag(Info)) GetInfoError!usize {
|
|
const InfoType = @FieldType(Info, @tagName(info));
|
|
|
|
var len: usize = 0;
|
|
switch (self._get_info(self, &InfoType.guid, &len, null)) {
|
|
.success, .buffer_too_small => return len,
|
|
.unsupported => return Error.Unsupported,
|
|
.no_media => return Error.NoMedia,
|
|
.device_error => return Error.DeviceError,
|
|
.volume_corrupted => return Error.VolumeCorrupted,
|
|
else => |status| return uefi.unexpectedStatus(status),
|
|
}
|
|
}
|
|
|
|
/// If `buffer` is too small to contain all of the info, this function returns
|
|
/// `Error.BufferTooSmall`. You should call `getInfoSize` first to determine
|
|
/// how big the buffer should be to safely call this function.
|
|
pub fn getInfo(
|
|
self: *const File,
|
|
comptime info: std.meta.Tag(Info),
|
|
buffer: []u8,
|
|
) GetInfoError!*@FieldType(Info, @tagName(info)) {
|
|
const InfoType = @FieldType(Info, @tagName(info));
|
|
|
|
var len = buffer.len;
|
|
switch (self._get_info(
|
|
self,
|
|
&InfoType.guid,
|
|
&len,
|
|
buffer.ptr,
|
|
)) {
|
|
.success => return @as(*InfoType, @ptrCast(buffer.ptr)),
|
|
.buffer_too_small => return Error.BufferTooSmall,
|
|
.unsupported => return Error.Unsupported,
|
|
.no_media => return Error.NoMedia,
|
|
.device_error => return Error.DeviceError,
|
|
.volume_corrupted => return Error.VolumeCorrupted,
|
|
else => |status| return uefi.unexpectedStatus(status),
|
|
}
|
|
}
|
|
|
|
pub fn setInfo(
|
|
self: *File,
|
|
comptime info: std.meta.Tag(Info),
|
|
data: *const @FieldType(Info, @tagName(info)),
|
|
) SetInfoError!void {
|
|
const InfoType = @FieldType(Info, @tagName(info));
|
|
|
|
const attached_str: [*:0]const u16 = switch (info) {
|
|
.file => data.getFileName(),
|
|
.file_system, .volume_label => data.getVolumeLabel(),
|
|
};
|
|
const attached_str_len = std.mem.sliceTo(attached_str, 0).len;
|
|
|
|
// add the length (not +1 for sentinel) because `@sizeOf(InfoType)`
|
|
// already contains the first utf16 char
|
|
const len = @sizeOf(InfoType) + (attached_str_len * 2);
|
|
|
|
switch (self._set_info(self, &InfoType.guid, len, @ptrCast(data))) {
|
|
.success => {},
|
|
.unsupported => return Error.Unsupported,
|
|
.no_media => return Error.NoMedia,
|
|
.device_error => return Error.DeviceError,
|
|
.volume_corrupted => return Error.VolumeCorrupted,
|
|
.write_protected => return Error.WriteProtected,
|
|
.access_denied => return Error.AccessDenied,
|
|
.volume_full => return Error.VolumeFull,
|
|
.bad_buffer_size => return Error.BadBufferSize,
|
|
else => |status| return uefi.unexpectedStatus(status),
|
|
}
|
|
}
|
|
|
|
pub fn flush(self: *File) FlushError!void {
|
|
switch (self._flush(self)) {
|
|
.success => {},
|
|
.device_error => return Error.DeviceError,
|
|
.volume_corrupted => return Error.VolumeCorrupted,
|
|
.write_protected => return Error.WriteProtected,
|
|
.access_denied => return Error.AccessDenied,
|
|
.volume_full => return Error.VolumeFull,
|
|
else => |status| return uefi.unexpectedStatus(status),
|
|
}
|
|
}
|
|
|
|
pub const OpenMode = enum(u64) {
|
|
pub const Bits = packed struct(u64) {
|
|
// 0x0000000000000001
|
|
read: bool = false,
|
|
// 0x0000000000000002
|
|
write: bool = false,
|
|
_pad: u61 = 0,
|
|
// 0x8000000000000000
|
|
create: bool = false,
|
|
};
|
|
|
|
read = @bitCast(Bits{ .read = true }),
|
|
read_write = @bitCast(Bits{ .read = true, .write = true }),
|
|
read_write_create = @bitCast(Bits{ .read = true, .write = true, .create = true }),
|
|
};
|
|
|
|
pub const Attributes = packed struct(u64) {
|
|
// 0x0000000000000001
|
|
read_only: bool = false,
|
|
// 0x0000000000000002
|
|
hidden: bool = false,
|
|
// 0x0000000000000004
|
|
system: bool = false,
|
|
// 0x0000000000000008
|
|
reserved: bool = false,
|
|
// 0x0000000000000010
|
|
directory: bool = false,
|
|
// 0x0000000000000020
|
|
archive: bool = false,
|
|
_pad: u58 = 0,
|
|
};
|
|
|
|
pub const Info = union(enum) {
|
|
file: Info.File,
|
|
file_system: FileSystem,
|
|
volume_label: VolumeLabel,
|
|
|
|
pub const File = extern struct {
|
|
size: u64,
|
|
file_size: u64,
|
|
physical_size: u64,
|
|
create_time: Time,
|
|
last_access_time: Time,
|
|
modification_time: Time,
|
|
attribute: Attributes,
|
|
_file_name: u16,
|
|
|
|
pub fn getFileName(self: *const Info.File) [*:0]const u16 {
|
|
return @as([*:0]const u16, @ptrCast(&self._file_name));
|
|
}
|
|
|
|
pub const guid align(8) = Guid{
|
|
.time_low = 0x09576e92,
|
|
.time_mid = 0x6d3f,
|
|
.time_high_and_version = 0x11d2,
|
|
.clock_seq_high_and_reserved = 0x8e,
|
|
.clock_seq_low = 0x39,
|
|
.node = [_]u8{ 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b },
|
|
};
|
|
};
|
|
|
|
pub const FileSystem = extern struct {
|
|
size: u64,
|
|
read_only: bool,
|
|
volume_size: u64,
|
|
free_space: u64,
|
|
block_size: u32,
|
|
_volume_label: u16,
|
|
|
|
pub fn getVolumeLabel(self: *const FileSystem) [*:0]const u16 {
|
|
return @as([*:0]const u16, @ptrCast(&self._volume_label));
|
|
}
|
|
|
|
pub const guid align(8) = Guid{
|
|
.time_low = 0x09576e93,
|
|
.time_mid = 0x6d3f,
|
|
.time_high_and_version = 0x11d2,
|
|
.clock_seq_high_and_reserved = 0x8e,
|
|
.clock_seq_low = 0x39,
|
|
.node = [_]u8{ 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b },
|
|
};
|
|
};
|
|
|
|
pub const VolumeLabel = extern struct {
|
|
_volume_label: u16,
|
|
|
|
pub fn getVolumeLabel(self: *const VolumeLabel) [*:0]const u16 {
|
|
return @as([*:0]const u16, @ptrCast(&self._volume_label));
|
|
}
|
|
|
|
pub const guid align(8) = Guid{
|
|
.time_low = 0xdb47d7d3,
|
|
.time_mid = 0xfe81,
|
|
.time_high_and_version = 0x11d3,
|
|
.clock_seq_high_and_reserved = 0x9a,
|
|
.clock_seq_low = 0x35,
|
|
.node = [_]u8{ 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d },
|
|
};
|
|
};
|
|
};
|
|
|
|
const end_of_file: u64 = 0xffffffffffffffff;
|
|
};
|