1 // Copyright 2013-2014 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.
13 use os
::unix
::prelude
::*;
15 use ffi
::{CString, CStr, OsString, OsStr}
;
16 use io
::{self, Error, SeekFrom}
;
17 use libc
::{self, c_int, size_t, off_t, c_char, mode_t}
;
19 use path
::{Path, PathBuf}
;
22 use sys
::fd
::FileDesc
;
23 use sys
::{c, cvt, cvt_r}
;
24 use sys_common
::FromInner
;
27 pub struct File(FileDesc
);
38 struct Dir(*mut libc
::DIR
);
40 unsafe impl Send
for Dir {}
41 unsafe impl Sync
for Dir {}
44 buf
: Vec
<u8>, // actually *mut libc::dirent_t
49 pub struct OpenOptions
{
56 #[derive(Clone, PartialEq, Eq, Debug)]
57 pub struct FilePermissions { mode: mode_t }
60 pub fn is_dir(&self) -> bool
{
61 (self.stat
.st_mode
as mode_t
) & libc
::S_IFMT
== libc
::S_IFDIR
63 pub fn is_file(&self) -> bool
{
64 (self.stat
.st_mode
as mode_t
) & libc
::S_IFMT
== libc
::S_IFREG
66 pub fn size(&self) -> u64 { self.stat.st_size as u64 }
67 pub fn perm(&self) -> FilePermissions
{
68 FilePermissions { mode: (self.stat.st_mode as mode_t) & 0o777 }
71 pub fn accessed(&self) -> u64 {
72 self.mktime(self.stat
.st_atime
as u64, self.stat
.st_atime_nsec
as u64)
74 pub fn modified(&self) -> u64 {
75 self.mktime(self.stat
.st_mtime
as u64, self.stat
.st_mtime_nsec
as u64)
78 // times are in milliseconds (currently)
79 fn mktime(&self, secs
: u64, nsecs
: u64) -> u64 {
80 secs
* 1000 + nsecs
/ 1000000
84 impl FilePermissions
{
85 pub fn readonly(&self) -> bool { self.mode & 0o222 == 0 }
86 pub fn set_readonly(&mut self, readonly
: bool
) {
93 pub fn mode(&self) -> i32 { self.mode as i32 }
96 impl FromInner
<i32> for FilePermissions
{
97 fn from_inner(mode
: i32) -> FilePermissions
{
98 FilePermissions { mode: mode as mode_t }
102 impl Iterator
for ReadDir
{
103 type Item
= io
::Result
<DirEntry
>;
105 fn next(&mut self) -> Option
<io
::Result
<DirEntry
>> {
107 fn rust_dirent_t_size() -> c_int
;
110 let mut buf
: Vec
<u8> = Vec
::with_capacity(unsafe {
111 rust_dirent_t_size() as usize
113 let ptr
= buf
.as_mut_ptr() as *mut libc
::dirent_t
;
115 let mut entry_ptr
= ptr
::null_mut();
117 if unsafe { libc::readdir_r(self.dirp.0, ptr, &mut entry_ptr) != 0 }
{
118 return Some(Err(Error
::last_os_error()))
120 if entry_ptr
.is_null() {
124 let entry
= DirEntry
{
126 root
: self.root
.clone()
128 if entry
.name_bytes() == b
"." || entry
.name_bytes() == b
".." {
131 return Some(Ok(entry
))
139 let r
= unsafe { libc::closedir(self.0) }
;
140 debug_assert_eq
!(r
, 0);
145 pub fn path(&self) -> PathBuf
{
146 self.root
.join(<OsStr
as OsStrExt
>::from_bytes(self.name_bytes()))
149 fn name_bytes(&self) -> &[u8] {
151 fn rust_list_dir_val(ptr
: *mut libc
::dirent_t
) -> *const c_char
;
154 CStr
::from_ptr(rust_list_dir_val(self.dirent())).to_bytes()
158 fn dirent(&self) -> *mut libc
::dirent_t
{
159 self.buf
.as_ptr() as *mut _
164 pub fn new() -> OpenOptions
{
173 pub fn read(&mut self, read
: bool
) {
177 pub fn write(&mut self, write
: bool
) {
181 pub fn append(&mut self, append
: bool
) {
182 self.flag(libc
::O_APPEND
, append
);
185 pub fn truncate(&mut self, truncate
: bool
) {
186 self.flag(libc
::O_TRUNC
, truncate
);
189 pub fn create(&mut self, create
: bool
) {
190 self.flag(libc
::O_CREAT
, create
);
193 pub fn mode(&mut self, mode
: i32) {
194 self.mode
= mode
as mode_t
;
197 fn flag(&mut self, bit
: c_int
, on
: bool
) {
207 pub fn open(path
: &Path
, opts
: &OpenOptions
) -> io
::Result
<File
> {
208 let flags
= opts
.flags
| match (opts
.read
, opts
.write
) {
209 (true, true) => libc
::O_RDWR
,
210 (false, true) => libc
::O_WRONLY
,
212 (false, false) => libc
::O_RDONLY
,
214 let path
= try
!(cstr(path
));
215 let fd
= try
!(cvt_r(|| unsafe {
216 libc
::open(path
.as_ptr(), flags
, opts
.mode
)
218 Ok(File(FileDesc
::new(fd
)))
221 pub fn file_attr(&self) -> io
::Result
<FileAttr
> {
222 let mut stat
: libc
::stat
= unsafe { mem::zeroed() }
;
223 try
!(cvt(unsafe { libc::fstat(self.0.raw(), &mut stat) }
));
224 Ok(FileAttr { stat: stat }
)
227 pub fn fsync(&self) -> io
::Result
<()> {
228 try
!(cvt_r(|| unsafe { libc::fsync(self.0.raw()) }
));
232 pub fn datasync(&self) -> io
::Result
<()> {
233 try
!(cvt_r(|| unsafe { os_datasync(self.0.raw()) }
));
236 #[cfg(any(target_os = "macos", target_os = "ios"))]
237 unsafe fn os_datasync(fd
: c_int
) -> c_int
{
238 libc
::fcntl(fd
, libc
::F_FULLFSYNC
)
240 #[cfg(target_os = "linux")]
241 unsafe fn os_datasync(fd
: c_int
) -> c_int { libc::fdatasync(fd) }
242 #[cfg(not(any(target_os = "macos",
244 target_os
= "linux")))]
245 unsafe fn os_datasync(fd
: c_int
) -> c_int { libc::fsync(fd) }
248 pub fn truncate(&self, size
: u64) -> io
::Result
<()> {
249 try
!(cvt_r(|| unsafe {
250 libc
::ftruncate(self.0.raw(), size
as libc
::off_t
)
255 pub fn read(&self, buf
: &mut [u8]) -> io
::Result
<usize> {
259 pub fn write(&self, buf
: &[u8]) -> io
::Result
<usize> {
263 pub fn flush(&self) -> io
::Result
<()> { Ok(()) }
265 pub fn seek(&self, pos
: SeekFrom
) -> io
::Result
<u64> {
266 let (whence
, pos
) = match pos
{
267 SeekFrom
::Start(off
) => (libc
::SEEK_SET
, off
as off_t
),
268 SeekFrom
::End(off
) => (libc
::SEEK_END
, off
as off_t
),
269 SeekFrom
::Current(off
) => (libc
::SEEK_CUR
, off
as off_t
),
271 let n
= try
!(cvt(unsafe { libc::lseek(self.0.raw(), pos, whence) }
));
275 pub fn fd(&self) -> &FileDesc { &self.0 }
278 fn cstr(path
: &Path
) -> io
::Result
<CString
> {
279 path
.as_os_str().to_cstring().ok_or(
280 io
::Error
::new(io
::ErrorKind
::InvalidInput
, "path contained a null"))
283 impl FromInner
<c_int
> for File
{
284 fn from_inner(fd
: c_int
) -> File
{
285 File(FileDesc
::new(fd
))
289 pub fn mkdir(p
: &Path
) -> io
::Result
<()> {
290 let p
= try
!(cstr(p
));
291 try
!(cvt(unsafe { libc::mkdir(p.as_ptr(), 0o777) }
));
295 pub fn readdir(p
: &Path
) -> io
::Result
<ReadDir
> {
296 let root
= Arc
::new(p
.to_path_buf());
297 let p
= try
!(cstr(p
));
299 let ptr
= libc
::opendir(p
.as_ptr());
301 Err(Error
::last_os_error())
303 Ok(ReadDir { dirp: Dir(ptr), root: root }
)
308 pub fn unlink(p
: &Path
) -> io
::Result
<()> {
309 let p
= try
!(cstr(p
));
310 try
!(cvt(unsafe { libc::unlink(p.as_ptr()) }
));
314 pub fn rename(old
: &Path
, new
: &Path
) -> io
::Result
<()> {
315 let old
= try
!(cstr(old
));
316 let new
= try
!(cstr(new
));
317 try
!(cvt(unsafe { libc::rename(old.as_ptr(), new.as_ptr()) }
));
321 pub fn set_perm(p
: &Path
, perm
: FilePermissions
) -> io
::Result
<()> {
322 let p
= try
!(cstr(p
));
323 try
!(cvt_r(|| unsafe { libc::chmod(p.as_ptr(), perm.mode) }
));
327 pub fn rmdir(p
: &Path
) -> io
::Result
<()> {
328 let p
= try
!(cstr(p
));
329 try
!(cvt(unsafe { libc::rmdir(p.as_ptr()) }
));
333 pub fn readlink(p
: &Path
) -> io
::Result
<PathBuf
> {
334 let c_path
= try
!(cstr(p
));
335 let p
= c_path
.as_ptr();
336 let mut len
= unsafe { libc::pathconf(p as *mut _, libc::_PC_NAME_MAX) }
;
338 len
= 1024; // FIXME: read PATH_MAX from C ffi?
340 let mut buf
: Vec
<u8> = Vec
::with_capacity(len
as usize);
343 libc
::readlink(p
, buf
.as_ptr() as *mut c_char
, len
as size_t
)
345 buf
.set_len(n
as usize);
347 Ok(PathBuf
::from(OsString
::from_vec(buf
)))
350 pub fn symlink(src
: &Path
, dst
: &Path
) -> io
::Result
<()> {
351 let src
= try
!(cstr(src
));
352 let dst
= try
!(cstr(dst
));
353 try
!(cvt(unsafe { libc::symlink(src.as_ptr(), dst.as_ptr()) }
));
357 pub fn link(src
: &Path
, dst
: &Path
) -> io
::Result
<()> {
358 let src
= try
!(cstr(src
));
359 let dst
= try
!(cstr(dst
));
360 try
!(cvt(unsafe { libc::link(src.as_ptr(), dst.as_ptr()) }
));
364 pub fn stat(p
: &Path
) -> io
::Result
<FileAttr
> {
365 let p
= try
!(cstr(p
));
366 let mut stat
: libc
::stat
= unsafe { mem::zeroed() }
;
367 try
!(cvt(unsafe { libc::stat(p.as_ptr(), &mut stat) }
));
368 Ok(FileAttr { stat: stat }
)
371 pub fn lstat(p
: &Path
) -> io
::Result
<FileAttr
> {
372 let p
= try
!(cstr(p
));
373 let mut stat
: libc
::stat
= unsafe { mem::zeroed() }
;
374 try
!(cvt(unsafe { libc::lstat(p.as_ptr(), &mut stat) }
));
375 Ok(FileAttr { stat: stat }
)
378 pub fn utimes(p
: &Path
, atime
: u64, mtime
: u64) -> io
::Result
<()> {
379 let p
= try
!(cstr(p
));
380 let buf
= [super::ms_to_timeval(atime
), super::ms_to_timeval(mtime
)];
381 try
!(cvt(unsafe { c::utimes(p.as_ptr(), buf.as_ptr()) }
));