1 // Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 use os
::unix
::prelude
::*;
13 use ffi
::{OsString, OsStr}
;
15 use io
::{self, Error, ErrorKind, SeekFrom}
;
16 use path
::{Path, PathBuf}
;
18 use sys
::fd
::FileDesc
;
19 use sys
::time
::SystemTime
;
20 use sys
::{cvt, syscall}
;
21 use sys_common
::{AsInner, FromInner}
;
23 pub struct File(FileDesc
);
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 { mode: u16 }
63 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
64 pub struct FileType { mode: u16 }
67 pub struct DirBuilder { mode: u16 }
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 u16) & 0o777 }
75 pub fn file_type(&self) -> FileType
{
76 FileType { mode: self.stat.st_mode as u16 }
81 pub fn modified(&self) -> io
::Result
<SystemTime
> {
82 Ok(SystemTime
::from(syscall
::TimeSpec
{
83 tv_sec
: self.stat
.st_mtime
as i64,
84 tv_nsec
: self.stat
.st_mtime_nsec
as i32,
88 pub fn accessed(&self) -> io
::Result
<SystemTime
> {
89 Ok(SystemTime
::from(syscall
::TimeSpec
{
90 tv_sec
: self.stat
.st_atime
as i64,
91 tv_nsec
: self.stat
.st_atime_nsec
as i32,
95 pub fn created(&self) -> io
::Result
<SystemTime
> {
96 Ok(SystemTime
::from(syscall
::TimeSpec
{
97 tv_sec
: self.stat
.st_ctime
as i64,
98 tv_nsec
: self.stat
.st_ctime_nsec
as i32,
103 impl AsInner
<syscall
::Stat
> for FileAttr
{
104 fn as_inner(&self) -> &syscall
::Stat { &self.stat }
107 impl FilePermissions
{
108 pub fn readonly(&self) -> bool { self.mode & 0o222 == 0 }
109 pub fn set_readonly(&mut self, readonly
: bool
) {
116 pub fn mode(&self) -> u32 { self.mode as u32 }
120 pub fn is_dir(&self) -> bool { self.is(syscall::MODE_DIR) }
121 pub fn is_file(&self) -> bool { self.is(syscall::MODE_FILE) }
122 pub fn is_symlink(&self) -> bool { self.is(syscall::MODE_SYMLINK) }
124 pub fn is(&self, mode
: u16) -> bool
{
125 self.mode
& syscall
::MODE_TYPE
== mode
129 impl FromInner
<u32> for FilePermissions
{
130 fn from_inner(mode
: u32) -> FilePermissions
{
131 FilePermissions { mode: mode as u16 }
135 impl fmt
::Debug
for ReadDir
{
136 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
137 // This will only be called from std::fs::ReadDir, which will add a "ReadDir()" frame.
138 // Thus the result will be e g 'ReadDir("/home")'
139 fmt
::Debug
::fmt(&*self.root
, f
)
143 impl Iterator
for ReadDir
{
144 type Item
= io
::Result
<DirEntry
>;
146 fn next(&mut self) -> Option
<io
::Result
<DirEntry
>> {
150 while i
< self.data
.len() {
152 if self.data
[i
] == b'
\n'
{
159 name
: self.data
[start
.. i
].to_owned().into_boxed_slice(),
160 root
: self.root
.clone()
162 if ret
.name_bytes() != b
"." && ret
.name_bytes() != b
".." {
173 pub fn path(&self) -> PathBuf
{
174 self.root
.join(OsStr
::from_bytes(self.name_bytes()))
177 pub fn file_name(&self) -> OsString
{
178 OsStr
::from_bytes(self.name_bytes()).to_os_string()
181 pub fn metadata(&self) -> io
::Result
<FileAttr
> {
185 pub fn file_type(&self) -> io
::Result
<FileType
> {
186 lstat(&self.path()).map(|m
| m
.file_type())
189 fn name_bytes(&self) -> &[u8] {
195 pub fn new() -> OpenOptions
{
210 pub fn read(&mut self, read
: bool
) { self.read = read; }
211 pub fn write(&mut self, write
: bool
) { self.write = write; }
212 pub fn append(&mut self, append
: bool
) { self.append = append; }
213 pub fn truncate(&mut self, truncate
: bool
) { self.truncate = truncate; }
214 pub fn create(&mut self, create
: bool
) { self.create = create; }
215 pub fn create_new(&mut self, create_new
: bool
) { self.create_new = create_new; }
217 pub fn custom_flags(&mut self, flags
: i32) { self.custom_flags = flags; }
218 pub fn mode(&mut self, mode
: u32) { self.mode = mode as u16; }
220 fn get_access_mode(&self) -> io
::Result
<usize> {
221 match (self.read
, self.write
, self.append
) {
222 (true, false, false) => Ok(syscall
::O_RDONLY
),
223 (false, true, false) => Ok(syscall
::O_WRONLY
),
224 (true, true, false) => Ok(syscall
::O_RDWR
),
225 (false, _
, true) => Ok(syscall
::O_WRONLY
| syscall
::O_APPEND
),
226 (true, _
, true) => Ok(syscall
::O_RDWR
| syscall
::O_APPEND
),
227 (false, false, false) => Err(Error
::from_raw_os_error(syscall
::EINVAL
)),
231 fn get_creation_mode(&self) -> io
::Result
<usize> {
232 match (self.write
, self.append
) {
235 if self.truncate
|| self.create
|| self.create_new
{
236 return Err(Error
::from_raw_os_error(syscall
::EINVAL
));
239 if self.truncate
&& !self.create_new
{
240 return Err(Error
::from_raw_os_error(syscall
::EINVAL
));
244 Ok(match (self.create
, self.truncate
, self.create_new
) {
245 (false, false, false) => 0,
246 (true, false, false) => syscall
::O_CREAT
,
247 (false, true, false) => syscall
::O_TRUNC
,
248 (true, true, false) => syscall
::O_CREAT
| syscall
::O_TRUNC
,
249 (_
, _
, true) => syscall
::O_CREAT
| syscall
::O_EXCL
,
255 pub fn open(path
: &Path
, opts
: &OpenOptions
) -> io
::Result
<File
> {
256 let flags
= syscall
::O_CLOEXEC
|
257 opts
.get_access_mode()?
as usize |
258 opts
.get_creation_mode()?
as usize |
259 (opts
.custom_flags
as usize & !syscall
::O_ACCMODE
);
260 let fd
= cvt(syscall
::open(path
.to_str().unwrap(), flags
| opts
.mode
as usize))?
;
261 Ok(File(FileDesc
::new(fd
)))
264 pub fn file_attr(&self) -> io
::Result
<FileAttr
> {
265 let mut stat
= syscall
::Stat
::default();
266 cvt(syscall
::fstat(self.0.raw(), &mut stat
))?
;
267 Ok(FileAttr { stat: stat }
)
270 pub fn fsync(&self) -> io
::Result
<()> {
271 cvt(syscall
::fsync(self.0.raw()))?
;
275 pub fn datasync(&self) -> io
::Result
<()> {
279 pub fn truncate(&self, size
: u64) -> io
::Result
<()> {
280 cvt(syscall
::ftruncate(self.0.raw(), size
as usize))?
;
284 pub fn read(&self, buf
: &mut [u8]) -> io
::Result
<usize> {
288 pub fn write(&self, buf
: &[u8]) -> io
::Result
<usize> {
292 pub fn flush(&self) -> io
::Result
<()> { Ok(()) }
294 pub fn seek(&self, pos
: SeekFrom
) -> io
::Result
<u64> {
295 let (whence
, pos
) = match pos
{
296 // Casting to `i64` is fine, too large values will end up as
297 // negative which will cause an error in `lseek64`.
298 SeekFrom
::Start(off
) => (syscall
::SEEK_SET
, off
as i64),
299 SeekFrom
::End(off
) => (syscall
::SEEK_END
, off
),
300 SeekFrom
::Current(off
) => (syscall
::SEEK_CUR
, off
),
302 let n
= cvt(syscall
::lseek(self.0.raw(), pos
as isize, whence
))?
;
306 pub fn duplicate(&self) -> io
::Result
<File
> {
307 self.0.duplicate().map(File
)
310 pub fn dup(&self, buf
: &[u8]) -> io
::Result
<File
> {
311 let fd
= cvt(syscall
::dup(*self.fd().as_inner() as usize, buf
))?
;
312 Ok(File(FileDesc
::new(fd
)))
315 pub fn set_permissions(&self, perm
: FilePermissions
) -> io
::Result
<()> {
316 set_perm(&self.path()?
, perm
)
319 pub fn path(&self) -> io
::Result
<PathBuf
> {
320 let mut buf
: [u8; 4096] = [0; 4096];
321 let count
= cvt(syscall
::fpath(*self.fd().as_inner() as usize, &mut buf
))?
;
322 Ok(PathBuf
::from(unsafe { String::from_utf8_unchecked(Vec::from(&buf[..count])) }
))
325 pub fn fd(&self) -> &FileDesc { &self.0 }
327 pub fn into_fd(self) -> FileDesc { self.0 }
331 pub fn new() -> DirBuilder
{
332 DirBuilder { mode: 0o777 }
335 pub fn mkdir(&self, p
: &Path
) -> io
::Result
<()> {
336 let flags
= syscall
::O_CREAT
| syscall
::O_CLOEXEC
| syscall
::O_DIRECTORY
| syscall
::O_EXCL
;
337 let fd
= cvt(syscall
::open(p
.to_str().unwrap(), flags
| (self.mode
as usize & 0o777)))?
;
338 let _
= syscall
::close(fd
);
342 pub fn set_mode(&mut self, mode
: u32) {
343 self.mode
= mode
as u16;
347 impl FromInner
<usize> for File
{
348 fn from_inner(fd
: usize) -> File
{
349 File(FileDesc
::new(fd
))
353 impl fmt
::Debug
for File
{
354 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
355 let mut b
= f
.debug_struct("File");
356 b
.field("fd", &self.0.raw());
357 if let Ok(path
) = self.path() {
358 b
.field("path", &path
);
361 if let Some((read, write)) = get_mode(fd) {
362 b.field("read", &read).field("write", &write);
369 pub fn readdir(p
: &Path
) -> io
::Result
<ReadDir
> {
370 let root
= Arc
::new(p
.to_path_buf());
372 let flags
= syscall
::O_CLOEXEC
| syscall
::O_RDONLY
| syscall
::O_DIRECTORY
;
373 let fd
= cvt(syscall
::open(p
.to_str().unwrap(), flags
))?
;
374 let file
= FileDesc
::new(fd
);
375 let mut data
= Vec
::new();
376 file
.read_to_end(&mut data
)?
;
378 Ok(ReadDir { data: data, i: 0, root: root }
)
381 pub fn unlink(p
: &Path
) -> io
::Result
<()> {
382 cvt(syscall
::unlink(p
.to_str().unwrap()))?
;
386 pub fn rename(old
: &Path
, new
: &Path
) -> io
::Result
<()> {
387 let fd
= cvt(syscall
::open(old
.to_str().unwrap(),
388 syscall
::O_CLOEXEC
| syscall
::O_STAT
| syscall
::O_NOFOLLOW
))?
;
389 let res
= cvt(syscall
::frename(fd
, new
.to_str().unwrap()));
390 cvt(syscall
::close(fd
))?
;
395 pub fn set_perm(p
: &Path
, perm
: FilePermissions
) -> io
::Result
<()> {
396 cvt(syscall
::chmod(p
.to_str().unwrap(), perm
.mode
as usize))?
;
400 pub fn rmdir(p
: &Path
) -> io
::Result
<()> {
401 cvt(syscall
::rmdir(p
.to_str().unwrap()))?
;
405 pub fn remove_dir_all(path
: &Path
) -> io
::Result
<()> {
406 let filetype
= lstat(path
)?
.file_type();
407 if filetype
.is_symlink() {
410 remove_dir_all_recursive(path
)
414 fn remove_dir_all_recursive(path
: &Path
) -> io
::Result
<()> {
415 for child
in readdir(path
)?
{
417 if child
.file_type()?
.is_dir() {
418 remove_dir_all_recursive(&child
.path())?
;
420 unlink(&child
.path())?
;
426 pub fn readlink(p
: &Path
) -> io
::Result
<PathBuf
> {
427 let fd
= cvt(syscall
::open(p
.to_str().unwrap(),
428 syscall
::O_CLOEXEC
| syscall
::O_SYMLINK
| syscall
::O_RDONLY
))?
;
429 let mut buf
: [u8; 4096] = [0; 4096];
430 let res
= cvt(syscall
::read(fd
, &mut buf
));
431 cvt(syscall
::close(fd
))?
;
433 Ok(PathBuf
::from(unsafe { String::from_utf8_unchecked(Vec::from(&buf[..count])) }
))
436 pub fn symlink(src
: &Path
, dst
: &Path
) -> io
::Result
<()> {
437 let fd
= cvt(syscall
::open(dst
.to_str().unwrap(),
438 syscall
::O_CLOEXEC
| syscall
::O_SYMLINK
|
439 syscall
::O_CREAT
| syscall
::O_WRONLY
| 0o777))?
;
440 let res
= cvt(syscall
::write(fd
, src
.to_str().unwrap().as_bytes()));
441 cvt(syscall
::close(fd
))?
;
446 pub fn link(_src
: &Path
, _dst
: &Path
) -> io
::Result
<()> {
447 Err(Error
::from_raw_os_error(syscall
::ENOSYS
))
450 pub fn stat(p
: &Path
) -> io
::Result
<FileAttr
> {
451 let fd
= cvt(syscall
::open(p
.to_str().unwrap(), syscall
::O_CLOEXEC
| syscall
::O_STAT
))?
;
452 let file
= File(FileDesc
::new(fd
));
456 pub fn lstat(p
: &Path
) -> io
::Result
<FileAttr
> {
457 let fd
= cvt(syscall
::open(p
.to_str().unwrap(),
458 syscall
::O_CLOEXEC
| syscall
::O_STAT
| syscall
::O_NOFOLLOW
))?
;
459 let file
= File(FileDesc
::new(fd
));
463 pub fn canonicalize(p
: &Path
) -> io
::Result
<PathBuf
> {
464 let fd
= cvt(syscall
::open(p
.to_str().unwrap(), syscall
::O_CLOEXEC
| syscall
::O_STAT
))?
;
465 let file
= File(FileDesc
::new(fd
));
469 pub fn copy(from
: &Path
, to
: &Path
) -> io
::Result
<u64> {
470 use fs
::{File, set_permissions}
;
472 return Err(Error
::new(ErrorKind
::InvalidInput
,
473 "the source path is not an existing regular file"))
476 let mut reader
= File
::open(from
)?
;
477 let mut writer
= File
::create(to
)?
;
478 let perm
= reader
.metadata()?
.permissions();
480 let ret
= io
::copy(&mut reader
, &mut writer
)?
;
481 set_permissions(to
, perm
)?
;