From 20b8a84595b14f0cee873f9da65a41d52b79d0cc Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Fri, 15 Jan 2021 17:50:57 +0000 Subject: [PATCH] [core] fix potential "loss" of disk after writing Ubuntu 20.10 in DD mode * Due to the partition gymnastic that is required by the hack that is ISOHybrid, some ISOHybrid images that are written in DD mode, such as Ubuntu 20.10, may result in Windows somehow "losing" the target disk from some of its listings. * This "removal" can be seen for instance if you have diskpart already open and issue 'list disk' after Rufus 3.13 completed its image writing. * In the worst case scenario, Windows may flat out refuse to access the disk at the sector level be it in diskpart or disk manager, which forces ones to clear the partition tables on Linux or some other OS to be able to "recover" the disk. * This appears to be mostly due to Windows VDS cache (which Microsoft assures should be able to do a proper job of refreshing itself on its own, in the same stride as they also feel the need to introduce IVdsService::Refresh whose sole purpose appears to work around a limitation that Microsoft knows exists) not being in sync with the actual disk layout. * So we now add calls to VDS layout refresh where needed, to work around the issue. * Also fix an ext2fs Coverity warning. --- src/drive.c | 77 ++++++++++++++++++++++++++++++++++++++++++-- src/drive.h | 6 +++- src/ext2fs/symlink.c | 4 ++- src/format.c | 3 +- src/rufus.rc | 10 +++--- 5 files changed, 89 insertions(+), 11 deletions(-) diff --git a/src/drive.c b/src/drive.c index ceca853d..471f727f 100644 --- a/src/drive.c +++ b/src/drive.c @@ -1,7 +1,7 @@ /* * Rufus: The Reliable USB Formatting Utility * Drive access function calls - * Copyright © 2011-2020 Pete Batard + * Copyright © 2011-2021 Pete Batard * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -649,6 +649,7 @@ static BOOL GetVdsDiskInterface(DWORD DriveIndex, const IID* InterfaceIID, void* } // Check if we are on the target disk + // uprintf("GetVdsDiskInterface: Seeking %S found %S", wPhysicalName, prop.pwszName); hr = (HRESULT)_wcsicmp(wPhysicalName, prop.pwszName); CoTaskMemFree(prop.pwszName); if (hr != S_OK) { @@ -676,6 +677,71 @@ out: return (hr == S_OK); } +/* + * Invoke IVdsService::Refresh() and/or IVdsService::Reenumerate() to force a + * rescan of the VDS disks. This can become necessary after writing an image + * such as Ubuntu 20.10, as Windows may "lose" the active disk otherwise... + */ +BOOL VdsRescan(DWORD dwRescanType, DWORD dwSleepTime, BOOL bSilent) +{ + BOOL ret = TRUE; + HRESULT hr = S_FALSE; + IVdsServiceLoader* pLoader; + IVdsService* pService; + + IGNORE_RETVAL(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED)); + IGNORE_RETVAL(CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_CONNECT, + RPC_C_IMP_LEVEL_IMPERSONATE, NULL, 0, NULL)); + + hr = CoCreateInstance(&CLSID_VdsLoader, NULL, CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER, + &IID_IVdsServiceLoader, (void**)&pLoader); + if (hr != S_OK) { + suprintf("Could not create VDS Loader Instance: %s", VdsErrorString(hr)); + return FALSE; + } + + hr = IVdsServiceLoader_LoadService(pLoader, L"", &pService); + IVdsServiceLoader_Release(pLoader); + if (hr != S_OK) { + suprintf("Could not load VDS Service: %s", VdsErrorString(hr)); + return FALSE; + } + + hr = IVdsService_WaitForServiceReady(pService); + if (hr != S_OK) { + suprintf("VDS Service is not ready: %s", VdsErrorString(hr)); + return FALSE; + } + + // https://docs.microsoft.com/en-us/windows/win32/api/vds/nf-vds-ivdsservice-refresh + // This method synchronizes the disk layout to the layout known to the disk driver. + // It does not force the driver to read the layout from the disk. + // Additionally, this method refreshes the view of all objects in the VDS cache. + if (dwRescanType & VDS_RESCAN_REFRESH) { + hr = IVdsService_Refresh(pService); + if (hr != S_OK) { + suprintf("VDS Refresh failed: %s", VdsErrorString(hr)); + ret = FALSE; + } + } + + // https://docs.microsoft.com/en-us/windows/win32/api/vds/nf-vds-ivdsservice-reenumerate + // This method returns immediately after a bus rescan request is issued. + // The operation might be incomplete when the method returns. + if (dwRescanType & VDS_RESCAN_REENUMERATE) { + hr = IVdsService_Reenumerate(pService); + if (hr != S_OK) { + suprintf("VDS Re-enumeration failed: %s", VdsErrorString(hr)); + ret = FALSE; + } + } + + if (dwSleepTime != 0) + Sleep(dwSleepTime); + + return ret; +} + /* * Delete one partition at offset PartitionOffset, or all partitions if the offset is 0. */ @@ -689,8 +755,13 @@ BOOL DeletePartition(DWORD DriveIndex, ULONGLONG PartitionOffset, BOOL bSilent) if (!GetVdsDiskInterface(DriveIndex, &IID_IVdsAdvancedDisk, (void**)&pAdvancedDisk, bSilent)) return FALSE; if (pAdvancedDisk == NULL) { - suprintf("No partition to delete on disk"); - return TRUE; + suprintf("Looks like Windows has \"lost\" our disk - Forcing a VDS rescan..."); + VdsRescan(VDS_RESCAN_REFRESH | VDS_RESCAN_REENUMERATE, 1000, bSilent); + if (!GetVdsDiskInterface(DriveIndex, &IID_IVdsAdvancedDisk, (void**)&pAdvancedDisk, bSilent) || + (pAdvancedDisk == NULL)) { + suprintf("Could not locate disk - Aborting."); + return FALSE; + } } // Query the partition data, so we can get the start offset, which we need for deletion diff --git a/src/drive.h b/src/drive.h index 44df0298..461fc097 100644 --- a/src/drive.h +++ b/src/drive.h @@ -1,7 +1,7 @@ /* * Rufus: The Reliable USB Formatting Utility * Drive access function calls - * Copyright © 2011-2020 Pete Batard + * Copyright © 2011-2021 Pete Batard * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -54,6 +54,9 @@ #define FILE_FLOPPY_DISKETTE 0x00000004 +#define VDS_RESCAN_REFRESH 0x00000001 +#define VDS_RESCAN_REENUMERATE 0x00000002 + #define VDS_SET_ERROR(hr) do { if (hr != S_OK) { SetLastError(hr); FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_GEN_FAILURE; } } while(0) #if !defined(__MINGW32__) @@ -373,6 +376,7 @@ BOOL GetAutoMount(BOOL* enabled); char* GetPhysicalName(DWORD DriveIndex); BOOL DeletePartition(DWORD DriveIndex, ULONGLONG PartitionOffset, BOOL bSilent); BOOL ListVdsVolumes(BOOL bSilent); +BOOL VdsRescan(DWORD dwRescanType, DWORD dwSleepTime, BOOL bSilent); HANDLE GetPhysicalHandle(DWORD DriveIndex, BOOL bLockDrive, BOOL bWriteAccess, BOOL bWriteShare); char* GetLogicalName(DWORD DriveIndex, uint64_t PartitionOffset, BOOL bKeepTrailingBackslash, BOOL bSilent); char* AltGetLogicalName(DWORD DriveIndex, uint64_t PartitionOffset, BOOL bKeepTrailingBackslash, BOOL bSilent); diff --git a/src/ext2fs/symlink.c b/src/ext2fs/symlink.c index a66fb7ec..6b0a7397 100644 --- a/src/ext2fs/symlink.c +++ b/src/ext2fs/symlink.c @@ -104,7 +104,9 @@ errcode_t ext2fs_symlink(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t ino, inode.i_mode = LINUX_S_IFLNK | 0777; inode.i_uid = inode.i_gid = 0; inode.i_links_count = 1; - ext2fs_inode_size_set(fs, &inode, target_len); + retval = ext2fs_inode_size_set(fs, &inode, target_len); + if (retval) + goto cleanup; /* The time fields are set by ext2fs_write_new_inode() */ inlinelink = !fastlink && ext2fs_has_feature_inline_data(fs->super); diff --git a/src/format.c b/src/format.c index 27ded0d3..d9344957 100644 --- a/src/format.c +++ b/src/format.c @@ -1,7 +1,7 @@ /* * Rufus: The Reliable USB Formatting Utility * Formatting function calls - * Copyright © 2011-2020 Pete Batard + * Copyright © 2011-2021 Pete Batard * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -2181,6 +2181,7 @@ DWORD WINAPI FormatThread(void* param) } out: + VdsRescan(VDS_RESCAN_REFRESH, 0, TRUE); safe_free(volume_name); safe_free(buffer); safe_closehandle(hSourceImage); diff --git a/src/rufus.rc b/src/rufus.rc index 8aa67275..1a4dd45f 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -35,7 +35,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 232, 326 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 3.14.1733" +CAPTION "Rufus 3.14.1734" FONT 9, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP @@ -397,8 +397,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 3,14,1733,0 - PRODUCTVERSION 3,14,1733,0 + FILEVERSION 3,14,1734,0 + PRODUCTVERSION 3,14,1734,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -416,13 +416,13 @@ BEGIN VALUE "Comments", "https://rufus.ie" VALUE "CompanyName", "Akeo Consulting" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "3.14.1733" + VALUE "FileVersion", "3.14.1734" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", "© 2011-2021 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "https://www.gnu.org/licenses/gpl-3.0.html" VALUE "OriginalFilename", "rufus-3.14.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "3.14.1733" + VALUE "ProductVersion", "3.14.1734" END END BLOCK "VarFileInfo"