diff --git a/Sources/PerfectLib/File.swift b/Sources/PerfectLib/File.swift index 926e010f..7dcc0728 100644 --- a/Sources/PerfectLib/File.swift +++ b/Sources/PerfectLib/File.swift @@ -350,17 +350,6 @@ public extension File { return Int(st.st_size) } - /// Returns true if the file is a symbolic link - public var isLink: Bool { - var st = stat() - let statRes = lstat(internalPath, &st) - guard statRes != -1 else { - return false - } - let mode = st.st_mode - return (Int32(mode) & Int32(S_IFMT)) == Int32(S_IFLNK) - } - /// Returns true if the file is actually a directory public var isDir: Bool { var st = stat() @@ -389,6 +378,35 @@ public extension File { } } +public extension File { + /// Returns true if the file is a symbolic link + public var isLink: Bool { + var st = stat() + let statRes = lstat(internalPath, &st) + guard statRes != -1 else { + return false + } + let mode = st.st_mode + return (Int32(mode) & Int32(S_IFMT)) == Int32(S_IFLNK) + } + + @discardableResult + public func linkTo(path: String, overWrite: Bool = false) throws -> File { + let destFile = File(path) + if destFile.exists { + guard overWrite else { + throw PerfectError.fileError(-1, "Can not overwrite existing file") + } + destFile.delete() + } + let res = symlink(self.path, path) + if res == 0 { + return File(path) + } + try ThrowFileError() + } +} + public extension File { /// Reads up to the indicated number of bytes from the file diff --git a/Tests/PerfectLibTests/PerfectLibTests.swift b/Tests/PerfectLibTests/PerfectLibTests.swift index eacaeda3..c31ca8de 100644 --- a/Tests/PerfectLibTests/PerfectLibTests.swift +++ b/Tests/PerfectLibTests/PerfectLibTests.swift @@ -191,96 +191,6 @@ class PerfectLibTests: XCTestCase { XCTAssert(emojiStr == "😳") } - - -// func testNetSendFile() { -// -// let testFile = File("/tmp/file_to_send.txt") -// let testContents = "Here are the contents" -// let sock = "/tmp/foo.sock" -// let sockFile = File(sock) -// if sockFile.exists { -// sockFile.delete() -// } -// -// do { -// -// try testFile.open(.truncate) -// let _ = try testFile.write(string: testContents) -// testFile.close() -// try testFile.open() -// -// let server = NetNamedPipe() -// let client = NetNamedPipe() -// -// try server.bind(address: sock) -// server.listen() -// -// let serverExpectation = self.expectation(description: "server") -// let clientExpectation = self.expectation(description: "client") -// -// try server.accept(timeoutSeconds: NetEvent.noTimeout) { -// (inn: NetTCP?) -> () in -// let n = inn as? NetNamedPipe -// XCTAssertNotNil(n) -// -// do { -// try n?.sendFile(testFile) { -// (b: Bool) in -// -// XCTAssertTrue(b) -// -// n!.close() -// -// serverExpectation.fulfill() -// } -// } catch let e { -// XCTAssert(false, "Exception accepting connection: \(e)") -// serverExpectation.fulfill() -// } -// } -// -// try client.connect(address: sock, timeoutSeconds: 5) { -// (inn: NetTCP?) -> () in -// let n = inn as? NetNamedPipe -// XCTAssertNotNil(n) -// do { -// try n!.receiveFile { -// f in -// -// XCTAssertNotNil(f) -// do { -// let testDataRead = try f!.readSomeBytes(count: f!.size) -// if testDataRead.count > 0 { -// XCTAssertEqual(UTF8Encoding.encode(bytes: testDataRead), testContents) -// } else { -// XCTAssertTrue(false, "Got no data from received file") -// } -// f!.close() -// } catch let e { -// XCTAssert(false, "Exception in connection: \(e)") -// } -// clientExpectation.fulfill() -// } -// } catch let e { -// XCTAssert(false, "Exception in connection: \(e)") -// clientExpectation.fulfill() -// } -// } -// self.waitForExpectations(timeout: 10000) { -// _ in -// server.close() -// client.close() -// testFile.close() -// testFile.delete() -// } -// } catch PerfectError.networkError(let code, let msg) { -// XCTAssert(false, "Exception: \(code) \(msg)") -// } catch let e { -// XCTAssert(false, "Exception: \(e)") -// } -// } - func testSysProcess() { #if !Xcode // this always fails in Xcode but passes on the cli and on Linux. // I think it's some interaction with the debugger. System call interrupted. @@ -545,6 +455,27 @@ class PerfectLibTests: XCTestCase { XCTAssert(bytes2.availableExportBytes == 1) XCTAssert(i8 == bytes2.export8Bits()) } + + func testSymlink() { + let f1 = File("./foo") + let f2 = File("./foo2") + do { + f2.delete() + try f1.open(.truncate) + try f1.write(string: "test") + f1.close() + defer { + f1.delete() + } + + let newF2 = try f1.linkTo(path: f2.path) + + XCTAssert(try newF2.readString() == "test") + XCTAssert(newF2.isLink) + } catch { + XCTAssert(false, "\(error)") + } + } } extension PerfectLibTests {