8
8
//
9
9
10
10
import CoreFoundation
11
+ #if os(Windows)
12
+ import WinSDK
13
+ #endif
11
14
12
15
open class FileHandle : NSObject , NSSecureCoding {
16
+ #if os(Windows)
17
+ private var _handle : HANDLE
18
+ #else
13
19
private var _fd : Int32
20
+ #endif
14
21
private var _closeOnDealloc : Bool
15
22
23
+ @available ( windows, unavailable,
24
+ message: " cannot perform non-owning handle to fd conversion " )
16
25
open var fileDescriptor : Int32 {
26
+ #if os(Windows)
27
+ return - 1
28
+ #else
17
29
return _fd
30
+ #endif
18
31
}
19
32
20
33
open var readabilityHandler : ( ( FileHandle ) -> Void ) ? = {
@@ -47,6 +60,79 @@ open class FileHandle : NSObject, NSSecureCoding {
47
60
}
48
61
49
62
internal func _readDataOfLength( _ length: Int , untilEOF: Bool , options: NSData . ReadingOptions = [ ] ) throws -> NSData . NSDataReadResult {
63
+ #if os(Windows)
64
+ if _handle == INVALID_HANDLE_VALUE {
65
+ return NSData . NSDataReadResult ( bytes: nil , length: 0 , deallocator: nil )
66
+ }
67
+ if length == 0 && !untilEOF {
68
+ // Nothing requested, return empty response
69
+ return NSData . NSDataReadResult ( bytes: nil , length: 0 , deallocator: nil )
70
+ }
71
+
72
+ var fiFileInfo : BY_HANDLE_FILE_INFORMATION = BY_HANDLE_FILE_INFORMATION ( )
73
+ if GetFileInformationByHandle ( _handle, & fiFileInfo) == FALSE {
74
+ throw NSError ( domain: NSPOSIXErrorDomain, code: Int ( GetLastError ( ) ) ,
75
+ userInfo: nil )
76
+ }
77
+
78
+ if fiFileInfo. dwFileAttributes & DWORD ( FILE_ATTRIBUTE_NORMAL) == FILE_ATTRIBUTE_NORMAL {
79
+ if options. contains ( . alwaysMapped) {
80
+ let hMapping : HANDLE =
81
+ CreateFileMappingA ( _handle, nil , DWORD ( PAGE_READONLY) , 0 , 0 , nil )
82
+ if hMapping == HANDLE ( bitPattern: 0 ) {
83
+ fatalError ( " CrateFileMappingA failed " )
84
+ }
85
+
86
+ let szFileSize : UInt64 = ( UInt64 ( fiFileInfo. nFileSizeHigh) << 32 ) | UInt64 ( fiFileInfo. nFileSizeLow << 0 )
87
+ let szMapSize : UInt64 = Swift . min ( UInt64 ( length) , szFileSize)
88
+ let pData : UnsafeMutableRawPointer =
89
+ MapViewOfFile ( hMapping, DWORD ( FILE_MAP_READ) , 0 , 0 , szMapSize)
90
+
91
+ return NSData . NSDataReadResult ( bytes: pData, length: Int ( szMapSize) ) { buffer, length in
92
+ if UnmapViewOfFile ( buffer) == FALSE {
93
+ fatalError ( " UnmapViewOfFile failed " )
94
+ }
95
+ if CloseHandle ( hMapping) == FALSE {
96
+ fatalError ( " CloseHandle failed " )
97
+ }
98
+ }
99
+ }
100
+ }
101
+
102
+ let blockSize : Int = 8 * 1024
103
+ var allocated : Int = blockSize
104
+ var buffer : UnsafeMutableRawPointer = malloc ( allocated) !
105
+ var total : Int = 0
106
+
107
+ defer { free ( buffer) }
108
+
109
+ while total < length {
110
+ let remaining = length - total
111
+ let BytesToRead : DWORD = DWORD ( min ( blockSize, remaining) )
112
+
113
+ if ( allocated - total) < BytesToRead {
114
+ allocated *= 2
115
+ buffer = _CFReallocf ( buffer, allocated)
116
+ }
117
+
118
+ var BytesRead : DWORD = 0
119
+ if ReadFile ( _handle, buffer. advanced ( by: total) , BytesToRead, & BytesRead, nil ) == FALSE {
120
+ throw NSError ( domain: NSPOSIXErrorDomain, code: Int ( GetLastError ( ) ) , userInfo: nil )
121
+ }
122
+ total += Int ( BytesRead)
123
+ if BytesRead == 0 || !untilEOF {
124
+ break
125
+ }
126
+ }
127
+
128
+ if total == 0 {
129
+ return NSData . NSDataReadResult ( bytes: nil , length: 0 , deallocator: nil )
130
+ }
131
+
132
+ buffer = _CFReallocf ( buffer, total)
133
+ let data = buffer. bindMemory ( to: UInt8 . self, capacity: total)
134
+ return NSData . NSDataReadResult ( bytes: data, length: total)
135
+ #else
50
136
precondition ( _fd >= 0 , " Bad file descriptor " )
51
137
if length == 0 && !untilEOF {
52
138
// Nothing requested, return empty response
@@ -114,9 +200,22 @@ open class FileHandle : NSObject, NSSecureCoding {
114
200
return NSData . NSDataReadResult ( bytes: bytePtr, length: total) { buffer, length in
115
201
free ( buffer)
116
202
}
203
+ #endif
117
204
}
118
-
205
+
119
206
open func write( _ data: Data ) {
207
+ #if os(Windows)
208
+ guard _handle != INVALID_HANDLE_VALUE else { return }
209
+ data. enumerateBytes ( ) { ( bytes, range, stop) in
210
+ do {
211
+ try NSData . write ( toHandle: self . _handle, path: nil ,
212
+ buf: UnsafeRawPointer ( bytes. baseAddress!) ,
213
+ length: bytes. count)
214
+ } catch {
215
+ fatalError ( " Write failure " )
216
+ }
217
+ }
218
+ #else
120
219
guard _fd >= 0 else { return }
121
220
data. enumerateBytes ( ) { ( bytes, range, stop) in
122
221
do {
@@ -125,44 +224,136 @@ open class FileHandle : NSObject, NSSecureCoding {
125
224
fatalError ( " Write failure " )
126
225
}
127
226
}
227
+ #endif
128
228
}
129
-
229
+
130
230
// TODO: Error handling.
131
-
231
+
132
232
open var offsetInFile : UInt64 {
233
+ #if os(Windows)
234
+ if _handle == INVALID_HANDLE_VALUE { return 0 }
235
+ var liPointer : LARGE_INTEGER = LARGE_INTEGER ( QuadPart: 0 )
236
+ if SetFilePointerEx ( _handle, LARGE_INTEGER ( QuadPart: 0 ) ,
237
+ & liPointer, DWORD ( FILE_CURRENT) ) == FALSE {
238
+ fatalError ( " SetFilePointerEx failed " )
239
+ }
240
+ return UInt64 ( liPointer. QuadPart)
241
+ #else
133
242
precondition ( _fd >= 0 , " Bad file descriptor " )
134
243
return UInt64 ( lseek ( _fd, 0 , SEEK_CUR) )
244
+ #endif
135
245
}
136
-
246
+
137
247
@discardableResult
138
248
open func seekToEndOfFile( ) -> UInt64 {
249
+ #if os(Windows)
250
+ if _handle == INVALID_HANDLE_VALUE { return 0 }
251
+ var liPointer : LARGE_INTEGER = LARGE_INTEGER ( QuadPart: 0 )
252
+ if SetFilePointerEx ( _handle, LARGE_INTEGER ( QuadPart: 0 ) ,
253
+ & liPointer, DWORD ( FILE_END) ) == FALSE {
254
+ fatalError ( " SetFilePointerEx failed " )
255
+ }
256
+ return UInt64 ( liPointer. QuadPart)
257
+ #else
139
258
precondition ( _fd >= 0 , " Bad file descriptor " )
140
259
return UInt64 ( lseek ( _fd, 0 , SEEK_END) )
260
+ #endif
141
261
}
142
-
262
+
143
263
open func seek( toFileOffset offset: UInt64 ) {
264
+ #if os(Windows)
265
+ if _handle == INVALID_HANDLE_VALUE { return }
266
+ if SetFilePointerEx ( _handle, LARGE_INTEGER ( QuadPart: LONGLONG ( offset) ) ,
267
+ nil , DWORD ( FILE_BEGIN) ) == FALSE {
268
+ fatalError ( " SetFilePointerEx failed " )
269
+ }
270
+ #else
144
271
precondition ( _fd >= 0 , " Bad file descriptor " )
145
272
lseek ( _fd, off_t ( offset) , SEEK_SET)
273
+ #endif
146
274
}
147
275
148
276
open func truncateFile( atOffset offset: UInt64 ) {
277
+ #if os(Windows)
278
+ if _handle == INVALID_HANDLE_VALUE { return }
279
+ if SetFilePointerEx ( _handle, LARGE_INTEGER ( QuadPart: LONGLONG ( offset) ) ,
280
+ nil , DWORD ( FILE_BEGIN) ) == FALSE {
281
+ fatalError ( " SetFilePointerEx failed " )
282
+ }
283
+ if SetEndOfFile ( _handle) == FALSE {
284
+ fatalError ( " SetEndOfFile failed " )
285
+ }
286
+ #else
149
287
precondition ( _fd >= 0 , " Bad file descriptor " )
150
288
if lseek ( _fd, off_t ( offset) , SEEK_SET) < 0 { fatalError ( " lseek() failed. " ) }
151
289
if ftruncate ( _fd, off_t ( offset) ) < 0 { fatalError ( " ftruncate() failed. " ) }
290
+ #endif
152
291
}
153
292
154
293
open func synchronizeFile( ) {
294
+ #if os(Windows)
295
+ if _handle == INVALID_HANDLE_VALUE { return }
296
+ if FlushFileBuffers ( _handle) == FALSE {
297
+ fatalError ( " FlushFileBuffers failed: \( GetLastError ( ) ) " )
298
+ }
299
+ #else
155
300
precondition ( _fd >= 0 , " Bad file descriptor " )
156
301
fsync ( _fd)
302
+ #endif
157
303
}
158
-
304
+
159
305
open func closeFile( ) {
306
+ #if os(Windows)
307
+ if _handle != INVALID_HANDLE_VALUE {
308
+ if CloseHandle ( _handle) == FALSE {
309
+ fatalError ( " CloseHandle failed " )
310
+ }
311
+ _handle = INVALID_HANDLE_VALUE
312
+ }
313
+ #else
160
314
if _fd >= 0 {
161
315
close ( _fd)
162
316
_fd = - 1
163
317
}
318
+ #endif
319
+ }
320
+
321
+ #if os(Windows)
322
+ public init ( handle: HANDLE , closeOnDealloc closeopt: Bool ) {
323
+ _handle = handle
324
+ _closeOnDealloc = closeopt
164
325
}
165
326
327
+ public init ( fileDescriptor fd: Int32 , closeOnDealloc closeopt: Bool ) {
328
+ if ( closeopt) {
329
+ var handle : HANDLE ?
330
+ if DuplicateHandle ( GetCurrentProcess ( ) ,
331
+ HANDLE ( bitPattern: _get_osfhandle ( fd) ) !,
332
+ GetCurrentProcess ( ) , & handle,
333
+ DWORD ( DUPLICATE_SAME_ACCESS) , FALSE, 0 ) == FALSE {
334
+ fatalError ( " DuplicateHandle() failed " )
335
+ }
336
+ _close ( fd)
337
+ _handle = handle!
338
+ _closeOnDealloc = true
339
+ } else {
340
+ _handle = HANDLE ( bitPattern: _get_osfhandle ( fd) ) !
341
+ _closeOnDealloc = false
342
+ }
343
+ }
344
+
345
+ public convenience init ( fileDescriptor fd: Int32 ) {
346
+ self . init ( handle: HANDLE ( bitPattern: _get_osfhandle ( fd) ) !,
347
+ closeOnDealloc: false )
348
+ }
349
+
350
+ internal convenience init ? ( path: String , flags: Int32 , createMode: Int ) {
351
+ self . init ( fileDescriptor: _CFOpenFileWithMode ( path, flags,
352
+ mode_t ( createMode) ) ,
353
+ closeOnDealloc: true )
354
+ if _handle == INVALID_HANDLE_VALUE { return nil }
355
+ }
356
+ #else
166
357
public init ( fileDescriptor fd: Int32 , closeOnDealloc closeopt: Bool ) {
167
358
_fd = fd
168
359
_closeOnDealloc = closeopt
@@ -180,14 +371,25 @@ open class FileHandle : NSObject, NSSecureCoding {
180
371
return nil
181
372
}
182
373
}
183
-
374
+ #endif
375
+
184
376
deinit {
185
- if _fd >= 0 && _closeOnDealloc {
377
+ guard _closeOnDealloc == true else { return }
378
+ #if os(Windows)
379
+ if _handle != INVALID_HANDLE_VALUE {
380
+ if CloseHandle ( _handle) == FALSE {
381
+ fatalError ( " CloseHandle failed " )
382
+ }
383
+ _handle = INVALID_HANDLE_VALUE
384
+ }
385
+ #else
386
+ if _fd >= 0 {
186
387
close ( _fd)
187
388
_fd = - 1
188
389
}
390
+ #endif
189
391
}
190
-
392
+
191
393
public required init ? ( coder: NSCoder ) {
192
394
NSUnimplemented ( )
193
395
}
@@ -324,31 +526,31 @@ public let NSFileHandleNotificationDataItem: String = "NSFileHandleNotificationD
324
526
public let NSFileHandleNotificationFileHandleItem : String = " NSFileHandleNotificationFileHandleItem "
325
527
326
528
extension FileHandle {
327
- open func readInBackgroundAndNotify( forModes modes: [ RunLoopMode ] ? ) {
529
+ open func readInBackgroundAndNotify( forModes modes: [ RunLoop . Mode ] ? ) {
328
530
NSUnimplemented ( )
329
531
}
330
532
331
533
open func readInBackgroundAndNotify( ) {
332
534
NSUnimplemented ( )
333
535
}
334
536
335
- open func readToEndOfFileInBackgroundAndNotify( forModes modes: [ RunLoopMode ] ? ) {
537
+ open func readToEndOfFileInBackgroundAndNotify( forModes modes: [ RunLoop . Mode ] ? ) {
336
538
NSUnimplemented ( )
337
539
}
338
540
339
541
open func readToEndOfFileInBackgroundAndNotify( ) {
340
542
NSUnimplemented ( )
341
543
}
342
544
343
- open func acceptConnectionInBackgroundAndNotify( forModes modes: [ RunLoopMode ] ? ) {
545
+ open func acceptConnectionInBackgroundAndNotify( forModes modes: [ RunLoop . Mode ] ? ) {
344
546
NSUnimplemented ( )
345
547
}
346
548
347
549
open func acceptConnectionInBackgroundAndNotify( ) {
348
550
NSUnimplemented ( )
349
551
}
350
552
351
- open func waitForDataInBackgroundAndNotify( forModes modes: [ RunLoopMode ] ? ) {
553
+ open func waitForDataInBackgroundAndNotify( forModes modes: [ RunLoop . Mode ] ? ) {
352
554
NSUnimplemented ( )
353
555
}
354
556
@@ -362,6 +564,17 @@ open class Pipe: NSObject {
362
564
public let fileHandleForWriting : FileHandle
363
565
364
566
public override init ( ) {
567
+ #if os(Windows)
568
+ var hReadPipe : HANDLE ?
569
+ var hWritePipe : HANDLE ?
570
+ if CreatePipe ( & hReadPipe, & hWritePipe, nil , 0 ) == FALSE {
571
+ fatalError ( " CreatePipe failed " )
572
+ }
573
+ self . fileHandleForReading = FileHandle ( handle: hReadPipe!,
574
+ closeOnDealloc: true )
575
+ self . fileHandleForWriting = FileHandle ( handle: hWritePipe!,
576
+ closeOnDealloc: true )
577
+ #else
365
578
/// the `pipe` system call creates two `fd` in a malloc'ed area
366
579
var fds = UnsafeMutablePointer< Int32> . allocate( capacity: 2 )
367
580
defer {
@@ -383,6 +596,7 @@ open class Pipe: NSObject {
383
596
default :
384
597
fatalError ( " Error calling pipe(): \( errno) " )
385
598
}
599
+ #endif
386
600
super. init ( )
387
601
}
388
602
}
0 commit comments