Skip to content

Commit 88d6a8d

Browse files
authored
FoundationEssentials: make build on Android (#705)
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 cd6d25b commit 88d6a8d

File tree

4 files changed

+43
-34
lines changed

4 files changed

+43
-34
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/Error/ErrorCodes+POSIX.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
// Import for POSIXErrorCode
1313
#if os(Android)
14-
import Android
14+
@preconcurrency import Android
1515
#elseif canImport(Glibc)
1616
@preconcurrency import Glibc
1717
#elseif canImport(Darwin)

Sources/FoundationEssentials/FileManager/FileOperations+Enumeration.swift

Lines changed: 4 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), nil].withUnsafeBufferPointer { dirList in
170170
guard let stream = fts_open(dirList.baseAddress!, opts, nil) else {
171171
return .error(errno, String(cString: path))
172172
}
@@ -299,13 +299,13 @@ extension Sequence<_FTSSequence.Element> {
299299
case FTS_NSOK: fallthrough // No stat(2) information was requested, but that's OK.
300300
case FTS_SL: fallthrough // Symlink.
301301
case FTS_SLNONE: // Symlink with no target.
302-
return .entry(String(cString: ent.ftsEnt.fts_path))
302+
return .entry(String(cString: ent.ftsEnt.fts_path!))
303303

304304
// Error returns
305305
case FTS_DNR: fallthrough // Directory cannot be read.
306306
case FTS_ERR: fallthrough // Some error occurred, but we don't know what.
307307
case FTS_NS: // No stat(2) information is available.
308-
let path = String(cString: ent.ftsEnt.fts_path)
308+
let path = String(cString: ent.ftsEnt.fts_path!)
309309
return .error(ent.ftsEnt.fts_errno, path)
310310

311311
default: return nil

Sources/FoundationEssentials/FileManager/FileOperations.swift

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

522522
case let .entry(entry):
523+
let fts_path = entry.ftsEnt.fts_path!
523524
switch Int32(entry.ftsEnt.fts_info) {
524525
case FTS_DEFAULT, FTS_F, FTS_NSOK, FTS_SL, FTS_SLNONE:
525-
let currentPathStr = resolve(path: String(cString: entry.ftsEnt.fts_path))
526+
let currentPathStr = resolve(path: String(cString: fts_path))
526527
guard fileManager?._shouldRemoveItemAtPath(currentPathStr) ?? true else {
527528
break
528529
}
529-
if unlink(entry.ftsEnt.fts_path) != 0 {
530+
if unlink(fts_path) != 0 {
530531
let error = CocoaError.removeFileError(errno, currentPathStr)
531532
if !(fileManager?._shouldProceedAfter(error: error, removingItemAtPath: currentPathStr) ?? false) {
532533
throw error
@@ -538,20 +539,20 @@ enum _FileOperations {
538539
isFirst = false
539540
break
540541
}
541-
let currentPathStr = resolve(path: String(cString: entry.ftsEnt.fts_path))
542+
let currentPathStr = resolve(path: String(cString: fts_path))
542543
if !(fileManager?._shouldRemoveItemAtPath(currentPathStr) ?? true) {
543544
iterator.skipDescendants(of: entry, skipPostProcessing: true)
544545
}
545546
case FTS_DP:
546-
if rmdir(entry.ftsEnt.fts_path) != 0 {
547-
let currentPathStr = resolve(path: String(cString: entry.ftsEnt.fts_path))
547+
if rmdir(fts_path) != 0 {
548+
let currentPathStr = resolve(path: String(cString: fts_path))
548549
let error = CocoaError.removeFileError(errno, currentPathStr)
549550
if !(fileManager?._shouldProceedAfter(error: error, removingItemAtPath: currentPathStr) ?? false) {
550551
throw error
551552
}
552553
}
553554
case FTS_DNR, FTS_ERR, FTS_NS:
554-
let currentPathStr = resolve(path: String(cString: entry.ftsEnt.fts_path))
555+
let currentPathStr = resolve(path: String(cString: fts_path))
555556
throw CocoaError.removeFileError(entry.ftsEnt.fts_errno, currentPathStr)
556557
default:
557558
break
@@ -866,12 +867,12 @@ enum _FileOperations {
866867
return
867868
}
868869

869-
let total = fileInfo.st_size
870-
let chunkSize = Int(fileInfo.st_blksize)
871-
var current = 0
870+
let total: Int = Int(fileInfo.st_size)
871+
let chunkSize: Int = Int(fileInfo.st_blksize)
872+
var current: off_t = 0
872873

873874
while current < total {
874-
guard sendfile(dstfd, srcfd, &current, Swift.min(total - current, chunkSize)) != -1 else {
875+
guard sendfile(dstfd, srcfd, &current, Swift.min(total - Int(current), chunkSize)) != -1 else {
875876
try delegate.throwIfNecessary(errno, String(cString: srcPtr), String(cString: dstPtr))
876877
return
877878
}
@@ -894,11 +895,12 @@ enum _FileOperations {
894895
throw CocoaError.errorWithFilePath(path, errno: errno, reading: true)
895896

896897
case let .entry(entry):
897-
let trimmedPathPtr = entry.ftsEnt.fts_path.advanced(by: srcLen)
898+
let fts_path = entry.ftsEnt.fts_path!
899+
let trimmedPathPtr = fts_path.advanced(by: srcLen)
898900
Platform.copyCString(dst: dstAppendPtr, src: trimmedPathPtr, size: remainingBuffer)
899901

900902
// 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 {
903+
guard entry.ftsEnt.fts_info == FTS_DP || delegate.shouldPerformOnItemAtPath(String(cString: fts_path), to: String(cString: buffer.baseAddress!)) else {
902904
if entry.ftsEnt.fts_info == FTS_D {
903905
iterator.skipDescendants(of: entry, skipPostProcessing: true)
904906
}
@@ -911,29 +913,29 @@ enum _FileOperations {
911913
case FTS_D:
912914
// Directory being visited in pre-order - create it with whatever default perms will be on the destination.
913915
#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!))
916+
if copyfile(fts_path, buffer.baseAddress!, nil, copyfile_flags_t(COPYFILE_DATA | COPYFILE_EXCL | COPYFILE_NOFOLLOW | extraFlags)) != 0 {
917+
try delegate.throwIfNecessary(errno, String(cString: fts_path), String(cString: buffer.baseAddress!))
916918
}
917919
#else
918920
do {
919921
try fileManager.createDirectory(atPath: String(cString: buffer.baseAddress!), withIntermediateDirectories: true)
920922
} catch {
921-
try delegate.throwIfNecessary(error, String(cString: entry.ftsEnt.fts_path), String(cString: buffer.baseAddress!))
923+
try delegate.throwIfNecessary(error, String(cString: fts_path), String(cString: buffer.baseAddress!))
922924
}
923925
#endif
924926

925927
case FTS_DP:
926928
// Directory being visited in post-order - copy the permissions over.
927929
#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!))
930+
if copyfile(fts_path, buffer.baseAddress!, nil, copyfile_flags_t(COPYFILE_METADATA | COPYFILE_NOFOLLOW | extraFlags)) != 0 {
931+
try delegate.throwIfNecessary(errno, String(cString: fts_path), String(cString: buffer.baseAddress!))
930932
}
931933
#else
932934
do {
933-
let attributes = try fileManager.attributesOfItem(atPath: String(cString: entry.ftsEnt.fts_path))
935+
let attributes = try fileManager.attributesOfItem(atPath: String(cString: fts_path))
934936
try fileManager.setAttributes(attributes, ofItemAtPath: String(cString: buffer.baseAddress!))
935937
} catch {
936-
try delegate.throwIfNecessary(error, String(cString: entry.ftsEnt.fts_path), String(cString: buffer.baseAddress!))
938+
try delegate.throwIfNecessary(error, String(cString: fts_path), String(cString: buffer.baseAddress!))
937939
}
938940
#endif
939941

@@ -947,42 +949,42 @@ enum _FileOperations {
947949
} else {
948950
flags = COPYFILE_DATA | COPYFILE_METADATA | COPYFILE_EXCL | COPYFILE_NOFOLLOW | extraFlags
949951
}
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!))
952+
if copyfile(fts_path, buffer.baseAddress!, nil, copyfile_flags_t(flags)) != 0 {
953+
try delegate.throwIfNecessary(errno, String(cString: fts_path), String(cString: buffer.baseAddress!))
952954
}
953955
#else
954956
try withUnsafeTemporaryAllocation(of: CChar.self, capacity: FileManager.MAX_PATH_SIZE) { tempBuff in
955957
tempBuff.initialize(repeating: 0)
956958
defer { tempBuff.deinitialize() }
957-
let len = readlink(entry.ftsEnt.fts_path, tempBuff.baseAddress!, FileManager.MAX_PATH_SIZE - 1)
959+
let len = readlink(fts_path, tempBuff.baseAddress!, FileManager.MAX_PATH_SIZE - 1)
958960
if len >= 0, symlink(tempBuff.baseAddress!, buffer.baseAddress!) != -1 {
959961
return
960962
}
961-
try delegate.throwIfNecessary(errno, String(cString: entry.ftsEnt.fts_path), String(cString: buffer.baseAddress!))
963+
try delegate.throwIfNecessary(errno, String(cString: fts_path), String(cString: buffer.baseAddress!))
962964
}
963965
#endif
964966

965967
case FTS_DEFAULT: fallthrough // Something not defined anywhere else.
966968
case FTS_F: // Regular file.
967969
if delegate.copyData {
968970
#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!))
971+
if copyfile(fts_path, buffer.baseAddress!, nil, copyfile_flags_t(COPYFILE_CLONE | COPYFILE_ALL | COPYFILE_EXCL | COPYFILE_NOFOLLOW | extraFlags)) != 0 {
972+
try delegate.throwIfNecessary(errno, String(cString: fts_path), String(cString: buffer.baseAddress!))
971973
}
972974
#else
973-
try Self._copyRegularFile(entry.ftsEnt.fts_path, buffer.baseAddress!, delegate: delegate)
975+
try Self._copyRegularFile(fts_path, buffer.baseAddress!, delegate: delegate)
974976
#endif
975977
} 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!))
978+
if link(fts_path, buffer.baseAddress!) != 0 {
979+
try delegate.throwIfNecessary(errno, String(cString: fts_path), String(cString: buffer.baseAddress!))
978980
}
979981
}
980982

981983
// Error returns
982984
case FTS_DNR: fallthrough // Directory cannot be read.
983985
case FTS_ERR: fallthrough // Some error occurred, but we don't know what.
984986
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!))
987+
try delegate.throwIfNecessary(entry.ftsEnt.fts_errno, String(cString: fts_path), String(cString: buffer.baseAddress!))
986988

987989
default: break
988990
}

0 commit comments

Comments
 (0)