authorgravatar for toast@bunkerlabs.netChloé Vulquin <toast@bunkerlabs.net> 2026-05-31 16:37:18+02:00
committergravatar for mail@linusgroh.delinus <mail@linusgroh.de> 2026-06-01 18:09:12+02:00
log45c4f781a5a831dd08cbab745a55834d514e45f5
tree152834264b68109e525790fd30d9907ee90cfc15
parent8fe1ec0cc9cfd0f3cf85b97889b4b9735e906926

std.uefi.protocol.File: add readSize for directory entries

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 {
125125 }
126126 }
127127
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.
128144 pub fn read(self: *File, buffer: []u8) ReadError!usize {
129145 var size: usize = buffer.len;
130146 switch (self._read(self, &size, buffer.ptr)) {