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()) {
|
if (directory.existsSync()) {
|
||||||
directory.deleteSync(recursive: true);
|
directory.deleteSync(recursive: true);
|
||||||
}
|
}
|
||||||
Directory(temp.path);
|
await Directory(temp.path).safeMoveDirectory(item.path);
|
||||||
Directory(temp.path).renameSync(item.path);
|
|
||||||
case FileSystemEntityType.file:
|
case FileSystemEntityType.file:
|
||||||
var file = File(item.path);
|
var file = File(item.path);
|
||||||
if (file.existsSync()) {
|
if (file.existsSync()) {
|
||||||
file.deleteSync();
|
file.deleteSync();
|
||||||
}
|
}
|
||||||
temp.renameSync(item.path);
|
await temp.safeMoveFile(item.path);
|
||||||
default:
|
default:
|
||||||
print('Failed: $fileSystemEntityType');
|
print('Failed: $fileSystemEntityType');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loadLocalStatus();
|
||||||
|
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
SnackBar(
|
SnackBar(
|
||||||
@@ -211,3 +212,61 @@ extension DateTimeExt on DateTime {
|
|||||||
|
|
||||||
String padZero(int num, [fix = 2]) => num.toString().padLeft(fix, '0');
|
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