@@ -12,7 +12,7 @@ use prelude::*;
1212use super :: support:: PathLike ;
1313use super :: { Reader , Writer , Seek } ;
1414use super :: { SeekStyle , SeekSet , SeekCur , SeekEnd ,
15- Open , Read , Create , ReadWrite } ;
15+ Open , Read , Write , Create , ReadWrite } ;
1616use rt:: rtio:: { RtioFileStream , IoFactory , IoFactoryObject } ;
1717use rt:: io:: { io_error, read_error, EndOfFile ,
1818 FileMode , FileAccess , FileStat } ;
@@ -57,26 +57,108 @@ pub fn unlink<P: PathLike>(path: &P) {
5757 }
5858}
5959
60- /// Abstraction representing *positional* access to a file. In this case,
61- /// *positional* refers to it keeping an encounter *cursor* of where in the
62- /// file a subsequent `read` or `write` will begin from. Users of a `FileStream`
63- /// can `seek` to move the cursor to a given location *within the bounds of the
64- /// file* and can ask to have the `FileStream` `tell` them the location, in
65- /// bytes, of the cursor.
66- ///
67- /// This abstraction is roughly modeled on the access workflow as represented
68- /// by `open(2)`, `read(2)`, `write(2)` and friends.
60+ /// Create a new directory with default permissions (process user
61+ /// has read/write privs)
62+ pub fn mkdir < P : PathLike > ( path : & P ) {
63+ let mkdir_result = unsafe {
64+ let io: * mut IoFactoryObject = Local :: unsafe_borrow ( ) ;
65+ ( * io) . fs_mkdir ( path)
66+ } ;
67+ match mkdir_result {
68+ Ok ( _) => ( ) ,
69+ Err ( ioerr) => {
70+ io_error:: cond. raise ( ioerr) ;
71+ }
72+ }
73+ }
74+ /// Removes a directory
75+ pub fn rmdir < P : PathLike > ( path : & P ) {
76+ let rmdir_result = unsafe {
77+ let io: * mut IoFactoryObject = Local :: unsafe_borrow ( ) ;
78+ ( * io) . fs_rmdir ( path)
79+ } ;
80+ match rmdir_result {
81+ Ok ( _) => ( ) ,
82+ Err ( ioerr) => {
83+ io_error:: cond. raise ( ioerr) ;
84+ }
85+ }
86+ }
87+
88+ /// Given a `rt::io::support::PathLike`, query the file system to get
89+ /// information about a file, directory, etc.
6990///
70- /// The `open` and `unlink` static methods are provided to manage creation/removal
71- /// of files. All other methods operatin on an instance of `FileStream`.
91+ /// Returns a `Some(PathInfo)` on success, and raises a `rt::io::IoError` condition
92+ /// on failure and returns `None`.
93+ pub fn stat < P : PathLike > ( path : & P ) -> Option < FileStat > {
94+ let open_result = unsafe {
95+ let io: * mut IoFactoryObject = Local :: unsafe_borrow ( ) ;
96+ ( * io) . fs_stat ( path)
97+ } ;
98+ match open_result {
99+ Ok ( p) => {
100+ Some ( p)
101+ } ,
102+ Err ( ioerr) => {
103+ read_error:: cond. raise ( ioerr) ;
104+ None
105+ }
106+ }
107+ }
108+
109+ /// Read-only view of file
110+ pub struct FileReader { priv stream : FileStream }
111+
112+ impl Reader for FileReader {
113+ fn read ( & mut self , buf : & mut [ u8 ] ) -> Option < uint > {
114+ self . stream . read ( buf)
115+ }
116+
117+ fn eof ( & mut self ) -> bool {
118+ self . stream . eof ( )
119+ }
120+ }
121+
122+ impl Seek for FileReader {
123+ fn tell ( & self ) -> u64 {
124+ self . stream . tell ( )
125+ }
126+
127+ fn seek ( & mut self , pos : i64 , style : SeekStyle ) {
128+ self . stream . seek ( pos, style) ;
129+ }
130+ }
131+
132+ /// Write-only view of a file
133+ pub struct FileWriter { priv stream : FileStream }
134+
135+ impl Writer for FileWriter {
136+ fn write ( & mut self , buf : & [ u8 ] ) {
137+ self . stream . write ( buf) ;
138+ }
139+
140+ fn flush ( & mut self ) {
141+ self . stream . flush ( ) ;
142+ }
143+ }
144+
145+ impl Seek for FileWriter {
146+ fn tell ( & self ) -> u64 {
147+ self . stream . tell ( )
148+ }
149+
150+ fn seek ( & mut self , pos : i64 , style : SeekStyle ) {
151+ self . stream . seek ( pos, style) ;
152+ }
153+ }
154+
155+ /// Internal representation of a FileStream, used to consolidate functionality
156+ /// exposed in the public API
72157pub struct FileStream {
73158 fd : ~RtioFileStream ,
74159 last_nread : int ,
75160}
76161
77- impl FileStream {
78- }
79-
80162impl Reader for FileStream {
81163 fn read ( & mut self , buf : & mut [ u8 ] ) -> Option < uint > {
82164 match self . fd . read ( buf) {
@@ -148,69 +230,85 @@ impl Seek for FileStream {
148230 }
149231}
150232
151- pub struct FileInfo ( Path ) ;
152-
153- /// FIXME: DOCS
154- impl < ' self > FileInfo {
155- pub fn new < P : PathLike > ( path : & P ) -> FileInfo {
156- do path. path_as_str |p| {
157- FileInfo ( Path ( p) )
158- }
159- }
160- // FIXME #8873 can't put this in FileSystemInfo
161- pub fn get_path ( & ' self self ) -> & ' self Path {
162- & ( * * self )
163- }
164- pub fn stat ( & self ) -> Option < FileStat > {
165- do io_error:: cond. trap ( |_| {
233+ /// Represents passive information about a file (primarily exposed
234+ /// via the `stat()` method. Also provides methods for opening
235+ /// a file in various modes/permissions.
236+ pub trait FileInfo < ' self > {
237+ /// Get the filesystem path that this `FileInfo` points at,
238+ /// whether it is valid or not. This way, it can be used to
239+ /// to specify a file path of a non-existent file which it
240+ /// later create
241+ fn get_file_path ( & ' self self ) -> & ' self Path ;
242+
243+ /// Ask the operating system for information about the file
244+ fn stat ( & self ) -> Option < FileStat > {
245+ use mod_stat = super :: file:: stat;
246+ do read_error:: cond. trap ( |_| {
166247 // FIXME: can we do something more useful here?
167248 } ) . inside {
168- stat ( self . get_path ( ) )
249+ mod_stat ( self . get_file_path ( ) )
169250 }
170251 }
171- pub fn exists ( & self ) -> bool {
252+
253+ /// returns `true` if the location pointed at by the enclosing
254+ /// exists on the filesystem
255+ fn file_exists ( & self ) -> bool {
172256 match self . stat ( ) {
173- Some ( s) => {
174- match s. is_file {
175- true => {
176- true
177- } ,
178- false => {
179- // FIXME: raise condition?
180- false
181- }
182- }
183- } ,
257+ Some ( _) => true ,
184258 None => false
185259 }
186260 }
187- pub fn is_file ( & self ) -> bool {
261+
262+ /// Whether the underlying implemention (be it a file path
263+ /// or active file descriptor) is a "regular file". Will return
264+ /// false for paths to non-existent locations or directories or
265+ /// other non-regular files (named pipes, etc).
266+ fn is_file ( & self ) -> bool {
188267 match self . stat ( ) {
189268 Some ( s) => s. is_file ,
190- None => {
191- // FIXME: raise condition
192- false
193- }
269+ None => false
194270 }
195271 }
196- pub fn open ( & self , mode : FileMode , access : FileAccess ) -> Option < FileStream > {
197- match self . is_file ( ) {
198- true => {
199- open ( self . get_path ( ) , mode, access)
272+
273+ /// Attempts to open a regular file for reading/writing based
274+ /// on provided inputs
275+ fn open_stream ( & self , mode : FileMode , access : FileAccess ) -> Option < FileStream > {
276+ match self . stat ( ) {
277+ Some ( s) => match s. is_file {
278+ true => open ( self . get_file_path ( ) , mode, access) ,
279+ false => None // FIXME: raise condition, not a regular file..
200280 } ,
201- false => {
202- // FIXME: raise condition
203- None
204- }
281+ None => open ( self . get_file_path ( ) , mode, access)
282+ }
283+ }
284+ /// Attempts to open a regular file for reading-only based
285+ /// on provided inputs
286+ fn open_reader ( & self , mode : FileMode ) -> Option < FileReader > {
287+ match self . open_stream ( mode, Read ) {
288+ Some ( s) => Some ( FileReader { stream : s} ) ,
289+ None => None
290+ }
291+ }
292+
293+ /// Attempts to open a regular file for writing-only based
294+ /// on provided inputs
295+ fn open_writer ( & self , mode : FileMode ) -> Option < FileWriter > {
296+ match self . open_stream ( mode, Write ) {
297+ Some ( s) => Some ( FileWriter { stream : s} ) ,
298+ None => None
205299 }
206300 }
207- //fn open_read(&self) -> FileStream;
208- //fn open_write(&self) -> FileStream;
209- //fn create(&self) -> FileStream;
210- //fn truncate(&self) -> FileStream;
211- //fn open_or_create(&self) -> FileStream;
212- //fn create_or_truncate(&self) -> FileStream;
213- //fn unlink(&self);
301+
302+ /// Attempt to remove a file from the filesystem, pending the closing
303+ /// of any open file descriptors pointing to the file
304+ fn unlink ( & self ) {
305+ unlink ( self . get_file_path ( ) ) ;
306+ }
307+ }
308+
309+ /// `FileInfo` implementation for `Path`s
310+ impl < ' self > FileInfo < ' self > for Path {
311+ fn get_file_path ( & ' self self ) -> & ' self Path { self }
214312}
215313
216314/*
@@ -244,27 +342,6 @@ impl DirectoryInfo<'self> {
244342}
245343*/
246344
247- /// Given a `rt::io::support::PathLike`, query the file system to get
248- /// information about a file, directory, etc.
249- ///
250- /// Returns a `Some(PathInfo)` on success, and raises a `rt::io::IoError` condition
251- /// on failure and returns `None`.
252- pub fn stat < P : PathLike > ( path : & P ) -> Option < FileStat > {
253- let open_result = unsafe {
254- let io: * mut IoFactoryObject = Local :: unsafe_borrow ( ) ;
255- ( * io) . fs_stat ( path)
256- } ;
257- match open_result {
258- Ok ( p) => {
259- Some ( p)
260- } ,
261- Err ( ioerr) => {
262- read_error:: cond. raise ( ioerr) ;
263- None
264- }
265- }
266- }
267-
268345fn file_test_smoke_test_impl ( ) {
269346 do run_in_mt_newsched_task {
270347 let message = "it's alright. have a good time" ;
@@ -412,7 +489,7 @@ fn file_test_io_seek_and_write_impl() {
412489 read_stream. read ( read_mem) ;
413490 }
414491 unlink ( filename) ;
415- let read_str = str:: from_bytes ( read_mem) ;
492+ let read_str = str:: from_utf8 ( read_mem) ;
416493 assert ! ( read_str == final_msg. to_owned( ) ) ;
417494 }
418495}
@@ -463,8 +540,9 @@ fn file_test_io_seek_shakedown() {
463540}
464541
465542#[ test]
543+ #[ ignore( cfg( windows) ) ] // FIXME #8810
466544fn file_test_stat_is_correct_on_is_file ( ) {
467- do run_in_newsched_task {
545+ do run_in_mt_newsched_task {
468546 let filename = & Path ( "./tmp/file_stat_correct_on_is_file.txt" ) ;
469547 {
470548 let mut fs = open ( filename, Create , ReadWrite ) . unwrap ( ) ;
@@ -476,20 +554,48 @@ fn file_test_stat_is_correct_on_is_file() {
476554 None => fail ! ( "shouldn't happen" )
477555 } ;
478556 assert ! ( stat_res. is_file) ;
557+ unlink ( filename) ;
479558 }
480559}
481560
482561#[ test]
562+ #[ ignore( cfg( windows) ) ] // FIXME #8810
483563fn file_test_stat_is_correct_on_is_dir ( ) {
484- //assert!(false);
564+ do run_in_mt_newsched_task {
565+ let filename = & Path ( "./tmp/file_stat_correct_on_is_dir" ) ;
566+ mkdir ( filename) ;
567+ let stat_res = match stat ( filename) {
568+ Some ( s) => s,
569+ None => fail ! ( "shouldn't happen" )
570+ } ;
571+ assert ! ( stat_res. is_dir) ;
572+ rmdir ( filename) ;
573+ }
485574}
486575
487576#[ test]
577+ #[ ignore( cfg( windows) ) ] // FIXME #8810
488578fn file_test_fileinfo_false_when_checking_is_file_on_a_directory ( ) {
489- //assert!(false);
579+ do run_in_mt_newsched_task {
580+ let dir = & Path ( "./tmp/fileinfo_false_on_dir" ) ;
581+ mkdir ( dir) ;
582+ assert ! ( dir. is_file( ) == false ) ;
583+ rmdir ( dir) ;
584+ }
490585}
491586
492587#[ test]
588+ #[ ignore( cfg( windows) ) ] // FIXME #8810
493589fn file_test_fileinfo_check_exists_before_and_after_file_creation ( ) {
494- //assert!(false);
590+ do run_in_mt_newsched_task {
591+ let file = & Path ( "./tmp/fileinfo_check_exists_b_and_a.txt" ) ;
592+ {
593+ let msg = "foo" . as_bytes ( ) ;
594+ let mut w = file. open_writer ( Create ) ;
595+ w. write ( msg) ;
596+ }
597+ assert ! ( file. file_exists( ) ) ;
598+ file. unlink ( ) ;
599+ assert ! ( !file. file_exists( ) ) ;
600+ }
495601}
0 commit comments