(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(fd: fd_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, pos: i64, style: SeekStyle) {
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