| 1397 | } |
| 1398 | |
| 1399 | bool win_ioctl_clone(const std::wstring& src_path, const std::wstring& dst_path, std::error_code& ec) |
| 1400 | { |
| 1401 | /** |
| 1402 | * This algorithm inspired from https://github.com/0xbadfca11/reflink |
| 1403 | * LICENSE MIT |
| 1404 | * |
| 1405 | * Additional references |
| 1406 | * https://learn.microsoft.com/en-us/windows/win32/api/winioctl/ni-winioctl-fsctl_duplicate_extents_to_file |
| 1407 | * https://github.com/microsoft/CopyOnWrite/blob/main/lib/Windows/WindowsCopyOnWriteFilesystem.cs#L94 |
| 1408 | */ |
| 1409 | |
| 1410 | HANDLE hSourceFile = CreateFileW(src_path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr); |
| 1411 | if (hSourceFile == INVALID_HANDLE_VALUE) { |
| 1412 | ec = std::error_code(GetLastError(), std::system_category()); |
| 1413 | qDebug() << "Failed to open source file" << src_path.c_str(); |
| 1414 | return false; |
| 1415 | } |
| 1416 | |
| 1417 | ULONG fs_flags; |
| 1418 | if (!GetVolumeInformationByHandleW(hSourceFile, nullptr, 0, nullptr, nullptr, &fs_flags, nullptr, 0)) { |
| 1419 | ec = std::error_code(GetLastError(), std::system_category()); |
| 1420 | qDebug() << "Failed to get Filesystem information for " << src_path.c_str(); |
| 1421 | CloseHandle(hSourceFile); |
| 1422 | return false; |
| 1423 | } |
| 1424 | if (!(fs_flags & FILE_SUPPORTS_BLOCK_REFCOUNTING)) { |
| 1425 | SetLastError(ERROR_NOT_CAPABLE); |
| 1426 | ec = std::error_code(GetLastError(), std::system_category()); |
| 1427 | qWarning() << "Filesystem at " << src_path.c_str() << " does not support reflink"; |
| 1428 | CloseHandle(hSourceFile); |
| 1429 | return false; |
| 1430 | } |
| 1431 | |
| 1432 | FILE_END_OF_FILE_INFO sourceFileLength; |
| 1433 | if (!GetFileSizeEx(hSourceFile, &sourceFileLength.EndOfFile)) { |
| 1434 | ec = std::error_code(GetLastError(), std::system_category()); |
| 1435 | qDebug() << "Failed to size of source file" << src_path.c_str(); |
| 1436 | CloseHandle(hSourceFile); |
| 1437 | return false; |
| 1438 | } |
| 1439 | FILE_BASIC_INFO sourceFileBasicInfo; |
| 1440 | if (!GetFileInformationByHandleEx(hSourceFile, FileBasicInfo, &sourceFileBasicInfo, sizeof(sourceFileBasicInfo))) { |
| 1441 | ec = std::error_code(GetLastError(), std::system_category()); |
| 1442 | qDebug() << "Failed to source file info" << src_path.c_str(); |
| 1443 | CloseHandle(hSourceFile); |
| 1444 | return false; |
| 1445 | } |
| 1446 | ULONG junk; |
| 1447 | FSCTL_GET_INTEGRITY_INFORMATION_BUFFER sourceFileIntegrity; |
| 1448 | if (!DeviceIoControl(hSourceFile, FSCTL_GET_INTEGRITY_INFORMATION, nullptr, 0, &sourceFileIntegrity, sizeof(sourceFileIntegrity), &junk, |
| 1449 | nullptr)) { |
| 1450 | ec = std::error_code(GetLastError(), std::system_category()); |
| 1451 | qDebug() << "Failed to source file integrity info" << src_path.c_str(); |
| 1452 | CloseHandle(hSourceFile); |
| 1453 | return false; |
| 1454 | } |
| 1455 | |
| 1456 | HANDLE hDestFile = CreateFileW(dst_path.c_str(), GENERIC_READ | GENERIC_WRITE | DELETE, 0, nullptr, CREATE_NEW, 0, hSourceFile); |
no test coverage detected