(index<- )        ./libstd/rt/io/native/file.rs

   1  // Copyright 2013 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.
   4  //
   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.
  10  
  11  //! Blocking posix-based file I/O
  12  
  13  #[allow(non_camel_case_types)];
  14  
  15  use libc;
  16  use os;
  17  use prelude::*;
  18  use super::super::*;
  19  
  20  fn raise_error() {
  21      // XXX: this should probably be a bit more descriptive...
  22      let (kind, desc) = match os::errno() as i32 {
  23          libc::EOF => (EndOfFile, "end of file"),
  24          _ => (OtherIoError, "unknown error"),
  25      };
  26  
  27      io_error::cond.raise(IoError {
  28          kind: kind,
  29          desc: desc,
  30          detail: Some(os::last_os_error())
  31      });
  32  }
  33  
  34  fn keep_going(data&[u8], f&fn(*u8, uint) -> i64) -> i64 {
  35      #[cfg(windows)] static eintr: int = 0; // doesn't matter
  36      #[cfg(not(windows))] static eintr: int = libc::EINTR as int;
  37  
  38      let (data, origamt) = do data.as_imm_buf |data, amt| { (data, amt) };
  39      let mut data = data;
  40      let mut amt = origamt;
  41      while amt > 0 {
  42          let mut ret;
  43          loop {
  44              ret = f(data, amt);
  45              if cfg!(not(windows)) { break } // windows has no eintr
  46              // if we get an eintr, then try again
  47              if ret != -1 || os::errno() as int != eintr { break }
  48          }
  49          if ret == 0 {
  50              break
  51          } else if ret != -1 {
  52              amt -= ret as uint;
  53              data = unsafe { data.offset(ret as int) };
  54          } else {
  55              return ret;
  56          }
  57      }
  58      return (origamt - amt) as i64;
  59  }
  60  
  61  pub type fd_t = libc::c_int;
  62  
  63  pub struct FileDesc {
  64      priv fd: fd_t,
  65  }
  66  
  67  impl FileDesc {
  68      /// Create a `FileDesc` from an open C file descriptor.
  69      ///
  70      /// The `FileDesc` will take ownership of the specified file descriptor and
  71      /// close it upon destruction.
  72      ///
  73      /// Note that all I/O operations done on this object will be *blocking*, but
  74      /// they do not require the runtime to be active.
  75      pub fn new(fdfd_t) -> FileDesc {
  76          FileDesc { fd: fd }
  77      }
  78  }
  79  
  80  impl Reader for FileDesc {
  81      #[fixed_stack_segment] #[inline(never)]
  82      fn read(&mut self, buf&mut [u8]) -> Option<uint> {
  83          #[cfg(windows)] type rlen = libc::c_uint;
  84          #[cfg(not(windows))] type rlen = libc::size_t;
  85          let ret = do keep_going(buf) |buf, len| {
  86              unsafe {
  87                  libc::read(self.fd, buf as *mut libc::c_void, len as rlen) as i64
  88              }
  89          };
  90          if ret == 0 {
  91              None
  92          } else if ret < 0 {
  93              raise_error();
  94              None
  95          } else {
  96              Some(ret as uint)
  97          }
  98      }
  99  
 100      fn eof(&mut self) -> bool { false }
 101  }
 102  
 103  impl Writer for FileDesc {
 104      #[fixed_stack_segment] #[inline(never)]
 105      fn write(&mut self, buf&[u8]) {
 106          #[cfg(windows)] type wlen = libc::c_uint;
 107          #[cfg(not(windows))] type wlen = libc::size_t;
 108          let ret = do keep_going(buf) |buf, len| {
 109              unsafe {
 110                  libc::write(self.fd, buf as *libc::c_void, len as wlen) as i64
 111              }
 112          };
 113          if ret < 0 {
 114              raise_error();
 115          }
 116      }
 117  
 118      fn flush(&mut self) {}
 119  }
 120  
 121  impl Drop for FileDesc {
 122      #[fixed_stack_segment] #[inline(never)]
 123      fn drop(&mut self) {
 124          unsafe { libc::close(self.fd); }
 125      }
 126  }
 127  
 128  pub struct CFile {
 129      priv file: *libc::FILE
 130  }
 131  
 132  impl CFile {
 133      /// Create a `CFile` from an open `FILE` pointer.
 134      ///
 135      /// The `CFile` takes ownership of the `FILE` pointer and will close it upon
 136      /// destruction.
 137      pub fn new(file*libc::FILE) -> CFile { CFile { file: file } }
 138  }
 139  
 140  impl Reader for CFile {
 141      #[fixed_stack_segment] #[inline(never)]
 142      fn read(&mut self, buf&mut [u8]) -> Option<uint> {
 143          let ret = do keep_going(buf) |buf, len| {
 144              unsafe {
 145                  libc::fread(buf as *mut libc::c_void, 1, len as libc::size_t,
 146                              self.file) as i64
 147              }
 148          };
 149          if ret == 0 {
 150              None
 151          } else if ret < 0 {
 152              raise_error();
 153              None
 154          } else {
 155              Some(ret as uint)
 156          }
 157      }
 158  
 159      #[fixed_stack_segment] #[inline(never)]
 160      fn eof(&mut self) -> bool {
 161          unsafe { libc::feof(self.file) != 0 }
 162      }
 163  }
 164  
 165  impl Writer for CFile {
 166      #[fixed_stack_segment] #[inline(never)]
 167      fn write(&mut self, buf&[u8]) {
 168          let ret = do keep_going(buf) |buf, len| {
 169              unsafe {
 170                  libc::fwrite(buf as *libc::c_void, 1, len as libc::size_t,
 171                              self.file) as i64
 172              }
 173          };
 174          if ret < 0 {
 175              raise_error();
 176          }
 177      }
 178  
 179      #[fixed_stack_segment] #[inline(never)]
 180      fn flush(&mut self) {
 181          if unsafe { libc::fflush(self.file) } < 0 {
 182              raise_error();
 183          }
 184      }
 185  }
 186  
 187  impl Seek for CFile {
 188      #[fixed_stack_segment] #[inline(never)]
 189      fn tell(&self) -> u64 {
 190          let ret = unsafe { libc::ftell(self.file) };
 191          if ret < 0 {
 192              raise_error();
 193          }
 194          return ret as u64;
 195      }
 196  
 197      #[fixed_stack_segment] #[inline(never)]
 198      fn seek(&mut self, posi64, styleSeekStyle) {
 199          let whence = match style {
 200              SeekSet => libc::SEEK_SET,
 201              SeekEnd => libc::SEEK_END,
 202              SeekCur => libc::SEEK_CUR,
 203          };
 204          if unsafe { libc::fseek(self.file, pos as libc::c_long, whence) } < 0 {
 205              raise_error();
 206          }
 207      }
 208  }
 209  
 210  impl Drop for CFile {
 211      #[fixed_stack_segment] #[inline(never)]
 212      fn drop(&mut self) {
 213          unsafe { libc::fclose(self.file); }
 214      }
 215  }
 216  
 217  #[cfg(test)]
 218  mod tests {
 219      use libc;
 220      use os;
 221      use prelude::*;
 222      use rt::io::{io_error, SeekSet};
 223      use super::*;
 224  
 225      #[test] #[fixed_stack_segment]
 226      #[ignore(cfg(target_os = "freebsd"))] // hmm, maybe pipes have a tiny buffer
 227      fn test_file_desc() {
 228          // Run this test with some pipes so we don't have to mess around with
 229          // opening or closing files.
 230          unsafe {
 231              let os::Pipe { input, out } = os::pipe();
 232              let mut reader = FileDesc::new(input);
 233              let mut writer = FileDesc::new(out);
 234  
 235              writer.write(bytes!("test"));
 236              let mut buf = [0u8, ..4];
 237              match reader.read(buf) {
 238                  Some(4) => {
 239                      assert_eq!(buf[0], 't' as u8);
 240                      assert_eq!(buf[1], 'e' as u8);
 241                      assert_eq!(buf[2], 's' as u8);
 242                      assert_eq!(buf[3], 't' as u8);
 243                  }
 244                  r => fail2!("invalid read: {:?}", r)
 245              }
 246  
 247              let mut raised = false;
 248              do io_error::cond.trap(|_| { raised = true; }).inside {
 249                  writer.read(buf);
 250              }
 251              assert!(raised);
 252  
 253              raised = false;
 254              do io_error::cond.trap(|_| { raised = true; }).inside {
 255                  reader.write(buf);
 256              }
 257              assert!(raised);
 258          }
 259      }
 260  
 261      #[test] #[fixed_stack_segment]
 262      #[ignore(cfg(windows))] // apparently windows doesn't like tmpfile
 263      fn test_cfile() {
 264          unsafe {
 265              let f = libc::tmpfile();
 266              assert!(!f.is_null());
 267              let mut file = CFile::new(f);
 268  
 269              file.write(bytes!("test"));
 270              let mut buf = [0u8, ..4];
 271              file.seek(0, SeekSet);
 272              match file.read(buf) {
 273                  Some(4) => {
 274                      assert_eq!(buf[0], 't' as u8);
 275                      assert_eq!(buf[1], 'e' as u8);
 276                      assert_eq!(buf[2], 's' as u8);
 277                      assert_eq!(buf[3], 't' as u8);
 278                  }
 279                  r => fail2!("invalid read: {:?}", r)
 280              }
 281          }
 282      }
 283  }

