|
@@ -1,4 +1,5 @@
|
|
use c_str::CStr;
|
|
use c_str::CStr;
|
|
|
|
+use core::ops::Deref;
|
|
use header::fcntl::O_CREAT;
|
|
use header::fcntl::O_CREAT;
|
|
use header::unistd::{SEEK_SET, SEEK_CUR, SEEK_END};
|
|
use header::unistd::{SEEK_SET, SEEK_CUR, SEEK_END};
|
|
use io;
|
|
use io;
|
|
@@ -11,48 +12,70 @@ fn last_os_error() -> io::Error {
|
|
io::Error::from_raw_os_error(errno)
|
|
io::Error::from_raw_os_error(errno)
|
|
}
|
|
}
|
|
|
|
|
|
-pub struct File(c_int);
|
|
|
|
|
|
+pub struct File {
|
|
|
|
+ pub fd: c_int,
|
|
|
|
+ /// To avoid self referential FILE struct that needs both a reader and a writer,
|
|
|
|
+ /// make "reference" files that share fd but don't close on drop.
|
|
|
|
+ pub reference: bool
|
|
|
|
+}
|
|
|
|
|
|
impl File {
|
|
impl File {
|
|
|
|
+ pub fn new(fd: c_int) -> Self {
|
|
|
|
+ Self {
|
|
|
|
+ fd,
|
|
|
|
+ reference: false
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
pub fn open(path: &CStr, oflag: c_int) -> io::Result<Self> {
|
|
pub fn open(path: &CStr, oflag: c_int) -> io::Result<Self> {
|
|
match Sys::open(path, oflag, 0) {
|
|
match Sys::open(path, oflag, 0) {
|
|
-1 => Err(last_os_error()),
|
|
-1 => Err(last_os_error()),
|
|
- ok => Ok(File(ok)),
|
|
|
|
|
|
+ ok => Ok(Self::new(ok)),
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
pub fn create(path: &CStr, oflag: c_int, mode: mode_t) -> io::Result<Self> {
|
|
pub fn create(path: &CStr, oflag: c_int, mode: mode_t) -> io::Result<Self> {
|
|
match Sys::open(path, oflag | O_CREAT, mode) {
|
|
match Sys::open(path, oflag | O_CREAT, mode) {
|
|
-1 => Err(last_os_error()),
|
|
-1 => Err(last_os_error()),
|
|
- ok => Ok(File(ok)),
|
|
|
|
|
|
+ ok => Ok(Self::new(ok)),
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
pub fn sync_all(&self) -> io::Result<()> {
|
|
pub fn sync_all(&self) -> io::Result<()> {
|
|
- match Sys::fsync(self.0) {
|
|
|
|
|
|
+ match Sys::fsync(self.fd) {
|
|
-1 => Err(last_os_error()),
|
|
-1 => Err(last_os_error()),
|
|
_ok => Ok(()),
|
|
_ok => Ok(()),
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
pub fn set_len(&self, size: u64) -> io::Result<()> {
|
|
pub fn set_len(&self, size: u64) -> io::Result<()> {
|
|
- match Sys::ftruncate(self.0, size as off_t) {
|
|
|
|
|
|
+ match Sys::ftruncate(self.fd, size as off_t) {
|
|
-1 => Err(last_os_error()),
|
|
-1 => Err(last_os_error()),
|
|
_ok => Ok(()),
|
|
_ok => Ok(()),
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
pub fn try_clone(&self) -> io::Result<Self> {
|
|
pub fn try_clone(&self) -> io::Result<Self> {
|
|
- match Sys::dup(self.0) {
|
|
|
|
|
|
+ match Sys::dup(self.fd) {
|
|
-1 => Err(last_os_error()),
|
|
-1 => Err(last_os_error()),
|
|
- ok => Ok(File(ok)),
|
|
|
|
|
|
+ ok => Ok(Self::new(ok)),
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// Create a new file pointing to the same underlying descriptor. This file
|
|
|
|
+ /// will know it's a "reference" and won't close the fd. It will, however,
|
|
|
|
+ /// not prevent the original file from closing the fd.
|
|
|
|
+ pub unsafe fn get_ref(&self) -> Self {
|
|
|
|
+ Self {
|
|
|
|
+ fd: self.fd,
|
|
|
|
+ reference: false
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
impl io::Read for File {
|
|
impl io::Read for File {
|
|
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
|
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
|
- match Sys::read(self.0, buf) {
|
|
|
|
|
|
+ match Sys::read(self.fd, buf) {
|
|
-1 => Err(last_os_error()),
|
|
-1 => Err(last_os_error()),
|
|
ok => Ok(ok as usize),
|
|
ok => Ok(ok as usize),
|
|
}
|
|
}
|
|
@@ -61,7 +84,7 @@ impl io::Read for File {
|
|
|
|
|
|
impl io::Write for File {
|
|
impl io::Write for File {
|
|
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
|
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
|
- match Sys::write(self.0, buf) {
|
|
|
|
|
|
+ match Sys::write(self.fd, buf) {
|
|
-1 => Err(last_os_error()),
|
|
-1 => Err(last_os_error()),
|
|
ok => Ok(ok as usize),
|
|
ok => Ok(ok as usize),
|
|
}
|
|
}
|
|
@@ -80,9 +103,25 @@ impl io::Seek for File {
|
|
io::SeekFrom::End(end) => (end as off_t, SEEK_END),
|
|
io::SeekFrom::End(end) => (end as off_t, SEEK_END),
|
|
};
|
|
};
|
|
|
|
|
|
- match Sys::lseek(self.0, offset, whence) {
|
|
|
|
|
|
+ match Sys::lseek(self.fd, offset, whence) {
|
|
-1 => Err(last_os_error()),
|
|
-1 => Err(last_os_error()),
|
|
ok => Ok(ok as u64),
|
|
ok => Ok(ok as u64),
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+impl Deref for File {
|
|
|
|
+ type Target = c_int;
|
|
|
|
+
|
|
|
|
+ fn deref(&self) -> &Self::Target {
|
|
|
|
+ &self.fd
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl Drop for File {
|
|
|
|
+ fn drop(&mut self) {
|
|
|
|
+ if !self.reference {
|
|
|
|
+ let _ = Sys::close(self.fd);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|