| author | |
| committer | |
| log | 45c4f781a5a831dd08cbab745a55834d514e45f5 |
| tree | 152834264b68109e525790fd30d9907ee90cfc15 |
| parent | 8fe1ec0cc9cfd0f3cf85b97889b4b9735e906926 |
EFI_FILE_PROTOCOL does not differentiate between reading directory
entries and files in the API. When calling `EFI_FILE_PROTOCOL.Read()`
against a File, the buffer is filled up with BufferSize from the
file's position. However, when calling it against a Directory, an
entire directory entry is placed into the buffer. If the buffer is not
large enough, BufferTooSmall is returned, and the BufferSize is
updated to the needed size to hold the entire directory entry.
When wanting to read an entire file, you can accomplish this by
calling `getInfoSize`, allocating a buffer to hold the file's info
structure, then calling `getInfo` to get the file's size, allocating
that much, then calling `read`.
This is impossible in this case, since `getInfo` would return data to
do with the directory itself, as opposed to the next directory
entry. As such, the only place this information can be gotten is from
the `read` call itself.
This creates a new `readSize` function that mirrors `getInfoSize`,
returning the protocol-given size in case of `BufferTooSmall`. It is
called with an initial size of 0 and a zero-item buffer to avoid the
case where the buffer happens to be large enough (e.g. if `readSize`
is called before `read`), which would advance the file position. Same
as `read`, this may return 0 to indicate that there are no future
files. As a consequence, it is safe to call either before or after a
potentially failing call to `read`.1 files changed, 16 insertions(+), 0 deletions(-)
lib/std/os/uefi/protocol/file.zig+16| ... | @@ -125,6 +125,22 @@ pub const File = extern struct { | ... | @@ -125,6 +125,22 @@ pub const File = extern struct { |
| 125 | } | 125 | } |
| 126 | } | 126 | } |
| 127 | 127 | ||
| 128 | pub fn readSize(self: *File) ReadError!usize { | ||
| 129 | const zerobuf: [0]u8 = undefined; | ||
| 130 | var size: usize = 0; | ||
| 131 | switch (self._read(self, &size, &zerobuf)) { | ||
| 132 | .success, .buffer_too_small => return size, | ||
| 133 | .no_media => return error.NoMedia, | ||
| 134 | .device_error => return error.DeviceError, | ||
| 135 | .volume_corrupted => return error.VolumeCorrupted, | ||
| 136 | else => |status| return uefi.unexpectedStatus(status), | ||
| 137 | } | ||
| 138 | } | ||
| 139 | |||
| 140 | /// If `self` is a directory entry and `buffer` is too small to contain the | ||
| 141 | /// next entry, this function returns `Error.BufferTooSmall`. You can call | ||
| 142 | /// `readSize` before or after to determine how big the buffer should be to | ||
| 143 | /// call this function. | ||
| 128 | pub fn read(self: *File, buffer: []u8) ReadError!usize { | 144 | pub fn read(self: *File, buffer: []u8) ReadError!usize { |
| 129 | var size: usize = buffer.len; | 145 | var size: usize = buffer.len; |
| 130 | switch (self._read(self, &size, buffer.ptr)) { | 146 | switch (self._read(self, &size, buffer.ptr)) { |