Skip to content

Commit c2a4159

Browse files
authored
Merge pull request swiftlang#1515 from spevans/pr_fm_copyitem_fixes
2 parents 366a366 + 3c454b7 commit c2a4159

File tree

2 files changed

+51
-8
lines changed

2 files changed

+51
-8
lines changed

Foundation/FileManager.swift

+22-4
Original file line numberDiff line numberDiff line change
@@ -442,16 +442,34 @@ open class FileManager : NSObject {
442442
else {
443443
return
444444
}
445+
446+
func copyNonDirectory(srcPath: String, dstPath: String, fileType: FileAttributeType) throws {
447+
if fileType == .typeSymbolicLink {
448+
let destination = try destinationOfSymbolicLink(atPath: srcPath)
449+
try createSymbolicLink(atPath: dstPath, withDestinationPath: destination)
450+
} else if fileType == .typeRegular {
451+
if createFile(atPath: dstPath, contents: contents(atPath: srcPath), attributes: nil) == false {
452+
throw NSError(domain: NSCocoaErrorDomain, code: CocoaError.fileWriteUnknown.rawValue, userInfo: [NSFilePathErrorKey : NSString(string: dstPath)])
453+
}
454+
}
455+
}
456+
445457
if fileType == .typeDirectory {
446458
try createDirectory(atPath: dstPath, withIntermediateDirectories: false, attributes: nil)
447459
let subpaths = try subpathsOfDirectory(atPath: srcPath)
448460
for subpath in subpaths {
449-
try copyItem(atPath: srcPath + "/" + subpath, toPath: dstPath + "/" + subpath)
461+
let src = srcPath + "/" + subpath
462+
let dst = dstPath + "/" + subpath
463+
if let attrs = try? attributesOfItem(atPath: src), let fileType = attrs[.type] as? FileAttributeType {
464+
if fileType == .typeDirectory {
465+
try createDirectory(atPath: dst, withIntermediateDirectories: false, attributes: nil)
466+
} else {
467+
try copyNonDirectory(srcPath: src, dstPath: dst, fileType: fileType)
468+
}
469+
}
450470
}
451471
} else {
452-
if createFile(atPath: dstPath, contents: contents(atPath: srcPath), attributes: nil) == false {
453-
throw NSError(domain: NSCocoaErrorDomain, code: CocoaError.fileWriteUnknown.rawValue, userInfo: [NSFilePathErrorKey : NSString(string: dstPath)])
454-
}
472+
try copyNonDirectory(srcPath: srcPath, dstPath: dstPath, fileType: fileType)
455473
}
456474
}
457475

TestFoundation/TestFileManager.swift

+29-4
Original file line numberDiff line numberDiff line change
@@ -563,7 +563,7 @@ class TestFileManager : XCTestCase {
563563
let fm = FileManager.default
564564
let srcPath = NSTemporaryDirectory() + "testdir\(NSUUID().uuidString)"
565565
let destPath = NSTemporaryDirectory() + "testdir\(NSUUID().uuidString)"
566-
566+
567567
func cleanup() {
568568
ignoreError { try fm.removeItem(atPath: srcPath) }
569569
ignoreError { try fm.removeItem(atPath: destPath) }
@@ -599,8 +599,13 @@ class TestFileManager : XCTestCase {
599599
cleanup()
600600
createDirectory(atPath: srcPath)
601601
createDirectory(atPath: "\(srcPath)/tempdir")
602+
createDirectory(atPath: "\(srcPath)/tempdir/subdir")
603+
createDirectory(atPath: "\(srcPath)/tempdir/subdir/otherdir")
604+
createDirectory(atPath: "\(srcPath)/tempdir/subdir/otherdir/extradir")
602605
createFile(atPath: "\(srcPath)/tempdir/tempfile")
603606
createFile(atPath: "\(srcPath)/tempdir/tempfile2")
607+
createFile(atPath: "\(srcPath)/tempdir/subdir/otherdir/extradir/tempfile2")
608+
604609
do {
605610
try fm.copyItem(atPath: srcPath, toPath: destPath)
606611
} catch let error {
@@ -610,16 +615,36 @@ class TestFileManager : XCTestCase {
610615
XCTAssertTrue(directoryExists(atPath: "\(destPath)/tempdir"))
611616
XCTAssertTrue(fm.fileExists(atPath: "\(destPath)/tempdir/tempfile"))
612617
XCTAssertTrue(fm.fileExists(atPath: "\(destPath)/tempdir/tempfile2"))
613-
618+
XCTAssertTrue(directoryExists(atPath: "\(destPath)/tempdir/subdir/otherdir/extradir"))
619+
XCTAssertTrue(fm.fileExists(atPath: "\(destPath)/tempdir/subdir/otherdir/extradir/tempfile2"))
620+
614621
if (false == directoryExists(atPath: destPath)) {
615622
return
616623
}
617624
do {
618625
try fm.copyItem(atPath: srcPath, toPath: destPath)
626+
XCTFail("Copy overwrites a file/folder that already exists")
619627
} catch {
620-
return
628+
// ignore
629+
}
630+
631+
// Test copying a symlink
632+
let srcLink = srcPath + "/testlink"
633+
let destLink = destPath + "/testlink"
634+
do {
635+
try fm.createSymbolicLink(atPath: srcLink, withDestinationPath: "linkdest")
636+
try fm.copyItem(atPath: srcLink, toPath: destLink)
637+
XCTAssertEqual(try fm.destinationOfSymbolicLink(atPath: destLink), "linkdest")
638+
} catch {
639+
XCTFail("\(error)")
640+
}
641+
642+
do {
643+
try fm.copyItem(atPath: srcLink, toPath: destLink)
644+
XCTFail("Creating link where one already exists")
645+
} catch {
646+
// ignore
621647
}
622-
XCTFail("Copy overwrites a file/folder that already exists")
623648
}
624649

625650
func test_homedirectoryForUser() {

0 commit comments

Comments
 (0)