(index<- ) ./libstd/rt/io/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 /*! Synchronous File I/O
12
13 This module provides a set of functions and traits for working
14 with regular files & directories on a filesystem.
15
16 At the top-level of the module are a set of freestanding functions,
17 associated with various filesystem operations. They all operate
18 on a `PathLike` object.
19
20 All operations in this module, including those as part of `FileStream` et al
21 block the task during execution. Most will raise `std::rt::io::{io_error,read_error}`
22 conditions in the event of failure.
23
24 Also included in this module are the `FileInfo` and `DirectoryInfo` traits. When
25 `use`'d alongside a value whose type implements them (A `std::path::Path` impl is
26 a part of this module), they expose a set of functions for operations against
27 a given file location, depending on whether the path already exists. Whenever
28 possible, the `{FileInfo, DirectoryInfo}` preserve the same semantics as their
29 free function counterparts.
30 */
31
32 use prelude::*;
33 use super::support::PathLike;
34 use super::{Reader, Writer, Seek};
35 use super::{SeekStyle, Read, Write};
36 use rt::rtio::{RtioFileStream, IoFactory, IoFactoryObject};
37 use rt::io::{io_error, read_error, EndOfFile,
38 FileMode, FileAccess, FileStat, IoError,
39 PathAlreadyExists, PathDoesntExist,
40 MismatchedFileTypeForOperation, ignore_io_error};
41 use rt::local::Local;
42 use option::{Some, None};
43 use path::Path;
44
45 /// Open a file for reading/writing, as indicated by `path`.
46 ///
47 /// # Example
48 ///
49 /// use std;
50 /// use std::path::Path;
51 /// use std::rt::io::support::PathLike;
52 /// use std::rt::io::file::open;
53 /// use std::rt::io::{FileMode, FileAccess};
54 ///
55 /// let p = &Path("/some/file/path.txt");
56 ///
57 /// do io_error::cond.trap(|_| {
58 /// // hoo-boy...
59 /// }).inside {
60 /// let stream = match open(p, Create, ReadWrite) {
61 /// Some(s) => s,
62 /// None => fail2!("whoops! I'm sure this raised, anyways..");
63 /// }
64 /// // do some stuff with that stream
65 ///
66 /// // the file stream will be closed at the end of this block
67 /// }
68 /// // ..
69 ///
70 /// `FileMode` and `FileAccess` provide information about the permissions
71 /// context in which a given stream is created. More information about them
72 /// can be found in `std::rt::io`'s docs.
73 ///
74 /// Note that, with this function, a `FileStream` is returned regardless of
75 /// the access-limitations indicated by `FileAccess` (e.g. calling `write` on a
76 /// `FileStream` opened as `ReadOnly` will raise an `io_error` condition at runtime). If you
77 /// desire a more-correctly-constrained interface to files, use the
78 /// `{open_stream, open_reader, open_writer}` methods that are a part of `FileInfo`
79 ///
80 /// # Errors
81 ///
82 /// This function will raise an `io_error` condition under a number of different circumstances,
83 /// to include but not limited to:
84 ///
85 /// * Opening a file that already exists with `FileMode` of `Create` or vice versa (e.g.
86 /// opening a non-existant file with `FileMode` or `Open`)
87 /// * Attempting to open a file with a `FileAccess` that the user lacks permissions
88 /// for
89 /// * Filesystem-level errors (full disk, etc)
90 pub fn open<P: PathLike>(path: &P,
91 mode: FileMode,
92 access: FileAccess
93 ) -> Option<FileStream> {
94 let open_result = unsafe {
95 let io: *mut IoFactoryObject = Local::unsafe_borrow();
96 (*io).fs_open(path, mode, access)
97 };
98 match open_result {
99 Ok(fd) => Some(FileStream {
100 fd: fd,
101 last_nread: -1
102 }),
103 Err(ioerr) => {
104 io_error::cond.raise(ioerr);
105 None
106 }
107 }
108 }
109
110 /// Unlink a file from the underlying filesystem.
111 ///
112 /// # Example
113 ///
114 /// use std;
115 /// use std::path::Path;
116 /// use std::rt::io::support::PathLike;
117 /// use std::rt::io::file::unlink;
118 ///
119 /// let p = &Path("/some/file/path.txt");
120 /// unlink(p);
121 /// // if we made it here without failing, then the
122 /// // unlink operation was successful
123 ///
124 /// Note that, just because an unlink call was successful, it is not
125 /// guaranteed that a file is immediately deleted (e.g. depending on
126 /// platform, other open file descriptors may prevent immediate removal)
127 ///
128 /// # Errors
129 ///
130 /// This function will raise an `io_error` condition if the user lacks permissions to
131 /// remove the file or if some other filesystem-level error occurs
132 pub fn unlink<P: PathLike>(path: &P) {
133 let unlink_result = unsafe {
134 let io: *mut IoFactoryObject = Local::unsafe_borrow();
135 (*io).fs_unlink(path)
136 };
137 match unlink_result {
138 Ok(_) => (),
139 Err(ioerr) => {
140 io_error::cond.raise(ioerr);
141 }
142 }
143 }
144
145 /// Create a new, empty directory at the provided path
146 ///
147 /// # Example
148 ///
149 /// use std;
150 /// use std::path::Path;
151 /// use std::rt::io::support::PathLike;
152 /// use std::rt::io::file::mkdir;
153 ///
154 /// let p = &Path("/some/dir");
155 /// mkdir(p);
156 /// // If we got here, our directory exists! Horray!
157 ///
158 /// # Errors
159 ///
160 /// This call will raise an `io_error` condition if the user lacks permissions to make a
161 /// new directory at the provided path, or if the directory already exists
162 pub fn mkdir<P: PathLike>(path: &P) {
163 let mkdir_result = unsafe {
164 let io: *mut IoFactoryObject = Local::unsafe_borrow();
165 (*io).fs_mkdir(path)
166 };
167 match mkdir_result {
168 Ok(_) => (),
169 Err(ioerr) => {
170 io_error::cond.raise(ioerr);
171 }
172 }
173 }
174
175 /// Remove an existing, empty directory
176 ///
177 /// # Example
178 ///
179 /// use std;
180 /// use std::path::Path;
181 /// use std::rt::io::support::PathLike;
182 /// use std::rt::io::file::rmdir;
183 ///
184 /// let p = &Path("/some/dir");
185 /// rmdir(p);
186 /// // good riddance, you mean ol' directory
187 ///
188 /// # Errors
189 ///
190 /// This call will raise an `io_error` condition if the user lacks permissions to remove the
191 /// directory at the provided path, or if the directory isn't empty
192 pub fn rmdir<P: PathLike>(path: &P) {
193 let rmdir_result = unsafe {
194 let io: *mut IoFactoryObject = Local::unsafe_borrow();
195 (*io).fs_rmdir(path)
196 };
197 match rmdir_result {
198 Ok(_) => (),
199 Err(ioerr) => {
200 io_error::cond.raise(ioerr);
201 }
202 }
203 }
204
205 /// Get information on the file, directory, etc at the provided path
206 ///
207 /// Given a `rt::io::support::PathLike`, query the file system to get
208 /// information about a file, directory, etc.
209 ///
210 /// Returns a `Some(std::rt::io::PathInfo)` on success
211 ///
212 /// # Example
213 ///
214 /// use std;
215 /// use std::path::Path;
216 /// use std::rt::io::support::PathLike;
217 /// use std::rt::io::file::stat;
218 ///
219 /// let p = &Path("/some/file/path.txt");
220 ///
221 /// do io_error::cond.trap(|_| {
222 /// // hoo-boy...
223 /// }).inside {
224 /// let info = match stat(p) {
225 /// Some(s) => s,
226 /// None => fail2!("whoops! I'm sure this raised, anyways..");
227 /// }
228 /// if stat.is_file {
229 /// // just imagine the possibilities ...
230 /// }
231 ///
232 /// // the file stream will be closed at the end of this block
233 /// }
234 /// // ..
235 ///
236 /// # Errors
237 ///
238 /// This call will raise an `io_error` condition if the user lacks the requisite
239 /// permissions to perform a `stat` call on the given path or if there is no
240 /// entry in the filesystem at the provided path.
241 pub fn stat<P: PathLike>(path: &P) -> Option<FileStat> {
242 let open_result = unsafe {
243 let io: *mut IoFactoryObject = Local::unsafe_borrow();
244 (*io).fs_stat(path)
245 };
246 match open_result {
247 Ok(p) => {
248 Some(p)
249 },
250 Err(ioerr) => {
251 io_error::cond.raise(ioerr);
252 None
253 }
254 }
255 }
256
257 /// Retrieve a vector containing all entries within a provided directory
258 ///
259 /// # Example
260 ///
261 /// use std;
262 /// use std::path::Path;
263 /// use std::rt::io::support::PathLike;
264 /// use std::rt::io::file::readdir;
265 ///
266 /// fn visit_dirs(dir: &Path, cb: &fn(&Path)) {
267 /// if dir.is_dir() {
268 /// let contents = dir.readdir();
269 /// for entry in contents.iter() {
270 /// if entry.is_dir() { visit_dirs(entry, cb); }
271 /// else { cb(entry); }
272 /// }
273 /// }
274 /// else { fail2!("nope"); }
275 /// }
276 ///
277 /// # Errors
278 ///
279 /// Will raise an `io_error` condition if the provided `path` doesn't exist,
280 /// the process lacks permissions to view the contents or if the `path` points
281 /// at a non-directory file
282 pub fn readdir<P: PathLike>(path: &P) -> Option<~[Path]> {
283 let readdir_result = unsafe {
284 let io: *mut IoFactoryObject = Local::unsafe_borrow();
285 (*io).fs_readdir(path, 0)
286 };
287 match readdir_result {
288 Ok(p) => {
289 Some(p)
290 },
291 Err(ioerr) => {
292 io_error::cond.raise(ioerr);
293 None
294 }
295 }
296 }
297
298 /// Constrained version of `FileStream` that only exposes read-specific operations.
299 ///
300 /// Can be retreived via `FileInfo.open_reader()`.
301 pub struct FileReader { priv stream: FileStream }
302
303 /// a `std::rt::io::Reader` trait impl for file I/O.
304 impl Reader for FileReader {
305 fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
306 self.stream.read(buf)
307 }
308
309 fn eof(&mut self) -> bool {
310 self.stream.eof()
311 }
312 }
313
314 /// a `std::rt::io::Seek` trait impl for file I/O.
315 impl Seek for FileReader {
316 fn tell(&self) -> u64 {
317 self.stream.tell()
318 }
319
320 fn seek(&mut self, pos: i64, style: SeekStyle) {
321 self.stream.seek(pos, style);
322 }
323 }
324
325 /// Constrained version of `FileStream` that only exposes write-specific operations.
326 ///
327 /// Can be retreived via `FileInfo.open_writer()`.
328 pub struct FileWriter { priv stream: FileStream }
329
330 /// a `std::rt::io::Writer` trait impl for file I/O.
331 impl Writer for FileWriter {
332 fn write(&mut self, buf: &[u8]) {
333 self.stream.write(buf);
334 }
335
336 fn flush(&mut self) {
337 self.stream.flush();
338 }
339 }
340
341 /// a `std::rt::io::Seek` trait impl for file I/O.
342 impl Seek for FileWriter {
343 fn tell(&self) -> u64 {
344 self.stream.tell()
345 }
346
347 fn seek(&mut self, pos: i64, style: SeekStyle) {
348 self.stream.seek(pos, style);
349 }
350 }
351
352 /// Unconstrained file access type that exposes read and write operations
353 ///
354 /// Can be retreived via `file::open()` and `FileInfo.open_stream()`.
355 ///
356 /// # Errors
357 ///
358 /// This type will raise an io_error condition if operations are attempted against
359 /// it for which its underlying file descriptor was not configured at creation
360 /// time, via the `FileAccess` parameter to `file::open()`.
361 ///
362 /// For this reason, it is best to use the access-constrained wrappers that are
363 /// exposed via `FileInfo.open_reader()` and `FileInfo.open_writer()`.
364 pub struct FileStream {
365 fd: ~RtioFileStream,
366 last_nread: int,
367 }
368
369 /// a `std::rt::io::Reader` trait impl for file I/O.
370 impl Reader for FileStream {
371 fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
372 match self.fd.read(buf) {
373 Ok(read) => {
374 self.last_nread = read;
375 match read {
376 0 => None,
377 _ => Some(read as uint)
378 }
379 },
380 Err(ioerr) => {
381 // EOF is indicated by returning None
382 if ioerr.kind != EndOfFile {
383 read_error::cond.raise(ioerr);
384 }
385 return None;
386 }
387 }
388 }
389
390 fn eof(&mut self) -> bool {
391 self.last_nread == 0
392 }
393 }
394
395 /// a `std::rt::io::Writer` trait impl for file I/O.
396 impl Writer for FileStream {
397 fn write(&mut self, buf: &[u8]) {
398 match self.fd.write(buf) {
399 Ok(_) => (),
400 Err(ioerr) => {
401 io_error::cond.raise(ioerr);
402 }
403 }
404 }
405
406 fn flush(&mut self) {
407 match self.fd.flush() {
408 Ok(_) => (),
409 Err(ioerr) => {
410 read_error::cond.raise(ioerr);
411 }
412 }
413 }
414 }
415
416 /// a `std::rt::io:Seek` trait impl for file I/O.
417 impl Seek for FileStream {
418 fn tell(&self) -> u64 {
419 let res = self.fd.tell();
420 match res {
421 Ok(cursor) => cursor,
422 Err(ioerr) => {
423 read_error::cond.raise(ioerr);
424 return -1;
425 }
426 }
427 }
428
429 fn seek(&mut self, pos: i64, style: SeekStyle) {
430 match self.fd.seek(pos, style) {
431 Ok(_) => {
432 // successful seek resets EOF indicator
433 self.last_nread = -1;
434 ()
435 },
436 Err(ioerr) => {
437 read_error::cond.raise(ioerr);
438 }
439 }
440 }
441 }
442
443 /// Shared functionality between `FileInfo` and `DirectoryInfo`
444 pub trait FileSystemInfo {
445 /// Get the filesystem path that this instance points at,
446 /// whether it is valid or not. In this way, it can be used to
447 /// to specify a path of a non-existent file which it
448 /// later creates
449 fn get_path<'a>(&'a self) -> &'a Path;
450
451 /// Get information on the file, directory, etc at the provided path
452 ///
453 /// Consult the `file::stat` documentation for more info.
454 ///
455 /// This call preserves identical runtime/error semantics with `file::stat`
456 fn stat(&self) -> Option<FileStat> {
457 stat(self.get_path())
458 }
459
460 /// Boolean value indicator whether the underlying file exists on the filesystem
461 ///
462 /// # Errors
463 ///
464 /// Will not raise a condition
465 fn exists(&self) -> bool {
466 match ignore_io_error(|| self.stat()) {
467 Some(_) => true,
468 None => false
469 }
470 }
471
472 }
473
474 /// Represents a file, whose underlying path may or may not be valid
475 ///
476 /// # Example
477 ///
478 /// * Check if a file exists, reading from it if so
479 ///
480 /// ```rust
481 /// use std;
482 /// use std::path::Path;
483 /// use std::rt::io::file::{FileInfo, FileReader};
484 ///
485 /// let f = &Path("/some/file/path.txt");
486 /// if f.exists() {
487 /// let reader = f.open_reader(Open);
488 /// let mut mem = [0u8, 8*64000];
489 /// reader.read(mem);
490 /// // ...
491 /// }
492 /// ```
493 ///
494 /// * Is the given path a file?
495 ///
496 /// ```rust
497 /// let f = get_file_path_from_wherever();
498 /// match f.is_file() {
499 /// true => doing_something_with_a_file(f),
500 /// _ => {}
501 /// }
502 /// ```
503 pub trait FileInfo : FileSystemInfo {
504 /// Whether the underlying implemention (be it a file path,
505 /// or something else) points at a "regular file" on the FS. Will return
506 /// false for paths to non-existent locations or directories or
507 /// other non-regular files (named pipes, etc).
508 ///
509 /// # Errors
510 ///
511 /// Will not raise a condition
512 fn is_file(&self) -> bool {
513 match ignore_io_error(|| self.stat()) {
514 Some(s) => s.is_file,
515 None => false
516 }
517 }
518
519 /// Attempts to open a regular file for reading/writing based
520 /// on provided inputs
521 ///
522 /// See `file::open` for more information on runtime semantics and error conditions
523 fn open_stream(&self, mode: FileMode, access: FileAccess) -> Option<FileStream> {
524 match ignore_io_error(|| self.stat()) {
525 Some(s) => match s.is_file {
526 true => open(self.get_path(), mode, access),
527 false => None
528 },
529 None => open(self.get_path(), mode, access)
530 }
531 }
532
533 /// Attempts to open a regular file in read-only mode, based
534 /// on provided inputs
535 ///
536 /// See `file::open` for more information on runtime semantics and error conditions
537 fn open_reader(&self, mode: FileMode) -> Option<FileReader> {
538 match self.open_stream(mode, Read) {
539 Some(s) => Some(FileReader { stream: s}),
540 None => None
541 }
542 }
543
544 /// Attempts to open a regular file in write-only mode, based
545 /// on provided inputs
546 ///
547 /// See `file::open` for more information on runtime semantics and error conditions
548 fn open_writer(&self, mode: FileMode) -> Option<FileWriter> {
549 match self.open_stream(mode, Write) {
550 Some(s) => Some(FileWriter { stream: s}),
551 None => None
552 }
553 }
554
555 /// Attempt to remove a file from the filesystem
556 ///
557 /// See `file::unlink` for more information on runtime semantics and error conditions
558 fn unlink(&self) {
559 unlink(self.get_path());
560 }
561 }
562
563 /// `FileSystemInfo` implementation for `Path`s
564 impl FileSystemInfo for Path {
565 fn get_path<'a>(&'a self) -> &'a Path { self }
566 }
567
568 /// `FileInfo` implementation for `Path`s
569 impl FileInfo for Path { }
570
571 /// Represents a directory, whose underlying path may or may not be valid
572 ///
573 /// # Example
574 ///
575 /// * Check if a directory exists, `mkdir`'ing it if not
576 ///
577 /// ```rust
578 /// use std;
579 /// use std::path::Path;
580 /// use std::rt::io::file::{DirectoryInfo};
581 ///
582 /// let dir = &Path("/some/dir");
583 /// if !dir.exists() {
584 /// dir.mkdir();
585 /// }
586 /// ```
587 ///
588 /// * Is the given path a directory? If so, iterate on its contents
589 ///
590 /// ```rust
591 /// fn visit_dirs(dir: &Path, cb: &fn(&Path)) {
592 /// if dir.is_dir() {
593 /// let contents = dir.readdir();
594 /// for entry in contents.iter() {
595 /// if entry.is_dir() { visit_dirs(entry, cb); }
596 /// else { cb(entry); }
597 /// }
598 /// }
599 /// else { fail2!("nope"); }
600 /// }
601 /// ```
602 pub trait DirectoryInfo : FileSystemInfo {
603 /// Whether the underlying implemention (be it a file path,
604 /// or something else) is pointing at a directory in the underlying FS.
605 /// Will return false for paths to non-existent locations or if the item is
606 /// not a directory (eg files, named pipes, links, etc)
607 ///
608 /// # Errors
609 ///
610 /// Will not raise a condition
611 fn is_dir(&self) -> bool {
612 match ignore_io_error(|| self.stat()) {
613 Some(s) => s.is_dir,
614 None => false
615 }
616 }
617
618 /// Create a directory at the location pointed to by the
619 /// type underlying the given `DirectoryInfo`.
620 ///
621 /// # Errors
622 ///
623 /// This method will raise a `PathAlreadyExists` kind of `io_error` condition
624 /// if the provided path exists
625 ///
626 /// See `file::mkdir` for more information on runtime semantics and error conditions
627 fn mkdir(&self) {
628 match ignore_io_error(|| self.stat()) {
629 Some(_) => {
630 let path = self.get_path();
631 io_error::cond.raise(IoError {
632 kind: PathAlreadyExists,
633 desc: "Path already exists",
634 detail:
635 Some(format!("{} already exists; can't mkdir it",
636 path.display()))
637 })
638 },
639 None => mkdir(self.get_path())
640 }
641 }
642
643 /// Remove a directory at the given location.
644 ///
645 /// # Errors
646 ///
647 /// This method will raise a `PathDoesntExist` kind of `io_error` condition
648 /// if the provided path exists. It will raise a `MismatchedFileTypeForOperation`
649 /// kind of `io_error` condition if the provided path points at any
650 /// non-directory file type
651 ///
652 /// See `file::rmdir` for more information on runtime semantics and error conditions
653 fn rmdir(&self) {
654 match ignore_io_error(|| self.stat()) {
655 Some(s) => {
656 match s.is_dir {
657 true => rmdir(self.get_path()),
658 false => {
659 let path = self.get_path();
660 let ioerr = IoError {
661 kind: MismatchedFileTypeForOperation,
662 desc: "Cannot do rmdir() on a non-directory",
663 detail: Some(format!(
664 "{} is a non-directory; can't rmdir it",
665 path.display()))
666 };
667 io_error::cond.raise(ioerr);
668 }
669 }
670 },
671 None => {
672 let path = self.get_path();
673 io_error::cond.raise(IoError {
674 kind: PathDoesntExist,
675 desc: "Path doesn't exist",
676 detail: Some(format!("{} doesn't exist; can't rmdir it",
677 path.display()))
678 })
679 }
680 }
681 }
682
683 // Get a collection of all entries at the given
684 // directory
685 fn readdir(&self) -> Option<~[Path]> {
686 readdir(self.get_path())
687 }
688 }
689
690 /// `DirectoryInfo` impl for `path::Path`
691 impl DirectoryInfo for Path { }
692
693 #[cfg(test)]
694 mod test {
695 use super::super::{SeekSet, SeekCur, SeekEnd,
696 io_error, Read, Create, Open, ReadWrite};
697 use super::super::super::test::*;
698 use option::{Some, None};
699 use path::Path;
700 use super::*;
701 use iter::range;
702 #[test]
703 fn file_test_io_smoke_test() {
704 do run_in_mt_newsched_task {
705 let message = "it's alright. have a good time";
706 let filename = &Path::new("./tmp/file_rt_io_file_test.txt");
707 {
708 let mut write_stream = open(filename, Create, ReadWrite).unwrap();
709 write_stream.write(message.as_bytes());
710 }
711 {
712 use str;
713 let mut read_stream = open(filename, Open, Read).unwrap();
714 let mut read_buf = [0, .. 1028];
715 let read_str = match read_stream.read(read_buf).unwrap() {
716 -1|0 => fail2!("shouldn't happen"),
717 n => str::from_utf8(read_buf.slice_to(n))
718 };
719 assert!(read_str == message.to_owned());
720 }
721 unlink(filename);
722 }
723 }
724
725 #[test]
726 fn file_test_io_invalid_path_opened_without_create_should_raise_condition() {
727 do run_in_mt_newsched_task {
728 let filename = &Path::new("./tmp/file_that_does_not_exist.txt");
729 let mut called = false;
730 do io_error::cond.trap(|_| {
731 called = true;
732 }).inside {
733 let result = open(filename, Open, Read);
734 assert!(result.is_none());
735 }
736 assert!(called);
737 }
738 }
739
740 #[test]
741 fn file_test_iounlinking_invalid_path_should_raise_condition() {
742 do run_in_mt_newsched_task {
743 let filename = &Path::new("./tmp/file_another_file_that_does_not_exist.txt");
744 let mut called = false;
745 do io_error::cond.trap(|_| {
746 called = true;
747 }).inside {
748 unlink(filename);
749 }
750 assert!(called);
751 }
752 }
753
754 #[test]
755 fn file_test_io_non_positional_read() {
756 do run_in_mt_newsched_task {
757 use str;
758 let message = "ten-four";
759 let mut read_mem = [0, .. 8];
760 let filename = &Path::new("./tmp/file_rt_io_file_test_positional.txt");
761 {
762 let mut rw_stream = open(filename, Create, ReadWrite).unwrap();
763 rw_stream.write(message.as_bytes());
764 }
765 {
766 let mut read_stream = open(filename, Open, Read).unwrap();
767 {
768 let read_buf = read_mem.mut_slice(0, 4);
769 read_stream.read(read_buf);
770 }
771 {
772 let read_buf = read_mem.mut_slice(4, 8);
773 read_stream.read(read_buf);
774 }
775 }
776 unlink(filename);
777 let read_str = str::from_utf8(read_mem);
778 assert!(read_str == message.to_owned());
779 }
780 }
781
782 #[test]
783 fn file_test_io_seek_and_tell_smoke_test() {
784 do run_in_mt_newsched_task {
785 use str;
786 let message = "ten-four";
787 let mut read_mem = [0, .. 4];
788 let set_cursor = 4 as u64;
789 let mut tell_pos_pre_read;
790 let mut tell_pos_post_read;
791 let filename = &Path::new("./tmp/file_rt_io_file_test_seeking.txt");
792 {
793 let mut rw_stream = open(filename, Create, ReadWrite).unwrap();
794 rw_stream.write(message.as_bytes());
795 }
796 {
797 let mut read_stream = open(filename, Open, Read).unwrap();
798 read_stream.seek(set_cursor as i64, SeekSet);
799 tell_pos_pre_read = read_stream.tell();
800 read_stream.read(read_mem);
801 tell_pos_post_read = read_stream.tell();
802 }
803 unlink(filename);
804 let read_str = str::from_utf8(read_mem);
805 assert!(read_str == message.slice(4, 8).to_owned());
806 assert!(tell_pos_pre_read == set_cursor);
807 assert!(tell_pos_post_read == message.len() as u64);
808 }
809 }
810
811 #[test]
812 fn file_test_io_seek_and_write() {
813 do run_in_mt_newsched_task {
814 use str;
815 let initial_msg = "food-is-yummy";
816 let overwrite_msg = "-the-bar!!";
817 let final_msg = "foo-the-bar!!";
818 let seek_idx = 3;
819 let mut read_mem = [0, .. 13];
820 let filename = &Path::new("./tmp/file_rt_io_file_test_seek_and_write.txt");
821 {
822 let mut rw_stream = open(filename, Create, ReadWrite).unwrap();
823 rw_stream.write(initial_msg.as_bytes());
824 rw_stream.seek(seek_idx as i64, SeekSet);
825 rw_stream.write(overwrite_msg.as_bytes());
826 }
827 {
828 let mut read_stream = open(filename, Open, Read).unwrap();
829 read_stream.read(read_mem);
830 }
831 unlink(filename);
832 let read_str = str::from_utf8(read_mem);
833 assert!(read_str == final_msg.to_owned());
834 }
835 }
836
837 #[test]
838 fn file_test_io_seek_shakedown() {
839 do run_in_mt_newsched_task {
840 use str; // 01234567890123
841 let initial_msg = "qwer-asdf-zxcv";
842 let chunk_one = "qwer";
843 let chunk_two = "asdf";
844 let chunk_three = "zxcv";
845 let mut read_mem = [0, .. 4];
846 let filename = &Path::new("./tmp/file_rt_io_file_test_seek_shakedown.txt");
847 {
848 let mut rw_stream = open(filename, Create, ReadWrite).unwrap();
849 rw_stream.write(initial_msg.as_bytes());
850 }
851 {
852 let mut read_stream = open(filename, Open, Read).unwrap();
853
854 read_stream.seek(-4, SeekEnd);
855 read_stream.read(read_mem);
856 let read_str = str::from_utf8(read_mem);
857 assert!(read_str == chunk_three.to_owned());
858
859 read_stream.seek(-9, SeekCur);
860 read_stream.read(read_mem);
861 let read_str = str::from_utf8(read_mem);
862 assert!(read_str == chunk_two.to_owned());
863
864 read_stream.seek(0, SeekSet);
865 read_stream.read(read_mem);
866 let read_str = str::from_utf8(read_mem);
867 assert!(read_str == chunk_one.to_owned());
868 }
869 unlink(filename);
870 }
871 }
872
873 #[test]
874 fn file_test_stat_is_correct_on_is_file() {
875 do run_in_mt_newsched_task {
876 let filename = &Path::new("./tmp/file_stat_correct_on_is_file.txt");
877 {
878 let mut fs = open(filename, Create, ReadWrite).unwrap();
879 let msg = "hw";
880 fs.write(msg.as_bytes());
881 }
882 let stat_res = match stat(filename) {
883 Some(s) => s,
884 None => fail2!("shouldn't happen")
885 };
886 assert!(stat_res.is_file);
887 unlink(filename);
888 }
889 }
890
891 #[test]
892 fn file_test_stat_is_correct_on_is_dir() {
893 do run_in_mt_newsched_task {
894 let filename = &Path::new("./tmp/file_stat_correct_on_is_dir");
895 mkdir(filename);
896 let stat_res = match stat(filename) {
897 Some(s) => s,
898 None => fail2!("shouldn't happen")
899 };
900 assert!(stat_res.is_dir);
901 rmdir(filename);
902 }
903 }
904
905 #[test]
906 fn file_test_fileinfo_false_when_checking_is_file_on_a_directory() {
907 do run_in_mt_newsched_task {
908 let dir = &Path::new("./tmp/fileinfo_false_on_dir");
909 mkdir(dir);
910 assert!(dir.is_file() == false);
911 rmdir(dir);
912 }
913 }
914
915 #[test]
916 fn file_test_fileinfo_check_exists_before_and_after_file_creation() {
917 do run_in_mt_newsched_task {
918 let file = &Path::new("./tmp/fileinfo_check_exists_b_and_a.txt");
919 {
920 let msg = "foo".as_bytes();
921 let mut w = file.open_writer(Create);
922 w.write(msg);
923 }
924 assert!(file.exists());
925 file.unlink();
926 assert!(!file.exists());
927 }
928 }
929
930 #[test]
931 fn file_test_directoryinfo_check_exists_before_and_after_mkdir() {
932 do run_in_mt_newsched_task {
933 let dir = &Path::new("./tmp/before_and_after_dir");
934 assert!(!dir.exists());
935 dir.mkdir();
936 assert!(dir.exists());
937 assert!(dir.is_dir());
938 dir.rmdir();
939 assert!(!dir.exists());
940 }
941 }
942
943 #[test]
944 fn file_test_directoryinfo_readdir() {
945 use str;
946 do run_in_mt_newsched_task {
947 let dir = &Path::new("./tmp/di_readdir");
948 dir.mkdir();
949 let prefix = "foo";
950 for n in range(0,3) {
951 let f = dir.join(format!("{}.txt", n));
952 let mut w = f.open_writer(Create);
953 let msg_str = (prefix + n.to_str().to_owned()).to_owned();
954 let msg = msg_str.as_bytes();
955 w.write(msg);
956 }
957 match dir.readdir() {
958 Some(files) => {
959 let mut mem = [0u8, .. 4];
960 for f in files.iter() {
961 {
962 let n = f.filestem_str();
963 let mut r = f.open_reader(Open);
964 r.read(mem);
965 let read_str = str::from_utf8(mem);
966 let expected = match n {
967 None|Some("") => fail2!("really shouldn't happen.."),
968 Some(n) => prefix+n
969 };
970 assert!(expected == read_str);
971 }
972 f.unlink();
973 }
974 },
975 None => fail2!("shouldn't happen")
976 }
977 dir.rmdir();
978 }
979 }
980 }
libstd/rt/io/file.rs:131:67-131:67 -fn- definition:
/// remove the file or if some other filesystem-level error occurs
pub fn unlink<P: PathLike>(path: &P) {
references:-559: unlink(self.get_path());
libstd/rt/io/file.rs:300:51-300:51 -struct- definition:
/// Can be retreived via `FileInfo.open_reader()`.
pub struct FileReader { priv stream: FileStream }
references:-539: Some(s) => Some(FileReader { stream: s}),
537: fn open_reader(&self, mode: FileMode) -> Option<FileReader> {
315: impl Seek for FileReader {
304: impl Reader for FileReader {
libstd/rt/io/file.rs:191:68-191:68 -fn- definition:
/// directory at the provided path, or if the directory isn't empty
pub fn rmdir<P: PathLike>(path: &P) {
references:-657: true => rmdir(self.get_path()),
libstd/rt/io/file.rs:327:51-327:51 -struct- definition:
/// Can be retreived via `FileInfo.open_writer()`.
pub struct FileWriter { priv stream: FileStream }
references:-331: impl Writer for FileWriter {
342: impl Seek for FileWriter {
550: Some(s) => Some(FileWriter { stream: s}),
548: fn open_writer(&self, mode: FileMode) -> Option<FileWriter> {
libstd/rt/io/file.rs:443:64-443:64 -trait- definition:
/// Shared functionality between `FileInfo` and `DirectoryInfo`
pub trait FileSystemInfo {
references:-602: pub trait DirectoryInfo : FileSystemInfo {
564: impl FileSystemInfo for Path {
503: pub trait FileInfo : FileSystemInfo {
libstd/rt/io/file.rs:363:71-363:71 -struct- definition:
/// exposed via `FileInfo.open_reader()` and `FileInfo.open_writer()`.
pub struct FileStream {
references:-99: Ok(fd) => Some(FileStream {
396: impl Writer for FileStream {
417: impl Seek for FileStream {
93: ) -> Option<FileStream> {
301: pub struct FileReader { priv stream: FileStream }
370: impl Reader for FileStream {
523: fn open_stream(&self, mode: FileMode, access: FileAccess) -> Option<FileStream> {
328: pub struct FileWriter { priv stream: FileStream }
libstd/rand/os.rs:
39: priv inner: ReaderRng<file::FileStream>
libstd/rt/io/file.rs:601:8-601:8 -trait- definition:
/// ```
pub trait DirectoryInfo : FileSystemInfo {
references:-691: impl DirectoryInfo for Path { }
libstd/rt/io/file.rs:89:47-89:47 -fn- definition:
/// * Filesystem-level errors (full disk, etc)
pub fn open<P: PathLike>(path: &P,
references:-529: None => open(self.get_path(), mode, access)
526: true => open(self.get_path(), mode, access),
libstd/rand/os.rs:
55: let reader = file::open(& &"/dev/urandom", Open, Read).expect("Error opening /dev/urandom");
libstd/rt/io/file.rs:281:28-281:28 -fn- definition:
/// at a non-directory file
pub fn readdir<P: PathLike>(path: &P) -> Option<~[Path]> {
references:-686: readdir(self.get_path())
libstd/rt/io/file.rs:240:50-240:50 -fn- definition:
/// entry in the filesystem at the provided path.
pub fn stat<P: PathLike>(path: &P) -> Option<FileStat> {
references:-457: stat(self.get_path())
libstd/rt/io/file.rs:502:8-502:8 -trait- definition:
/// ```
pub trait FileInfo : FileSystemInfo {
references:-569: impl FileInfo for Path { }
libstd/rt/io/file.rs:161:75-161:75 -fn- definition:
/// new directory at the provided path, or if the directory already exists
pub fn mkdir<P: PathLike>(path: &P) {
references:-639: None => mkdir(self.get_path())