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