@@ -12,7 +12,7 @@ use prelude::*;
12
12
use super :: support:: PathLike ;
13
13
use super :: { Reader , Writer , Seek } ;
14
14
use super :: { SeekStyle , SeekSet , SeekCur , SeekEnd ,
15
- Open , Read , Create , ReadWrite } ;
15
+ Open , Read , Write , Create , ReadWrite } ;
16
16
use rt:: rtio:: { RtioFileStream , IoFactory , IoFactoryObject } ;
17
17
use rt:: io:: { io_error, read_error, EndOfFile ,
18
18
FileMode , FileAccess , FileStat } ;
@@ -57,26 +57,108 @@ pub fn unlink<P: PathLike>(path: &P) {
57
57
}
58
58
}
59
59
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.
69
90
///
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
72
157
pub struct FileStream {
73
158
fd : ~RtioFileStream ,
74
159
last_nread : int ,
75
160
}
76
161
77
- impl FileStream {
78
- }
79
-
80
162
impl Reader for FileStream {
81
163
fn read ( & mut self , buf : & mut [ u8 ] ) -> Option < uint > {
82
164
match self . fd . read ( buf) {
@@ -148,69 +230,85 @@ impl Seek for FileStream {
148
230
}
149
231
}
150
232
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 ( |_| {
166
247
// FIXME: can we do something more useful here?
167
248
} ) . inside {
168
- stat ( self . get_path ( ) )
249
+ mod_stat ( self . get_file_path ( ) )
169
250
}
170
251
}
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 {
172
256
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 ,
184
258
None => false
185
259
}
186
260
}
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 {
188
267
match self . stat ( ) {
189
268
Some ( s) => s. is_file ,
190
- None => {
191
- // FIXME: raise condition
192
- false
193
- }
269
+ None => false
194
270
}
195
271
}
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..
200
280
} ,
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
205
299
}
206
300
}
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 }
214
312
}
215
313
216
314
/*
@@ -244,27 +342,6 @@ impl DirectoryInfo<'self> {
244
342
}
245
343
*/
246
344
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
-
268
345
fn file_test_smoke_test_impl ( ) {
269
346
do run_in_mt_newsched_task {
270
347
let message = "it's alright. have a good time" ;
@@ -412,7 +489,7 @@ fn file_test_io_seek_and_write_impl() {
412
489
read_stream. read ( read_mem) ;
413
490
}
414
491
unlink ( filename) ;
415
- let read_str = str:: from_bytes ( read_mem) ;
492
+ let read_str = str:: from_utf8 ( read_mem) ;
416
493
assert ! ( read_str == final_msg. to_owned( ) ) ;
417
494
}
418
495
}
@@ -463,8 +540,9 @@ fn file_test_io_seek_shakedown() {
463
540
}
464
541
465
542
#[ test]
543
+ #[ ignore( cfg( windows) ) ] // FIXME #8810
466
544
fn file_test_stat_is_correct_on_is_file ( ) {
467
- do run_in_newsched_task {
545
+ do run_in_mt_newsched_task {
468
546
let filename = & Path ( "./tmp/file_stat_correct_on_is_file.txt" ) ;
469
547
{
470
548
let mut fs = open ( filename, Create , ReadWrite ) . unwrap ( ) ;
@@ -476,20 +554,48 @@ fn file_test_stat_is_correct_on_is_file() {
476
554
None => fail ! ( "shouldn't happen" )
477
555
} ;
478
556
assert ! ( stat_res. is_file) ;
557
+ unlink ( filename) ;
479
558
}
480
559
}
481
560
482
561
#[ test]
562
+ #[ ignore( cfg( windows) ) ] // FIXME #8810
483
563
fn 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
+ }
485
574
}
486
575
487
576
#[ test]
577
+ #[ ignore( cfg( windows) ) ] // FIXME #8810
488
578
fn 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
+ }
490
585
}
491
586
492
587
#[ test]
588
+ #[ ignore( cfg( windows) ) ] // FIXME #8810
493
589
fn 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
+ }
495
601
}
0 commit comments