diff --git a/Foundation/FileHandle.swift b/Foundation/FileHandle.swift index 04e2d690b6..0f86c59789 100644 --- a/Foundation/FileHandle.swift +++ b/Foundation/FileHandle.swift @@ -142,13 +142,12 @@ open class FileHandle : NSObject, NSSecureCoding { open func seek(toFileOffset offset: UInt64) { lseek(_fd, off_t(offset), SEEK_SET) } - + open func truncateFile(atOffset offset: UInt64) { - if lseek(_fd, off_t(offset), SEEK_SET) == 0 { - ftruncate(_fd, off_t(offset)) - } + if lseek(_fd, off_t(offset), SEEK_SET) < 0 { fatalError("lseek() failed.") } + if ftruncate(_fd, off_t(offset)) < 0 { fatalError("ftruncate() failed.") } } - + open func synchronizeFile() { fsync(_fd) } diff --git a/TestFoundation/TestFileHandle.swift b/TestFoundation/TestFileHandle.swift index 1b389ff0f7..ca728bdbe2 100644 --- a/TestFoundation/TestFileHandle.swift +++ b/TestFoundation/TestFileHandle.swift @@ -21,6 +21,7 @@ class TestFileHandle : XCTestCase { ("test_constants", test_constants), ("test_pipe", test_pipe), ("test_nullDevice", test_nullDevice), + ("test_truncateFile", test_truncateFile) ] } @@ -64,4 +65,39 @@ class TestFileHandle : XCTestCase { fh.seek(toFileOffset: 0) XCTAssertEqual(fh.readDataToEndOfFile().count, 0) } + + func test_truncateFile() { + mkstemp(template: "test_truncateFile.XXXXXX") { (fh) in + fh.truncateFile(atOffset: 50) + XCTAssertEqual(fh.offsetInFile, 50) + + fh.truncateFile(atOffset: 0) + XCTAssertEqual(fh.offsetInFile, 0) + + fh.truncateFile(atOffset: 100) + XCTAssertEqual(fh.offsetInFile, 100) + + fh.write(Data(bytes: [1, 2])) + XCTAssertEqual(fh.offsetInFile, 102) + + fh.seek(toFileOffset: 4) + XCTAssertEqual(fh.offsetInFile, 4) + + (0..<20).forEach { fh.write(Data(bytes: [$0])) } + XCTAssertEqual(fh.offsetInFile, 24) + + fh.seekToEndOfFile() + XCTAssertEqual(fh.offsetInFile, 102) + + fh.truncateFile(atOffset: 10) + XCTAssertEqual(fh.offsetInFile, 10) + + fh.seek(toFileOffset: 0) + XCTAssertEqual(fh.offsetInFile, 0) + + let data = fh.readDataToEndOfFile() + XCTAssertEqual(data.count, 10) + XCTAssertEqual(data, Data(bytes: [0, 0, 0, 0, 0, 1, 2, 3, 4, 5])) + } + } } diff --git a/TestFoundation/TestProcess.swift b/TestFoundation/TestProcess.swift index 6af3e37df3..58ffafa896 100644 --- a/TestFoundation/TestProcess.swift +++ b/TestFoundation/TestProcess.swift @@ -297,20 +297,6 @@ class TestProcess : XCTestCase { #endif } -private func mkstemp(template: String, body: (FileHandle) throws -> Void) rethrows { - let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("TestProcess.XXXXXX") - - try url.withUnsafeFileSystemRepresentation { - switch mkstemp(UnsafeMutablePointer(mutating: $0!)) { - case -1: XCTFail("Could not create temporary file") - case let fd: - defer { url.withUnsafeFileSystemRepresentation { _ = unlink($0!) } } - try body(FileHandle(fileDescriptor: fd, closeOnDealloc: true)) - } - } - -} - private enum Error: Swift.Error { case TerminationStatus(Int32) case UnicodeDecodingError(Data) diff --git a/TestFoundation/TestUtils.swift b/TestFoundation/TestUtils.swift index 860e1291d9..c9ab02b917 100644 --- a/TestFoundation/TestUtils.swift +++ b/TestFoundation/TestUtils.swift @@ -50,3 +50,16 @@ func ensureFiles(_ fileNames: [String]) -> Bool { } return result } + +func mkstemp(template: String, body: (FileHandle) throws -> Void) rethrows { + let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(template) + + try url.withUnsafeFileSystemRepresentation { + switch mkstemp(UnsafeMutablePointer(mutating: $0!)) { + case -1: XCTFail("Could not create temporary file") + case let fd: + defer { url.withUnsafeFileSystemRepresentation { _ = unlink($0!) } } + try body(FileHandle(fileDescriptor: fd, closeOnDealloc: true)) + } + } +}