@@ -12,29 +12,41 @@ import CoreFoundation
1212open class FileHandle : NSObject , NSSecureCoding {
1313#if os(Windows)
1414 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+
1525#else
1626 private var _fd : Int32
17- #endif
18- private var _closeOnDealloc : Bool
1927
20- @available ( windows, unavailable,
21- message: " cannot perform non-owning handle to fd conversion " )
2228 open var fileDescriptor : Int32 {
23- #if os(Windows)
24- return - 1
25- #else
2629 return _fd
27- #endif
2830 }
2931
32+ private func _checkFileHandle( ) {
33+ precondition ( _fd >= 0 , " Bad file descriptor " )
34+ }
35+ #endif
36+
37+ private var _closeOnDealloc : Bool
38+
39+
3040 open var readabilityHandler : ( ( FileHandle ) -> Void ) ? = {
3141 ( FileHandle) -> Void in NSUnimplemented ( )
3242 }
43+
3344 open var writeabilityHandler : ( ( FileHandle ) -> Void ) ? = {
3445 ( FileHandle) -> Void in NSUnimplemented ( )
3546 }
3647
3748 open var availableData : Data {
49+ _checkFileHandle ( )
3850 do {
3951 let readResult = try _readDataOfLength ( Int . max, untilEOF: false )
4052 return readResult. toData ( )
@@ -44,10 +56,12 @@ open class FileHandle : NSObject, NSSecureCoding {
4456 }
4557
4658 open func readDataToEndOfFile( ) -> Data {
59+ _checkFileHandle ( )
4760 return readData ( ofLength: Int . max)
4861 }
4962
5063 open func readData( ofLength length: Int ) -> Data {
64+ _checkFileHandle ( )
5165 do {
5266 let readResult = try _readDataOfLength ( length, untilEOF: true )
5367 return readResult. toData ( )
@@ -58,7 +72,6 @@ open class FileHandle : NSObject, NSSecureCoding {
5872
5973 internal func _readDataOfLength( _ length: Int , untilEOF: Bool , options: NSData . ReadingOptions = [ ] ) throws -> NSData . NSDataReadResult {
6074#if os(Windows)
61- precondition ( _handle != INVALID_HANDLE_VALUE, " invalid file handle " )
6275
6376 if length == 0 && !untilEOF {
6477 // Nothing requested, return empty response
@@ -131,7 +144,6 @@ open class FileHandle : NSObject, NSSecureCoding {
131144 free ( buffer)
132145 }
133146#else
134- precondition ( _fd >= 0 , " Bad file descriptor " )
135147 if length == 0 && !untilEOF {
136148 // Nothing requested, return empty response
137149 return NSData . NSDataReadResult ( bytes: nil , length: 0 , deallocator: nil )
@@ -202,78 +214,94 @@ open class FileHandle : NSObject, NSSecureCoding {
202214 }
203215
204216 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 ( )
218218 data. enumerateBytes ( ) { ( bytes, range, stop) in
219219 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)
221221 } 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 )
223253 }
254+ bytesRemaining -= bytesWritten
224255 }
225256#endif
226257 }
227258
228259 // TODO: Error handling.
229260
230261 open var offsetInFile : UInt64 {
262+ _checkFileHandle ( )
231263#if os(Windows)
232- precondition ( _handle != INVALID_HANDLE_VALUE, " invalid file handle " )
233264 var liPointer : LARGE_INTEGER = LARGE_INTEGER ( QuadPart: 0 )
234265 if SetFilePointerEx ( _handle, LARGE_INTEGER ( QuadPart: 0 ) ,
235266 & liPointer, DWORD ( FILE_CURRENT) ) == FALSE {
236267 fatalError ( " SetFilePointerEx failed " )
237268 }
238269 return UInt64 ( liPointer. QuadPart)
239270#else
240- precondition ( _fd >= 0 , " Bad file descriptor " )
241271 return UInt64 ( lseek ( _fd, 0 , SEEK_CUR) )
242272#endif
243273 }
244274
245275 @discardableResult
246276 open func seekToEndOfFile( ) -> UInt64 {
277+ _checkFileHandle ( )
247278#if os(Windows)
248- precondition ( _handle != INVALID_HANDLE_VALUE, " invalid file handle " )
249279 var liPointer : LARGE_INTEGER = LARGE_INTEGER ( QuadPart: 0 )
250280 if SetFilePointerEx ( _handle, LARGE_INTEGER ( QuadPart: 0 ) ,
251281 & liPointer, DWORD ( FILE_END) ) == FALSE {
252282 fatalError ( " SetFilePointerEx failed " )
253283 }
254284 return UInt64 ( liPointer. QuadPart)
255285#else
256- precondition ( _fd >= 0 , " Bad file descriptor " )
257286 return UInt64 ( lseek ( _fd, 0 , SEEK_END) )
258287#endif
259288 }
260289
261290 open func seek( toFileOffset offset: UInt64 ) {
291+ _checkFileHandle ( )
262292#if os(Windows)
263- precondition ( _handle != INVALID_HANDLE_VALUE, " invalid file handle " )
264293 if SetFilePointerEx ( _handle, LARGE_INTEGER ( QuadPart: LONGLONG ( offset) ) ,
265294 nil , DWORD ( FILE_BEGIN) ) == FALSE {
266295 fatalError ( " SetFilePointerEx failed " )
267296 }
268297#else
269- precondition ( _fd >= 0 , " Bad file descriptor " )
270298 lseek ( _fd, off_t ( offset) , SEEK_SET)
271299#endif
272300 }
273301
274302 open func truncateFile( atOffset offset: UInt64 ) {
303+ _checkFileHandle ( )
275304#if os(Windows)
276- precondition ( _handle != INVALID_HANDLE_VALUE, " invalid file handle " )
277305 if SetFilePointerEx ( _handle, LARGE_INTEGER ( QuadPart: LONGLONG ( offset) ) ,
278306 nil , DWORD ( FILE_BEGIN) ) == FALSE {
279307 fatalError ( " SetFilePointerEx failed " )
@@ -282,21 +310,29 @@ open class FileHandle : NSObject, NSSecureCoding {
282310 fatalError ( " SetEndOfFile failed " )
283311 }
284312#else
285- precondition ( _fd >= 0 , " Bad file descriptor " )
286313 if lseek ( _fd, off_t ( offset) , SEEK_SET) < 0 { fatalError ( " lseek() failed. " ) }
287314 if ftruncate ( _fd, off_t ( offset) ) < 0 { fatalError ( " ftruncate() failed. " ) }
288315#endif
289316 }
290317
291318 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 {
292328#if os(Windows)
293- precondition ( _handle != INVALID_HANDLE_VALUE, " invalid file handle " )
294329 if FlushFileBuffers ( _handle) == FALSE {
295- fatalError ( " FlushFileBuffers failed: \( GetLastError ( ) ) " )
330+ throw _NSErrorWithErrno ( Int32 ( GetLastError ( ) ) , reading : false )
296331 }
297332#else
298- precondition ( _fd >= 0 , " Bad file descriptor " )
299- fsync ( _fd)
333+ guard fsync ( _fd) == 0 else {
334+ throw _NSErrorWithErrno ( errno, reading: false )
335+ }
300336#endif
301337 }
302338
0 commit comments