Skip to content

Commit b39bca9

Browse files
committed
File.linkTo
Former-commit-id: 7aea6c5
1 parent 831b724 commit b39bca9

File tree

2 files changed

+50
-101
lines changed

2 files changed

+50
-101
lines changed

Sources/PerfectLib/File.swift

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -350,17 +350,6 @@ public extension File {
350350
return Int(st.st_size)
351351
}
352352

353-
/// Returns true if the file is a symbolic link
354-
public var isLink: Bool {
355-
var st = stat()
356-
let statRes = lstat(internalPath, &st)
357-
guard statRes != -1 else {
358-
return false
359-
}
360-
let mode = st.st_mode
361-
return (Int32(mode) & Int32(S_IFMT)) == Int32(S_IFLNK)
362-
}
363-
364353
/// Returns true if the file is actually a directory
365354
public var isDir: Bool {
366355
var st = stat()
@@ -389,6 +378,35 @@ public extension File {
389378
}
390379
}
391380

381+
public extension File {
382+
/// Returns true if the file is a symbolic link
383+
public var isLink: Bool {
384+
var st = stat()
385+
let statRes = lstat(internalPath, &st)
386+
guard statRes != -1 else {
387+
return false
388+
}
389+
let mode = st.st_mode
390+
return (Int32(mode) & Int32(S_IFMT)) == Int32(S_IFLNK)
391+
}
392+
393+
@discardableResult
394+
public func linkTo(path: String, overWrite: Bool = false) throws -> File {
395+
let destFile = File(path)
396+
if destFile.exists {
397+
guard overWrite else {
398+
throw PerfectError.fileError(-1, "Can not overwrite existing file")
399+
}
400+
destFile.delete()
401+
}
402+
let res = symlink(self.path, path)
403+
if res == 0 {
404+
return File(path)
405+
}
406+
try ThrowFileError()
407+
}
408+
}
409+
392410
public extension File {
393411

394412
/// Reads up to the indicated number of bytes from the file

Tests/PerfectLibTests/PerfectLibTests.swift

Lines changed: 21 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -191,96 +191,6 @@ class PerfectLibTests: XCTestCase {
191191
XCTAssert(emojiStr == "😳")
192192
}
193193

194-
195-
196-
// func testNetSendFile() {
197-
//
198-
// let testFile = File("/tmp/file_to_send.txt")
199-
// let testContents = "Here are the contents"
200-
// let sock = "/tmp/foo.sock"
201-
// let sockFile = File(sock)
202-
// if sockFile.exists {
203-
// sockFile.delete()
204-
// }
205-
//
206-
// do {
207-
//
208-
// try testFile.open(.truncate)
209-
// let _ = try testFile.write(string: testContents)
210-
// testFile.close()
211-
// try testFile.open()
212-
//
213-
// let server = NetNamedPipe()
214-
// let client = NetNamedPipe()
215-
//
216-
// try server.bind(address: sock)
217-
// server.listen()
218-
//
219-
// let serverExpectation = self.expectation(description: "server")
220-
// let clientExpectation = self.expectation(description: "client")
221-
//
222-
// try server.accept(timeoutSeconds: NetEvent.noTimeout) {
223-
// (inn: NetTCP?) -> () in
224-
// let n = inn as? NetNamedPipe
225-
// XCTAssertNotNil(n)
226-
//
227-
// do {
228-
// try n?.sendFile(testFile) {
229-
// (b: Bool) in
230-
//
231-
// XCTAssertTrue(b)
232-
//
233-
// n!.close()
234-
//
235-
// serverExpectation.fulfill()
236-
// }
237-
// } catch let e {
238-
// XCTAssert(false, "Exception accepting connection: \(e)")
239-
// serverExpectation.fulfill()
240-
// }
241-
// }
242-
//
243-
// try client.connect(address: sock, timeoutSeconds: 5) {
244-
// (inn: NetTCP?) -> () in
245-
// let n = inn as? NetNamedPipe
246-
// XCTAssertNotNil(n)
247-
// do {
248-
// try n!.receiveFile {
249-
// f in
250-
//
251-
// XCTAssertNotNil(f)
252-
// do {
253-
// let testDataRead = try f!.readSomeBytes(count: f!.size)
254-
// if testDataRead.count > 0 {
255-
// XCTAssertEqual(UTF8Encoding.encode(bytes: testDataRead), testContents)
256-
// } else {
257-
// XCTAssertTrue(false, "Got no data from received file")
258-
// }
259-
// f!.close()
260-
// } catch let e {
261-
// XCTAssert(false, "Exception in connection: \(e)")
262-
// }
263-
// clientExpectation.fulfill()
264-
// }
265-
// } catch let e {
266-
// XCTAssert(false, "Exception in connection: \(e)")
267-
// clientExpectation.fulfill()
268-
// }
269-
// }
270-
// self.waitForExpectations(timeout: 10000) {
271-
// _ in
272-
// server.close()
273-
// client.close()
274-
// testFile.close()
275-
// testFile.delete()
276-
// }
277-
// } catch PerfectError.networkError(let code, let msg) {
278-
// XCTAssert(false, "Exception: \(code) \(msg)")
279-
// } catch let e {
280-
// XCTAssert(false, "Exception: \(e)")
281-
// }
282-
// }
283-
284194
func testSysProcess() {
285195
#if !Xcode // this always fails in Xcode but passes on the cli and on Linux.
286196
// I think it's some interaction with the debugger. System call interrupted.
@@ -545,6 +455,27 @@ class PerfectLibTests: XCTestCase {
545455
XCTAssert(bytes2.availableExportBytes == 1)
546456
XCTAssert(i8 == bytes2.export8Bits())
547457
}
458+
459+
func testSymlink() {
460+
let f1 = File("./foo")
461+
let f2 = File("./foo2")
462+
do {
463+
f2.delete()
464+
try f1.open(.truncate)
465+
try f1.write(string: "test")
466+
f1.close()
467+
defer {
468+
f1.delete()
469+
}
470+
471+
let newF2 = try f1.linkTo(path: f2.path)
472+
473+
XCTAssert(try newF2.readString() == "test")
474+
XCTAssert(newF2.isLink)
475+
} catch {
476+
XCTAssert(false, "\(error)")
477+
}
478+
}
548479
}
549480

550481
extension PerfectLibTests {

0 commit comments

Comments
 (0)