]> git.lizzy.rs Git - rust.git/blob - src/libstd/sys/vxworks/fs.rs
Auto merge of #63124 - Centril:rollup-onohtqt, r=Centril
[rust.git] / src / libstd / sys / vxworks / fs.rs
1 // copies from linuxx
2 use crate::ffi::{CString, CStr, OsString, OsStr};
3 use crate::sys::vxworks::ext::ffi::OsStrExt;
4 use crate::fmt;
5 use crate::io::{self, Error, ErrorKind, SeekFrom, IoSlice, IoSliceMut};
6 use crate::mem;
7 use crate::path::{Path, PathBuf};
8 use crate::ptr;
9 use crate::sync::Arc;
10 use crate::sys::fd::FileDesc;
11 use crate::sys::time::SystemTime;
12 use crate::sys::{cvt, cvt_r};
13 use crate::sys_common::{AsInner, FromInner};
14 use libc::{self, c_int, mode_t, stat64, off_t};
15 use libc::{ftruncate, lseek, dirent, readdir_r as readdir64_r, open};
16 use crate::sys::vxworks::ext::ffi::OsStringExt;
17 pub struct File(FileDesc);
18
19 #[derive(Clone)]
20 pub struct FileAttr {
21     stat: stat64,
22 }
23
24 // all DirEntry's will have a reference to this struct
25 struct InnerReadDir {
26     dirp: Dir,
27     root: PathBuf,
28 }
29
30 #[derive(Clone)]
31 pub struct ReadDir {
32     inner: Arc<InnerReadDir>,
33     end_of_stream: bool,
34 }
35
36 struct Dir(*mut libc::DIR);
37
38 unsafe impl Send for Dir {}
39 unsafe impl Sync for Dir {}
40
41 pub struct DirEntry {
42     entry: dirent,
43     dir: ReadDir,
44 }
45
46 #[derive(Clone, Debug)]
47 pub struct OpenOptions {
48     // generic
49     read: bool,
50     write: bool,
51     append: bool,
52     truncate: bool,
53     create: bool,
54     create_new: bool,
55     // system-specific
56     custom_flags: i32,
57     mode: mode_t,
58 }
59
60 #[derive(Clone, PartialEq, Eq, Debug)]
61 pub struct FilePermissions { mode: mode_t }
62
63 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
64 pub struct FileType { mode: mode_t }
65
66 #[derive(Debug)]
67 pub struct DirBuilder { mode: mode_t }
68
69 impl FileAttr {
70     pub fn size(&self) -> u64 { self.stat.st_size as u64 }
71     pub fn perm(&self) -> FilePermissions {
72         FilePermissions { mode: (self.stat.st_mode as mode_t) }
73     }
74
75     pub fn file_type(&self) -> FileType {
76         FileType { mode: self.stat.st_mode as mode_t }
77     }
78
79     pub fn modified(&self) -> io::Result<SystemTime> {
80         Ok(SystemTime::from(libc::timespec {
81             tv_sec: self.stat.st_mtime as libc::time_t,
82             tv_nsec: 0, // hack 2.0;
83         }))
84     }
85
86     pub fn accessed(&self) -> io::Result<SystemTime> {
87         Ok(SystemTime::from(libc::timespec {
88         tv_sec: self.stat.st_atime as libc::time_t,
89         tv_nsec: 0, // hack - a proper fix would be better
90         }))
91     }
92
93     pub fn created(&self) -> io::Result<SystemTime> {
94         Err(io::Error::new(io::ErrorKind::Other,
95                            "creation time is not available on this platform currently"))
96     }
97
98 }
99
100 impl AsInner<stat64> for FileAttr {
101     fn as_inner(&self) -> &stat64 { &self.stat }
102 }
103
104 impl FilePermissions {
105     pub fn readonly(&self) -> bool {
106         // check if any class (owner, group, others) has write permission
107         self.mode & 0o222 == 0
108     }
109
110     pub fn set_readonly(&mut self, readonly: bool) {
111         if readonly {
112             // remove write permission for all classes; equivalent to `chmod a-w <file>`
113             self.mode &= !0o222;
114         } else {
115             // add write permission for all classes; equivalent to `chmod a+w <file>`
116             self.mode |= 0o222;
117         }
118     }
119     pub fn mode(&self) -> u32 { self.mode as u32 }
120 }
121
122 impl FileType {
123     pub fn is_dir(&self) -> bool { self.is(libc::S_IFDIR) }
124     pub fn is_file(&self) -> bool { self.is(libc::S_IFREG) }
125     pub fn is_symlink(&self) -> bool { self.is(libc::S_IFLNK) }
126
127     pub fn is(&self, mode: mode_t) -> bool { self.mode & libc::S_IFMT == mode }
128 }
129
130 impl FromInner<u32> for FilePermissions {
131     fn from_inner(mode: u32) -> FilePermissions {
132         FilePermissions { mode: mode as mode_t }
133     }
134 }
135
136 impl fmt::Debug for ReadDir {
137     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
138         // This will only be called from std::fs::ReadDir, which will add a "ReadDir()" frame.
139         // Thus the result will be e g 'ReadDir("/home")'
140         fmt::Debug::fmt(&*self.inner.root, f)
141     }
142 }
143
144 impl Iterator for ReadDir {
145     type Item = io::Result<DirEntry>;
146     fn next(&mut self) -> Option<io::Result<DirEntry>> {
147         if self.end_of_stream {
148             return None;
149         }
150
151         unsafe {
152             let mut ret = DirEntry {
153                 entry: mem::zeroed(),
154                 dir: self.clone(),
155             };
156             let mut entry_ptr = ptr::null_mut();
157             loop {
158                 if readdir64_r(self.inner.dirp.0, &mut ret.entry, &mut entry_ptr) != 0 {
159                     if entry_ptr.is_null() {
160                         // We encountered an error (which will be returned in this iteration), but
161                         // we also reached the end of the directory stream. The `end_of_stream`
162                         // flag is enabled to make sure that we return `None` in the next iteration
163                         // (instead of looping forever)
164                         self.end_of_stream = true;
165                     }
166                     return Some(Err(Error::last_os_error()))
167                 }
168                 if entry_ptr.is_null() {
169                     return None
170                 }
171                 if ret.name_bytes() != b"." && ret.name_bytes() != b".." {
172                     return Some(Ok(ret))
173                 }
174             }
175         }
176     }
177 }
178
179 impl Drop for Dir {
180     fn drop(&mut self) {
181         let r = unsafe { libc::closedir(self.0) };
182         debug_assert_eq!(r, 0);
183     }
184 }
185
186 impl DirEntry {
187     pub fn path(&self) -> PathBuf {
188             use crate::sys::vxworks::ext::ffi::OsStrExt;
189             self.dir.inner.root.join(OsStr::from_bytes(self.name_bytes()))
190     }
191
192     pub fn file_name(&self) -> OsString {
193         OsStr::from_bytes(self.name_bytes()).to_os_string()
194     }
195
196
197     pub fn metadata(&self) -> io::Result<FileAttr> {
198         lstat(&self.path())
199     }
200
201     pub fn file_type(&self) -> io::Result<FileType> {
202         lstat(&self.path()).map(|m| m.file_type())
203
204     }
205
206     pub fn ino(&self) -> u64 {
207         self.entry.d_ino as u64
208     }
209
210     fn name_bytes(&self) -> &[u8] {
211         unsafe {
212             //&*self.name
213             CStr::from_ptr(self.entry.d_name.as_ptr()).to_bytes()
214         }
215     }
216 }
217
218 impl OpenOptions {
219     pub fn new() -> OpenOptions {
220         OpenOptions {
221             // generic
222             read: false,
223             write: false,
224             append: false,
225             truncate: false,
226             create: false,
227             create_new: false,
228             // system-specific
229             custom_flags: 0,
230             mode: 0o666,
231         }
232     }
233
234     pub fn read(&mut self, read: bool) { self.read = read; }
235     pub fn write(&mut self, write: bool) { self.write = write; }
236     pub fn append(&mut self, append: bool) { self.append = append; }
237     pub fn truncate(&mut self, truncate: bool) { self.truncate = truncate; }
238     pub fn create(&mut self, create: bool) { self.create = create; }
239     pub fn create_new(&mut self, create_new: bool) { self.create_new = create_new; }
240     pub fn mode(&mut self, mode: u32) { self.mode = mode as mode_t; }
241
242     fn get_access_mode(&self) -> io::Result<c_int> {
243         match (self.read, self.write, self.append) {
244             (true,  false, false) => Ok(libc::O_RDONLY),
245             (false, true,  false) => Ok(libc::O_WRONLY),
246             (true,  true,  false) => Ok(libc::O_RDWR),
247             (false, _,     true)  => Ok(libc::O_WRONLY | libc::O_APPEND),
248             (true,  _,     true)  => Ok(libc::O_RDWR | libc::O_APPEND),
249             (false, false, false) => Err(Error::from_raw_os_error(libc::EINVAL)),
250         }
251     }
252
253     fn get_creation_mode(&self) -> io::Result<c_int> {
254         match (self.write, self.append) {
255             (true, false) => {}
256             (false, false) =>
257                 if self.truncate || self.create || self.create_new {
258                     return Err(Error::from_raw_os_error(libc::EINVAL));
259                 },
260             (_, true) =>
261                 if self.truncate && !self.create_new {
262                     return Err(Error::from_raw_os_error(libc::EINVAL));
263                 },
264         }
265
266         Ok(match (self.create, self.truncate, self.create_new) {
267                 (false, false, false) => 0,
268                 (true,  false, false) => libc::O_CREAT,
269                 (false, true,  false) => libc::O_TRUNC,
270                 (true,  true,  false) => libc::O_CREAT | libc::O_TRUNC,
271                 (_,      _,    true)  => libc::O_CREAT | libc::O_EXCL,
272            })
273     }
274 }
275
276 impl File {
277     pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
278         let path = cstr(path)?;
279         File::open_c(&path, opts)
280     }
281
282     pub fn open_c(path: &CStr, opts: &OpenOptions) -> io::Result<File> {
283         let flags = libc::O_CLOEXEC |
284                 opts.get_access_mode()? |
285                 opts.get_creation_mode()? |
286                 (opts.custom_flags as c_int & !libc::O_ACCMODE);
287         let fd = cvt_r(|| unsafe {
288             open(path.as_ptr(), flags, opts.mode as c_int)
289         })?;
290         Ok(File(FileDesc::new(fd)))
291     }
292
293     pub fn file_attr(&self) -> io::Result<FileAttr> {
294         let mut stat: stat64 = unsafe { mem::zeroed() };
295         cvt(unsafe {
296             ::libc::fstat(self.0.raw(), &mut stat)
297         })?;
298         Ok(FileAttr { stat: stat })
299     }
300
301     pub fn fsync(&self) -> io::Result<()> {
302         cvt_r(|| unsafe { libc::fsync(self.0.raw()) })?;
303         Ok(())
304     }
305
306     pub fn datasync(&self) -> io::Result<()> {
307         cvt_r(|| unsafe { os_datasync(self.0.raw()) })?;
308         return Ok(());
309         unsafe fn os_datasync(fd: c_int) -> c_int { libc::fsync(fd) } //not supported
310     }
311
312     pub fn truncate(&self, size: u64) -> io::Result<()> {
313         return cvt_r(|| unsafe {
314             ftruncate(self.0.raw(), size as off_t)
315         }).map(|_| ());
316     }
317
318     pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
319         self.0.read(buf)
320     }
321
322     pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
323         self.0.read_vectored(bufs)
324     }
325
326     pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
327         self.0.read_at(buf, offset)
328     }
329
330     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
331         self.0.write(buf)
332     }
333
334     pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
335         self.0.write_vectored(bufs)
336     }
337
338     pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
339         self.0.write_at(buf, offset)
340     }
341
342     pub fn flush(&self) -> io::Result<()> { Ok(()) }
343
344     pub fn seek(&self, pos: SeekFrom) -> io::Result<u64> {
345         let (whence, pos) = match pos {
346             // Casting to `i64` is fine, too large values will end up as
347             // negative which will cause an error in `"lseek64"`.
348             SeekFrom::Start(off) => (libc::SEEK_SET, off as i64),
349             SeekFrom::End(off) => (libc::SEEK_END, off),
350             SeekFrom::Current(off) => (libc::SEEK_CUR, off),
351         };
352         let n = cvt(unsafe { lseek(self.0.raw(), pos, whence) })?;
353         Ok(n as u64)
354     }
355
356     pub fn duplicate(&self) -> io::Result<File> {
357         self.0.duplicate().map(File)
358     }
359
360     pub fn fd(&self) -> &FileDesc { &self.0 }
361
362     pub fn into_fd(self) -> FileDesc { self.0 }
363
364     pub fn set_permissions(&self, perm: FilePermissions) -> io::Result<()> {
365         cvt_r(|| unsafe { libc::fchmod(self.0.raw(), perm.mode) })?;
366         Ok(())
367     }
368
369     pub fn diverge(&self) -> ! {
370         panic!()
371     }
372 }
373
374 impl DirBuilder {
375     pub fn new() -> DirBuilder {
376         DirBuilder { mode: 0o777 }
377     }
378
379     pub fn mkdir(&self, p: &Path) -> io::Result<()> {
380         let p = cstr(p)?;
381         cvt(unsafe { libc::mkdir(p.as_ptr(), self.mode) })?;
382         Ok(())
383     }
384
385     pub fn set_mode(&mut self, mode: u32) {
386         self.mode = mode as mode_t;
387     }
388 }
389
390 fn cstr(path: &Path) -> io::Result<CString> {
391     use crate::sys::vxworks::ext::ffi::OsStrExt;
392     Ok(CString::new(path.as_os_str().as_bytes())?)
393 }
394
395 impl FromInner<c_int> for File {
396     fn from_inner(fd: c_int) -> File {
397         File(FileDesc::new(fd))
398     }
399 }
400
401 impl fmt::Debug for File {
402     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
403         fn get_path(_fd: c_int) -> Option<PathBuf> {
404             // FIXME(#:(): implement this for VxWorks
405             None
406         }
407         fn get_mode(_fd: c_int) -> Option<(bool, bool)> {
408             // FIXME(#:(): implement this for VxWorks
409             None
410         }
411
412         let fd = self.0.raw();
413         let mut b = f.debug_struct("File");
414         b.field("fd", &fd);
415         if let Some(path) = get_path(fd) {
416             b.field("path", &path);
417         }
418         if let Some((read, write)) = get_mode(fd) {
419             b.field("read", &read).field("write", &write);
420         }
421         b.finish()
422     }
423 }
424
425 pub fn readdir(p: &Path) -> io::Result<ReadDir> {
426     let root = p.to_path_buf();
427     let p = cstr(p)?;
428     unsafe {
429         let ptr = libc::opendir(p.as_ptr());
430         if ptr.is_null() {
431             Err(Error::last_os_error())
432         } else {
433             let inner = InnerReadDir { dirp: Dir(ptr), root };
434             Ok(ReadDir{
435                 inner: Arc::new(inner),
436                 end_of_stream: false,
437             })
438         }
439     }
440 }
441
442 pub fn unlink(p: &Path) -> io::Result<()> {
443     let p = cstr(p)?;
444     cvt(unsafe { libc::unlink(p.as_ptr()) })?;
445     Ok(())
446 }
447
448 pub fn rename(old: &Path, new: &Path) -> io::Result<()> {
449     let old = cstr(old)?;
450     let new = cstr(new)?;
451     cvt(unsafe { libc::rename(old.as_ptr(), new.as_ptr()) })?;
452     Ok(())
453 }
454
455 pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> {
456     let p = cstr(p)?;
457     cvt_r(|| unsafe { libc::chmod(p.as_ptr(), perm.mode) })?;
458     Ok(())
459 }
460
461 pub fn rmdir(p: &Path) -> io::Result<()> {
462     let p = cstr(p)?;
463     cvt(unsafe { libc::rmdir(p.as_ptr()) })?;
464     Ok(())
465 }
466
467 pub fn remove_dir_all(path: &Path) -> io::Result<()> {
468     let filetype = lstat(path)?.file_type();
469     if filetype.is_symlink() {
470         unlink(path)
471     } else {
472         remove_dir_all_recursive(path)
473     }
474 }
475
476 fn remove_dir_all_recursive(path: &Path) -> io::Result<()> {
477     for child in readdir(path)? {
478         let child = child?;
479         if child.file_type()?.is_dir() {
480             remove_dir_all_recursive(&child.path())?;
481         } else {
482             unlink(&child.path())?;
483         }
484     }
485     rmdir(path)
486 }
487
488 pub fn readlink(p: &Path) -> io::Result<PathBuf> {
489     let c_path = cstr(p)?;
490     let p = c_path.as_ptr();
491
492     let mut buf = Vec::with_capacity(256);
493
494     loop {
495         let buf_read = cvt(unsafe {
496             libc::readlink(p, buf.as_mut_ptr() as *mut _, buf.capacity())
497         })? as usize;
498
499         unsafe { buf.set_len(buf_read); }
500
501         if buf_read != buf.capacity() {
502             buf.shrink_to_fit();
503
504             return Ok(PathBuf::from(OsString::from_vec(buf)));
505         }
506
507         // Trigger the internal buffer resizing logic of `Vec` by requiring
508         // more space than the current capacity. The length is guaranteed to be
509         // the same as the capacity due to the if statement above.
510         buf.reserve(1);
511     }
512 }
513
514 pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> {
515     let src = cstr(src)?;
516     let dst = cstr(dst)?;
517     cvt(unsafe { libc::symlink(src.as_ptr(), dst.as_ptr()) })?;
518     Ok(())
519 }
520
521 pub fn link(src: &Path, dst: &Path) -> io::Result<()> {
522     let src = cstr(src)?;
523     let dst = cstr(dst)?;
524     cvt(unsafe { libc::link(src.as_ptr(), dst.as_ptr()) })?;
525     Ok(())
526 }
527
528 pub fn stat(p: &Path) -> io::Result<FileAttr> {
529     let p = cstr(p)?;
530     let mut stat: stat64 = unsafe { mem::zeroed() };
531     cvt(unsafe {
532         libc::lstat(p.as_ptr(), &mut stat as *mut _ as *mut _)
533     })?;
534     Ok(FileAttr { stat })
535 }
536
537 pub fn lstat(p: &Path) -> io::Result<FileAttr> {
538     let p = cstr(p)?;
539     let mut stat: stat64 = unsafe { mem::zeroed() };
540     cvt(unsafe {
541         ::libc::lstat(p.as_ptr(), &mut stat as *mut _ as *mut _)
542     })?;
543     Ok(FileAttr { stat })
544 }
545
546 pub fn canonicalize(p: &Path) -> io::Result<PathBuf> {
547     use crate::sys::vxworks::ext::ffi::OsStrExt;
548     let path = CString::new(p.as_os_str().as_bytes())?;
549     let buf;
550     unsafe {
551         let r = libc::realpath(path.as_ptr(), ptr::null_mut());
552         if r.is_null() {
553             return Err(io::Error::last_os_error())
554         }
555         buf = CStr::from_ptr(r).to_bytes().to_vec();
556         libc::free(r as *mut _);
557     }
558     Ok(PathBuf::from(OsString::from_vec(buf)))
559 }
560
561 pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
562     use crate::fs::File;
563     if !from.is_file() {
564         return Err(Error::new(ErrorKind::InvalidInput,
565                               "the source path is not an existing regular file"))
566     }
567
568     let mut reader = File::open(from)?;
569     let mut writer = File::create(to)?;
570     let perm = reader.metadata()?.permissions();
571
572     let ret = io::copy(&mut reader, &mut writer)?;
573     writer.set_permissions(perm)?;
574     Ok(ret)
575 }