Skip to content

Commit 5c9b89e

Browse files
committed
FoundationEssentials: make build on Android
This adjusts the API usage to account for differences on Android. The biggest source of difference is the nullability, particularly in the `fts` APIs. Unfortunately, `MMAP_FAILED` is not imported by the clang importer due to the casting involved so we manually inline the constant at the single site.
1 parent a769223 commit 5c9b89e

File tree

3 files changed

+57
-33
lines changed

3 files changed

+57
-33
lines changed

Sources/FoundationEssentials/Data/Data+Reading.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,13 +356,20 @@ internal func readBytesFromFile(path inPath: PathOrURL, reportProgress: Bool, ma
356356
result = ReadBytesResult(bytes: nil, length: 0, deallocator: nil)
357357
} else if shouldMap {
358358
#if !NO_FILESYSTEM
359+
#if os(Android)
360+
let bytes = mmap(nil, Int(fileSize), PROT_READ, MAP_PRIVATE, fd, 0)
361+
if bytes == UnsafeMutableRawPointer(bitPattern: -1) {
362+
throw CocoaError.errorWithFilePath(inPath, errno: errno, reading: true)
363+
}
364+
#else
359365
guard let bytes = mmap(nil, Int(fileSize), PROT_READ, MAP_PRIVATE, fd, 0) else {
360366
throw CocoaError.errorWithFilePath(inPath, errno: errno, reading: true)
361367
}
362368

363369
guard bytes != MAP_FAILED else {
364370
throw CocoaError.errorWithFilePath(inPath, errno: errno, reading: true)
365371
}
372+
#endif
366373

367374
// Using bytes as the unit in this case doesn't really make any sense, since the amount of work required for mmap isn't meanginfully proportional to the size being mapped.
368375
localProgress?.totalUnitCount = 1

Sources/FoundationEssentials/FileManager/FileOperations+Enumeration.swift

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -165,8 +165,8 @@ struct _FTSSequence: Sequence {
165165
state = .error(errno, String(cString: path))
166166
return
167167
}
168-
169-
state = [UnsafeMutablePointer(mutating: path), nil].withUnsafeBufferPointer{ dirList in
168+
169+
state = [UnsafeMutablePointer(mutating: path), UnsafeMutablePointer<CChar>(nil)!].withUnsafeBufferPointer { dirList in
170170
guard let stream = fts_open(dirList.baseAddress!, opts, nil) else {
171171
return .error(errno, String(cString: path))
172172
}
@@ -291,6 +291,12 @@ extension Sequence<_FTSSequence.Element> {
291291
switch $0 {
292292
case .error(let error, let path): return .error(error, path)
293293
case .entry(let ent):
294+
#if os(Android)
295+
guard let fts_path = ent.ftsEnt.fts_path else { return nil }
296+
#else
297+
let fts_path = ent.ftsEnt.fts_path
298+
#endif
299+
294300
switch Int32(ent.ftsEnt.fts_info) {
295301
// Do the action
296302
case FTS_D: fallthrough // Directory being visited in pre-order.
@@ -299,13 +305,13 @@ extension Sequence<_FTSSequence.Element> {
299305
case FTS_NSOK: fallthrough // No stat(2) information was requested, but that's OK.
300306
case FTS_SL: fallthrough // Symlink.
301307
case FTS_SLNONE: // Symlink with no target.
302-
return .entry(String(cString: ent.ftsEnt.fts_path))
308+
return .entry(String(cString: fts_path))
303309

304310
// Error returns
305311
case FTS_DNR: fallthrough // Directory cannot be read.
306312
case FTS_ERR: fallthrough // Some error occurred, but we don't know what.
307313
case FTS_NS: // No stat(2) information is available.
308-
let path = String(cString: ent.ftsEnt.fts_path)
314+
let path = String(cString: fts_path)
309315
return .error(ent.ftsEnt.fts_errno, path)
310316

311317
default: return nil

Sources/FoundationEssentials/FileManager/FileOperations.swift

Lines changed: 40 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -520,13 +520,19 @@ enum _FileOperations {
520520
throw CocoaError.removeFileError(err, errPath)
521521

522522
case let .entry(entry):
523+
#if os(Android)
524+
guard let fts_path = entry.ftsEnt.fts_path else { continue }
525+
#else
526+
let fts_path = entry.ftsEnt.fts_path
527+
#endif
528+
523529
switch Int32(entry.ftsEnt.fts_info) {
524530
case FTS_DEFAULT, FTS_F, FTS_NSOK, FTS_SL, FTS_SLNONE:
525-
let currentPathStr = resolve(path: String(cString: entry.ftsEnt.fts_path))
531+
let currentPathStr = resolve(path: String(cString: fts_path))
526532
guard fileManager?._shouldRemoveItemAtPath(currentPathStr) ?? true else {
527533
break
528534
}
529-
if unlink(entry.ftsEnt.fts_path) != 0 {
535+
if unlink(fts_path) != 0 {
530536
let error = CocoaError.removeFileError(errno, currentPathStr)
531537
if !(fileManager?._shouldProceedAfter(error: error, removingItemAtPath: currentPathStr) ?? false) {
532538
throw error
@@ -538,20 +544,20 @@ enum _FileOperations {
538544
isFirst = false
539545
break
540546
}
541-
let currentPathStr = resolve(path: String(cString: entry.ftsEnt.fts_path))
547+
let currentPathStr = resolve(path: String(cString: fts_path))
542548
if !(fileManager?._shouldRemoveItemAtPath(currentPathStr) ?? true) {
543549
iterator.skipDescendants(of: entry, skipPostProcessing: true)
544550
}
545551
case FTS_DP:
546-
if rmdir(entry.ftsEnt.fts_path) != 0 {
547-
let currentPathStr = resolve(path: String(cString: entry.ftsEnt.fts_path))
552+
if rmdir(fts_path) != 0 {
553+
let currentPathStr = resolve(path: String(cString: fts_path))
548554
let error = CocoaError.removeFileError(errno, currentPathStr)
549555
if !(fileManager?._shouldProceedAfter(error: error, removingItemAtPath: currentPathStr) ?? false) {
550556
throw error
551557
}
552558
}
553559
case FTS_DNR, FTS_ERR, FTS_NS:
554-
let currentPathStr = resolve(path: String(cString: entry.ftsEnt.fts_path))
560+
let currentPathStr = resolve(path: String(cString: fts_path))
555561
throw CocoaError.removeFileError(entry.ftsEnt.fts_errno, currentPathStr)
556562
default:
557563
break
@@ -866,12 +872,12 @@ enum _FileOperations {
866872
return
867873
}
868874

869-
let total = fileInfo.st_size
870-
let chunkSize = Int(fileInfo.st_blksize)
871-
var current = 0
875+
let total: Int = Int(fileInfo.st_size)
876+
let chunkSize: Int = Int(fileInfo.st_blksize)
877+
var current: off_t = 0
872878

873879
while current < total {
874-
guard sendfile(dstfd, srcfd, &current, Swift.min(total - current, chunkSize)) != -1 else {
880+
guard sendfile(dstfd, srcfd, &current, Swift.min(total - Int(current), chunkSize)) != -1 else {
875881
try delegate.throwIfNecessary(errno, String(cString: srcPtr), String(cString: dstPtr))
876882
return
877883
}
@@ -894,11 +900,16 @@ enum _FileOperations {
894900
throw CocoaError.errorWithFilePath(path, errno: errno, reading: true)
895901

896902
case let .entry(entry):
897-
let trimmedPathPtr = entry.ftsEnt.fts_path.advanced(by: srcLen)
903+
#if os(Android)
904+
guard let fts_path = entry.ftsEnt.fts_path else { continue }
905+
#else
906+
let fts_path = entry.ftsEnt.fts_path
907+
#endif
908+
let trimmedPathPtr = fts_path.advanced(by: srcLen)
898909
Platform.copyCString(dst: dstAppendPtr, src: trimmedPathPtr, size: remainingBuffer)
899910

900911
// we don't want to ask the delegate on the way back -up- the hierarchy if they want to copy a directory they've already seen and therefore already said "YES" to.
901-
guard entry.ftsEnt.fts_info == FTS_DP || delegate.shouldPerformOnItemAtPath(String(cString: entry.ftsEnt.fts_path), to: String(cString: buffer.baseAddress!)) else {
912+
guard entry.ftsEnt.fts_info == FTS_DP || delegate.shouldPerformOnItemAtPath(String(cString: fts_path), to: String(cString: buffer.baseAddress!)) else {
902913
if entry.ftsEnt.fts_info == FTS_D {
903914
iterator.skipDescendants(of: entry, skipPostProcessing: true)
904915
}
@@ -911,29 +922,29 @@ enum _FileOperations {
911922
case FTS_D:
912923
// Directory being visited in pre-order - create it with whatever default perms will be on the destination.
913924
#if canImport(Darwin)
914-
if copyfile(entry.ftsEnt.fts_path, buffer.baseAddress!, nil, copyfile_flags_t(COPYFILE_DATA | COPYFILE_EXCL | COPYFILE_NOFOLLOW | extraFlags)) != 0 {
915-
try delegate.throwIfNecessary(errno, String(cString: entry.ftsEnt.fts_path), String(cString: buffer.baseAddress!))
925+
if copyfile(fts_path, buffer.baseAddress!, nil, copyfile_flags_t(COPYFILE_DATA | COPYFILE_EXCL | COPYFILE_NOFOLLOW | extraFlags)) != 0 {
926+
try delegate.throwIfNecessary(errno, String(cString: fts_path), String(cString: buffer.baseAddress!))
916927
}
917928
#else
918929
do {
919930
try fileManager.createDirectory(atPath: String(cString: buffer.baseAddress!), withIntermediateDirectories: true)
920931
} catch {
921-
try delegate.throwIfNecessary(error, String(cString: entry.ftsEnt.fts_path), String(cString: buffer.baseAddress!))
932+
try delegate.throwIfNecessary(error, String(cString: fts_path), String(cString: buffer.baseAddress!))
922933
}
923934
#endif
924935

925936
case FTS_DP:
926937
// Directory being visited in post-order - copy the permissions over.
927938
#if canImport(Darwin)
928-
if copyfile(entry.ftsEnt.fts_path, buffer.baseAddress!, nil, copyfile_flags_t(COPYFILE_METADATA | COPYFILE_NOFOLLOW | extraFlags)) != 0 {
929-
try delegate.throwIfNecessary(errno, String(cString: entry.ftsEnt.fts_path), String(cString: buffer.baseAddress!))
939+
if copyfile(fts_path, buffer.baseAddress!, nil, copyfile_flags_t(COPYFILE_METADATA | COPYFILE_NOFOLLOW | extraFlags)) != 0 {
940+
try delegate.throwIfNecessary(errno, String(cString: fts_path), String(cString: buffer.baseAddress!))
930941
}
931942
#else
932943
do {
933-
let attributes = try fileManager.attributesOfItem(atPath: String(cString: entry.ftsEnt.fts_path))
944+
let attributes = try fileManager.attributesOfItem(atPath: String(cString: fts_path))
934945
try fileManager.setAttributes(attributes, ofItemAtPath: String(cString: buffer.baseAddress!))
935946
} catch {
936-
try delegate.throwIfNecessary(error, String(cString: entry.ftsEnt.fts_path), String(cString: buffer.baseAddress!))
947+
try delegate.throwIfNecessary(error, String(cString: fts_path), String(cString: buffer.baseAddress!))
937948
}
938949
#endif
939950

@@ -947,42 +958,42 @@ enum _FileOperations {
947958
} else {
948959
flags = COPYFILE_DATA | COPYFILE_METADATA | COPYFILE_EXCL | COPYFILE_NOFOLLOW | extraFlags
949960
}
950-
if copyfile(entry.ftsEnt.fts_path, buffer.baseAddress!, nil, copyfile_flags_t(flags)) != 0 {
951-
try delegate.throwIfNecessary(errno, String(cString: entry.ftsEnt.fts_path), String(cString: buffer.baseAddress!))
961+
if copyfile(fts_path, buffer.baseAddress!, nil, copyfile_flags_t(flags)) != 0 {
962+
try delegate.throwIfNecessary(errno, String(cString: fts_path), String(cString: buffer.baseAddress!))
952963
}
953964
#else
954965
try withUnsafeTemporaryAllocation(of: CChar.self, capacity: FileManager.MAX_PATH_SIZE) { tempBuff in
955966
tempBuff.initialize(repeating: 0)
956967
defer { tempBuff.deinitialize() }
957-
let len = readlink(entry.ftsEnt.fts_path, tempBuff.baseAddress!, FileManager.MAX_PATH_SIZE - 1)
968+
let len = readlink(fts_path, tempBuff.baseAddress!, FileManager.MAX_PATH_SIZE - 1)
958969
if len >= 0, symlink(tempBuff.baseAddress!, buffer.baseAddress!) != -1 {
959970
return
960971
}
961-
try delegate.throwIfNecessary(errno, String(cString: entry.ftsEnt.fts_path), String(cString: buffer.baseAddress!))
972+
try delegate.throwIfNecessary(errno, String(cString: fts_path), String(cString: buffer.baseAddress!))
962973
}
963974
#endif
964975

965976
case FTS_DEFAULT: fallthrough // Something not defined anywhere else.
966977
case FTS_F: // Regular file.
967978
if delegate.copyData {
968979
#if canImport(Darwin)
969-
if copyfile(entry.ftsEnt.fts_path, buffer.baseAddress!, nil, copyfile_flags_t(COPYFILE_CLONE | COPYFILE_ALL | COPYFILE_EXCL | COPYFILE_NOFOLLOW | extraFlags)) != 0 {
970-
try delegate.throwIfNecessary(errno, String(cString: entry.ftsEnt.fts_path), String(cString: buffer.baseAddress!))
980+
if copyfile(fts_path, buffer.baseAddress!, nil, copyfile_flags_t(COPYFILE_CLONE | COPYFILE_ALL | COPYFILE_EXCL | COPYFILE_NOFOLLOW | extraFlags)) != 0 {
981+
try delegate.throwIfNecessary(errno, String(cString: fts_path), String(cString: buffer.baseAddress!))
971982
}
972983
#else
973-
try Self._copyRegularFile(entry.ftsEnt.fts_path, buffer.baseAddress!, delegate: delegate)
984+
try Self._copyRegularFile(fts_path, buffer.baseAddress!, delegate: delegate)
974985
#endif
975986
} else {
976-
if link(entry.ftsEnt.fts_path, buffer.baseAddress!) != 0 {
977-
try delegate.throwIfNecessary(errno, String(cString: entry.ftsEnt.fts_path), String(cString: buffer.baseAddress!))
987+
if link(fts_path, buffer.baseAddress!) != 0 {
988+
try delegate.throwIfNecessary(errno, String(cString: fts_path), String(cString: buffer.baseAddress!))
978989
}
979990
}
980991

981992
// Error returns
982993
case FTS_DNR: fallthrough // Directory cannot be read.
983994
case FTS_ERR: fallthrough // Some error occurred, but we don't know what.
984995
case FTS_NS: // No stat(2) information is available.
985-
try delegate.throwIfNecessary(entry.ftsEnt.fts_errno, String(cString: entry.ftsEnt.fts_path), String(cString: buffer.baseAddress!))
996+
try delegate.throwIfNecessary(entry.ftsEnt.fts_errno, String(cString: fts_path), String(cString: buffer.baseAddress!))
986997

987998
default: break
988999
}

0 commit comments

Comments
 (0)