zig/lib/std / os/uefi/protocol/file.zig

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.

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;

File

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.


File

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,

CloseError


    pub const OpenError = uefi.UnexpectedError || error{
        NotFound,
        NoMedia,
        MediaChanged,
        DeviceError,
        VolumeCorrupted,
        WriteProtected,
        AccessDenied,
        OutOfResources,
        VolumeFull,
        InvalidParameter,
    };
    pub const CloseError = uefi.UnexpectedError;

SeekError

    pub const SeekError = uefi.UnexpectedError || error{
        Unsupported,
        DeviceError,
    };

ReadError

    pub const ReadError = uefi.UnexpectedError || error{
        NoMedia,
        DeviceError,
        VolumeCorrupted,
        BufferTooSmall,
    };

WriteError

    pub const WriteError = uefi.UnexpectedError || error{
        Unsupported,
        NoMedia,
        DeviceError,
        VolumeCorrupted,
        WriteProtected,
        AccessDenied,
        VolumeFull,
    };

GetInfoSizeError

    pub const GetInfoSizeError = uefi.UnexpectedError || error{
        Unsupported,
        NoMedia,
        DeviceError,
        VolumeCorrupted,
    };

GetInfoError

    pub const GetInfoError = GetInfoSizeError || error{
        BufferTooSmall,
    };

SetInfoError

    pub const SetInfoError = uefi.UnexpectedError || error{
        Unsupported,
        NoMedia,
        DeviceError,
        VolumeCorrupted,
        WriteProtected,
        AccessDenied,
        VolumeFull,
        BadBufferSize,
    };

FlushError

    pub const FlushError = uefi.UnexpectedError || error{
        DeviceError,
        VolumeCorrupted,
        WriteProtected,
        AccessDenied,
        VolumeFull,
    };

open()


    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),
        }
    }

close()


    pub fn close(self: *File) CloseError!void {
        switch (self._close(self)) {
            .success => {},
            else => |status| return uefi.unexpectedStatus(status),
        }
    }

delete()


    /// 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),
        }
    }

read()


    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),
        }
    }

write()


    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),
        }
    }

getPosition()


    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),
        }
    }

setPosition()


    fn getEndPos(self: *File) SeekError!u64 {
        const start_pos = try self.getPosition();
        // ignore error
        defer self.setPosition(start_pos) catch {};

getInfoSize()


        try self.setPosition(end_of_file);
        return self.getPosition();
    }

getInfo()


    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),
        }
    }

setInfo()


    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);
    }

flush()


    pub fn getInfoSize(self: *const File, comptime info: std.meta.Tag(Info)) GetInfoError!usize {
        const InfoType = @FieldType(Info, @tagName(info));

OpenMode


        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),
        }
    }

Bits


    /// 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: []align(@alignOf(@FieldType(Info, @tagName(info)))) u8,
    ) GetInfoError!*@FieldType(Info, @tagName(info)) {
        const InfoType = @FieldType(Info, @tagName(info));

Attributes


        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),
        }
    }

Info


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

File


        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;

getFileName()


        // add the length (not +1 for sentinel) because `@sizeOf(InfoType)`
        // already contains the first utf16 char
        const len = @sizeOf(InfoType) + (attached_str_len * 2);

guid


        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),
        }
    }

FileSystem


    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),
        }
    }

getVolumeLabel()


    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,
        };

guid


        read = @bitCast(Bits{ .read = true }),
        read_write = @bitCast(Bits{ .read = true, .write = true }),
        read_write_create = @bitCast(Bits{ .read = true, .write = true, .create = true }),
    };

VolumeLabel


    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,
    };

getVolumeLabel()


    pub const Info = union(enum) {
        file: Info.File,
        file_system: FileSystem,
        volume_label: VolumeLabel,

guid


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