11
11
use prelude:: * ;
12
12
use super :: support:: PathLike ;
13
13
use super :: { Reader , Writer , Seek } ;
14
- use super :: SeekStyle ;
15
- use rt:: rtio:: { RtioFileDescriptor , IoFactory , IoFactoryObject } ;
14
+ use super :: { SeekSet , SeekStyle } ;
15
+ use rt:: rtio:: { RtioFileStream , IoFactory , IoFactoryObject } ;
16
16
use rt:: io:: { io_error, read_error, EndOfFile } ;
17
17
use rt:: local:: Local ;
18
18
use rt:: test:: * ;
19
19
use libc:: { O_RDWR , O_RDONLY , O_WRONLY , S_IWUSR , S_IRUSR ,
20
20
O_CREAT , O_TRUNC , O_APPEND } ;
21
21
22
- /// # FIXME #7785
23
- /// * Ugh, this is ridiculous. What is the best way to represent these options?
22
+ /// Instructions on how to open a file and return a `FileStream`.
24
23
enum FileMode {
25
24
/// Opens an existing file. IoError if file does not exist.
26
25
Open ,
@@ -36,15 +35,29 @@ enum FileMode {
36
35
CreateOrTruncate ,
37
36
}
38
37
38
+ /// How should the file be opened? `FileStream`s opened with `Read` will
39
+ /// raise an `io_error` condition if written to.
39
40
enum FileAccess {
40
41
Read ,
41
42
Write ,
42
43
ReadWrite
43
44
}
44
45
46
+ /// Abstraction representing *positional* access to a file. In this case,
47
+ /// *positional* refers to it keeping an encounter *cursor* of where in the
48
+ /// file a subsequent `read` or `write` will begin from. Users of a `FileStream`
49
+ /// can `seek` to move the cursor to a given location *within the bounds of the
50
+ /// file* and can ask to have the `FileStream` `tell` them the location, in
51
+ /// bytes, of the cursor.
52
+ ///
53
+ /// This abstraction is roughly modeled on the access workflow as represented
54
+ /// by `open(2)`, `read(2)`, `write(2)` and friends.
55
+ ///
56
+ /// The `open` and `unlink` static methods are provided to manage creation/removal
57
+ /// of files. All other methods operatin on an instance of `FileStream`.
45
58
pub struct FileStream {
46
- fd : ~RtioFileDescriptor ,
47
- last_nread : int
59
+ fd : ~RtioFileStream ,
60
+ last_nread : int ,
48
61
}
49
62
50
63
impl FileStream {
@@ -101,7 +114,7 @@ impl FileStream {
101
114
102
115
impl Reader for FileStream {
103
116
fn read ( & mut self , buf : & mut [ u8 ] ) -> Option < uint > {
104
- match self . fd . read ( buf, 0 ) {
117
+ match self . fd . read ( buf) {
105
118
Ok ( read) => {
106
119
self . last_nread = read;
107
120
match read {
@@ -126,21 +139,54 @@ impl Reader for FileStream {
126
139
127
140
impl Writer for FileStream {
128
141
fn write ( & mut self , buf : & [ u8 ] ) {
129
- match self . fd . write ( buf, 0 ) {
142
+ match self . fd . write ( buf) {
130
143
Ok ( _) => ( ) ,
131
144
Err ( ioerr) => {
132
145
io_error:: cond. raise ( ioerr) ;
133
146
}
134
147
}
135
148
}
136
149
137
- fn flush ( & mut self ) { fail ! ( ) }
150
+ fn flush ( & mut self ) {
151
+ match self . fd . flush ( ) {
152
+ Ok ( _) => ( ) ,
153
+ Err ( ioerr) => {
154
+ read_error:: cond. raise ( ioerr) ;
155
+ }
156
+ }
157
+ }
138
158
}
139
159
140
160
impl Seek for FileStream {
141
- fn tell ( & self ) -> u64 { fail ! ( ) }
161
+ fn tell ( & self ) -> u64 {
162
+ let res = self . fd . tell ( ) ;
163
+ match res {
164
+ Ok ( cursor) => cursor,
165
+ Err ( ioerr) => {
166
+ read_error:: cond. raise ( ioerr) ;
167
+ return -1 ;
168
+ }
169
+ }
170
+ }
142
171
143
- fn seek ( & mut self , _pos : i64 , _style : SeekStyle ) { fail ! ( ) }
172
+ fn seek ( & mut self , pos : i64 , style : SeekStyle ) {
173
+ use libc:: { SEEK_SET , SEEK_CUR , SEEK_END } ;
174
+ let whence = match style {
175
+ SeekSet => SEEK_SET ,
176
+ SeekCur => SEEK_CUR ,
177
+ SeekEnd => SEEK_END
178
+ } as i64 ;
179
+ match self . fd . seek ( pos, whence) {
180
+ Ok ( _) => {
181
+ // successful seek resets EOF indocator
182
+ self . last_nread = -1 ;
183
+ ( )
184
+ } ,
185
+ Err ( ioerr) => {
186
+ read_error:: cond. raise ( ioerr) ;
187
+ }
188
+ }
189
+ }
144
190
}
145
191
146
192
fn file_test_smoke_test_impl ( ) {
@@ -166,7 +212,7 @@ fn file_test_smoke_test_impl() {
166
212
}
167
213
168
214
#[ test]
169
- fn file_test_smoke_test ( ) {
215
+ fn file_test_io_smoke_test ( ) {
170
216
file_test_smoke_test_impl ( ) ;
171
217
}
172
218
@@ -184,17 +230,15 @@ fn file_test_invalid_path_opened_without_create_should_raise_condition_impl() {
184
230
}
185
231
}
186
232
#[ test]
187
- fn file_test_invalid_path_opened_without_create_should_raise_condition ( ) {
233
+ fn file_test_io_invalid_path_opened_without_create_should_raise_condition ( ) {
188
234
file_test_invalid_path_opened_without_create_should_raise_condition_impl ( ) ;
189
235
}
190
236
191
237
fn file_test_unlinking_invalid_path_should_raise_condition_impl ( ) {
192
- use io;
193
238
do run_in_newsched_task {
194
239
let filename = & Path ( "./another_file_that_does_not_exist.txt" ) ;
195
240
let mut called = false ;
196
241
do io_error:: cond. trap ( |e| {
197
- io:: println ( fmt ! ( "condition kind: %?" , e. kind) ) ;
198
242
called = true ;
199
243
} ) . inside {
200
244
FileStream :: unlink ( filename) ;
@@ -203,6 +247,70 @@ fn file_test_unlinking_invalid_path_should_raise_condition_impl() {
203
247
}
204
248
}
205
249
#[ test]
206
- fn file_test_unlinking_invalid_path_should_raise_condition ( ) {
250
+ fn file_test_iounlinking_invalid_path_should_raise_condition ( ) {
207
251
file_test_unlinking_invalid_path_should_raise_condition_impl ( ) ;
208
252
}
253
+
254
+ fn file_test_io_non_positional_read_impl ( ) {
255
+ do run_in_newsched_task {
256
+ use str;
257
+ let message = "ten-four" ;
258
+ let mut read_mem = [ 0 , .. 8 ] ;
259
+ let filename = & Path ( "./rt_io_file_test_positional.txt" ) ;
260
+ {
261
+ let mut rw_stream = FileStream :: open ( filename, Create , ReadWrite ) . unwrap ( ) ;
262
+ rw_stream. write ( message. as_bytes ( ) ) ;
263
+ }
264
+ {
265
+ let mut read_stream = FileStream :: open ( filename, Open , Read ) . unwrap ( ) ;
266
+ {
267
+ let read_buf = read_mem. mut_slice ( 0 , 4 ) ;
268
+ read_stream. read ( read_buf) ;
269
+ }
270
+ {
271
+ let read_buf = read_mem. mut_slice ( 4 , 8 ) ;
272
+ read_stream. read ( read_buf) ;
273
+ }
274
+ }
275
+ FileStream :: unlink ( filename) ;
276
+ let read_str = str:: from_bytes ( read_mem) ;
277
+ assert ! ( read_str == message. to_owned( ) ) ;
278
+ }
279
+ }
280
+
281
+ #[ test]
282
+ fn file_test_io_non_positional_read ( ) {
283
+ file_test_io_non_positional_read_impl ( ) ;
284
+ }
285
+
286
+ fn file_test_io_seeking_impl ( ) {
287
+ do run_in_newsched_task {
288
+ use str;
289
+ let message = "ten-four" ;
290
+ let mut read_mem = [ 0 , .. 4 ] ;
291
+ let set_cursor = 4 as u64 ;
292
+ let mut tell_pos_pre_read;
293
+ let mut tell_pos_post_read;
294
+ let filename = & Path ( "./rt_io_file_test_seeking.txt" ) ;
295
+ {
296
+ let mut rw_stream = FileStream :: open ( filename, Create , ReadWrite ) . unwrap ( ) ;
297
+ rw_stream. write ( message. as_bytes ( ) ) ;
298
+ }
299
+ {
300
+ let mut read_stream = FileStream :: open ( filename, Open , Read ) . unwrap ( ) ;
301
+ read_stream. seek ( set_cursor as i64 , SeekSet ) ;
302
+ tell_pos_pre_read = read_stream. tell ( ) ;
303
+ read_stream. read ( read_mem) ;
304
+ tell_pos_post_read = read_stream. tell ( ) ;
305
+ }
306
+ FileStream :: unlink ( filename) ;
307
+ let read_str = str:: from_bytes ( read_mem) ;
308
+ assert ! ( read_str == message. slice( 4 , 8 ) . to_owned( ) ) ;
309
+ assert ! ( tell_pos_pre_read == set_cursor) ;
310
+ assert ! ( tell_pos_post_read == message. len( ) as u64 ) ;
311
+ }
312
+ }
313
+ #[ test]
314
+ fn file_test_io_seek_and_tell_smoke_test ( ) {
315
+ file_test_io_seeking_impl ( ) ;
316
+ }
0 commit comments