1
1
// This source file is part of the Swift.org open source project
2
2
//
3
- // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
3
+ // Copyright (c) 2014 - 2016, 2018 Apple Inc. and the Swift project authors
4
4
// Licensed under Apache License v2.0 with Runtime Library Exception
5
5
//
6
- // See http ://swift.org/LICENSE.txt for license information
7
- // See http ://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
6
+ // See https ://swift.org/LICENSE.txt for license information
7
+ // See https ://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
8
8
//
9
9
10
10
import CoreFoundation
@@ -16,9 +16,12 @@ import Glibc
16
16
#endif
17
17
18
18
open class FileHandle : NSObject , NSSecureCoding {
19
- internal var _fd : Int32
20
- internal var _closeOnDealloc : Bool
21
- internal var _closed : Bool = false
19
+ private var _fd : Int32
20
+ private var _closeOnDealloc : Bool
21
+
22
+ open var fileDescriptor : Int32 {
23
+ return _fd
24
+ }
22
25
23
26
open var readabilityHandler : ( ( FileHandle ) -> Void ) ? = {
24
27
( FileHandle) -> Void in NSUnimplemented ( )
@@ -40,10 +43,11 @@ open class FileHandle : NSObject, NSSecureCoding {
40
43
}
41
44
42
45
internal func _readDataOfLength( _ length: Int , untilEOF: Bool ) -> Data {
46
+ precondition ( _fd >= 0 , " Bad file descriptor " )
43
47
var statbuf = stat ( )
44
48
var dynamicBuffer : UnsafeMutableRawPointer ? = nil
45
49
var total = 0
46
- if _closed || fstat ( _fd, & statbuf) < 0 {
50
+ if fstat ( _fd, & statbuf) < 0 {
47
51
fatalError ( " Unable to read file " )
48
52
}
49
53
if statbuf. st_mode & S_IFMT != S_IFREG {
@@ -126,6 +130,7 @@ open class FileHandle : NSObject, NSSecureCoding {
126
130
}
127
131
128
132
open func write( _ data: Data ) {
133
+ guard _fd >= 0 else { return }
129
134
data. enumerateBytes ( ) { ( bytes, range, stop) in
130
135
do {
131
136
try NSData . write ( toFileDescriptor: self . _fd, path: nil , buf: UnsafeRawPointer ( bytes. baseAddress!) , length: bytes. count)
@@ -138,39 +143,48 @@ open class FileHandle : NSObject, NSSecureCoding {
138
143
// TODO: Error handling.
139
144
140
145
open var offsetInFile : UInt64 {
146
+ precondition ( _fd >= 0 , " Bad file descriptor " )
141
147
return UInt64 ( lseek ( _fd, 0 , SEEK_CUR) )
142
148
}
143
149
144
150
@discardableResult
145
151
open func seekToEndOfFile( ) -> UInt64 {
152
+ precondition ( _fd >= 0 , " Bad file descriptor " )
146
153
return UInt64 ( lseek ( _fd, 0 , SEEK_END) )
147
154
}
148
155
149
156
open func seek( toFileOffset offset: UInt64 ) {
157
+ precondition ( _fd >= 0 , " Bad file descriptor " )
150
158
lseek ( _fd, off_t ( offset) , SEEK_SET)
151
159
}
152
160
153
161
open func truncateFile( atOffset offset: UInt64 ) {
162
+ precondition ( _fd >= 0 , " Bad file descriptor " )
154
163
if lseek ( _fd, off_t ( offset) , SEEK_SET) < 0 { fatalError ( " lseek() failed. " ) }
155
164
if ftruncate ( _fd, off_t ( offset) ) < 0 { fatalError ( " ftruncate() failed. " ) }
156
165
}
157
166
158
167
open func synchronizeFile( ) {
168
+ precondition ( _fd >= 0 , " Bad file descriptor " )
159
169
fsync ( _fd)
160
170
}
161
171
162
172
open func closeFile( ) {
163
- if !_closed {
173
+ if _fd >= 0 {
164
174
close ( _fd)
165
- _closed = true
175
+ _fd = - 1
166
176
}
167
177
}
168
-
178
+
169
179
public init ( fileDescriptor fd: Int32 , closeOnDealloc closeopt: Bool ) {
170
180
_fd = fd
171
181
_closeOnDealloc = closeopt
172
182
}
173
-
183
+
184
+ public convenience init ( fileDescriptor fd: Int32 ) {
185
+ self . init ( fileDescriptor: fd, closeOnDealloc: false )
186
+ }
187
+
174
188
internal init ? ( path: String , flags: Int32 , createMode: Int ) {
175
189
_fd = _CFOpenFileWithMode ( path, flags, mode_t ( createMode) )
176
190
_closeOnDealloc = true
@@ -181,8 +195,9 @@ open class FileHandle : NSObject, NSSecureCoding {
181
195
}
182
196
183
197
deinit {
184
- if _fd >= 0 && _closeOnDealloc && !_closed {
198
+ if _fd >= 0 && _closeOnDealloc {
185
199
close ( _fd)
200
+ _fd = - 1
186
201
}
187
202
}
188
203
@@ -355,38 +370,32 @@ extension FileHandle {
355
370
}
356
371
}
357
372
358
- extension FileHandle {
359
- public convenience init ( fileDescriptor fd: Int32 ) {
360
- self . init ( fileDescriptor: fd, closeOnDealloc: false )
361
- }
362
-
363
- open var fileDescriptor : Int32 {
364
- return _fd
365
- }
366
- }
367
-
368
373
open class Pipe : NSObject {
369
- open let fileHandleForReading : FileHandle
370
- open let fileHandleForWriting : FileHandle
374
+ public let fileHandleForReading : FileHandle
375
+ public let fileHandleForWriting : FileHandle
371
376
372
377
public override init ( ) {
373
378
/// the `pipe` system call creates two `fd` in a malloc'ed area
374
379
var fds = UnsafeMutablePointer< Int32> . allocate( capacity: 2 )
375
380
defer {
376
- free ( fds)
381
+ fds. deallocate ( )
377
382
}
378
383
/// If the operating system prevents us from creating file handles, stop
379
- guard pipe ( fds) == 0 else { fatalError ( " Could not open pipe file handles " ) }
380
-
381
- /// The handles below auto-close when the `NSFileHandle` is deallocated, so we
382
- /// don't need to add a `deinit` to this class
383
-
384
- /// Create the read handle from the first fd in `fds`
385
- self . fileHandleForReading = FileHandle ( fileDescriptor: fds. pointee, closeOnDealloc: true )
386
-
387
- /// Advance `fds` by one to create the write handle from the second fd
388
- self . fileHandleForWriting = FileHandle ( fileDescriptor: fds. successor ( ) . pointee, closeOnDealloc: true )
389
-
384
+ let ret = pipe ( fds)
385
+ switch ( ret, errno) {
386
+ case ( 0 , _) :
387
+ self . fileHandleForReading = FileHandle ( fileDescriptor: fds. pointee, closeOnDealloc: true )
388
+ self . fileHandleForWriting = FileHandle ( fileDescriptor: fds. successor ( ) . pointee, closeOnDealloc: true )
389
+
390
+ case ( - 1 , EMFILE) , ( - 1 , ENFILE) :
391
+ // Unfortunately this initializer does not throw and isnt failable so this is only
392
+ // way of handling this situation.
393
+ self . fileHandleForReading = FileHandle ( fileDescriptor: - 1 , closeOnDealloc: false )
394
+ self . fileHandleForWriting = FileHandle ( fileDescriptor: - 1 , closeOnDealloc: false )
395
+
396
+ default :
397
+ fatalError ( " Error calling pipe(): \( errno) " )
398
+ }
390
399
super. init ( )
391
400
}
392
401
}
0 commit comments