Fix OS Error: Cross-device link, errno = 18

This commit is contained in:
2026-07-15 00:46:34 +08:00
parent c9b282d985
commit 0aacef79e5
+62 -3
View File
@@ -181,18 +181,19 @@ Future<void> download(BuildContext context, SyncItemConfig item, dav.File cloudA
if (directory.existsSync()) {
directory.deleteSync(recursive: true);
}
Directory(temp.path);
Directory(temp.path).renameSync(item.path);
await Directory(temp.path).safeMoveDirectory(item.path);
case FileSystemEntityType.file:
var file = File(item.path);
if (file.existsSync()) {
file.deleteSync();
}
temp.renameSync(item.path);
await temp.safeMoveFile(item.path);
default:
print('Failed: $fileSystemEntityType');
}
loadLocalStatus();
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
@@ -211,3 +212,61 @@ extension DateTimeExt on DateTime {
String padZero(int num, [fix = 2]) => num.toString().padLeft(fix, '0');
}
/// 安全地移动文件和目录(支持跨分区)
extension on File {
Future<void> safeMoveFile(String destPath) async {
try {
await rename(destPath);
return;
} on FileSystemException catch (e) {
// 捕获到 errno = 18 (EXDEV) 跨分区错误时,退化到“复制+删除”方案
if (e.osError?.errorCode != 18) {
rethrow; // 其他错误继续抛出
}
}
await copy(destPath);
await delete();
}
}
extension on Directory {
Future<void> safeMoveDirectory(String destPath) async {
// 1. 如果在同一分区,优先尝试 rename,效率最高
try {
await rename(destPath);
return;
} on FileSystemException catch (e) {
// 捕获到 errno = 18 (EXDEV) 跨分区错误时,退化到“复制+删除”方案
if (e.osError?.errorCode != 18) {
rethrow; // 其他错误继续抛出
}
}
// 2. 跨分区移动:递归复制
await _copyDirectory(this, Directory(destPath));
// 3. 复制完成后删除源目录
await delete(recursive: true);
}
}
/// 递归复制目录
Future<void> _copyDirectory(Directory source, Directory destination) async {
// 确保目标目录存在
await destination.create(recursive: true);
await for (var entity in source.list(recursive: false)) {
// 计算在新目录下的对应路径
final newPath = '${destination.path}/${entity.uri.pathSegments.lastWhere((s) => s.isNotEmpty)}';
if (entity is File) {
await entity.copy(newPath);
} else if (entity is Directory) {
await _copyDirectory(entity, Directory(newPath));
}
}
}