2 use crate::ffi
::{CStr, CString, OsStr, OsString}
;
4 use crate::io
::{self, Error, ErrorKind, IoSlice, IoSliceMut, SeekFrom}
;
6 use crate::path
::{Path, PathBuf}
;
9 use crate::sys
::fd
::FileDesc
;
10 use crate::sys
::time
::SystemTime
;
11 use crate::sys
::vxworks
::ext
::ffi
::OsStrExt
;
12 use crate::sys
::vxworks
::ext
::ffi
::OsStringExt
;
13 use crate::sys
::{cvt, cvt_r}
;
14 use crate::sys_common
::{AsInner, FromInner}
;
15 use libc
::{self, c_int, mode_t, off_t, stat64}
;
16 use libc
::{dirent, ftruncate, lseek, open, readdir_r as readdir64_r}
;
17 pub struct File(FileDesc
);
24 // all DirEntry's will have a reference to this struct
32 inner
: Arc
<InnerReadDir
>,
36 struct Dir(*mut libc
::DIR
);
38 unsafe impl Send
for Dir {}
39 unsafe impl Sync
for Dir {}
46 #[derive(Clone, Debug)]
47 pub struct OpenOptions
{
60 #[derive(Clone, PartialEq, Eq, Debug)]
61 pub struct FilePermissions
{
65 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
71 pub struct DirBuilder
{
76 pub fn size(&self) -> u64 {
77 self.stat
.st_size
as u64
79 pub fn perm(&self) -> FilePermissions
{
80 FilePermissions { mode: (self.stat.st_mode as mode_t) }
83 pub fn file_type(&self) -> FileType
{
84 FileType { mode: self.stat.st_mode as mode_t }
87 pub fn modified(&self) -> io
::Result
<SystemTime
> {
88 Ok(SystemTime
::from(libc
::timespec
{
89 tv_sec
: self.stat
.st_mtime
as libc
::time_t
,
90 tv_nsec
: 0, // hack 2.0;
94 pub fn accessed(&self) -> io
::Result
<SystemTime
> {
95 Ok(SystemTime
::from(libc
::timespec
{
96 tv_sec
: self.stat
.st_atime
as libc
::time_t
,
97 tv_nsec
: 0, // hack - a proper fix would be better
101 pub fn created(&self) -> io
::Result
<SystemTime
> {
103 io
::ErrorKind
::Other
,
104 "creation time is not available on this platform currently",
109 impl AsInner
<stat64
> for FileAttr
{
110 fn as_inner(&self) -> &stat64
{
115 impl FilePermissions
{
116 pub fn readonly(&self) -> bool
{
117 // check if any class (owner, group, others) has write permission
118 self.mode
& 0o222 == 0
121 pub fn set_readonly(&mut self, readonly
: bool
) {
123 // remove write permission for all classes; equivalent to `chmod a-w <file>`
126 // add write permission for all classes; equivalent to `chmod a+w <file>`
130 pub fn mode(&self) -> u32 {
136 pub fn is_dir(&self) -> bool
{
137 self.is(libc
::S_IFDIR
)
139 pub fn is_file(&self) -> bool
{
140 self.is(libc
::S_IFREG
)
142 pub fn is_symlink(&self) -> bool
{
143 self.is(libc
::S_IFLNK
)
146 pub fn is(&self, mode
: mode_t
) -> bool
{
147 self.mode
& libc
::S_IFMT
== mode
151 impl FromInner
<u32> for FilePermissions
{
152 fn from_inner(mode
: u32) -> FilePermissions
{
153 FilePermissions { mode: mode as mode_t }
157 impl fmt
::Debug
for ReadDir
{
158 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
159 // This will only be called from std::fs::ReadDir, which will add a "ReadDir()" frame.
160 // Thus the result will be e g 'ReadDir("/home")'
161 fmt
::Debug
::fmt(&*self.inner
.root
, f
)
165 impl Iterator
for ReadDir
{
166 type Item
= io
::Result
<DirEntry
>;
167 fn next(&mut self) -> Option
<io
::Result
<DirEntry
>> {
168 if self.end_of_stream
{
173 let mut ret
= DirEntry { entry: mem::zeroed(), dir: self.clone() }
;
174 let mut entry_ptr
= ptr
::null_mut();
176 if readdir64_r(self.inner
.dirp
.0, &mut ret
.entry
, &mut entry_ptr
) != 0 {
177 if entry_ptr
.is_null() {
178 // We encountered an error (which will be returned in this iteration), but
179 // we also reached the end of the directory stream. The `end_of_stream`
180 // flag is enabled to make sure that we return `None` in the next iteration
181 // (instead of looping forever)
182 self.end_of_stream
= true;
184 return Some(Err(Error
::last_os_error()));
186 if entry_ptr
.is_null() {
189 if ret
.name_bytes() != b
"." && ret
.name_bytes() != b
".." {
190 return Some(Ok(ret
));
199 let r
= unsafe { libc::closedir(self.0) }
;
200 debug_assert_eq
!(r
, 0);
205 pub fn path(&self) -> PathBuf
{
206 use crate::sys
::vxworks
::ext
::ffi
::OsStrExt
;
207 self.dir
.inner
.root
.join(OsStr
::from_bytes(self.name_bytes()))
210 pub fn file_name(&self) -> OsString
{
211 OsStr
::from_bytes(self.name_bytes()).to_os_string()
214 pub fn metadata(&self) -> io
::Result
<FileAttr
> {
218 pub fn file_type(&self) -> io
::Result
<FileType
> {
219 lstat(&self.path()).map(|m
| m
.file_type())
222 pub fn ino(&self) -> u64 {
223 self.entry
.d_ino
as u64
226 fn name_bytes(&self) -> &[u8] {
229 CStr
::from_ptr(self.entry
.d_name
.as_ptr()).to_bytes()
235 pub fn new() -> OpenOptions
{
250 pub fn read(&mut self, read
: bool
) {
253 pub fn write(&mut self, write
: bool
) {
256 pub fn append(&mut self, append
: bool
) {
257 self.append
= append
;
259 pub fn truncate(&mut self, truncate
: bool
) {
260 self.truncate
= truncate
;
262 pub fn create(&mut self, create
: bool
) {
263 self.create
= create
;
265 pub fn create_new(&mut self, create_new
: bool
) {
266 self.create_new
= create_new
;
268 pub fn mode(&mut self, mode
: u32) {
269 self.mode
= mode
as mode_t
;
272 fn get_access_mode(&self) -> io
::Result
<c_int
> {
273 match (self.read
, self.write
, self.append
) {
274 (true, false, false) => Ok(libc
::O_RDONLY
),
275 (false, true, false) => Ok(libc
::O_WRONLY
),
276 (true, true, false) => Ok(libc
::O_RDWR
),
277 (false, _
, true) => Ok(libc
::O_WRONLY
| libc
::O_APPEND
),
278 (true, _
, true) => Ok(libc
::O_RDWR
| libc
::O_APPEND
),
279 (false, false, false) => Err(Error
::from_raw_os_error(libc
::EINVAL
)),
283 fn get_creation_mode(&self) -> io
::Result
<c_int
> {
284 match (self.write
, self.append
) {
287 if self.truncate
|| self.create
|| self.create_new
{
288 return Err(Error
::from_raw_os_error(libc
::EINVAL
));
292 if self.truncate
&& !self.create_new
{
293 return Err(Error
::from_raw_os_error(libc
::EINVAL
));
298 Ok(match (self.create
, self.truncate
, self.create_new
) {
299 (false, false, false) => 0,
300 (true, false, false) => libc
::O_CREAT
,
301 (false, true, false) => libc
::O_TRUNC
,
302 (true, true, false) => libc
::O_CREAT
| libc
::O_TRUNC
,
303 (_
, _
, true) => libc
::O_CREAT
| libc
::O_EXCL
,
309 pub fn open(path
: &Path
, opts
: &OpenOptions
) -> io
::Result
<File
> {
310 let path
= cstr(path
)?
;
311 File
::open_c(&path
, opts
)
314 pub fn open_c(path
: &CStr
, opts
: &OpenOptions
) -> io
::Result
<File
> {
315 let flags
= libc
::O_CLOEXEC
316 | opts
.get_access_mode()?
317 | opts
.get_creation_mode()?
318 | (opts
.custom_flags
as c_int
& !libc
::O_ACCMODE
);
319 let fd
= cvt_r(|| unsafe { open(path.as_ptr(), flags, opts.mode as c_int) }
)?
;
320 Ok(File(FileDesc
::new(fd
)))
323 pub fn file_attr(&self) -> io
::Result
<FileAttr
> {
324 let mut stat
: stat64
= unsafe { mem::zeroed() }
;
325 cvt(unsafe { ::libc::fstat(self.0.raw(), &mut stat) }
)?
;
326 Ok(FileAttr { stat: stat }
)
329 pub fn fsync(&self) -> io
::Result
<()> {
330 cvt_r(|| unsafe { libc::fsync(self.0.raw()) }
)?
;
334 pub fn datasync(&self) -> io
::Result
<()> {
335 cvt_r(|| unsafe { os_datasync(self.0.raw()) }
)?
;
337 unsafe fn os_datasync(fd
: c_int
) -> c_int
{
342 pub fn truncate(&self, size
: u64) -> io
::Result
<()> {
343 return cvt_r(|| unsafe { ftruncate(self.0.raw(), size as off_t) }
).map(drop
);
346 pub fn read(&self, buf
: &mut [u8]) -> io
::Result
<usize> {
350 pub fn read_vectored(&self, bufs
: &mut [IoSliceMut
<'_
>]) -> io
::Result
<usize> {
351 self.0.read_vectored(bufs
)
355 pub fn is_read_vectored(&self) -> bool
{
356 self.0.is_read_vectored
()
359 pub fn read_at(&self, buf
: &mut [u8], offset
: u64) -> io
::Result
<usize> {
360 self.0.read_at(buf
, offset
)
363 pub fn write(&self, buf
: &[u8]) -> io
::Result
<usize> {
367 pub fn write_vectored(&self, bufs
: &[IoSlice
<'_
>]) -> io
::Result
<usize> {
368 self.0.write_vectored(bufs
)
372 pub fn is_write_vectored(&self) -> bool
{
373 self.0.is_write_vectored
()
376 pub fn write_at(&self, buf
: &[u8], offset
: u64) -> io
::Result
<usize> {
377 self.0.write_at(buf
, offset
)
380 pub fn flush(&self) -> io
::Result
<()> {
384 pub fn seek(&self, pos
: SeekFrom
) -> io
::Result
<u64> {
385 let (whence
, pos
) = match pos
{
386 // Casting to `i64` is fine, too large values will end up as
387 // negative which will cause an error in `"lseek64"`.
388 SeekFrom
::Start(off
) => (libc
::SEEK_SET
, off
as i64),
389 SeekFrom
::End(off
) => (libc
::SEEK_END
, off
),
390 SeekFrom
::Current(off
) => (libc
::SEEK_CUR
, off
),
392 let n
= cvt(unsafe { lseek(self.0.raw(), pos, whence) }
)?
;
396 pub fn duplicate(&self) -> io
::Result
<File
> {
397 self.0.duplicate().map(File
)
400 pub fn fd(&self) -> &FileDesc
{
404 pub fn into_fd(self) -> FileDesc
{
408 pub fn set_permissions(&self, perm
: FilePermissions
) -> io
::Result
<()> {
409 cvt_r(|| unsafe { libc::fchmod(self.0.raw(), perm.mode) }
)?
;
413 pub fn diverge(&self) -> ! {
419 pub fn new() -> DirBuilder
{
420 DirBuilder { mode: 0o777 }
423 pub fn mkdir(&self, p
: &Path
) -> io
::Result
<()> {
425 cvt(unsafe { libc::mkdir(p.as_ptr(), self.mode) }
)?
;
429 pub fn set_mode(&mut self, mode
: u32) {
430 self.mode
= mode
as mode_t
;
434 fn cstr(path
: &Path
) -> io
::Result
<CString
> {
435 use crate::sys
::vxworks
::ext
::ffi
::OsStrExt
;
436 Ok(CString
::new(path
.as_os_str().as_bytes())?
)
439 impl FromInner
<c_int
> for File
{
440 fn from_inner(fd
: c_int
) -> File
{
441 File(FileDesc
::new(fd
))
445 impl fmt
::Debug
for File
{
446 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
447 fn get_path(fd
: c_int
) -> Option
<PathBuf
> {
448 let mut buf
= vec
![0; libc
::PATH_MAX
as usize];
449 let n
= unsafe { libc::ioctl(fd, libc::FIOGETNAME, buf.as_ptr()) }
;
453 let l
= buf
.iter().position(|&c
| c
== 0).unwrap();
454 buf
.truncate(l
as usize);
455 Some(PathBuf
::from(OsString
::from_vec(buf
)))
457 fn get_mode(fd
: c_int
) -> Option
<(bool
, bool
)> {
458 let mode
= unsafe { libc::fcntl(fd, libc::F_GETFL) }
;
462 match mode
& libc
::O_ACCMODE
{
463 libc
::O_RDONLY
=> Some((true, false)),
464 libc
::O_RDWR
=> Some((true, true)),
465 libc
::O_WRONLY
=> Some((false, true)),
470 let fd
= self.0.raw();
471 let mut b
= f
.debug_struct("File");
473 if let Some(path
) = get_path(fd
) {
474 b
.field("path", &path
);
476 if let Some((read
, write
)) = get_mode(fd
) {
477 b
.field("read", &read
).field("write", &write
);
483 pub fn readdir(p
: &Path
) -> io
::Result
<ReadDir
> {
484 let root
= p
.to_path_buf();
487 let ptr
= libc
::opendir(p
.as_ptr());
489 Err(Error
::last_os_error())
491 let inner
= InnerReadDir { dirp: Dir(ptr), root }
;
492 Ok(ReadDir { inner: Arc::new(inner), end_of_stream: false }
)
497 pub fn unlink(p
: &Path
) -> io
::Result
<()> {
499 cvt(unsafe { libc::unlink(p.as_ptr()) }
)?
;
503 pub fn rename(old
: &Path
, new
: &Path
) -> io
::Result
<()> {
504 let old
= cstr(old
)?
;
505 let new
= cstr(new
)?
;
506 cvt(unsafe { libc::rename(old.as_ptr(), new.as_ptr()) }
)?
;
510 pub fn set_perm(p
: &Path
, perm
: FilePermissions
) -> io
::Result
<()> {
512 cvt_r(|| unsafe { libc::chmod(p.as_ptr(), perm.mode) }
)?
;
516 pub fn rmdir(p
: &Path
) -> io
::Result
<()> {
518 cvt(unsafe { libc::rmdir(p.as_ptr()) }
)?
;
522 pub fn remove_dir_all(path
: &Path
) -> io
::Result
<()> {
523 let filetype
= lstat(path
)?
.file_type();
524 if filetype
.is_symlink() { unlink(path) }
else { remove_dir_all_recursive(path) }
527 fn remove_dir_all_recursive(path
: &Path
) -> io
::Result
<()> {
528 for child
in readdir(path
)?
{
530 if child
.file_type()?
.is_dir() {
531 remove_dir_all_recursive(&child
.path())?
;
533 unlink(&child
.path())?
;
539 pub fn readlink(p
: &Path
) -> io
::Result
<PathBuf
> {
540 let c_path
= cstr(p
)?
;
541 let p
= c_path
.as_ptr();
543 let mut buf
= Vec
::with_capacity(256);
547 cvt(unsafe { libc::readlink(p, buf.as_mut_ptr() as *mut _, buf.capacity()) }
)?
as usize;
550 buf
.set_len(buf_read
);
553 if buf_read
!= buf
.capacity() {
556 return Ok(PathBuf
::from(OsString
::from_vec(buf
)));
559 // Trigger the internal buffer resizing logic of `Vec` by requiring
560 // more space than the current capacity. The length is guaranteed to be
561 // the same as the capacity due to the if statement above.
566 pub fn symlink(src
: &Path
, dst
: &Path
) -> io
::Result
<()> {
567 let src
= cstr(src
)?
;
568 let dst
= cstr(dst
)?
;
569 cvt(unsafe { libc::symlink(src.as_ptr(), dst.as_ptr()) }
)?
;
573 pub fn link(src
: &Path
, dst
: &Path
) -> io
::Result
<()> {
574 let src
= cstr(src
)?
;
575 let dst
= cstr(dst
)?
;
576 cvt(unsafe { libc::link(src.as_ptr(), dst.as_ptr()) }
)?
;
580 pub fn stat(p
: &Path
) -> io
::Result
<FileAttr
> {
582 let mut stat
: stat64
= unsafe { mem::zeroed() }
;
583 cvt(unsafe { libc::stat(p.as_ptr(), &mut stat as *mut _ as *mut _) }
)?
;
584 Ok(FileAttr { stat }
)
587 pub fn lstat(p
: &Path
) -> io
::Result
<FileAttr
> {
589 let mut stat
: stat64
= unsafe { mem::zeroed() }
;
590 cvt(unsafe { ::libc::lstat(p.as_ptr(), &mut stat as *mut _ as *mut _) }
)?
;
591 Ok(FileAttr { stat }
)
594 pub fn canonicalize(p
: &Path
) -> io
::Result
<PathBuf
> {
595 use crate::sys
::vxworks
::ext
::ffi
::OsStrExt
;
596 let path
= CString
::new(p
.as_os_str().as_bytes())?
;
599 let r
= libc
::realpath(path
.as_ptr(), ptr
::null_mut());
601 return Err(io
::Error
::last_os_error());
603 buf
= CStr
::from_ptr(r
).to_bytes().to_vec();
604 libc
::free(r
as *mut _
);
606 Ok(PathBuf
::from(OsString
::from_vec(buf
)))
609 pub fn copy(from
: &Path
, to
: &Path
) -> io
::Result
<u64> {
612 return Err(Error
::new(
613 ErrorKind
::InvalidInput
,
614 "the source path is not an existing regular file",
618 let mut reader
= File
::open(from
)?
;
619 let mut writer
= File
::create(to
)?
;
620 let perm
= reader
.metadata()?
.permissions();
622 let ret
= io
::copy(&mut reader
, &mut writer
)?
;
623 writer
.set_permissions(perm
)?
;