@@ -15,7 +15,9 @@ use super::{SeekStyle,SeekSet, SeekCur, SeekEnd,
1515 Open , Read , Write , Create , ReadWrite } ;
1616use rt:: rtio:: { RtioFileStream , IoFactory , IoFactoryObject } ;
1717use rt:: io:: { io_error, read_error, EndOfFile ,
18- FileMode , FileAccess , FileStat } ;
18+ FileMode , FileAccess , FileStat , IoError ,
19+ PathAlreadyExists , PathDoesntExist ,
20+ MismatchedFileTypeForOperation } ;
1921use rt:: local:: Local ;
2022use option:: { Some , None } ;
2123use path:: Path ;
@@ -100,7 +102,7 @@ pub fn stat<P: PathLike>(path: &P) -> Option<FileStat> {
100102 Some ( p)
101103 } ,
102104 Err ( ioerr) => {
103- read_error :: cond. raise ( ioerr) ;
105+ io_error :: cond. raise ( ioerr) ;
104106 None
105107 }
106108 }
@@ -230,41 +232,53 @@ impl Seek for FileStream {
230232 }
231233}
232234
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
235+ // helper for grabbing a stat and ignoring any
236+ // error.. used in Info wrappers
237+ fn suppressed_stat ( cb : & fn ( ) -> Option < FileStat > ) -> Option < FileStat > {
238+ do io_error:: cond. trap ( |_| {
239+ // just swallow the error.. downstream users
240+ // who can make a decision based on a None result
241+ // won't care
242+ } ) . inside {
243+ cb ( )
244+ }
245+ }
246+
247+ /// Shared functionality between `FileInfo` and `DirectoryInfo`
248+ pub trait FileSystemInfo {
249+ /// Get the filesystem path that this instance points at,
250+ /// whether it is valid or not. In this way, it can be used to
251+ /// to specify a path of a non-existent file which it
252+ /// later creates
253+ fn get_path < ' a > ( & ' a self ) -> & ' a Path ;
254+
255+ /// Ask the operating system for information about the path,
256+ /// will raise a condition if an error occurs during the process
244257 fn stat ( & self ) -> Option < FileStat > {
245- use mod_stat = super :: file:: stat;
246- do read_error:: cond. trap ( |_| {
247- // FIXME: can we do something more useful here?
248- } ) . inside {
249- mod_stat ( self . get_file_path ( ) )
250- }
258+ stat ( self . get_path ( ) )
251259 }
252260
253261 /// returns `true` if the location pointed at by the enclosing
254262 /// exists on the filesystem
255- fn file_exists ( & self ) -> bool {
256- match self . stat ( ) {
263+ fn exists ( & self ) -> bool {
264+ match suppressed_stat ( || self . stat ( ) ) {
257265 Some ( _) => true ,
258266 None => false
259267 }
260268 }
261269
262- /// Whether the underlying implemention (be it a file path
263- /// or active file descriptor) is a "regular file". Will return
270+ }
271+
272+ /// Represents passive information about a file (primarily exposed
273+ /// via the `stat()` method. Also provides methods for opening
274+ /// a file in various modes/permissions.
275+ pub trait FileInfo : FileSystemInfo {
276+ /// Whether the underlying implemention (be it a file path,
277+ /// or something else) points at a "regular file" on the FS. Will return
264278 /// false for paths to non-existent locations or directories or
265279 /// other non-regular files (named pipes, etc).
266280 fn is_file ( & self ) -> bool {
267- match self . stat ( ) {
281+ match suppressed_stat ( || self . stat ( ) ) {
268282 Some ( s) => s. is_file ,
269283 None => false
270284 }
@@ -273,12 +287,12 @@ pub trait FileInfo<'self> {
273287 /// Attempts to open a regular file for reading/writing based
274288 /// on provided inputs
275289 fn open_stream ( & self , mode : FileMode , access : FileAccess ) -> Option < FileStream > {
276- match self . stat ( ) {
290+ match suppressed_stat ( || self . stat ( ) ) {
277291 Some ( s) => match s. is_file {
278- true => open ( self . get_file_path ( ) , mode, access) ,
292+ true => open ( self . get_path ( ) , mode, access) ,
279293 false => None // FIXME: raise condition, not a regular file..
280294 } ,
281- None => open ( self . get_file_path ( ) , mode, access)
295+ None => open ( self . get_path ( ) , mode, access)
282296 }
283297 }
284298 /// Attempts to open a regular file for reading-only based
@@ -302,45 +316,82 @@ pub trait FileInfo<'self> {
302316 /// Attempt to remove a file from the filesystem, pending the closing
303317 /// of any open file descriptors pointing to the file
304318 fn unlink ( & self ) {
305- unlink ( self . get_file_path ( ) ) ;
319+ unlink ( self . get_path ( ) ) ;
306320 }
307321}
308322
309- /// `FileInfo ` implementation for `Path`s
310- impl < ' self > FileInfo < ' self > for Path {
311- fn get_file_path ( & ' self self ) -> & ' self Path { self }
323+ /// `FileSystemInfo ` implementation for `Path`s
324+ impl FileSystemInfo for Path {
325+ fn get_path < ' a > ( & ' a self ) -> & ' a Path { self }
312326}
327+ /// `FileInfo` implementation for `Path`s
328+ impl FileInfo for Path { }
313329
314- /*
315- /// FIXME: DOCS
316- impl DirectoryInfo<'self> {
317- fn new<P: PathLike>(path: &P) -> FileInfo {
318- FileInfo(Path(path.path_as_str()))
319- }
320- // FIXME #8873 can't put this in FileSystemInfo
321- fn get_path(&'self self) -> &'self Path {
322- &*self
330+ trait DirectoryInfo : FileSystemInfo {
331+ /// Whether the underlying implemention (be it a file path,
332+ /// or something else) points at a directory file" on the FS. Will return
333+ /// false for paths to non-existent locations or if the item is
334+ /// not a directory (eg files, named pipes, links, etc)
335+ fn is_dir ( & self ) -> bool {
336+ match suppressed_stat ( || self . stat ( ) ) {
337+ Some ( s) => s. is_dir ,
338+ None => false
339+ }
323340 }
324- fn stat(&self) -> Option<FileStat> {
325- file::stat(self.get_path())
341+ /// Create a directory at the location pointed to by the
342+ /// type underlying the given `DirectoryInfo`. Raises a
343+ /// condition if a file, directory, etc already exists
344+ /// at that location or if some other error occurs during
345+ /// the mkdir operation
346+ fn mkdir ( & self ) {
347+ match suppressed_stat ( || self . stat ( ) ) {
348+ Some ( _) => {
349+ io_error:: cond. raise ( IoError {
350+ kind : PathAlreadyExists ,
351+ desc : "path already exists" ,
352+ detail :
353+ Some ( fmt ! ( "%s already exists; can't mkdir it" , self . get_path( ) . to_str( ) ) )
354+ } )
355+ } ,
356+ None => mkdir ( self . get_path ( ) )
357+ }
326358 }
327- fn exists(&self) -> bool {
328- do io_error::cond.trap(|_| {
329- }).inside {
330- match self.stat() {
331- Some(_) => true,
332- None => false
333- }
359+ /// Remove a directory at the given location pointed to by
360+ /// the type underlying the given `DirectoryInfo`. Will fail
361+ /// if there is no directory at the given location or if
362+ fn rmdir ( & self ) {
363+ match suppressed_stat ( || self . stat ( ) ) {
364+ Some ( s) => {
365+ match s. is_dir {
366+ true => rmdir ( self . get_path ( ) ) ,
367+ false => {
368+ let ioerr = IoError {
369+ kind : MismatchedFileTypeForOperation ,
370+ desc : "Cannot do rmdir() on a non-directory" ,
371+ detail :
372+ Some ( fmt ! ( "%s is a non-directory; can't rmdir it" , self . get_path( ) . to_str( ) ) )
373+ } ;
374+ io_error:: cond. raise ( ioerr) ;
375+ }
376+ }
377+ } ,
378+ None =>
379+ io_error:: cond. raise ( IoError {
380+ kind : PathDoesntExist ,
381+ desc : "path doesn't exist" ,
382+ detail : Some ( fmt ! ( "%s doesn't exist; can't rmdir it" , self . get_path( ) . to_str( ) ) )
383+ } )
334384 }
335385 }
336- fn is_dir (&self) -> bool {
337-
386+ fn readdir ( & self ) -> ~ [ ~ str ] {
387+ ~ [ ]
338388 }
339- fn create(&self);
340- fn get_subdirs(&self, filter: &str) -> ~[Path];
341- fn get_files(&self, filter: &str) -> ~[Path];
389+ //fn get_subdirs(&self, filter: &str) -> ~[Path];
390+ //fn get_files(&self, filter: &str) -> ~[Path];
342391}
343- */
392+
393+ /// FIXME: DOCS
394+ impl DirectoryInfo for Path { }
344395
345396fn file_test_smoke_test_impl ( ) {
346397 do run_in_mt_newsched_task {
@@ -594,8 +645,21 @@ fn file_test_fileinfo_check_exists_before_and_after_file_creation() {
594645 let mut w = file. open_writer ( Create ) ;
595646 w. write ( msg) ;
596647 }
597- assert ! ( file. file_exists ( ) ) ;
648+ assert ! ( file. exists ( ) ) ;
598649 file. unlink ( ) ;
599- assert ! ( !file. file_exists( ) ) ;
650+ assert ! ( !file. exists( ) ) ;
651+ }
652+ }
653+
654+ #[ test]
655+ fn file_test_directoryinfo_check_exists_before_and_after_mkdir ( ) {
656+ do run_in_mt_newsched_task {
657+ let dir = & Path ( "./tmp/before_and_after_dir" ) ;
658+ assert ! ( !dir. exists( ) ) ;
659+ dir. mkdir ( ) ;
660+ assert ! ( dir. exists( ) ) ;
661+ assert ! ( dir. is_dir( ) ) ;
662+ dir. rmdir ( ) ;
663+ assert ! ( !dir. exists( ) ) ;
600664 }
601665}
0 commit comments