diff --git a/INSTALL/Ventoy2Disk.exe b/INSTALL/Ventoy2Disk.exe index 66d871e0..63cb2bca 100644 Binary files a/INSTALL/Ventoy2Disk.exe and b/INSTALL/Ventoy2Disk.exe differ diff --git a/Ventoy2Disk/Ventoy2Disk/DiskService.h b/Ventoy2Disk/Ventoy2Disk/DiskService.h index a8b68af7..95b8bbc4 100644 --- a/Ventoy2Disk/Ventoy2Disk/DiskService.h +++ b/Ventoy2Disk/Ventoy2Disk/DiskService.h @@ -41,7 +41,7 @@ BOOL VDS_ChangeVtoyEFIAttr(int DriveIndex, UINT64 Attr); BOOL VDS_CreateVtoyEFIPart(int DriveIndex, UINT64 Offset); BOOL VDS_ChangeVtoyEFI2ESP(int DriveIndex, UINT64 Offset); BOOL VDS_ChangeVtoyEFI2Basic(int DriveIndex, UINT64 Offset); - +BOOL VDS_FormatVtoyEFIPart(int DriveIndex, UINT64 Offset); //diskpart.exe BOOL DSPT_CleanDisk(int DriveIndex); diff --git a/Ventoy2Disk/Ventoy2Disk/DiskService_vds.c b/Ventoy2Disk/Ventoy2Disk/DiskService_vds.c index 7fd3f111..69f09967 100644 --- a/Ventoy2Disk/Ventoy2Disk/DiskService_vds.c +++ b/Ventoy2Disk/Ventoy2Disk/DiskService_vds.c @@ -28,9 +28,515 @@ #include "DiskService.h" + +// Count on Microsoft to add a new API while not bothering updating the existing error facilities, +// so that the new error messages have to be handled manually. Now, since I don't have all day: +// 1. Copy text from https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-vds/5102cc53-3143-4268-ba4c-6ea39e999ab4 +// 2. awk '{l[NR%7]=$0} {if (NR%7==0) printf "\tcase %s:\t// %s\n\t\treturn \"%s\";\n", l[1], l[3], l[6]}' vds.txt +// 3. Filter out the crap we don't need. +static const char *GetVdsError(DWORD error_code) +{ + switch (error_code) { + case 0x80042400: // VDS_E_NOT_SUPPORTED + return "The operation is not supported by the object."; + case 0x80042401: // VDS_E_INITIALIZED_FAILED + return "VDS or the provider failed to initialize."; + case 0x80042402: // VDS_E_INITIALIZE_NOT_CALLED + return "VDS did not call the hardware provider's initialization method."; + case 0x80042403: // VDS_E_ALREADY_REGISTERED + return "The provider is already registered."; + case 0x80042404: // VDS_E_ANOTHER_CALL_IN_PROGRESS + return "A concurrent second call is made on an object before the first call is completed."; + case 0x80042405: // VDS_E_OBJECT_NOT_FOUND + return "The specified object was not found."; + case 0x80042406: // VDS_E_INVALID_SPACE + return "The specified space is neither free nor valid."; + case 0x80042407: // VDS_E_PARTITION_LIMIT_REACHED + return "No more partitions can be created on the specified disk."; + case 0x80042408: // VDS_E_PARTITION_NOT_EMPTY + return "The extended partition is not empty."; + case 0x80042409: // VDS_E_OPERATION_PENDING + return "The operation is still in progress."; + case 0x8004240A: // VDS_E_OPERATION_DENIED + return "The operation is not permitted on the specified disk, partition, or volume."; + case 0x8004240B: // VDS_E_OBJECT_DELETED + return "The object no longer exists."; + case 0x8004240C: // VDS_E_CANCEL_TOO_LATE + return "The operation can no longer be canceled."; + case 0x8004240D: // VDS_E_OPERATION_CANCELED + return "The operation has already been canceled."; + case 0x8004240E: // VDS_E_CANNOT_EXTEND + return "The file system does not support extending this volume."; + case 0x8004240F: // VDS_E_NOT_ENOUGH_SPACE + return "There is not enough space to complete the operation."; + case 0x80042410: // VDS_E_NOT_ENOUGH_DRIVE + return "There are not enough free disk drives in the subsystem to complete the operation."; + case 0x80042411: // VDS_E_BAD_COOKIE + return "The cookie was not found."; + case 0x80042412: // VDS_E_NO_MEDIA + return "There is no removable media in the drive."; + case 0x80042413: // VDS_E_DEVICE_IN_USE + return "The device is currently in use."; + case 0x80042414: // VDS_E_DISK_NOT_EMPTY + return "The disk contains partitions or volumes."; + case 0x80042415: // VDS_E_INVALID_OPERATION + return "The specified operation is not valid."; + case 0x80042416: // VDS_E_PATH_NOT_FOUND + return "The specified path was not found."; + case 0x80042417: // VDS_E_DISK_NOT_INITIALIZED + return "The specified disk has not been initialized."; + case 0x80042418: // VDS_E_NOT_AN_UNALLOCATED_DISK + return "The specified disk is not an unallocated disk."; + case 0x80042419: // VDS_E_UNRECOVERABLE_ERROR + return "An unrecoverable error occurred. The service MUST shut down."; + case 0x0004241A: // VDS_S_DISK_PARTIALLY_CLEANED + return "The clean operation was not a full clean or was canceled before it could be completed."; + case 0x8004241B: // VDS_E_DMADMIN_SERVICE_CONNECTION_FAILED + return "The provider failed to connect to the LDMA service."; + case 0x8004241C: // VDS_E_PROVIDER_INITIALIZATION_FAILED + return "The provider failed to initialize."; + case 0x8004241D: // VDS_E_OBJECT_EXISTS + return "The object already exists."; + case 0x8004241E: // VDS_E_NO_DISKS_FOUND + return "No disks were found on the target machine."; + case 0x8004241F: // VDS_E_PROVIDER_CACHE_CORRUPT + return "The cache for a provider is corrupt."; + case 0x80042420: // VDS_E_DMADMIN_METHOD_CALL_FAILED + return "A method call to the LDMA service failed."; + case 0x00042421: // VDS_S_PROVIDER_ERROR_LOADING_CACHE + return "The provider encountered errors while loading the cache."; + case 0x80042422: // VDS_E_PROVIDER_VOL_DEVICE_NAME_NOT_FOUND + return "The device form of the volume pathname could not be retrieved."; + case 0x80042423: // VDS_E_PROVIDER_VOL_OPEN + return "Failed to open the volume device"; + case 0x80042424: // VDS_E_DMADMIN_CORRUPT_NOTIFICATION + return "A corrupt notification was sent from the LDMA service."; + case 0x80042425: // VDS_E_INCOMPATIBLE_FILE_SYSTEM + return "The file system is incompatible with the specified operation."; + case 0x80042426: // VDS_E_INCOMPATIBLE_MEDIA + return "The media is incompatible with the specified operation."; + case 0x80042427: // VDS_E_ACCESS_DENIED + return "Access is denied. A VDS operation MUST run elevated."; + case 0x80042428: // VDS_E_MEDIA_WRITE_PROTECTED + return "The media is write-protected."; + case 0x80042429: // VDS_E_BAD_LABEL + return "The volume label is not valid."; + case 0x8004242A: // VDS_E_CANT_QUICK_FORMAT + return "The volume cannot be quick-formatted."; + case 0x8004242B: // VDS_E_IO_ERROR + return "An I/O error occurred during the operation."; + case 0x8004242C: // VDS_E_VOLUME_TOO_SMALL + return "The volume size is too small."; + case 0x8004242D: // VDS_E_VOLUME_TOO_BIG + return "The volume size is too large."; + case 0x8004242E: // VDS_E_CLUSTER_SIZE_TOO_SMALL + return "The cluster size is too small."; + case 0x8004242F: // VDS_E_CLUSTER_SIZE_TOO_BIG + return "The cluster size is too large."; + case 0x80042430: // VDS_E_CLUSTER_COUNT_BEYOND_32BITS + return "The number of clusters is too large to be represented as a 32-bit integer."; + case 0x80042431: // VDS_E_OBJECT_STATUS_FAILED + return "The component that the object represents has failed."; + case 0x80042432: // VDS_E_VOLUME_INCOMPLETE + return "The volume is incomplete."; + case 0x80042433: // VDS_E_EXTENT_SIZE_LESS_THAN_MIN + return "The specified extent size is too small."; + case 0x00042434: // VDS_S_UPDATE_BOOTFILE_FAILED + return "The operation was successful, but VDS failed to update the boot options."; + case 0x00042436: // VDS_S_BOOT_PARTITION_NUMBER_CHANGE + case 0x80042436: // VDS_E_BOOT_PARTITION_NUMBER_CHANGE + return "The boot partition's partition number will change as a result of the operation."; + case 0x80042437: // VDS_E_NO_FREE_SPACE + return "The specified disk does not have enough free space to complete the operation."; + case 0x80042438: // VDS_E_ACTIVE_PARTITION + return "An active partition was detected on the selected disk."; + case 0x80042439: // VDS_E_PARTITION_OF_UNKNOWN_TYPE + return "The partition information cannot be read."; + case 0x8004243A: // VDS_E_LEGACY_VOLUME_FORMAT + return "A partition with an unknown type was detected on the specified disk."; + case 0x8004243C: // VDS_E_MIGRATE_OPEN_VOLUME + return "A volume on the specified disk could not be opened."; + case 0x8004243D: // VDS_E_VOLUME_NOT_ONLINE + return "The volume is not online."; + case 0x8004243E: // VDS_E_VOLUME_NOT_HEALTHY + return "The volume is failing or has failed."; + case 0x8004243F: // VDS_E_VOLUME_SPANS_DISKS + return "The volume spans multiple disks."; + case 0x80042440: // VDS_E_REQUIRES_CONTIGUOUS_DISK_SPACE + return "The volume does not consist of a single disk extent."; + case 0x80042441: // VDS_E_BAD_PROVIDER_DATA + return "A provider returned bad data."; + case 0x80042442: // VDS_E_PROVIDER_FAILURE + return "A provider failed to complete an operation."; + case 0x00042443: // VDS_S_VOLUME_COMPRESS_FAILED + return "The file system was formatted successfully but could not be compressed."; + case 0x80042444: // VDS_E_PACK_OFFLINE + return "The pack is offline."; + case 0x80042445: // VDS_E_VOLUME_NOT_A_MIRROR + return "The volume is not a mirror."; + case 0x80042446: // VDS_E_NO_EXTENTS_FOR_VOLUME + return "No extents were found for the volume."; + case 0x80042447: // VDS_E_DISK_NOT_LOADED_TO_CACHE + return "The migrated disk failed to load to the cache."; + case 0x80042448: // VDS_E_INTERNAL_ERROR + return "VDS encountered an internal error."; + case 0x8004244A: // VDS_E_PROVIDER_TYPE_NOT_SUPPORTED + return "The method call is not supported for the specified provider type."; + case 0x8004244B: // VDS_E_DISK_NOT_ONLINE + return "One or more of the specified disks are not online."; + case 0x8004244C: // VDS_E_DISK_IN_USE_BY_VOLUME + return "One or more extents of the disk are already being used by the volume."; + case 0x0004244D: // VDS_S_IN_PROGRESS + return "The asynchronous operation is in progress."; + case 0x8004244E: // VDS_E_ASYNC_OBJECT_FAILURE + return "Failure initializing the asynchronous object."; + case 0x8004244F: // VDS_E_VOLUME_NOT_MOUNTED + return "The volume is not mounted."; + case 0x80042450: // VDS_E_PACK_NOT_FOUND + return "The pack was not found."; + case 0x80042453: // VDS_E_OBJECT_OUT_OF_SYNC + return "The reference to the object might be stale."; + case 0x80042454: // VDS_E_MISSING_DISK + return "The specified disk could not be found."; + case 0x80042455: // VDS_E_DISK_PNP_REG_CORRUPT + return "The provider's list of PnP registered disks has become corrupted."; + case 0x80042457: // VDS_E_NO_DRIVELETTER_FLAG + return "The provider does not support the VDS_VF_NO DRIVELETTER volume flag."; + case 0x80042459: // VDS_E_REVERT_ON_CLOSE_SET + return "Some volume flags are already set."; + case 0x0004245B: // VDS_S_UNABLE_TO_GET_GPT_ATTRIBUTES + return "Unable to retrieve the GPT attributes for this volume."; + case 0x8004245C: // VDS_E_VOLUME_TEMPORARILY_DISMOUNTED + return "The volume is already dismounted temporarily."; + case 0x8004245D: // VDS_E_VOLUME_PERMANENTLY_DISMOUNTED + return "The volume is already permanently dismounted."; + case 0x8004245E: // VDS_E_VOLUME_HAS_PATH + return "The volume cannot be dismounted permanently because it still has an access path."; + case 0x8004245F: // VDS_E_TIMEOUT + return "The operation timed out."; + case 0x80042461: // VDS_E_LDM_TIMEOUT + return "The operation timed out in the LDMA service. Retry the operation."; + case 0x80042462: // VDS_E_REVERT_ON_CLOSE_MISMATCH + return "The flags to be cleared do not match the flags that were set previously."; + case 0x80042463: // VDS_E_RETRY + return "The operation failed. Retry the operation."; + case 0x80042464: // VDS_E_ONLINE_PACK_EXISTS + return "The operation failed, because an online pack object already exists."; + case 0x80042468: // VDS_E_MAX_USABLE_MBR + return "Only the first 2TB are usable on large MBR disks."; + case 0x80042500: // VDS_E_NO_SOFTWARE_PROVIDERS_LOADED + return "There are no software providers loaded."; + case 0x80042501: // VDS_E_DISK_NOT_MISSING + return "The disk is not missing."; + case 0x80042502: // VDS_E_NO_VOLUME_LAYOUT + return "The volume's layout could not be retrieved."; + case 0x80042503: // VDS_E_CORRUPT_VOLUME_INFO + return "The volume's driver information is corrupted."; + case 0x80042504: // VDS_E_INVALID_ENUMERATOR + return "The enumerator is corrupted"; + case 0x80042505: // VDS_E_DRIVER_INTERNAL_ERROR + return "An internal error occurred in the volume management driver."; + case 0x80042507: // VDS_E_VOLUME_INVALID_NAME + return "The volume name is not valid."; + case 0x00042508: // VDS_S_DISK_IS_MISSING + return "The disk is missing and not all information could be returned."; + case 0x80042509: // VDS_E_CORRUPT_PARTITION_INFO + return "The disk's partition information is corrupted."; + case 0x0004250A: // VDS_S_NONCONFORMANT_PARTITION_INFO + return "The disk's partition information does not conform to what is expected on a dynamic disk."; + case 0x8004250B: // VDS_E_CORRUPT_EXTENT_INFO + return "The disk's extent information is corrupted."; + case 0x0004250E: // VDS_S_SYSTEM_PARTITION + return "Warning: There was a failure while checking for the system partition."; + case 0x8004250F: // VDS_E_BAD_PNP_MESSAGE + return "The PNP service sent a corrupted notification to the provider."; + case 0x80042510: // VDS_E_NO_PNP_DISK_ARRIVE + case 0x80042511: // VDS_E_NO_PNP_VOLUME_ARRIVE + return "No disk/volume arrival notification was received."; + case 0x80042512: // VDS_E_NO_PNP_DISK_REMOVE + case 0x80042513: // VDS_E_NO_PNP_VOLUME_REMOVE + return "No disk/volume removal notification was received."; + case 0x80042514: // VDS_E_PROVIDER_EXITING + return "The provider is exiting."; + case 0x00042517: // VDS_S_NO_NOTIFICATION + return "No volume arrival notification was received."; + case 0x80042519: // VDS_E_INVALID_DISK + return "The specified disk is not valid."; + case 0x8004251A: // VDS_E_INVALID_PACK + return "The specified disk pack is not valid."; + case 0x8004251B: // VDS_E_VOLUME_ON_DISK + return "This operation is not allowed on disks with volumes."; + case 0x8004251C: // VDS_E_DRIVER_INVALID_PARAM + return "The driver returned an invalid parameter error."; + case 0x8004253D: // VDS_E_DRIVER_OBJECT_NOT_FOUND + return "The object was not found in the driver cache."; + case 0x8004253E: // VDS_E_PARTITION_NOT_CYLINDER_ALIGNED + return "The disk layout contains partitions which are not cylinder aligned."; + case 0x8004253F: // VDS_E_DISK_LAYOUT_PARTITIONS_TOO_SMALL + return "The disk layout contains partitions which are less than the minimum required size."; + case 0x80042540: // VDS_E_DISK_IO_FAILING + return "The I/O to the disk is failing."; + case 0x80042543: // VDS_E_GPT_ATTRIBUTES_INVALID + return "Invalid GPT attributes were specified."; + case 0x8004254D: // VDS_E_UNEXPECTED_DISK_LAYOUT_CHANGE + return "An unexpected layout change occurred external to the volume manager."; + case 0x8004254E: // VDS_E_INVALID_VOLUME_LENGTH + return "The volume length is invalid."; + case 0x8004254F: // VDS_E_VOLUME_LENGTH_NOT_SECTOR_SIZE_MULTIPLE + return "The volume length is not a multiple of the sector size."; + case 0x80042550: // VDS_E_VOLUME_NOT_RETAINED + return "The volume does not have a retained partition association."; + case 0x80042551: // VDS_E_VOLUME_RETAINED + return "The volume already has a retained partition association."; + case 0x80042553: // VDS_E_ALIGN_BEYOND_FIRST_CYLINDER + return "The specified alignment is beyond the first cylinder."; + case 0x80042554: // VDS_E_ALIGN_NOT_SECTOR_SIZE_MULTIPLE + return "The specified alignment is not a multiple of the sector size."; + case 0x80042555: // VDS_E_ALIGN_NOT_ZERO + return "The specified partition type cannot be created with a non-zero alignment."; + case 0x80042556: // VDS_E_CACHE_CORRUPT + return "The service's cache has become corrupt."; + case 0x80042557: // VDS_E_CANNOT_CLEAR_VOLUME_FLAG + return "The specified volume flag cannot be cleared."; + case 0x80042558: // VDS_E_DISK_BEING_CLEANED + return "The operation is not allowed on a disk that is in the process of being cleaned."; + case 0x8004255A: // VDS_E_DISK_REMOVEABLE + return "The operation is not supported on removable media."; + case 0x8004255B: // VDS_E_DISK_REMOVEABLE_NOT_EMPTY + return "The operation is not supported on a non-empty removable disk."; + case 0x8004255C: // VDS_E_DRIVE_LETTER_NOT_FREE + return "The specified drive letter is not free to be assigned."; + case 0x8004255E: // VDS_E_INVALID_DRIVE_LETTER + return "The specified drive letter is not valid."; + case 0x8004255F: // VDS_E_INVALID_DRIVE_LETTER_COUNT + return "The specified number of drive letters to retrieve is not valid."; + case 0x80042560: // VDS_E_INVALID_FS_FLAG + return "The specified file system flag is not valid."; + case 0x80042561: // VDS_E_INVALID_FS_TYPE + return "The specified file system is not valid."; + case 0x80042562: // VDS_E_INVALID_OBJECT_TYPE + return "The specified object type is not valid."; + case 0x80042563: // VDS_E_INVALID_PARTITION_LAYOUT + return "The specified partition layout is invalid."; + case 0x80042564: // VDS_E_INVALID_PARTITION_STYLE + return "VDS only supports MBR or GPT partition style disks."; + case 0x80042565: // VDS_E_INVALID_PARTITION_TYPE + return "The specified partition type is not valid for this operation."; + case 0x80042566: // VDS_E_INVALID_PROVIDER_CLSID + case 0x80042567: // VDS_E_INVALID_PROVIDER_ID + case 0x8004256A: // VDS_E_INVALID_PROVIDER_VERSION_GUID + return "A NULL GUID was passed to the provider."; + case 0x80042568: // VDS_E_INVALID_PROVIDER_NAME + return "The specified provider name is invalid."; + case 0x80042569: // VDS_E_INVALID_PROVIDER_TYPE + return "The specified provider type is invalid."; + case 0x8004256B: // VDS_E_INVALID_PROVIDER_VERSION_STRING + return "The specified provider version string is invalid."; + case 0x8004256C: // VDS_E_INVALID_QUERY_PROVIDER_FLAG + return "The specified query provider flag is invalid."; + case 0x8004256D: // VDS_E_INVALID_SERVICE_FLAG + return "The specified service flag is invalid."; + case 0x8004256E: // VDS_E_INVALID_VOLUME_FLAG + return "The specified volume flag is invalid."; + case 0x8004256F: // VDS_E_PARTITION_NOT_OEM + return "The operation is only supported on an OEM, ESP, or unknown partition."; + case 0x80042570: // VDS_E_PARTITION_PROTECTED + return "Cannot delete a protected partition without the force protected parameter set."; + case 0x80042571: // VDS_E_PARTITION_STYLE_MISMATCH + return "The specified partition style is not the same as the disk's partition style."; + case 0x80042572: // VDS_E_PROVIDER_INTERNAL_ERROR + return "An internal error has occurred in the provider."; + case 0x80042575: // VDS_E_UNRECOVERABLE_PROVIDER_ERROR + return "An unrecoverable error occurred in the provider."; + case 0x80042576: // VDS_E_VOLUME_HIDDEN + return "Cannot assign a mount point to a hidden volume."; + case 0x00042577: // VDS_S_DISMOUNT_FAILED + case 0x00042578: // VDS_S_REMOUNT_FAILED + return "Failed to dismount/remount the volume after setting the volume flags."; + case 0x80042579: // VDS_E_FLAG_ALREADY_SET + return "Cannot set the specified flag as revert-on-close because it is already set."; + case 0x8004257B: // VDS_E_DISTINCT_VOLUME + return "The input volume id cannot be the id of the volume that is the target of the operation."; + case 0x00042583: // VDS_S_FS_LOCK + return "Failed to obtain a file system lock."; + case 0x80042584: // VDS_E_READONLY + return "The volume is read only."; + case 0x80042585: // VDS_E_INVALID_VOLUME_TYPE + return "The volume type is invalid for this operation."; + case 0x80042588: // VDS_E_VOLUME_MIRRORED + return "This operation is not supported on a mirrored volume."; + case 0x80042589: // VDS_E_VOLUME_SIMPLE_SPANNED + return "The operation is only supported on simple or spanned volumes."; + case 0x8004258C: // VDS_E_PARTITION_MSR + case 0x8004258D: // VDS_E_PARTITION_LDM + return "The operation is not supported on this type of partitions."; + case 0x0004258E: // VDS_S_WINPE_BOOTENTRY + return "The boot entries cannot be updated automatically on WinPE."; + case 0x8004258F: // VDS_E_ALIGN_NOT_A_POWER_OF_TWO + return "The alignment is not a power of two."; + case 0x80042590: // VDS_E_ALIGN_IS_ZERO + return "The alignment is zero."; + case 0x80042593: // VDS_E_FS_NOT_DETERMINED + return "The default file system could not be determined."; + case 0x80042595: // VDS_E_DISK_NOT_OFFLINE + return "This disk is already online."; + case 0x80042596: // VDS_E_FAILED_TO_ONLINE_DISK + return "The online operation failed."; + case 0x80042597: // VDS_E_FAILED_TO_OFFLINE_DISK + return "The offline operation failed."; + case 0x80042598: // VDS_E_BAD_REVISION_NUMBER + return "The operation could not be completed because the specified revision number is not supported."; + case 0x00042700: // VDS_S_NAME_TRUNCATED + return "The name was set successfully but had to be truncated."; + case 0x80042701: // VDS_E_NAME_NOT_UNIQUE + return "The specified name is not unique."; + case 0x8004270F: // VDS_E_NO_DISK_PATHNAME + return "The disk's path could not be retrieved. Some operations on the disk might fail."; + case 0x80042711: // VDS_E_NO_VOLUME_PATHNAME + return "The path could not be retrieved for one or more volumes."; + case 0x80042712: // VDS_E_PROVIDER_CACHE_OUTOFSYNC + return "The provider's cache is not in sync with the driver cache."; + case 0x80042713: // VDS_E_NO_IMPORT_TARGET + return "No import target was set for the subsystem."; + case 0x00042714: // VDS_S_ALREADY_EXISTS + return "The object already exists."; + case 0x00042715: // VDS_S_PROPERTIES_INCOMPLETE + return "Some, but not all, of the properties were successfully retrieved."; + case 0x80042803: // VDS_E_UNABLE_TO_FIND_BOOT_DISK + return "Volume disk extent information could not be retrieved for the boot volume."; + case 0x80042807: // VDS_E_BOOT_DISK + return "Disk attributes cannot be changed on the boot disk."; + case 0x00042808: // VDS_S_DISK_MOUNT_FAILED + case 0x00042809: // VDS_S_DISK_DISMOUNT_FAILED + return "One or more of the volumes on the disk could not be mounted/dismounted."; + case 0x8004280A: // VDS_E_DISK_IS_OFFLINE + case 0x8004280B: // VDS_E_DISK_IS_READ_ONLY + return "The operation cannot be performed on a disk that is offline or read-only."; + case 0x8004280C: // VDS_E_PAGEFILE_DISK + case 0x8004280D: // VDS_E_HIBERNATION_FILE_DISK + case 0x8004280E: // VDS_E_CRASHDUMP_DISK + return "The operation cannot be performed on a disk that contains a pagefile, hibernation or crashdump volume."; + case 0x8004280F: // VDS_E_UNABLE_TO_FIND_SYSTEM_DISK + return "A system error occurred while retrieving the system disk information."; + case 0x80042810: // VDS_E_INCORRECT_SYSTEM_VOLUME_EXTENT_INFO + return "Multiple disk extents reported for the system volume - system error."; + case 0x80042811: // VDS_E_SYSTEM_DISK + return "Disk attributes cannot be changed on the current system disk or BIOS disk 0."; + case 0x80042823: // VDS_E_SECTOR_SIZE_ERROR + return "The sector size MUST be non-zero, a power of 2, and less than the maximum sector size."; + case 0x80042907: // VDS_E_SUBSYSTEM_ID_IS_NULL + return "The provider returned a NULL subsystem identification string."; + case 0x8004290C: // VDS_E_REBOOT_REQUIRED + return "A reboot is required before any further operations are initiated."; + case 0x8004290D: // VDS_E_VOLUME_GUID_PATHNAME_NOT_ALLOWED + return "Volume GUID pathnames are not valid input to this method."; + case 0x8004290E: // VDS_E_BOOT_PAGEFILE_DRIVE_LETTER + return "Assigning or removing drive letters on the current boot or pagefile volume is not allowed."; + case 0x8004290F: // VDS_E_DELETE_WITH_CRITICAL + return "Delete is not allowed on a critical volume."; + case 0x80042910: // VDS_E_CLEAN_WITH_DATA + case 0x80042911: // VDS_E_CLEAN_WITH_OEM + return "The FORCE parameter MUST be set to TRUE in order to clean a disk that contains a data or OEM volume."; + case 0x80042912: // VDS_E_CLEAN_WITH_CRITICAL + return "Clean is not allowed on a critical disk."; + case 0x80042913: // VDS_E_FORMAT_CRITICAL + return "Format is not allowed on a critical volume."; + case 0x80042914: // VDS_E_NTFS_FORMAT_NOT_SUPPORTED + case 0x80042915: // VDS_E_FAT32_FORMAT_NOT_SUPPORTED + case 0x80042916: // VDS_E_FAT_FORMAT_NOT_SUPPORTED + return "The requested file system format is not supported on this volume."; + case 0x80042917: // VDS_E_FORMAT_NOT_SUPPORTED + return "The volume is not formattable."; + case 0x80042918: // VDS_E_COMPRESSION_NOT_SUPPORTED + return "The specified file system does not support compression."; + default: + return NULL; + } +} + +static const char* GetVimError(DWORD error_code) +{ + switch (error_code) { + case 0xC1420127: + return "The specified image in the specified wim is already mounted for read and write access."; + default: + return NULL; + } +} + +#define sfree(p) do {if (p != NULL) {free((void*)(p)); p = NULL;}} while(0) +#define wconvert(p) wchar_t* w ## p = utf8_to_wchar(p) +#define walloc(p, size) wchar_t* w ## p = (p == NULL)?NULL:(wchar_t*)calloc(size, sizeof(wchar_t)) +#define wfree(p) sfree(w ## p) +#define wchar_to_utf8_no_alloc(wsrc, dest, dest_size) \ + WideCharToMultiByte(CP_UTF8, 0, wsrc, -1, dest, dest_size, NULL, NULL) + +static __inline DWORD FormatMessageU(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, + DWORD dwLanguageId, char* lpBuffer, DWORD nSize, va_list *Arguments) +{ + DWORD ret = 0, err = ERROR_INVALID_DATA; + // coverity[returned_null] + walloc(lpBuffer, nSize); + ret = FormatMessageW(dwFlags, lpSource, dwMessageId, dwLanguageId, wlpBuffer, nSize, Arguments); + err = GetLastError(); + if ((ret != 0) && ((ret = wchar_to_utf8_no_alloc(wlpBuffer, lpBuffer, nSize)) == 0)) { + err = GetLastError(); + ret = 0; + } + wfree(lpBuffer); + SetLastError(err); + return ret; +} + + +// Convert a windows error to human readable string +const char *WindowsErrorString(DWORD error_code) +{ + static char err_string[256] = { 0 }; + + DWORD size, presize; + DWORD format_error; + + // Check for VDS error codes + if ((HRESULT_FACILITY(error_code) == FACILITY_ITF) && (GetVdsError(error_code) != NULL)) { + sprintf_s(err_string, sizeof(err_string), "[0x%08lX] %s", error_code, GetVdsError(error_code)); + return err_string; + } + if ((HRESULT_FACILITY(error_code) == 322) && (GetVimError(error_code) != NULL)) { + sprintf_s(err_string, sizeof(err_string), "[0x%08lX] %s", error_code, GetVimError(error_code)); + return err_string; + } + sprintf_s(err_string, sizeof(err_string), "[0x%08lX] ", error_code); + presize = (DWORD)strlen(err_string); + + size = FormatMessageU(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, + HRESULT_CODE(error_code), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), + &err_string[presize], sizeof(err_string)-(DWORD)strlen(err_string), NULL); + if (size == 0) { + format_error = GetLastError(); + if ((format_error) && (format_error != ERROR_MR_MID_NOT_FOUND) && (format_error != ERROR_MUI_FILE_NOT_LOADED)) + sprintf_s(err_string, sizeof(err_string), "Windows error code 0x%08lX (FormatMessage error code 0x%08lX)", + error_code, format_error); + else + sprintf_s(err_string, sizeof(err_string), "Windows error code 0x%08lX", error_code); + } + else { + // Microsoft may suffix CRLF to error messages, which we need to remove... + size += presize - 2; + // Cannot underflow if the above assert passed since our first char is neither of the following + while ((err_string[size] == 0x0D) || (err_string[size] == 0x0A) || (err_string[size] == 0x20)) + err_string[size--] = 0; + } + + return err_string; +} + + + #define INTF_ADVANCEDDISK 1 #define INTF_ADVANCEDDISK2 2 #define INTF_CREATEPARTITIONEX 3 +#define INTF_PARTITIONMF 4 /* * Some code and functions in the file are copied from rufus. @@ -64,6 +570,11 @@ #define IVdsCreatePartitionEx_CreatePartitionEx(This, ullOffset, ullSize, ulAlign, para, ppAsync) (This)->lpVtbl->CreatePartitionEx(This, ullOffset, ullSize, ulAlign, para, ppAsync) #define IVdsCreatePartitionEx_Release(This) (This)->lpVtbl->Release(This) + +#define IVdsPartitionMF_FormatPartitionEx(This, ullOffset, pwszFileSystemTypeName, usFileSystemRevision, ulDesiredUnitAllocationSize, pwszLabel, bForce, bQuickFormat, bEnableCompression, ppAsync) \ + (This)->lpVtbl->FormatPartitionEx(This, ullOffset, pwszFileSystemTypeName, usFileSystemRevision, ulDesiredUnitAllocationSize, pwszLabel, bForce, bQuickFormat, bEnableCompression, ppAsync) +#define IVdsPartitionMF_Release(This) (This)->lpVtbl->Release(This) + #define IEnumVdsObject_Next(This, celt, ppObjectArray, pcFetched) (This)->lpVtbl->Next(This, celt, ppObjectArray, pcFetched) #define IVdsPack_QueryVolumes(This, ppEnum) (This)->lpVtbl->QueryVolumes(This, ppEnum) #define IVdsVolume_QueryInterface(This, riid, ppvObject) (This)->lpVtbl->QueryInterface(This, riid, ppvObject) @@ -222,6 +733,7 @@ STATIC BOOL VDS_DiskCommProc(int intf, int DriveIndex, VDS_Callback_PF callback, IVdsAdvancedDisk *pAdvancedDisk; IVdsAdvancedDisk2 *pAdvancedDisk2; IVdsCreatePartitionEx *pCreatePartitionEx; + IVdsDiskPartitionMF *pPartitionMP; // Get the disk interface. hr = IUnknown_QueryInterface(pDiskUnk, &IID_IVdsDisk, (void **)&pDisk); @@ -300,6 +812,24 @@ STATIC BOOL VDS_DiskCommProc(int intf, int DriveIndex, VDS_Callback_PF callback, } IVdsCreatePartitionEx_Release(pCreatePartitionEx); } + else if (intf == INTF_PARTITIONMF) + { + // Instantiate the DiskPartitionMF interface for our disk. + hr = IVdsDisk_QueryInterface(pDisk, &IID_IVdsDiskPartitionMF, (void **)&pPartitionMP); + IVdsDisk_Release(pDisk); + if (hr != S_OK) + { + VDS_SET_ERROR(hr); + Log("Could not access VDS PartitionMF interface: %u", LASTERR); + goto out; + } + else + { + Log("Callback %d process for disk <%S>", intf, diskprop.pwszName); + r = callback(pPartitionMP, &diskprop, data); + } + IVdsPartitionMF_Release(pPartitionMP); + } goto out; } @@ -524,7 +1054,7 @@ STATIC BOOL VDS_CallBack_ChangeEFIType(void *pInterface, VDS_DISK_PROP *pDiskPro } else { - Log("Failed to change partition type 0x%lx", hr); + Log("Failed to change partition type 0x%lx(%s)", hr, WindowsErrorString(hr)); } return r; @@ -604,7 +1134,7 @@ STATIC BOOL VDS_CallBack_CreateVtoyEFI(void *pInterface, VDS_DISK_PROP *pDiskPro if (hr != S_OK) { VDS_SET_ERROR(hr); - Log("Could not create partition, err:0x%lx", LASTERR); + Log("Could not create partition, err:0x%lx(%s)", LASTERR, WindowsErrorString(hr)); return FALSE; } @@ -632,3 +1162,62 @@ BOOL VDS_CreateVtoyEFIPart(int DriveIndex, UINT64 Offset) return ret; } + +STATIC BOOL VDS_CallBack_FormatVtoyEFI(void *pInterface, VDS_DISK_PROP *pDiskProp, UINT64 data) +{ + HRESULT hr, hr2; + ULONG completed; + IVdsAsync* pAsync; + IVdsDiskPartitionMF *pPartitionMF = (IVdsDiskPartitionMF *)pInterface; + VDS_PARA *VdsPara = (VDS_PARA *)(ULONG)data; + + (void)pDiskProp; + + hr = IVdsPartitionMF_FormatPartitionEx(pPartitionMF, VdsPara->Offset, L"FAT", 0x0100, 0, VdsPara->Name, TRUE, TRUE, FALSE, &pAsync); + while (SUCCEEDED(hr)) + { + hr = IVdsAsync_QueryStatus(pAsync, &hr2, &completed); + if (SUCCEEDED(hr)) + { + hr = hr2; + if (hr == S_OK) + { + Log("Disk format partition QueryStatus OK, %lu%%", completed); + break; + } + else if (hr == VDS_E_OPERATION_PENDING) + { + Log("Disk format finish: %lu%%", completed); + hr = S_OK; + } + else + { + Log("QueryStatus invalid status:0x%lx", hr); + } + } + Sleep(1000); + } + + if (hr != S_OK) + { + VDS_SET_ERROR(hr); + Log("Could not format partition, err:0x%lx (%s)", LASTERR, WindowsErrorString(hr)); + return FALSE; + } + + return TRUE; +} + +// Not supported for removable disk +BOOL VDS_FormatVtoyEFIPart(int DriveIndex, UINT64 Offset) +{ + VDS_PARA Para; + + memset(&Para, 0, sizeof(Para)); + Para.Offset = Offset; + memcpy(Para.Name, L"VTOYEFI", 7 * 2); + + BOOL ret = VDS_DiskCommProc(INTF_PARTITIONMF, DriveIndex, VDS_CallBack_FormatVtoyEFI, (ULONG)&Para); + Log("VDS_FormatVtoyEFIPart %d ret:%d", DriveIndex, ret); + return ret; +} \ No newline at end of file diff --git a/Ventoy2Disk/Ventoy2Disk/PhyDrive.c b/Ventoy2Disk/Ventoy2Disk/PhyDrive.c index 570f28ea..2fb5273d 100644 --- a/Ventoy2Disk/Ventoy2Disk/PhyDrive.c +++ b/Ventoy2Disk/Ventoy2Disk/PhyDrive.c @@ -20,6 +20,7 @@ */ #include +#include #include #include #include @@ -1827,6 +1828,103 @@ End: return rc; } +static BOOL BackupDataBeforeCleanDisk(int PhyDrive, UINT64 DiskSize, BYTE **pBackup) +{ + DWORD dwSize; + DWORD dwStatus; + BOOL Return = FALSE; + BOOL ret = FALSE; + BYTE *backup = NULL; + HANDLE hDrive = INVALID_HANDLE_VALUE; + LARGE_INTEGER liCurPosition; + LARGE_INTEGER liNewPosition; + + Log("BackupDataBeforeCleanDisk %d", PhyDrive); + + backup = malloc(SIZE_1MB * 3); + if (!backup) + { + goto out; + } + + hDrive = GetPhysicalHandle(PhyDrive, FALSE, FALSE, FALSE); + if (hDrive == INVALID_HANDLE_VALUE) + { + goto out; + } + + //read first 1MB + dwStatus = SetFilePointer(hDrive, 0, NULL, FILE_BEGIN); + if (dwStatus != 0) + { + goto out; + } + + dwSize = 0; + ret = ReadFile(hDrive, backup, SIZE_1MB, &dwSize, NULL); + if ((!ret) || (dwSize != SIZE_1MB)) + { + Log("Failed to read %d %u 0x%x", ret, dwSize, LASTERR); + goto out; + } + + liCurPosition.QuadPart = DiskSize - (SIZE_1MB * 2); + liNewPosition.QuadPart = 0; + if (0 == SetFilePointerEx(hDrive, liCurPosition, &liNewPosition, FILE_BEGIN) || + liNewPosition.QuadPart != liCurPosition.QuadPart) + { + goto out; + } + + dwSize = 0; + ret = ReadFile(hDrive, backup + SIZE_1MB, 2 * SIZE_1MB, &dwSize, NULL); + if ((!ret) || (dwSize != 2 * SIZE_1MB)) + { + Log("Failed to read %d %u 0x%x", ret, dwSize, LASTERR); + goto out; + } + + *pBackup = backup; + backup = NULL; //For don't free later + Return = TRUE; + +out: + CHECK_CLOSE_HANDLE(hDrive); + if (backup) + free(backup); + + return Return; +} + + +static BOOL WriteBackupDataToDisk(HANDLE hDrive, UINT64 Offset, BYTE *Data, DWORD Length) +{ + DWORD dwSize = 0; + BOOL ret = FALSE; + LARGE_INTEGER liCurPosition; + LARGE_INTEGER liNewPosition; + + Log("WriteBackupDataToDisk %llu %p %u", Offset, Data, Length); + + liCurPosition.QuadPart = Offset; + liNewPosition.QuadPart = 0; + if (0 == SetFilePointerEx(hDrive, liCurPosition, &liNewPosition, FILE_BEGIN) || + liNewPosition.QuadPart != liCurPosition.QuadPart) + { + return FALSE; + } + + ret = WriteFile(hDrive, Data, Length, &dwSize, NULL); + if ((!ret) || dwSize != Length) + { + Log("Failed to write %d %u %u", ret, dwSize, LASTERR); + return FALSE; + } + + Log("WriteBackupDataToDisk %llu %p %u success", Offset, Data, Length); + return TRUE; +} + int UpdateVentoy2PhyDrive(PHY_DRIVE_INFO *pPhyDrive, int TryId) { @@ -1835,6 +1933,8 @@ int UpdateVentoy2PhyDrive(PHY_DRIVE_INFO *pPhyDrive, int TryId) int MaxRetry = 3; BOOL ForceMBR = FALSE; BOOL Esp2Basic = FALSE; + BOOL ChangeAttr = FALSE; + BOOL CleanDisk = FALSE; HANDLE hVolume; HANDLE hDrive; DWORD Status; @@ -1846,6 +1946,7 @@ int UpdateVentoy2PhyDrive(PHY_DRIVE_INFO *pPhyDrive, int TryId) UINT64 ReservedMB = 0; MBR_HEAD BootImg; MBR_HEAD MBR; + BYTE *pBackup = NULL; VTOY_GPT_INFO *pGptInfo = NULL; UINT8 ReservedData[4096]; @@ -1935,20 +2036,43 @@ int UpdateVentoy2PhyDrive(PHY_DRIVE_INFO *pPhyDrive, int TryId) if (pPhyDrive->PartStyle == 1) { Log("TryId=%d EFI GPT partition type is 0x%llx", TryId, pPhyDrive->Part2GPTAttr); + PROGRESS_BAR_SET_POS(PT_DEL_ALL_PART); - if ((TryId == 1 && (pPhyDrive->Part2GPTAttr >> 56) == 0xC0) || TryId == 2) + if (TryId == 1) { - PROGRESS_BAR_SET_POS(PT_DEL_ALL_PART); Log("Change GPT partition type to ESP"); - if (VDS_ChangeVtoyEFI2ESP(pPhyDrive->PhyDrive, StartSector * 512)) { Esp2Basic = TRUE; Sleep(1000); } } + else if (TryId == 2) + { + Log("Change GPT partition attribute"); + if (VDS_ChangeVtoyEFIAttr(pPhyDrive->PhyDrive, 0x8000000000000001)) + { + ChangeAttr = TRUE; + Sleep(1000); + } + } + else if (TryId == 3) + { + Log("Clean disk GPT partition table"); + if (BackupDataBeforeCleanDisk(pPhyDrive->PhyDrive, pPhyDrive->SizeInBytes, &pBackup)) + { + Log("Success to backup data before clean"); + CleanDisk = TRUE; + VDS_CleanDisk(pPhyDrive->PhyDrive); + Sleep(1000); + } + else + { + Log("Failed to backup data before clean"); + } + } } - + PROGRESS_BAR_SET_POS(PT_LOCK_FOR_WRITE); Log("Lock disk for update ............................ "); @@ -1966,7 +2090,12 @@ int UpdateVentoy2PhyDrive(PHY_DRIVE_INFO *pPhyDrive, int TryId) hVolume = INVALID_HANDLE_VALUE; //If we change VTOYEFI to ESP, it can not have s volume name, so don't try to get it. - if (Esp2Basic) + if (CleanDisk) + { + WriteBackupDataToDisk(hDrive, pPhyDrive->SizeInBytes - (2 * SIZE_1MB), pBackup + SIZE_1MB, 2 * SIZE_1MB); + Status = ERROR_NOT_FOUND; + } + else if (Esp2Basic) { Status = ERROR_NOT_FOUND; } @@ -2131,6 +2260,13 @@ int UpdateVentoy2PhyDrive(PHY_DRIVE_INFO *pPhyDrive, int TryId) } } + if (CleanDisk) + { + WriteBackupDataToDisk(hDrive, 4 * 512, pBackup + 4 * 512, SIZE_1MB - 4 * 512); + WriteBackupDataToDisk(hDrive, 0, pBackup, 4 * 512); + free(pBackup); + } + //Refresh Drive Layout DeviceIoControl(hDrive, IOCTL_DISK_UPDATE_PROPERTIES, NULL, 0, NULL, 0, &dwSize, NULL); @@ -2153,6 +2289,20 @@ End: VDS_ChangeVtoyEFI2Basic(pPhyDrive->PhyDrive, StartSector * 512); } + if (ChangeAttr || ((pPhyDrive->Part2GPTAttr >> 56) != 0xC0)) + { + Log("Change EFI partition attr %u <0x%llx> to <0x%llx>", ChangeAttr, pPhyDrive->Part2GPTAttr, 0xC000000000000001ULL); + if (VDS_ChangeVtoyEFIAttr(pPhyDrive->PhyDrive, 0xC000000000000001ULL)) + { + Log("Change EFI partition attr success"); + pPhyDrive->Part2GPTAttr = 0xC000000000000001ULL; + } + else + { + Log("Change EFI partition attr failed"); + } + } + if (pGptInfo) { free(pGptInfo); diff --git a/Ventoy2Disk/Ventoy2Disk/WinDialog.c b/Ventoy2Disk/Ventoy2Disk/WinDialog.c index a2c41acd..0e5852c8 100644 Binary files a/Ventoy2Disk/Ventoy2Disk/WinDialog.c and b/Ventoy2Disk/Ventoy2Disk/WinDialog.c differ diff --git a/Ventoy2Disk/Ventoy2Disk/process.c b/Ventoy2Disk/Ventoy2Disk/process.c index 2f5d9709..39a5485d 100644 --- a/Ventoy2Disk/Ventoy2Disk/process.c +++ b/Ventoy2Disk/Ventoy2Disk/process.c @@ -25,6 +25,7 @@ #include +#include #include #include #include @@ -471,6 +472,7 @@ int FindProcessOccupyDisk(HANDLE hDrive, PHY_DRIVE_INFO *pPhyDrive) char cmdline[MAX_PATH] = { 0 }; wchar_t wexe_path[MAX_PATH], *wcmdline; int cur_pid; + time_t starttime, curtime; Log("FindProcessOccupyDisk for PhyDrive %d", pPhyDrive->PhyDrive); @@ -506,11 +508,28 @@ int FindProcessOccupyDisk(HANDLE hDrive, PHY_DRIVE_INFO *pPhyDrive) Log("handles->NumberOfHandles = %lu", (ULONG)handles->NumberOfHandles); + if (handles->NumberOfHandles > 10000) + { + goto out; + } + + starttime = time(NULL); + for (i = 0; i < handles->NumberOfHandles; i++) { ULONG attempts = 8; PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX handleInfo = (i < handles->NumberOfHandles) ? &handles->Handles[i] : NULL; + //limit the search time + if ((i % 100) == 0) + { + curtime = time(NULL); + if (curtime - starttime > 10) + { + break; + } + } + if ((dupHandle != NULL) && (processHandle != NtCurrentProcess())) { pfNtClose(dupHandle); dupHandle = NULL; @@ -665,8 +684,12 @@ out: else Log("NOTE: Could not identify the process(es) or service(s) accessing %S", _wHandleName); - PhFree(buffer); - PhFree(handles); + if (buffer) + PhFree(buffer); + + if (handles) + PhFree(handles); + PhDestroyHeap(); return 0;