@@ -12,29 +12,41 @@ import CoreFoundation
12
12
open class FileHandle : NSObject , NSSecureCoding {
13
13
#if os(Windows)
14
14
private var _handle : HANDLE
15
+
16
+ @available ( windows, unavailable, message: " cannot perform non-owning handle to fd conversion " )
17
+ open var fileDescriptor : Int32 {
18
+ NSUnsupported ( )
19
+ }
20
+
21
+ private func _checkFileHandle( ) {
22
+ precondition ( _handle != INVALID_HANDLE_VALUE, " Invalid file handle " )
23
+ }
24
+
15
25
#else
16
26
private var _fd : Int32
17
- #endif
18
- private var _closeOnDealloc : Bool
19
27
20
- @available ( windows, unavailable,
21
- message: " cannot perform non-owning handle to fd conversion " )
22
28
open var fileDescriptor : Int32 {
23
- #if os(Windows)
24
- return - 1
25
- #else
26
29
return _fd
27
- #endif
28
30
}
29
31
32
+ private func _checkFileHandle( ) {
33
+ precondition ( _fd >= 0 , " Bad file descriptor " )
34
+ }
35
+ #endif
36
+
37
+ private var _closeOnDealloc : Bool
38
+
39
+
30
40
open var readabilityHandler : ( ( FileHandle ) -> Void ) ? = {
31
41
( FileHandle) -> Void in NSUnimplemented ( )
32
42
}
43
+
33
44
open var writeabilityHandler : ( ( FileHandle ) -> Void ) ? = {
34
45
( FileHandle) -> Void in NSUnimplemented ( )
35
46
}
36
47
37
48
open var availableData : Data {
49
+ _checkFileHandle ( )
38
50
do {
39
51
let readResult = try _readDataOfLength ( Int . max, untilEOF: false )
40
52
return readResult. toData ( )
@@ -44,10 +56,12 @@ open class FileHandle : NSObject, NSSecureCoding {
44
56
}
45
57
46
58
open func readDataToEndOfFile( ) -> Data {
59
+ _checkFileHandle ( )
47
60
return readData ( ofLength: Int . max)
48
61
}
49
62
50
63
open func readData( ofLength length: Int ) -> Data {
64
+ _checkFileHandle ( )
51
65
do {
52
66
let readResult = try _readDataOfLength ( length, untilEOF: true )
53
67
return readResult. toData ( )
@@ -58,7 +72,6 @@ open class FileHandle : NSObject, NSSecureCoding {
58
72
59
73
internal func _readDataOfLength( _ length: Int , untilEOF: Bool , options: NSData . ReadingOptions = [ ] ) throws -> NSData . NSDataReadResult {
60
74
#if os(Windows)
61
- precondition ( _handle != INVALID_HANDLE_VALUE, " invalid file handle " )
62
75
63
76
if length == 0 && !untilEOF {
64
77
// Nothing requested, return empty response
@@ -131,7 +144,6 @@ open class FileHandle : NSObject, NSSecureCoding {
131
144
free ( buffer)
132
145
}
133
146
#else
134
- precondition ( _fd >= 0 , " Bad file descriptor " )
135
147
if length == 0 && !untilEOF {
136
148
// Nothing requested, return empty response
137
149
return NSData . NSDataReadResult ( bytes: nil , length: 0 , deallocator: nil )
@@ -202,78 +214,94 @@ open class FileHandle : NSObject, NSSecureCoding {
202
214
}
203
215
204
216
open func write( _ data: Data ) {
205
- #if os(Windows)
206
- precondition ( _handle != INVALID_HANDLE_VALUE, " invalid file handle " )
207
- data. enumerateBytes ( ) { ( bytes, range, stop) in
208
- do {
209
- try NSData . write ( toHandle: self . _handle, path: nil ,
210
- buf: UnsafeRawPointer ( bytes. baseAddress!) ,
211
- length: bytes. count)
212
- } catch {
213
- fatalError ( " Write failure " )
214
- }
215
- }
216
- #else
217
- guard _fd >= 0 else { return }
217
+ _checkFileHandle ( )
218
218
data. enumerateBytes ( ) { ( bytes, range, stop) in
219
219
do {
220
- try NSData . write ( toFileDescriptor : self . _fd , path : nil , buf: UnsafeRawPointer ( bytes. baseAddress!) , length: bytes. count)
220
+ try _write ( buf: UnsafeRawPointer ( bytes. baseAddress!) , length: bytes. count)
221
221
} catch {
222
- fatalError ( " Write failure " )
222
+ fatalError ( " Write failure: \( error) " )
223
+ }
224
+ }
225
+ }
226
+
227
+ internal func _write( buf: UnsafeRawPointer , length: Int ) throws {
228
+ #if os(Windows)
229
+ var bytesRemaining = length
230
+ while bytesRemaining > 0 {
231
+ var bytesWritten : DWORD = 0
232
+ if WriteFile ( handle, buf. advanced ( by: length - bytesRemaining) , DWORD ( bytesRemaining) , & bytesWritten, nil ) == FALSE {
233
+ throw _NSErrorWithErrno ( Int32 ( GetLastError ( ) ) , reading: false , path: nil )
234
+ }
235
+ if BytesWritten == 0 {
236
+ throw _NSErrorWithErrno ( Int32 ( GetLastError ( ) ) , reading: false , path: nil )
237
+ }
238
+ bytesRemaining -= Int ( bytesWritten)
239
+ }
240
+ #else
241
+ var bytesRemaining = length
242
+ while bytesRemaining > 0 {
243
+ var bytesWritten = 0
244
+ repeat {
245
+ #if canImport(Darwin)
246
+ bytesWritten = Darwin . write ( _fd, buf. advanced ( by: length - bytesRemaining) , bytesRemaining)
247
+ #elseif canImport(Glibc)
248
+ bytesWritten = Glibc . write ( _fd, buf. advanced ( by: length - bytesRemaining) , bytesRemaining)
249
+ #endif
250
+ } while ( bytesWritten < 0 && errno == EINTR)
251
+ if bytesWritten <= 0 {
252
+ throw _NSErrorWithErrno ( errno, reading: false , path: nil )
223
253
}
254
+ bytesRemaining -= bytesWritten
224
255
}
225
256
#endif
226
257
}
227
258
228
259
// TODO: Error handling.
229
260
230
261
open var offsetInFile : UInt64 {
262
+ _checkFileHandle ( )
231
263
#if os(Windows)
232
- precondition ( _handle != INVALID_HANDLE_VALUE, " invalid file handle " )
233
264
var liPointer : LARGE_INTEGER = LARGE_INTEGER ( QuadPart: 0 )
234
265
if SetFilePointerEx ( _handle, LARGE_INTEGER ( QuadPart: 0 ) ,
235
266
& liPointer, DWORD ( FILE_CURRENT) ) == FALSE {
236
267
fatalError ( " SetFilePointerEx failed " )
237
268
}
238
269
return UInt64 ( liPointer. QuadPart)
239
270
#else
240
- precondition ( _fd >= 0 , " Bad file descriptor " )
241
271
return UInt64 ( lseek ( _fd, 0 , SEEK_CUR) )
242
272
#endif
243
273
}
244
274
245
275
@discardableResult
246
276
open func seekToEndOfFile( ) -> UInt64 {
277
+ _checkFileHandle ( )
247
278
#if os(Windows)
248
- precondition ( _handle != INVALID_HANDLE_VALUE, " invalid file handle " )
249
279
var liPointer : LARGE_INTEGER = LARGE_INTEGER ( QuadPart: 0 )
250
280
if SetFilePointerEx ( _handle, LARGE_INTEGER ( QuadPart: 0 ) ,
251
281
& liPointer, DWORD ( FILE_END) ) == FALSE {
252
282
fatalError ( " SetFilePointerEx failed " )
253
283
}
254
284
return UInt64 ( liPointer. QuadPart)
255
285
#else
256
- precondition ( _fd >= 0 , " Bad file descriptor " )
257
286
return UInt64 ( lseek ( _fd, 0 , SEEK_END) )
258
287
#endif
259
288
}
260
289
261
290
open func seek( toFileOffset offset: UInt64 ) {
291
+ _checkFileHandle ( )
262
292
#if os(Windows)
263
- precondition ( _handle != INVALID_HANDLE_VALUE, " invalid file handle " )
264
293
if SetFilePointerEx ( _handle, LARGE_INTEGER ( QuadPart: LONGLONG ( offset) ) ,
265
294
nil , DWORD ( FILE_BEGIN) ) == FALSE {
266
295
fatalError ( " SetFilePointerEx failed " )
267
296
}
268
297
#else
269
- precondition ( _fd >= 0 , " Bad file descriptor " )
270
298
lseek ( _fd, off_t ( offset) , SEEK_SET)
271
299
#endif
272
300
}
273
301
274
302
open func truncateFile( atOffset offset: UInt64 ) {
303
+ _checkFileHandle ( )
275
304
#if os(Windows)
276
- precondition ( _handle != INVALID_HANDLE_VALUE, " invalid file handle " )
277
305
if SetFilePointerEx ( _handle, LARGE_INTEGER ( QuadPart: LONGLONG ( offset) ) ,
278
306
nil , DWORD ( FILE_BEGIN) ) == FALSE {
279
307
fatalError ( " SetFilePointerEx failed " )
@@ -282,21 +310,29 @@ open class FileHandle : NSObject, NSSecureCoding {
282
310
fatalError ( " SetEndOfFile failed " )
283
311
}
284
312
#else
285
- precondition ( _fd >= 0 , " Bad file descriptor " )
286
313
if lseek ( _fd, off_t ( offset) , SEEK_SET) < 0 { fatalError ( " lseek() failed. " ) }
287
314
if ftruncate ( _fd, off_t ( offset) ) < 0 { fatalError ( " ftruncate() failed. " ) }
288
315
#endif
289
316
}
290
317
291
318
open func synchronizeFile( ) {
319
+ _checkFileHandle ( )
320
+ do {
321
+ try _synchronizeFile ( )
322
+ } catch {
323
+ fatalError ( " synchronizeFile failed: \( error) " )
324
+ }
325
+ }
326
+
327
+ internal func _synchronizeFile( ) throws {
292
328
#if os(Windows)
293
- precondition ( _handle != INVALID_HANDLE_VALUE, " invalid file handle " )
294
329
if FlushFileBuffers ( _handle) == FALSE {
295
- fatalError ( " FlushFileBuffers failed: \( GetLastError ( ) ) " )
330
+ throw _NSErrorWithErrno ( Int32 ( GetLastError ( ) ) , reading : false )
296
331
}
297
332
#else
298
- precondition ( _fd >= 0 , " Bad file descriptor " )
299
- fsync ( _fd)
333
+ guard fsync ( _fd) == 0 else {
334
+ throw _NSErrorWithErrno ( errno, reading: false )
335
+ }
300
336
#endif
301
337
}
302
338
0 commit comments