Fix OS Error: Cross-device link, errno = 18
This commit is contained in:
+62
-3
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user