-
Notifications
You must be signed in to change notification settings - Fork 39
/
CommonFunctions.swift
131 lines (109 loc) · 4.76 KB
/
CommonFunctions.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// Copyright (c) 2021 Timofey Solomko
// Licensed under MIT License
//
// See LICENSE for license information
import Foundation
import SWCompression
func isValidOutputDirectory(_ outputPath: String, create: Bool) throws -> Bool {
let fileManager = FileManager.default
var isDir: ObjCBool = false
if fileManager.fileExists(atPath: outputPath, isDirectory: &isDir) {
return isDir.boolValue
} else if create {
try fileManager.createDirectory(atPath: outputPath, withIntermediateDirectories: true)
}
return true
}
func printInfo(_ entries: [ContainerEntryInfo]) {
for entry in entries {
print(entry)
print("------------------\n")
}
}
func write<T: ContainerEntry>(_ entries: [T], _ outputPath: String, _ verbose: Bool) throws {
let fileManager = FileManager.default
let outputURL = URL(fileURLWithPath: outputPath)
if verbose {
print("d = directory, f = file, l = symbolic link")
}
var directoryAttributes = [(attributes: [FileAttributeKey: Any], path: String)]()
// First, we create directories.
for entry in entries where entry.info.type == .directory {
let entryName = entry.info.name
let entryFullURL = outputURL.appendingPathComponent(entryName, isDirectory: true)
if verbose {
print("d: \(entryName)")
}
try fileManager.createDirectory(at: entryFullURL, withIntermediateDirectories: true)
var attributes = [FileAttributeKey: Any]()
#if !os(Linux) // On linux only permissions attribute is supported.
if let mtime = entry.info.modificationTime {
attributes[FileAttributeKey.modificationDate] = mtime
}
if let ctime = entry.info.creationTime {
attributes[FileAttributeKey.creationDate] = ctime
}
#endif
if let permissions = entry.info.permissions?.rawValue, permissions > 0 {
attributes[FileAttributeKey.posixPermissions] = NSNumber(value: permissions)
}
// We apply attributes to directories later, because extracting files into them changes mtime.
directoryAttributes.append((attributes, entryFullURL.path))
}
// Now, we create the rest of files.
for entry in entries where entry.info.type != .directory {
let entryName = entry.info.name
let entryFullURL = outputURL.appendingPathComponent(entryName, isDirectory: false)
if entry.info.type == .symbolicLink {
let destinationPath: String?
if let tarEntry = entry as? TarEntry {
destinationPath = tarEntry.info.linkName
} else {
guard let entryData = entry.data else {
print("ERROR: Unable to get destination path for symbolic link \(entryName).")
exit(1)
}
destinationPath = String(data: entryData, encoding: .utf8)
}
guard destinationPath != nil else {
print("ERROR: Unable to get destination path for symbolic link \(entryName).")
exit(1)
}
let endURL = entryFullURL.deletingLastPathComponent().appendingPathComponent(destinationPath!)
if verbose {
print("l: \(entryName) -> \(endURL.path)")
}
try fileManager.createSymbolicLink(atPath: entryFullURL.path, withDestinationPath: endURL.path)
// We cannot apply attributes to symbolic link.
continue
} else if entry.info.type == .regular {
if verbose {
print("f: \(entryName)")
}
guard let entryData = entry.data else {
print("ERROR: Unable to get data for the entry \(entryName).")
exit(1)
}
try entryData.write(to: entryFullURL)
} else {
print("WARNING: Unknown file type \(entry.info.type) for entry \(entryName). Skipping this entry.")
continue
}
var attributes = [FileAttributeKey: Any]()
#if !os(Linux) // On linux only permissions attribute is supported.
if let mtime = entry.info.modificationTime {
attributes[FileAttributeKey.modificationDate] = mtime
}
if let ctime = entry.info.creationTime {
attributes[FileAttributeKey.creationDate] = ctime
}
#endif
if let permissions = entry.info.permissions?.rawValue, permissions > 0 {
attributes[FileAttributeKey.posixPermissions] = NSNumber(value: permissions)
}
try fileManager.setAttributes(attributes, ofItemAtPath: entryFullURL.path)
}
for tuple in directoryAttributes {
try fileManager.setAttributes(tuple.attributes, ofItemAtPath: tuple.path)
}
}