1 | use super::{File, FileHandle, FileInternal}; |
2 | use crate::{Result, Status}; |
3 | |
4 | /// A `FileHandle` that is also a regular (data) file. |
5 | /// |
6 | /// Use `FileHandle::into_type` or `RegularFile::new` to create a `RegularFile`. |
7 | /// In addition to supporting the normal `File` operations, `RegularFile` |
8 | /// supports direct reading and writing. |
9 | #[repr (transparent)] |
10 | #[derive (Debug)] |
11 | pub struct RegularFile(FileHandle); |
12 | |
13 | impl RegularFile { |
14 | /// A special position used to seek to the end of a file with `set_position()`. |
15 | pub const END_OF_FILE: u64 = u64::MAX; |
16 | |
17 | /// Coverts a `FileHandle` into a `RegularFile` without checking the file kind. |
18 | /// # Safety |
19 | /// This function should only be called on handles which ARE NOT directories, |
20 | /// doing otherwise is unsafe. |
21 | #[must_use ] |
22 | pub unsafe fn new(handle: FileHandle) -> Self { |
23 | Self(handle) |
24 | } |
25 | |
26 | /// Read data from file. |
27 | /// |
28 | /// Try to read as much as possible into `buffer`. Returns the number of bytes that were |
29 | /// actually read. |
30 | /// |
31 | /// # Arguments |
32 | /// * `buffer` The target buffer of the read operation |
33 | /// |
34 | /// # Errors |
35 | /// |
36 | /// See section `EFI_FILE_PROTOCOL.Read()` in the UEFI Specification for more details. |
37 | /// |
38 | /// * [`uefi::Status::NO_MEDIA`] |
39 | /// * [`uefi::Status::DEVICE_ERROR`] |
40 | /// * [`uefi::Status::VOLUME_CORRUPTED`] |
41 | /// * [`uefi::Status::BUFFER_TOO_SMALL`] |
42 | pub fn read(&mut self, buffer: &mut [u8]) -> Result<usize, Option<usize>> { |
43 | let mut buffer_size = buffer.len(); |
44 | let status = |
45 | unsafe { (self.imp().read)(self.imp(), &mut buffer_size, buffer.as_mut_ptr()) }; |
46 | |
47 | status.into_with( |
48 | || buffer_size, |
49 | |s| { |
50 | if s == Status::BUFFER_TOO_SMALL { |
51 | // `buffer_size` was updated to the required buffer size by the underlying read |
52 | // function. |
53 | Some(buffer_size) |
54 | } else { |
55 | None |
56 | } |
57 | }, |
58 | ) |
59 | } |
60 | |
61 | /// Write data to file |
62 | /// |
63 | /// Write `buffer` to file, increment the file pointer. |
64 | /// |
65 | /// If an error occurs, returns the number of bytes that were actually written. If no error |
66 | /// occurred, the entire buffer is guaranteed to have been written successfully. |
67 | /// |
68 | /// # Arguments |
69 | /// * `buffer` Buffer to write to file |
70 | /// |
71 | /// # Errors |
72 | /// |
73 | /// See section `EFI_FILE_PROTOCOL.Write()` in the UEFI Specification for more details. |
74 | /// |
75 | /// * [`uefi::Status::NO_MEDIA`] |
76 | /// * [`uefi::Status::DEVICE_ERROR`] |
77 | /// * [`uefi::Status::VOLUME_CORRUPTED`] |
78 | /// * [`uefi::Status::WRITE_PROTECTED`] |
79 | /// * [`uefi::Status::ACCESS_DENIED`] |
80 | /// * [`uefi::Status::VOLUME_FULL`] |
81 | pub fn write(&mut self, buffer: &[u8]) -> Result<(), usize> { |
82 | let mut buffer_size = buffer.len(); |
83 | unsafe { (self.imp().write)(self.imp(), &mut buffer_size, buffer.as_ptr()) } |
84 | .into_with_err(|_| buffer_size) |
85 | } |
86 | |
87 | /// Get the file's current position |
88 | /// |
89 | /// # Errors |
90 | /// |
91 | /// See section `EFI_FILE_PROTOCOL.GetPosition()` in the UEFI Specification for more details. |
92 | /// |
93 | /// * [`uefi::Status::DEVICE_ERROR`] |
94 | pub fn get_position(&mut self) -> Result<u64> { |
95 | let mut pos = 0u64; |
96 | (self.imp().get_position)(self.imp(), &mut pos).into_with_val(|| pos) |
97 | } |
98 | |
99 | /// Sets the file's current position |
100 | /// |
101 | /// Set the position of this file handle to the absolute position specified by `position`. |
102 | /// |
103 | /// Seeking past the end of the file is allowed, it will trigger file growth on the next write. |
104 | /// Using a position of RegularFile::END_OF_FILE will seek to the end of the file. |
105 | /// |
106 | /// # Arguments |
107 | /// * `position` The new absolution position of the file handle |
108 | /// |
109 | /// # Errors |
110 | /// |
111 | /// See section `EFI_FILE_PROTOCOL.SetPosition()` in the UEFI Specification for more details. |
112 | /// |
113 | /// * [`uefi::Status::DEVICE_ERROR`] |
114 | pub fn set_position(&mut self, position: u64) -> Result { |
115 | (self.imp().set_position)(self.imp(), position).into() |
116 | } |
117 | } |
118 | |
119 | impl File for RegularFile { |
120 | #[inline ] |
121 | fn handle(&mut self) -> &mut FileHandle { |
122 | &mut self.0 |
123 | } |
124 | |
125 | fn is_regular_file(&self) -> Result<bool> { |
126 | Ok(true) |
127 | } |
128 | |
129 | fn is_directory(&self) -> Result<bool> { |
130 | Ok(false) |
131 | } |
132 | } |
133 | |