libstd/rt/io/native/file.rs:33:1-33:1 -fn- definition:

fn keep_going(data: &[u8], f: &fn(*u8, uint) -> i64) -> i64 {
references:-
168:         let ret = do keep_going(buf) |buf, len| {
85:         let ret = do keep_going(buf) |buf, len| {
143:         let ret = do keep_going(buf) |buf, len| {
108:         let ret = do keep_going(buf) |buf, len| {


libstd/rt/io/native/file.rs:19:1-19:1 -fn- definition:

fn raise_error() {
references:-
93:             raise_error();
205:             raise_error();
114:             raise_error();
152:             raise_error();
192:             raise_error();
182:             raise_error();
175:             raise_error();


libstd/rt/io/native/file.rs:60:1-60:1 -ty- definition:

pub type fd_t = libc::c_int;
references:-
64:     priv fd: fd_t,
75:     pub fn new(fd: fd_t) -> FileDesc {
libstd/rt/io/native/process.rs:
71:                stderr: Option<file::fd_t>) -> Process {
70:                stdout: Option<file::fd_t>,
69:                stdin: Option<file::fd_t>,
libstd/rt/io/native/stdio.rs:
58:     pub fn new(fd: file::fd_t) -> StdOut {


libstd/rt/io/native/file.rs:84:29-84:29 -ty- definition:
        #[cfg(not(windows))] type rlen = libc::size_t;
        let ret = do keep_going(buf) |buf, len| {
references:-
87:                 libc::read(self.fd, buf as *mut libc::c_void, len as rlen) as i64


libstd/rt/io/native/file.rs:107:29-107:29 -ty- definition:
        #[cfg(not(windows))] type wlen = libc::size_t;
        let ret = do keep_going(buf) |buf, len| {
references:-
110:                 libc::write(self.fd, buf as *libc::c_void, len as wlen) as i64


libstd/rt/io/native/file.rs:127:1-127:1 -struct- definition:

pub struct CFile {
references:-
165: impl Writer for CFile {
187: impl Seek for CFile {
137:     pub fn new(file: *libc::FILE) -> CFile { CFile { file: file } }
210: impl Drop for CFile {
140: impl Reader for CFile {
137:     pub fn new(file: *libc::FILE) -> CFile { CFile { file: file } }
132: impl CFile {


libstd/rt/io/native/file.rs:62:1-62:1 -struct- definition:

pub struct FileDesc {
references:-
103: impl Writer for FileDesc {
75:     pub fn new(fd: fd_t) -> FileDesc {
76:         FileDesc { fd: fd }
121: impl Drop for FileDesc {
80: impl Reader for FileDesc {
67: impl FileDesc {
libstd/rt/io/native/process.rs:
39:     priv output: Option<file::FileDesc>,
41:     priv error: Option<file::FileDesc>,
37:     priv input: Option<file::FileDesc>,
libstd/rt/io/native/stdio.rs:
52:     priv fd: file::FileDesc
34:     priv fd: file::FileDesc