1use core::fmt::Debug;
46
47use alloc::string::String;
48use alloc::vec::Vec;
49
50use iceoryx2_bb_concurrency::atomic::AtomicBool;
51use iceoryx2_bb_concurrency::atomic::Ordering;
52use iceoryx2_bb_container::semantic_string::SemanticString;
53use iceoryx2_bb_elementary::enum_gen;
54use iceoryx2_bb_system_types::file_path::FilePath;
55use iceoryx2_log::{fail, trace, warn};
56use iceoryx2_pal_posix::posix::errno::Errno;
57use iceoryx2_pal_posix::posix::MemZeroedStruct;
58use iceoryx2_pal_posix::*;
59
60pub use crate::creation_mode::CreationMode;
61use crate::file_descriptor::{FileDescriptor, FileDescriptorBased, FileDescriptorManagement};
62use crate::group::Gid;
63use crate::group::GroupError;
64use crate::ownership::OwnershipBuilder;
65use crate::user::{Uid, UserError};
66pub use crate::{access_mode::AccessMode, permission::*};
67
68enum_gen! { FileRemoveError
69 entry:
70 InsufficientPermissions,
71 CurrentlyInUse,
72 LoopInSymbolicLinks,
73 MaxSupportedPathLengthExceeded,
74 PartOfReadOnlyFileSystem,
75 UnknownError(i32)
76}
77
78impl core::fmt::Display for FileRemoveError {
79 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
80 write!(f, "FileRemoveError::{self:?}")
81 }
82}
83
84impl core::error::Error for FileRemoveError {}
85
86enum_gen! { FileAccessError
87 entry:
88 LoopInSymbolicLinks,
89 MaxSupportedPathLengthExceeded,
90 InsufficientPermissions,
91 UnknownError(i32)
92}
93
94impl core::fmt::Display for FileAccessError {
95 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
96 write!(f, "FileAccessError::{self:?}")
97 }
98}
99
100impl core::error::Error for FileAccessError {}
101
102enum_gen! { FileCreationError
103 entry:
104 InsufficientPermissions,
105 InsufficientMemory,
106 FileAlreadyExists,
107 NoSpaceLeft,
108 FileTooBig,
109 Interrupt,
110 IsDirectory,
111 LoopInSymbolicLinks,
112 FilesytemIsReadOnly,
113 DirectoryDoesNotExist,
114 PerProcessFileHandleLimitReached,
115 SystemWideFileHandleLimitReached,
116 MaxFilePathLengthExceeded,
117 UnknownError(i32)
118
119 mapping:
120 FileStatError,
121 UserError,
122 GroupError,
123 FileSetOwnerError,
124 FileTruncateError,
125 FileSetPermissionError,
126 FileAccessError,
127 FileRemoveError
128}
129
130impl core::fmt::Display for FileCreationError {
131 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
132 write!(f, "FileCreationError::{self:?}")
133 }
134}
135
136impl core::error::Error for FileCreationError {}
137
138enum_gen! { FileOpenError
139 entry:
140 InsufficientPermissions,
141 InsufficientMemory,
142 FileDoesNotExist,
143 FileTooBig,
144 Interrupt,
145 IsDirectory,
146 LoopInSymbolicLinks,
147 FilesytemIsReadOnly,
148 PerProcessFileHandleLimitReached,
149 SystemWideFileHandleLimitReached,
150 MaxFilePathLengthExceeded,
151 UnknownError(i32)
152}
153
154impl core::fmt::Display for FileOpenError {
155 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
156 write!(f, "FileOpenError::{self:?}")
157 }
158}
159
160impl core::error::Error for FileOpenError {}
161
162#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
163pub enum FileTruncateError {
164 Interrupt,
165 SizeTooBig,
166 IOerror,
167 FileNotOpenedForWriting,
168 ReadOnlyFilesystem,
169 UnknownError(i32),
170}
171
172impl core::fmt::Display for FileTruncateError {
173 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
174 write!(f, "FileTruncateError::{self:?}")
175 }
176}
177
178impl core::error::Error for FileTruncateError {}
179
180#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
181pub enum FileStatError {
182 InvalidFileDescriptor,
183 IOerror,
184 FileTooBig,
185 UnknownFileType,
186 UnknownError(i32),
187}
188
189impl core::fmt::Display for FileStatError {
190 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
191 write!(f, "FileStatError::{self:?}")
192 }
193}
194
195impl core::error::Error for FileStatError {}
196
197#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
198pub enum FileSetPermissionError {
199 InvalidFileDescriptor,
200 InsufficientPermissions,
201 ReadOnlyFilesystem,
202 UnknownError(i32),
203}
204
205impl core::fmt::Display for FileSetPermissionError {
206 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
207 write!(f, "FileSetPermissionError::{self:?}")
208 }
209}
210
211impl core::error::Error for FileSetPermissionError {}
212
213#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
214pub enum FileSetOwnerError {
215 InvalidFileDescriptor,
216 InsufficientPermissions,
217 ReadOnlyFilesystem,
218 InvalidId,
219 IOerror,
220 Interrupt,
221 UnknownError(i32),
222}
223
224impl core::fmt::Display for FileSetOwnerError {
225 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
226 write!(f, "FileSetOwnerError::{self:?}")
227 }
228}
229
230impl core::error::Error for FileSetOwnerError {}
231
232enum_gen! { FileReadError
233 entry:
234 Interrupt,
235 IOerror,
236 IsDirectory,
237 FileTooBig,
238 InsufficientResources,
239 InsufficientMemory,
240 NonExistingOrIncapableDevice,
241 UnknownError(i32)
242
243 mapping:
244 FileOffsetError,
245 FileStatError
246}
247
248impl core::fmt::Display for FileReadError {
249 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
250 write!(f, "FileReadError::{self:?}")
251 }
252}
253
254impl core::error::Error for FileReadError {}
255
256#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
257pub enum FileOffsetError {
258 InvalidFileDescriptor,
259 FileTooBig,
260 DoesNotSupportSeeking,
261 UnknownError(i32),
262}
263
264impl core::fmt::Display for FileOffsetError {
265 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
266 write!(f, "FileOffsetError::{self:?}")
267 }
268}
269
270impl core::error::Error for FileOffsetError {}
271
272enum_gen! { FileWriteError
273 entry:
274 Interrupt,
275 WriteBufferTooBig,
276 IOerror,
277 NoSpaceLeft,
278 InsufficientResources,
279 InsufficientPermissions,
280 NonExistingOrIncapableDevice,
281 UnknownError(i32)
282 mapping:
283 FileOffsetError
284}
285
286impl core::fmt::Display for FileWriteError {
287 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
288 write!(f, "FileWriteError::{self:?}")
289 }
290}
291
292impl core::error::Error for FileWriteError {}
293
294#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
295pub enum FileSyncError {
296 Interrupt,
297 NotSupported,
298 IOerror,
299 UnknownError(i32),
300}
301
302impl core::fmt::Display for FileSyncError {
303 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
304 write!(f, "FileSyncError::{self:?}")
305 }
306}
307
308impl core::error::Error for FileSyncError {}
309
310enum_gen! {
311 FileError
316 generalization:
317 Create <= FileCreationError,
318 Write <= FileSyncError; FileWriteError; FileTruncateError; FileRemoveError,
319 Read <= FileOffsetError; FileReadError; FileOpenError; FileAccessError,
320 Credentials <= FileSetOwnerError; FileSetPermissionError,
321 Stat <= FileStatError
322}
323
324impl core::fmt::Display for FileError {
325 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
326 write!(f, "FileError::{self:?}")
327 }
328}
329
330impl core::error::Error for FileError {}
331
332impl From<()> for FileStatError {
333 fn from(_: ()) -> Self {
334 FileStatError::UnknownFileType
335 }
336}
337
338#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
339pub enum FileReadLineState {
340 LineLen(usize),
341 EndOfFile(usize),
342}
343
344#[derive(Debug)]
385pub struct FileBuilder {
386 file_path: FilePath,
387 access_mode: AccessMode,
388 permission: Permission,
389 has_ownership: bool,
390 owner: Option<Uid>,
391 group: Option<Gid>,
392 truncate_size: Option<usize>,
393 creation_mode: Option<CreationMode>,
394}
395
396impl FileBuilder {
397 pub fn new(file_path: &FilePath) -> Self {
399 FileBuilder {
400 file_path: *file_path,
401 access_mode: AccessMode::Read,
402 permission: Permission::OWNER_ALL,
403 has_ownership: false,
404 owner: None,
405 group: None,
406 truncate_size: None,
407 creation_mode: None,
408 }
409 }
410
411 pub fn has_ownership(mut self, value: bool) -> Self {
414 self.has_ownership = value;
415 self
416 }
417
418 pub fn creation_mode(mut self, value: CreationMode) -> FileCreationBuilder {
421 self.creation_mode = Some(value);
422 self.access_mode = AccessMode::ReadWrite;
423 FileCreationBuilder { config: self }
424 }
425
426 pub fn open_existing(mut self, value: AccessMode) -> Result<File, FileOpenError> {
431 self.access_mode = value;
432 File::open(self)
433 }
434}
435
436pub struct FileCreationBuilder {
439 config: FileBuilder,
440}
441
442impl FileCreationBuilder {
443 pub fn permission(mut self, value: Permission) -> Self {
461 self.config.permission = value;
462 self
463 }
464
465 pub fn owner(mut self, value: Uid) -> Self {
484 self.config.owner = Some(value);
485 self
486 }
487
488 pub fn group(mut self, value: Gid) -> Self {
507 self.config.group = Some(value);
508 self
509 }
510
511 pub fn truncate_size(mut self, value: usize) -> Self {
513 self.config.truncate_size = Some(value);
514 self
515 }
516
517 pub fn create(self) -> Result<File, FileCreationError> {
519 let mut file = File::create(&self.config)?;
520 fail!(from self.config, when file.set_permission(self.config.permission), "Failed to set permissions.");
521
522 if self.config.truncate_size.is_some() {
523 fail!(from self.config, when File::truncate(&file, self.config.truncate_size.unwrap()), "Failed to truncate file size.");
524 }
525
526 if self.config.owner.is_some() || self.config.group.is_some() {
527 let owner =
528 fail!(from self.config, when file.ownership(), "Failed to acquire current owners.");
529
530 let owner_id = match self.config.owner.as_ref() {
531 Some(v) => *v,
532 None => owner.uid(),
533 };
534
535 let group_id = match self.config.group.as_ref() {
536 Some(v) => *v,
537 None => owner.gid(),
538 };
539
540 fail!(from self.config, when file.set_ownership(OwnershipBuilder::new().uid(owner_id).gid(group_id).create()),
541 "Failed to set ownership.");
542 }
543
544 trace!(from self.config, "created");
545 Ok(file)
546 }
547}
548
549#[derive(Debug)]
551pub struct File {
552 path: Option<FilePath>,
553 file_descriptor: FileDescriptor,
554 has_ownership: AtomicBool,
555}
556
557impl Drop for File {
558 fn drop(&mut self) {
559 if self.has_ownership.load(Ordering::Relaxed) {
560 if let Err(e) = self.set_permission(Permission::ALL) {
561 warn!(from self,
562 "Unable to adjust the files permission as preparation to remove the file ({e:?}).");
563 }
564
565 match &self.path {
566 None => {
567 warn!(from self, "Files created from file descriptors cannot remove themselves.")
568 }
569 Some(p) => match File::remove(p) {
570 Ok(false) | Err(_) => {
571 warn!(from self, "Failed to remove owned file");
572 }
573 Ok(true) => (),
574 },
575 };
576 }
577 }
578}
579
580impl File {
581 fn create(config: &FileBuilder) -> Result<File, FileCreationError> {
582 let msg = "Unable to create file";
583 let create_file = || -> Result<Option<FileDescriptor>, FileCreationError> {
584 Ok(FileDescriptor::new(unsafe {
585 posix::open_with_mode(
586 config.file_path.as_c_str(),
587 config
588 .creation_mode
589 .expect("CreationMode required when creating new file.")
590 .as_oflag()
591 | config.access_mode.as_oflag(),
592 config.permission.as_mode(),
593 )
594 }))
595 };
596
597 let file_descriptor = match config
598 .creation_mode
599 .expect("The creation mode must always be defined when creating a file.")
600 {
601 CreationMode::CreateExclusive => create_file(),
602 CreationMode::PurgeAndCreate => {
603 if fail!(from config, when File::does_exist(&config.file_path), "{} since the file existance verification failed.", msg)
604 {
605 fail!(from config, when File::remove(&config.file_path), "{} since the removal of the already existing file failed.", msg);
606 }
607
608 create_file()
609 }
610 CreationMode::OpenOrCreate => {
611 match fail!(from config, when File::does_exist(&config.file_path), "{} since the file existance verification failed.", msg)
612 {
613 true => Ok(FileDescriptor::new(unsafe {
614 posix::open(config.file_path.as_c_str(), config.access_mode.as_oflag())
615 })),
616 false => create_file(),
617 }
618 }
619 }?;
620
621 if let Some(v) = file_descriptor {
622 return Ok(File {
623 path: Some(config.file_path),
624 file_descriptor: v,
625 has_ownership: AtomicBool::new(config.has_ownership),
626 });
627 }
628
629 handle_errno!(FileCreationError, from config,
630 Errno::EACCES => (InsufficientPermissions, "{} due to insufficient permissions.", msg),
631 Errno::EEXIST => (FileAlreadyExists, "{} since the file already exists.", msg),
632 Errno::EINTR => (Interrupt, "{} since an interrupt signal was received.", msg),
633 Errno::ENOENT => (DirectoryDoesNotExist, "{} since the path points to a directory that does not exist.", msg),
634 Errno::EISDIR => (IsDirectory, "{} since the path is a directory.",msg),
635 Errno::ELOOP => (LoopInSymbolicLinks, "{} since a loop in the symbolic links was detected.", msg),
636 Errno::EMFILE => (PerProcessFileHandleLimitReached, "{} since the current process already holds the maximum amount of file descriptors.", msg),
637 Errno::ENAMETOOLONG => (MaxFilePathLengthExceeded, "{} since the file path length exceeds the maximum supported file path length.", msg),
638 Errno::ENFILE => (SystemWideFileHandleLimitReached, "{} since the system-wide maximum of filedescriptors is reached.", msg),
639 Errno::EOVERFLOW => (FileTooBig, "{} since it is too large to be represented with 'off_t'.", msg),
640 Errno::ENOSPC => (NoSpaceLeft, "{} since there is no space left on the target file-system.", msg),
641 Errno::EROFS => (FilesytemIsReadOnly, "{} with write access on an read-only file system.", msg),
642 Errno::ENOMEM => (InsufficientMemory, "{} due to insufficient memory.", msg),
643 v => (UnknownError(v as i32), "{} since an unknown error occurred ({}).",msg, v)
644 );
645 }
646
647 fn open(config: FileBuilder) -> Result<File, FileOpenError> {
648 let msg = "Unable to open file";
649 let file_descriptor = FileDescriptor::new(unsafe {
650 posix::open(config.file_path.as_c_str(), config.access_mode.as_oflag())
651 });
652
653 if let Some(v) = file_descriptor {
654 trace!(from config, "opened");
655 return Ok(File {
656 path: Some(config.file_path),
657 file_descriptor: v,
658 has_ownership: AtomicBool::new(config.has_ownership),
659 });
660 }
661
662 handle_errno!(FileOpenError, from config,
663 Errno::EACCES => (InsufficientPermissions, "{} due to insufficient permissions.", msg),
664 Errno::EINTR => (Interrupt, "{} since an interrupt signal was received.", msg),
665 Errno::EISDIR => (IsDirectory, "{} since the path is a directory.",msg),
666 Errno::ELOOP => (LoopInSymbolicLinks, "{} since a loop in the symbolic links was detected.", msg),
667 Errno::EMFILE => (PerProcessFileHandleLimitReached, "{} since the current process already holds the maximum amount of file descriptors.", msg),
668 Errno::ENAMETOOLONG => (MaxFilePathLengthExceeded, "{} since the file path length exceeds the maximum supported file path length.", msg),
669 Errno::ENFILE => (SystemWideFileHandleLimitReached, "{} since the system-wide maximum of filedescriptors is reached.", msg),
670 Errno::ENOENT => (FileDoesNotExist, "{} since it does not exist.", msg),
671 Errno::EOVERFLOW => (FileTooBig, "{} since it is too large to be represented with 'off_t'.", msg),
672 Errno::EROFS => (FilesytemIsReadOnly, "{} with write access on an read-only file system.", msg),
673 Errno::ENOMEM => (InsufficientMemory, "{} due to insufficient memory.", msg),
674 v => (UnknownError(v as i32), "{} since an unknown error occurred ({}).",msg, v)
675 );
676 }
677
678 pub fn has_ownership(&self) -> bool {
681 self.has_ownership.load(Ordering::Relaxed)
682 }
683
684 pub fn acquire_ownership(&self) {
687 self.has_ownership.store(true, Ordering::Relaxed);
688 }
689
690 pub fn release_ownership(&self) {
693 self.has_ownership.store(false, Ordering::Relaxed);
694 }
695
696 pub fn from_file_descriptor(file_descriptor: FileDescriptor) -> Self {
699 trace!(from "File::from_file_descriptor", "opened {:?}", file_descriptor);
700 Self {
701 path: None,
702 file_descriptor,
703 has_ownership: AtomicBool::new(false),
704 }
705 }
706
707 pub fn read_line_to_vector(
709 &self,
710 buf: &mut Vec<u8>,
711 ) -> Result<FileReadLineState, FileReadError> {
712 let mut buffer = [0u8; 1];
713
714 let mut counter = 0;
715 loop {
716 if self.read(&mut buffer)? == 0 {
717 return Ok(FileReadLineState::EndOfFile(counter));
718 }
719
720 if buffer[0] == b'\n' {
721 return Ok(FileReadLineState::LineLen(counter));
722 }
723
724 buf.push(buffer[0]);
725 counter += 1;
726 }
727 }
728
729 pub fn read_line_to_string(
731 &self,
732 buf: &mut String,
733 ) -> Result<FileReadLineState, FileReadError> {
734 self.read_line_to_vector(unsafe { buf.as_mut_vec() })
735 }
736
737 pub fn read(&self, buf: &mut [u8]) -> Result<u64, FileReadError> {
740 let bytes_read = unsafe {
741 posix::read(
742 self.file_descriptor.native_handle(),
743 buf.as_mut_ptr() as *mut posix::void,
744 buf.len(),
745 )
746 };
747
748 if bytes_read >= 0 {
749 return Ok(bytes_read as u64);
750 }
751
752 let msg = "Unable to read file";
753 handle_errno!(FileReadError, from self,
754 Errno::EINTR => (Interrupt, "{} since an interrupt signal was received.", msg),
755 Errno::EIO => (IOerror, "{} since an I/O error occurred.", msg),
756 Errno::EISDIR => (IsDirectory, "{} since it is actually a directory.", msg),
757 Errno::EOVERFLOW => (FileTooBig, "{} since the file is too big and would cause an overflow in an internal structure.", msg),
758 Errno::ENOBUFS => (InsufficientResources, "{} due to insufficient resources to perform the operation.", msg),
759 Errno::ENOMEM => (InsufficientMemory, "{} due to insufficient memory to perform the operation.", msg),
760 Errno::ENXIO => (NonExistingOrIncapableDevice, "{} since the device either does not exist or is not capable of that operation.", msg),
761 v => (UnknownError(v as i32), "{} since an unknown error occurred ({}).", msg, v)
762 )
763 }
764
765 pub fn read_to_vector(&self, buf: &mut Vec<u8>) -> Result<u64, FileReadError> {
767 let attr = fail!(from self, when File::acquire_attributes(self), "Unable to acquire file length to read contents of file.");
768
769 let start = buf.len();
770 buf.resize(attr.st_size as usize + start, 0u8);
771 self.read(&mut buf[start..])
772 }
773
774 pub fn read_to_string(&self, buf: &mut String) -> Result<u64, FileReadError> {
776 self.read_to_vector(unsafe { buf.as_mut_vec() })
777 }
778
779 pub fn read_range(&self, start: u64, buf: &mut [u8]) -> Result<u64, FileReadError> {
782 let offset = fail!(from self, when self.seek(start), "Unable to set offset to read a range from the file.");
783
784 if offset != start {
785 return Ok(0);
786 }
787
788 self.read(buf)
789 }
790
791 pub fn read_range_to_vector(
793 &self,
794 start: u64,
795 end: u64,
796 buf: &mut Vec<u8>,
797 ) -> Result<u64, FileReadError> {
798 if start >= end {
799 return Ok(0);
800 }
801
802 let start_of_vec = buf.len();
803 buf.resize((end - start) as usize + start_of_vec, 0u8);
804 self.read_range(start, &mut buf[start_of_vec..])
805 }
806
807 pub fn read_range_to_string(
809 &self,
810 start: u64,
811 end: u64,
812 buf: &mut String,
813 ) -> Result<u64, FileReadError> {
814 self.read_range_to_vector(start, end, unsafe { buf.as_mut_vec() })
815 }
816
817 pub fn write(&mut self, buf: &[u8]) -> Result<u64, FileWriteError> {
819 let bytes_written = unsafe {
820 posix::write(
821 self.file_descriptor.native_handle(),
822 buf.as_ptr() as *const posix::void,
823 buf.len(),
824 )
825 };
826
827 if bytes_written >= 0 {
828 return Ok(bytes_written as u64);
829 }
830
831 let msg = "Unable to write content";
832 handle_errno!(FileWriteError, from self,
833 Errno::EFBIG => (WriteBufferTooBig, "{} since the file size would then exceed the internal maximum file size limit.", msg),
834 Errno::EINTR => (Interrupt, "{} since an interrupt signal was received.", msg),
835 Errno::EIO => (IOerror, "{} due to an I/O error.", msg),
836 Errno::ENOSPC => (NoSpaceLeft, "{} since there is no space left on the device containing the file.", msg),
837 Errno::ENOBUFS => (InsufficientResources, "{} due to insufficient resources.", msg),
838 Errno::ENXIO => (NonExistingOrIncapableDevice, "{} since the operation is outside of the capabilities of the device or the device does not exists.", msg),
839 Errno::EACCES => (InsufficientPermissions, "{} due to insufficient permissions.", msg),
840 v => (UnknownError(v as i32), "{} since an unknown error occurred ({}).",msg, v)
841 );
842 }
843
844 pub fn write_at(&mut self, start: u64, buf: &[u8]) -> Result<u64, FileWriteError> {
846 let offset = fail!(from self, when self.seek(start), "Unable to set offset to write content at a specific position.");
847
848 if offset != start {
849 return Ok(0);
850 }
851
852 self.write(buf)
853 }
854
855 pub fn flush(&mut self) -> Result<(), FileSyncError> {
857 if unsafe { posix::fsync(self.file_descriptor.native_handle()) } == 0 {
858 return Ok(());
859 }
860
861 let msg = "Unable to sync file to device";
862 handle_errno!(FileSyncError, from self,
863 Errno::EINTR => (Interrupt, "{} since an interrupt signal was received.", msg),
864 Errno::EINVAL => (NotSupported, "{} since this operation is not supported by the file.", msg),
865 Errno::EIO => (IOerror, "{} due to an I/O error.", msg),
866 v => (UnknownError(v as i32), "{} since an unknown error occurred ({}).", msg,v)
867 );
868 }
869
870 pub fn does_exist(path: &FilePath) -> Result<bool, FileAccessError> {
872 let msg = "Unable to determine if file";
873 if unsafe { posix::access(path.as_c_str(), posix::F_OK) } == 0 {
874 return Ok(true);
875 }
876
877 handle_errno!(FileAccessError, from "File::does_exist",
878 success Errno::ENOENT => false,
879 Errno::ELOOP => (LoopInSymbolicLinks, "{} \"{}\" exists since a loop exists in the symbolic links.", msg, path),
880 Errno::ENAMETOOLONG => (MaxSupportedPathLengthExceeded, "{} \"{}\" exists since it is longer than the maximum path name length", msg, path),
881 Errno::EACCES => (InsufficientPermissions, "{} \"{}\" due to insufficient permissions.", msg, path),
882 Errno::EPERM => (InsufficientPermissions, "{} \"{}\" due to insufficient permissions.", msg, path),
883 v => (UnknownError(v as i32), "{} \"{}\" exists caused by an unknown error ({}).", msg, path, v)
884 );
885 }
886
887 pub fn remove_self(self) -> Result<bool, FileRemoveError> {
889 match &self.path {
890 None => {
891 warn!(from self, "Files created from file descriptors cannot remove themselves.");
892 Ok(false)
893 }
894 Some(p) => File::remove(p),
895 }
896 }
897
898 pub fn path(&self) -> Option<&FilePath> {
901 match self.path {
902 None => None,
903 Some(_) => self.path.as_ref(),
904 }
905 }
906
907 pub fn remove(path: &FilePath) -> Result<bool, FileRemoveError> {
910 let msg = "Unable to remove file";
911 if unsafe { posix::remove(path.as_c_str()) } >= 0 {
912 trace!(from "File::remove", "\"{}\"", path);
913 return Ok(true);
914 }
915
916 handle_errno!(FileRemoveError, from "File::remove",
917 success Errno::ENOENT => false,
918 Errno::EACCES => (InsufficientPermissions, "{} \"{}\" due to insufficient permissions.", msg, path),
919 Errno::EPERM => (InsufficientPermissions, "{} \"{}\" due to insufficient permissions.", msg, path),
920 Errno::EBUSY => (CurrentlyInUse, "{} \"{}\" since it is currently in use.", msg, path),
921 Errno::ELOOP => (LoopInSymbolicLinks, "{} \"{}\" since a loop exists in the symbolic links.", msg, path),
922 Errno::ENAMETOOLONG => (MaxSupportedPathLengthExceeded, "{} \"{}\" since it is longer than the maximum path name length.", msg, path),
923 Errno::EROFS => (PartOfReadOnlyFileSystem, "{} \"{}\" since it is part of a read-only filesystem.", msg, path),
924 v => (UnknownError(v as i32), "{} \"{}\" since an unkown error occurred ({}).", msg, path, v)
925 );
926 }
927
928 pub fn seek(&self, offset: u64) -> Result<u64, FileOffsetError> {
930 Self::set_offset(self, offset)
931 }
932
933 pub(crate) fn set_offset<T: FileDescriptorBased + Debug>(
934 this: &T,
935 offset: u64,
936 ) -> Result<u64, FileOffsetError> {
937 let new_offset = unsafe {
938 posix::lseek(
939 this.file_descriptor().native_handle(),
940 offset as posix::off_t,
941 posix::SEEK_SET,
942 )
943 };
944
945 if new_offset >= 0 {
946 return Ok(new_offset as u64);
947 }
948
949 let msg = "Unable to change read/write position to";
950 handle_errno!(FileOffsetError, from this,
951 Errno::EBADF => (InvalidFileDescriptor, "{} {} since the provide file-descriptor was not valid.", msg, offset),
952 Errno::EOVERFLOW => (FileTooBig, "{} {} since the file size is so large that ic cannot be represented by an internal structure.", msg, offset),
953 Errno::ESPIPE => (DoesNotSupportSeeking, "{} {} since the file type does not support seeking.", msg, offset),
954 v => (UnknownError(v as i32), "{} {} due to an unknown error ({}).", msg, offset, v)
955 );
956 }
957
958 pub(crate) fn truncate<T: FileDescriptorBased + Debug>(
959 this: &T,
960 size: usize,
961 ) -> Result<(), FileTruncateError> {
962 if unsafe { posix::ftruncate(this.file_descriptor().native_handle(), size as posix::off_t) }
963 == 0
964 {
965 return Ok(());
966 }
967
968 let msg = "Unable to resize file to";
969 handle_errno!(FileTruncateError, from this,
970 Errno::EINTR => (Interrupt, "{} {} since an interrupt signal was received.", msg, size),
971 Errno::EFBIG => (SizeTooBig, "{} {} since the size is too big. Maybe the file can only shrink?", msg, size),
972 Errno::EIO => (IOerror, "{} {} due to an I/O error while writing to the file system.", msg, size),
973 Errno::EBADF => (FileNotOpenedForWriting, "{} {} file is not opened for writing.", msg, size),
974 Errno::EROFS => (ReadOnlyFilesystem, "{} {} since the file resides on a read-only file system.", msg, size),
975 v => (UnknownError(v as i32), "{} {} due to an unknown error ({}).", msg, size, v)
976 );
977 }
978
979 pub(crate) fn acquire_attributes<T: FileDescriptorBased + Debug>(
980 this: &T,
981 ) -> Result<posix::stat_t, FileStatError> {
982 let mut attr = posix::stat_t::new_zeroed();
983 if unsafe { posix::fstat(this.file_descriptor().native_handle(), &mut attr) } == -1 {
984 let msg = "Unable to acquire file stats";
985 handle_errno!(FileStatError, from this,
986 Errno::EBADF => (InvalidFileDescriptor, "{} since an invalid file-descriptor was provided.", msg),
987 Errno::EIO => (IOerror, "{} due to an I/O error while reading from the file system.", msg),
988 Errno::EOVERFLOW => (FileTooBig, "{} since the file size is so large that it cannot be represented by an internal structure.", msg),
989 v => (UnknownError(v as i32), "{} since an unknown error occurred ({}).", msg, v)
990 );
991 }
992
993 Ok(attr)
994 }
995
996 pub(crate) fn set_permission<T: FileDescriptorBased + Debug>(
997 this: &T,
998 permission: Permission,
999 ) -> Result<(), FileSetPermissionError> {
1000 if unsafe { posix::fchmod(this.file_descriptor().native_handle(), permission.as_mode()) }
1001 == 0
1002 {
1003 return Ok(());
1004 }
1005
1006 let msg = "Unable to update permission";
1007 handle_errno!(FileSetPermissionError, from this,
1008 Errno::EBADF => (InvalidFileDescriptor, "{} to {} since an invalid file-descriptor was provided.", msg, permission),
1009 Errno::EPERM => (InsufficientPermissions, "{} {} due to insufficient permissions.", msg, permission),
1010 Errno::EROFS => (ReadOnlyFilesystem, "{} {} since the file resides on a read-only file system.", msg, permission),
1011 v => (UnknownError(v as i32), "{} {} due to an unknown error ({}).", msg, permission, v)
1012 );
1013 }
1014
1015 pub(crate) fn set_ownership<T: FileDescriptorBased + Debug>(
1016 this: &T,
1017 uid: Uid,
1018 gid: Gid,
1019 ) -> Result<(), FileSetOwnerError> {
1020 if unsafe {
1021 posix::fchown(
1022 this.file_descriptor().native_handle(),
1023 uid.to_native(),
1024 gid.to_native(),
1025 )
1026 } == 0
1027 {
1028 return Ok(());
1029 }
1030
1031 let msg = "Unable to update ownership";
1032 handle_errno!(FileSetOwnerError, from this,
1033 Errno::EBADF => (InvalidFileDescriptor, "{} to uid {}, gid {} since an invalid file-descriptor was provided.", msg, uid, gid),
1034 Errno::EPERM => (InsufficientPermissions, "{} to uid {}, gid {} due to insufficient permissions.", msg, uid, gid),
1035 Errno::EROFS => (ReadOnlyFilesystem, "{} to uid {}, gid {} since the file is located on an read-only filesystem.", msg, uid, gid),
1036 Errno::EINVAL => (InvalidId, "{} to uid {}, gid {} since the owner or group id is not a valid id.", msg, uid, gid),
1037 Errno::EIO => (IOerror, "{} to uid {}, gid {} due to an I/O error.", msg, uid, gid),
1038 Errno::EINTR => (Interrupt, "{} to uid {}, gid {} since an interrupt signal was received.", msg, uid, gid),
1039 v => (UnknownError(v as i32), "{} to uid {}, gid {} due to an unknown error ({}).", msg, uid, gid, v)
1040 );
1041 }
1042}
1043
1044impl FileDescriptorBased for File {
1045 fn file_descriptor(&self) -> &FileDescriptor {
1046 &self.file_descriptor
1047 }
1048}
1049
1050impl FileDescriptorManagement for File {}