@@ -31,102 +31,95 @@ open class FileHandle : NSObject, NSSecureCoding {
31
31
}
32
32
33
33
open var availableData : Data {
34
- return _readDataOfLength ( Int . max, untilEOF: false )
34
+ do {
35
+ let readResult = try _readDataOfLength ( Int . max, untilEOF: false )
36
+ return readResult. toData ( )
37
+ } catch {
38
+ fatalError ( " \( error) " )
39
+ }
35
40
}
36
41
37
42
open func readDataToEndOfFile( ) -> Data {
38
43
return readData ( ofLength: Int . max)
39
44
}
40
45
41
46
open func readData( ofLength length: Int ) -> Data {
42
- return _readDataOfLength ( length, untilEOF: true )
47
+ do {
48
+ let readResult = try _readDataOfLength ( length, untilEOF: true )
49
+ return readResult. toData ( )
50
+ } catch {
51
+ fatalError ( " \( error) " )
52
+ }
43
53
}
44
54
45
- internal func _readDataOfLength( _ length: Int , untilEOF: Bool ) -> Data {
55
+ internal func _readDataOfLength( _ length: Int , untilEOF: Bool , options : NSData . ReadingOptions = [ ] ) throws -> NSData . NSDataReadResult {
46
56
precondition ( _fd >= 0 , " Bad file descriptor " )
57
+ if length == 0 && !untilEOF {
58
+ // Nothing requested, return empty response
59
+ return NSData . NSDataReadResult ( bytes: nil , length: 0 , deallocator: nil )
60
+ }
61
+
47
62
var statbuf = stat ( )
48
- var dynamicBuffer : UnsafeMutableRawPointer ? = nil
49
- var total = 0
50
63
if fstat ( _fd, & statbuf) < 0 {
51
- fatalError ( " Unable to read file " )
64
+ throw NSError ( domain : NSPOSIXErrorDomain , code : Int ( errno ) , userInfo : nil )
52
65
}
53
- if statbuf. st_mode & S_IFMT != S_IFREG {
54
- /* We get here on sockets, character special files, FIFOs ... */
55
- var currentAllocationSize : size_t = 1024 * 8
56
- dynamicBuffer = malloc ( currentAllocationSize)
57
- var remaining = length
58
- while remaining > 0 {
59
- let amountToRead = min ( 1024 * 8 , remaining)
60
- // Make sure there is always at least amountToRead bytes available in the buffer.
61
- if ( currentAllocationSize - total) < amountToRead {
62
- currentAllocationSize *= 2
63
- dynamicBuffer = _CFReallocf ( dynamicBuffer!, currentAllocationSize)
64
- if dynamicBuffer == nil {
65
- fatalError ( " unable to allocate backing buffer " )
66
+
67
+ let readBlockSize : Int
68
+ if statbuf. st_mode & S_IFMT == S_IFREG {
69
+ // TODO: Should files over a certain size always be mmap()'d?
70
+ if options. contains ( . alwaysMapped) {
71
+ // Filesizes are often 64bit even on 32bit systems
72
+ let mapSize = min ( length, Int ( clamping: statbuf. st_size) )
73
+ let data = mmap ( nil , mapSize, PROT_READ, MAP_PRIVATE, _fd, 0 )
74
+ // Swift does not currently expose MAP_FAILURE
75
+ if data != UnsafeMutableRawPointer ( bitPattern: - 1 ) {
76
+ return NSData . NSDataReadResult ( bytes: data!, length: mapSize) { buffer, length in
77
+ munmap ( buffer, length)
66
78
}
67
79
}
68
- let amtRead = read ( _fd, dynamicBuffer!. advanced ( by: total) , amountToRead)
69
- if 0 > amtRead {
70
- free ( dynamicBuffer)
71
- fatalError ( " read failure " )
72
- }
73
- if 0 == amtRead {
74
- break // EOF
75
- }
76
-
77
- total += amtRead
78
- remaining -= amtRead
79
-
80
- if total == length || !untilEOF {
81
- break // We read everything the client asked for.
82
- }
80
+ }
81
+
82
+ if statbuf. st_blksize > 0 {
83
+ readBlockSize = Int ( clamping: statbuf. st_blksize)
84
+ } else {
85
+ readBlockSize = 1024 * 8
83
86
}
84
87
} else {
85
- let offset = lseek ( _fd, 0 , SEEK_CUR)
86
- if offset < 0 {
87
- fatalError ( " Unable to fetch current file offset " )
88
+ /* We get here on sockets, character special files, FIFOs ... */
89
+ readBlockSize = 1024 * 8
90
+ }
91
+ var currentAllocationSize = readBlockSize
92
+ var dynamicBuffer = malloc ( currentAllocationSize) !
93
+ var total = 0
94
+
95
+ while total < length {
96
+ let remaining = length - total
97
+ let amountToRead = min ( readBlockSize, remaining)
98
+ // Make sure there is always at least amountToRead bytes available in the buffer.
99
+ if ( currentAllocationSize - total) < amountToRead {
100
+ currentAllocationSize *= 2
101
+ dynamicBuffer = _CFReallocf ( dynamicBuffer, currentAllocationSize)
88
102
}
89
- if off_t ( statbuf. st_size) > offset {
90
- var remaining = size_t ( off_t ( statbuf. st_size) - offset)
91
- remaining = min ( remaining, size_t ( length) )
92
-
93
- dynamicBuffer = malloc ( remaining)
94
- if dynamicBuffer == nil {
95
- fatalError ( " Malloc failure " )
96
- }
97
-
98
- while remaining > 0 {
99
- let count = read ( _fd, dynamicBuffer!. advanced ( by: total) , remaining)
100
- if count < 0 {
101
- free ( dynamicBuffer)
102
- fatalError ( " Unable to read from fd " )
103
- }
104
- if count == 0 {
105
- break
106
- }
107
- total += count
108
- remaining -= count
109
- }
103
+ let amtRead = read ( _fd, dynamicBuffer. advanced ( by: total) , amountToRead)
104
+ if amtRead < 0 {
105
+ free ( dynamicBuffer)
106
+ throw NSError ( domain: NSPOSIXErrorDomain, code: Int ( errno) , userInfo: nil )
107
+ }
108
+ total += amtRead
109
+ if amtRead == 0 || !untilEOF { // If there is nothing more to read or we shouldnt keep reading then exit
110
+ break
110
111
}
111
112
}
112
113
113
- if length == Int . max && total > 0 {
114
- dynamicBuffer = _CFReallocf ( dynamicBuffer!, total)
115
- }
116
-
117
114
if total == 0 {
118
115
free ( dynamicBuffer)
116
+ return NSData . NSDataReadResult ( bytes: nil , length: 0 , deallocator: nil )
119
117
}
120
- else if total > 0 {
121
- let bytePtr = dynamicBuffer!. bindMemory ( to: UInt8 . self, capacity: total)
122
- return Data ( bytesNoCopy: bytePtr, count: total, deallocator: . free)
123
- }
124
- else {
125
- assertionFailure ( " The total number of read bytes must not be negative " )
126
- free ( dynamicBuffer)
118
+ dynamicBuffer = _CFReallocf ( dynamicBuffer, total)
119
+ let bytePtr = dynamicBuffer. bindMemory ( to: UInt8 . self, capacity: total)
120
+ return NSData . NSDataReadResult ( bytes: bytePtr, length: total) { buffer, length in
121
+ free ( buffer)
127
122
}
128
-
129
- return Data ( )
130
123
}
131
124
132
125
open func write( _ data: Data ) {
0 commit comments