]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - Ventoy2Disk/Ventoy2Disk/DiskService_vds.c
[Ventoy2Disk.exe] improve Windows edition reporting
[Ventoy.git] / Ventoy2Disk / Ventoy2Disk / DiskService_vds.c
1 /******************************************************************************
2 * DiskService_vds.c
3 *
4 * Copyright (c) 2021, longpanda <admin@ventoy.net>
5 * Copyright (c) 2011-2020, Pete Batard <pete@akeo.ie>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 3 of the
10 * License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
22 #include <Windows.h>
23 #include <winternl.h>
24 #include <commctrl.h>
25 #include <initguid.h>
26 #include <vds.h>
27 #include "Ventoy2Disk.h"
28 #include "DiskService.h"
29
30
31
32 // Count on Microsoft to add a new API while not bothering updating the existing error facilities,
33 // so that the new error messages have to be handled manually. Now, since I don't have all day:
34 // 1. Copy text from https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-vds/5102cc53-3143-4268-ba4c-6ea39e999ab4
35 // 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
36 // 3. Filter out the crap we don't need.
37 static const char *GetVdsError(DWORD error_code)
38 {
39 switch (error_code) {
40 case 0x80042400: // VDS_E_NOT_SUPPORTED
41 return "The operation is not supported by the object.";
42 case 0x80042401: // VDS_E_INITIALIZED_FAILED
43 return "VDS or the provider failed to initialize.";
44 case 0x80042402: // VDS_E_INITIALIZE_NOT_CALLED
45 return "VDS did not call the hardware provider's initialization method.";
46 case 0x80042403: // VDS_E_ALREADY_REGISTERED
47 return "The provider is already registered.";
48 case 0x80042404: // VDS_E_ANOTHER_CALL_IN_PROGRESS
49 return "A concurrent second call is made on an object before the first call is completed.";
50 case 0x80042405: // VDS_E_OBJECT_NOT_FOUND
51 return "The specified object was not found.";
52 case 0x80042406: // VDS_E_INVALID_SPACE
53 return "The specified space is neither free nor valid.";
54 case 0x80042407: // VDS_E_PARTITION_LIMIT_REACHED
55 return "No more partitions can be created on the specified disk.";
56 case 0x80042408: // VDS_E_PARTITION_NOT_EMPTY
57 return "The extended partition is not empty.";
58 case 0x80042409: // VDS_E_OPERATION_PENDING
59 return "The operation is still in progress.";
60 case 0x8004240A: // VDS_E_OPERATION_DENIED
61 return "The operation is not permitted on the specified disk, partition, or volume.";
62 case 0x8004240B: // VDS_E_OBJECT_DELETED
63 return "The object no longer exists.";
64 case 0x8004240C: // VDS_E_CANCEL_TOO_LATE
65 return "The operation can no longer be canceled.";
66 case 0x8004240D: // VDS_E_OPERATION_CANCELED
67 return "The operation has already been canceled.";
68 case 0x8004240E: // VDS_E_CANNOT_EXTEND
69 return "The file system does not support extending this volume.";
70 case 0x8004240F: // VDS_E_NOT_ENOUGH_SPACE
71 return "There is not enough space to complete the operation.";
72 case 0x80042410: // VDS_E_NOT_ENOUGH_DRIVE
73 return "There are not enough free disk drives in the subsystem to complete the operation.";
74 case 0x80042411: // VDS_E_BAD_COOKIE
75 return "The cookie was not found.";
76 case 0x80042412: // VDS_E_NO_MEDIA
77 return "There is no removable media in the drive.";
78 case 0x80042413: // VDS_E_DEVICE_IN_USE
79 return "The device is currently in use.";
80 case 0x80042414: // VDS_E_DISK_NOT_EMPTY
81 return "The disk contains partitions or volumes.";
82 case 0x80042415: // VDS_E_INVALID_OPERATION
83 return "The specified operation is not valid.";
84 case 0x80042416: // VDS_E_PATH_NOT_FOUND
85 return "The specified path was not found.";
86 case 0x80042417: // VDS_E_DISK_NOT_INITIALIZED
87 return "The specified disk has not been initialized.";
88 case 0x80042418: // VDS_E_NOT_AN_UNALLOCATED_DISK
89 return "The specified disk is not an unallocated disk.";
90 case 0x80042419: // VDS_E_UNRECOVERABLE_ERROR
91 return "An unrecoverable error occurred. The service MUST shut down.";
92 case 0x0004241A: // VDS_S_DISK_PARTIALLY_CLEANED
93 return "The clean operation was not a full clean or was canceled before it could be completed.";
94 case 0x8004241B: // VDS_E_DMADMIN_SERVICE_CONNECTION_FAILED
95 return "The provider failed to connect to the LDMA service.";
96 case 0x8004241C: // VDS_E_PROVIDER_INITIALIZATION_FAILED
97 return "The provider failed to initialize.";
98 case 0x8004241D: // VDS_E_OBJECT_EXISTS
99 return "The object already exists.";
100 case 0x8004241E: // VDS_E_NO_DISKS_FOUND
101 return "No disks were found on the target machine.";
102 case 0x8004241F: // VDS_E_PROVIDER_CACHE_CORRUPT
103 return "The cache for a provider is corrupt.";
104 case 0x80042420: // VDS_E_DMADMIN_METHOD_CALL_FAILED
105 return "A method call to the LDMA service failed.";
106 case 0x00042421: // VDS_S_PROVIDER_ERROR_LOADING_CACHE
107 return "The provider encountered errors while loading the cache.";
108 case 0x80042422: // VDS_E_PROVIDER_VOL_DEVICE_NAME_NOT_FOUND
109 return "The device form of the volume pathname could not be retrieved.";
110 case 0x80042423: // VDS_E_PROVIDER_VOL_OPEN
111 return "Failed to open the volume device";
112 case 0x80042424: // VDS_E_DMADMIN_CORRUPT_NOTIFICATION
113 return "A corrupt notification was sent from the LDMA service.";
114 case 0x80042425: // VDS_E_INCOMPATIBLE_FILE_SYSTEM
115 return "The file system is incompatible with the specified operation.";
116 case 0x80042426: // VDS_E_INCOMPATIBLE_MEDIA
117 return "The media is incompatible with the specified operation.";
118 case 0x80042427: // VDS_E_ACCESS_DENIED
119 return "Access is denied. A VDS operation MUST run elevated.";
120 case 0x80042428: // VDS_E_MEDIA_WRITE_PROTECTED
121 return "The media is write-protected.";
122 case 0x80042429: // VDS_E_BAD_LABEL
123 return "The volume label is not valid.";
124 case 0x8004242A: // VDS_E_CANT_QUICK_FORMAT
125 return "The volume cannot be quick-formatted.";
126 case 0x8004242B: // VDS_E_IO_ERROR
127 return "An I/O error occurred during the operation.";
128 case 0x8004242C: // VDS_E_VOLUME_TOO_SMALL
129 return "The volume size is too small.";
130 case 0x8004242D: // VDS_E_VOLUME_TOO_BIG
131 return "The volume size is too large.";
132 case 0x8004242E: // VDS_E_CLUSTER_SIZE_TOO_SMALL
133 return "The cluster size is too small.";
134 case 0x8004242F: // VDS_E_CLUSTER_SIZE_TOO_BIG
135 return "The cluster size is too large.";
136 case 0x80042430: // VDS_E_CLUSTER_COUNT_BEYOND_32BITS
137 return "The number of clusters is too large to be represented as a 32-bit integer.";
138 case 0x80042431: // VDS_E_OBJECT_STATUS_FAILED
139 return "The component that the object represents has failed.";
140 case 0x80042432: // VDS_E_VOLUME_INCOMPLETE
141 return "The volume is incomplete.";
142 case 0x80042433: // VDS_E_EXTENT_SIZE_LESS_THAN_MIN
143 return "The specified extent size is too small.";
144 case 0x00042434: // VDS_S_UPDATE_BOOTFILE_FAILED
145 return "The operation was successful, but VDS failed to update the boot options.";
146 case 0x00042436: // VDS_S_BOOT_PARTITION_NUMBER_CHANGE
147 case 0x80042436: // VDS_E_BOOT_PARTITION_NUMBER_CHANGE
148 return "The boot partition's partition number will change as a result of the operation.";
149 case 0x80042437: // VDS_E_NO_FREE_SPACE
150 return "The specified disk does not have enough free space to complete the operation.";
151 case 0x80042438: // VDS_E_ACTIVE_PARTITION
152 return "An active partition was detected on the selected disk.";
153 case 0x80042439: // VDS_E_PARTITION_OF_UNKNOWN_TYPE
154 return "The partition information cannot be read.";
155 case 0x8004243A: // VDS_E_LEGACY_VOLUME_FORMAT
156 return "A partition with an unknown type was detected on the specified disk.";
157 case 0x8004243C: // VDS_E_MIGRATE_OPEN_VOLUME
158 return "A volume on the specified disk could not be opened.";
159 case 0x8004243D: // VDS_E_VOLUME_NOT_ONLINE
160 return "The volume is not online.";
161 case 0x8004243E: // VDS_E_VOLUME_NOT_HEALTHY
162 return "The volume is failing or has failed.";
163 case 0x8004243F: // VDS_E_VOLUME_SPANS_DISKS
164 return "The volume spans multiple disks.";
165 case 0x80042440: // VDS_E_REQUIRES_CONTIGUOUS_DISK_SPACE
166 return "The volume does not consist of a single disk extent.";
167 case 0x80042441: // VDS_E_BAD_PROVIDER_DATA
168 return "A provider returned bad data.";
169 case 0x80042442: // VDS_E_PROVIDER_FAILURE
170 return "A provider failed to complete an operation.";
171 case 0x00042443: // VDS_S_VOLUME_COMPRESS_FAILED
172 return "The file system was formatted successfully but could not be compressed.";
173 case 0x80042444: // VDS_E_PACK_OFFLINE
174 return "The pack is offline.";
175 case 0x80042445: // VDS_E_VOLUME_NOT_A_MIRROR
176 return "The volume is not a mirror.";
177 case 0x80042446: // VDS_E_NO_EXTENTS_FOR_VOLUME
178 return "No extents were found for the volume.";
179 case 0x80042447: // VDS_E_DISK_NOT_LOADED_TO_CACHE
180 return "The migrated disk failed to load to the cache.";
181 case 0x80042448: // VDS_E_INTERNAL_ERROR
182 return "VDS encountered an internal error.";
183 case 0x8004244A: // VDS_E_PROVIDER_TYPE_NOT_SUPPORTED
184 return "The method call is not supported for the specified provider type.";
185 case 0x8004244B: // VDS_E_DISK_NOT_ONLINE
186 return "One or more of the specified disks are not online.";
187 case 0x8004244C: // VDS_E_DISK_IN_USE_BY_VOLUME
188 return "One or more extents of the disk are already being used by the volume.";
189 case 0x0004244D: // VDS_S_IN_PROGRESS
190 return "The asynchronous operation is in progress.";
191 case 0x8004244E: // VDS_E_ASYNC_OBJECT_FAILURE
192 return "Failure initializing the asynchronous object.";
193 case 0x8004244F: // VDS_E_VOLUME_NOT_MOUNTED
194 return "The volume is not mounted.";
195 case 0x80042450: // VDS_E_PACK_NOT_FOUND
196 return "The pack was not found.";
197 case 0x80042453: // VDS_E_OBJECT_OUT_OF_SYNC
198 return "The reference to the object might be stale.";
199 case 0x80042454: // VDS_E_MISSING_DISK
200 return "The specified disk could not be found.";
201 case 0x80042455: // VDS_E_DISK_PNP_REG_CORRUPT
202 return "The provider's list of PnP registered disks has become corrupted.";
203 case 0x80042457: // VDS_E_NO_DRIVELETTER_FLAG
204 return "The provider does not support the VDS_VF_NO DRIVELETTER volume flag.";
205 case 0x80042459: // VDS_E_REVERT_ON_CLOSE_SET
206 return "Some volume flags are already set.";
207 case 0x0004245B: // VDS_S_UNABLE_TO_GET_GPT_ATTRIBUTES
208 return "Unable to retrieve the GPT attributes for this volume.";
209 case 0x8004245C: // VDS_E_VOLUME_TEMPORARILY_DISMOUNTED
210 return "The volume is already dismounted temporarily.";
211 case 0x8004245D: // VDS_E_VOLUME_PERMANENTLY_DISMOUNTED
212 return "The volume is already permanently dismounted.";
213 case 0x8004245E: // VDS_E_VOLUME_HAS_PATH
214 return "The volume cannot be dismounted permanently because it still has an access path.";
215 case 0x8004245F: // VDS_E_TIMEOUT
216 return "The operation timed out.";
217 case 0x80042461: // VDS_E_LDM_TIMEOUT
218 return "The operation timed out in the LDMA service. Retry the operation.";
219 case 0x80042462: // VDS_E_REVERT_ON_CLOSE_MISMATCH
220 return "The flags to be cleared do not match the flags that were set previously.";
221 case 0x80042463: // VDS_E_RETRY
222 return "The operation failed. Retry the operation.";
223 case 0x80042464: // VDS_E_ONLINE_PACK_EXISTS
224 return "The operation failed, because an online pack object already exists.";
225 case 0x80042468: // VDS_E_MAX_USABLE_MBR
226 return "Only the first 2TB are usable on large MBR disks.";
227 case 0x80042500: // VDS_E_NO_SOFTWARE_PROVIDERS_LOADED
228 return "There are no software providers loaded.";
229 case 0x80042501: // VDS_E_DISK_NOT_MISSING
230 return "The disk is not missing.";
231 case 0x80042502: // VDS_E_NO_VOLUME_LAYOUT
232 return "The volume's layout could not be retrieved.";
233 case 0x80042503: // VDS_E_CORRUPT_VOLUME_INFO
234 return "The volume's driver information is corrupted.";
235 case 0x80042504: // VDS_E_INVALID_ENUMERATOR
236 return "The enumerator is corrupted";
237 case 0x80042505: // VDS_E_DRIVER_INTERNAL_ERROR
238 return "An internal error occurred in the volume management driver.";
239 case 0x80042507: // VDS_E_VOLUME_INVALID_NAME
240 return "The volume name is not valid.";
241 case 0x00042508: // VDS_S_DISK_IS_MISSING
242 return "The disk is missing and not all information could be returned.";
243 case 0x80042509: // VDS_E_CORRUPT_PARTITION_INFO
244 return "The disk's partition information is corrupted.";
245 case 0x0004250A: // VDS_S_NONCONFORMANT_PARTITION_INFO
246 return "The disk's partition information does not conform to what is expected on a dynamic disk.";
247 case 0x8004250B: // VDS_E_CORRUPT_EXTENT_INFO
248 return "The disk's extent information is corrupted.";
249 case 0x0004250E: // VDS_S_SYSTEM_PARTITION
250 return "Warning: There was a failure while checking for the system partition.";
251 case 0x8004250F: // VDS_E_BAD_PNP_MESSAGE
252 return "The PNP service sent a corrupted notification to the provider.";
253 case 0x80042510: // VDS_E_NO_PNP_DISK_ARRIVE
254 case 0x80042511: // VDS_E_NO_PNP_VOLUME_ARRIVE
255 return "No disk/volume arrival notification was received.";
256 case 0x80042512: // VDS_E_NO_PNP_DISK_REMOVE
257 case 0x80042513: // VDS_E_NO_PNP_VOLUME_REMOVE
258 return "No disk/volume removal notification was received.";
259 case 0x80042514: // VDS_E_PROVIDER_EXITING
260 return "The provider is exiting.";
261 case 0x00042517: // VDS_S_NO_NOTIFICATION
262 return "No volume arrival notification was received.";
263 case 0x80042519: // VDS_E_INVALID_DISK
264 return "The specified disk is not valid.";
265 case 0x8004251A: // VDS_E_INVALID_PACK
266 return "The specified disk pack is not valid.";
267 case 0x8004251B: // VDS_E_VOLUME_ON_DISK
268 return "This operation is not allowed on disks with volumes.";
269 case 0x8004251C: // VDS_E_DRIVER_INVALID_PARAM
270 return "The driver returned an invalid parameter error.";
271 case 0x8004253D: // VDS_E_DRIVER_OBJECT_NOT_FOUND
272 return "The object was not found in the driver cache.";
273 case 0x8004253E: // VDS_E_PARTITION_NOT_CYLINDER_ALIGNED
274 return "The disk layout contains partitions which are not cylinder aligned.";
275 case 0x8004253F: // VDS_E_DISK_LAYOUT_PARTITIONS_TOO_SMALL
276 return "The disk layout contains partitions which are less than the minimum required size.";
277 case 0x80042540: // VDS_E_DISK_IO_FAILING
278 return "The I/O to the disk is failing.";
279 case 0x80042543: // VDS_E_GPT_ATTRIBUTES_INVALID
280 return "Invalid GPT attributes were specified.";
281 case 0x8004254D: // VDS_E_UNEXPECTED_DISK_LAYOUT_CHANGE
282 return "An unexpected layout change occurred external to the volume manager.";
283 case 0x8004254E: // VDS_E_INVALID_VOLUME_LENGTH
284 return "The volume length is invalid.";
285 case 0x8004254F: // VDS_E_VOLUME_LENGTH_NOT_SECTOR_SIZE_MULTIPLE
286 return "The volume length is not a multiple of the sector size.";
287 case 0x80042550: // VDS_E_VOLUME_NOT_RETAINED
288 return "The volume does not have a retained partition association.";
289 case 0x80042551: // VDS_E_VOLUME_RETAINED
290 return "The volume already has a retained partition association.";
291 case 0x80042553: // VDS_E_ALIGN_BEYOND_FIRST_CYLINDER
292 return "The specified alignment is beyond the first cylinder.";
293 case 0x80042554: // VDS_E_ALIGN_NOT_SECTOR_SIZE_MULTIPLE
294 return "The specified alignment is not a multiple of the sector size.";
295 case 0x80042555: // VDS_E_ALIGN_NOT_ZERO
296 return "The specified partition type cannot be created with a non-zero alignment.";
297 case 0x80042556: // VDS_E_CACHE_CORRUPT
298 return "The service's cache has become corrupt.";
299 case 0x80042557: // VDS_E_CANNOT_CLEAR_VOLUME_FLAG
300 return "The specified volume flag cannot be cleared.";
301 case 0x80042558: // VDS_E_DISK_BEING_CLEANED
302 return "The operation is not allowed on a disk that is in the process of being cleaned.";
303 case 0x8004255A: // VDS_E_DISK_REMOVEABLE
304 return "The operation is not supported on removable media.";
305 case 0x8004255B: // VDS_E_DISK_REMOVEABLE_NOT_EMPTY
306 return "The operation is not supported on a non-empty removable disk.";
307 case 0x8004255C: // VDS_E_DRIVE_LETTER_NOT_FREE
308 return "The specified drive letter is not free to be assigned.";
309 case 0x8004255E: // VDS_E_INVALID_DRIVE_LETTER
310 return "The specified drive letter is not valid.";
311 case 0x8004255F: // VDS_E_INVALID_DRIVE_LETTER_COUNT
312 return "The specified number of drive letters to retrieve is not valid.";
313 case 0x80042560: // VDS_E_INVALID_FS_FLAG
314 return "The specified file system flag is not valid.";
315 case 0x80042561: // VDS_E_INVALID_FS_TYPE
316 return "The specified file system is not valid.";
317 case 0x80042562: // VDS_E_INVALID_OBJECT_TYPE
318 return "The specified object type is not valid.";
319 case 0x80042563: // VDS_E_INVALID_PARTITION_LAYOUT
320 return "The specified partition layout is invalid.";
321 case 0x80042564: // VDS_E_INVALID_PARTITION_STYLE
322 return "VDS only supports MBR or GPT partition style disks.";
323 case 0x80042565: // VDS_E_INVALID_PARTITION_TYPE
324 return "The specified partition type is not valid for this operation.";
325 case 0x80042566: // VDS_E_INVALID_PROVIDER_CLSID
326 case 0x80042567: // VDS_E_INVALID_PROVIDER_ID
327 case 0x8004256A: // VDS_E_INVALID_PROVIDER_VERSION_GUID
328 return "A NULL GUID was passed to the provider.";
329 case 0x80042568: // VDS_E_INVALID_PROVIDER_NAME
330 return "The specified provider name is invalid.";
331 case 0x80042569: // VDS_E_INVALID_PROVIDER_TYPE
332 return "The specified provider type is invalid.";
333 case 0x8004256B: // VDS_E_INVALID_PROVIDER_VERSION_STRING
334 return "The specified provider version string is invalid.";
335 case 0x8004256C: // VDS_E_INVALID_QUERY_PROVIDER_FLAG
336 return "The specified query provider flag is invalid.";
337 case 0x8004256D: // VDS_E_INVALID_SERVICE_FLAG
338 return "The specified service flag is invalid.";
339 case 0x8004256E: // VDS_E_INVALID_VOLUME_FLAG
340 return "The specified volume flag is invalid.";
341 case 0x8004256F: // VDS_E_PARTITION_NOT_OEM
342 return "The operation is only supported on an OEM, ESP, or unknown partition.";
343 case 0x80042570: // VDS_E_PARTITION_PROTECTED
344 return "Cannot delete a protected partition without the force protected parameter set.";
345 case 0x80042571: // VDS_E_PARTITION_STYLE_MISMATCH
346 return "The specified partition style is not the same as the disk's partition style.";
347 case 0x80042572: // VDS_E_PROVIDER_INTERNAL_ERROR
348 return "An internal error has occurred in the provider.";
349 case 0x80042575: // VDS_E_UNRECOVERABLE_PROVIDER_ERROR
350 return "An unrecoverable error occurred in the provider.";
351 case 0x80042576: // VDS_E_VOLUME_HIDDEN
352 return "Cannot assign a mount point to a hidden volume.";
353 case 0x00042577: // VDS_S_DISMOUNT_FAILED
354 case 0x00042578: // VDS_S_REMOUNT_FAILED
355 return "Failed to dismount/remount the volume after setting the volume flags.";
356 case 0x80042579: // VDS_E_FLAG_ALREADY_SET
357 return "Cannot set the specified flag as revert-on-close because it is already set.";
358 case 0x8004257B: // VDS_E_DISTINCT_VOLUME
359 return "The input volume id cannot be the id of the volume that is the target of the operation.";
360 case 0x00042583: // VDS_S_FS_LOCK
361 return "Failed to obtain a file system lock.";
362 case 0x80042584: // VDS_E_READONLY
363 return "The volume is read only.";
364 case 0x80042585: // VDS_E_INVALID_VOLUME_TYPE
365 return "The volume type is invalid for this operation.";
366 case 0x80042588: // VDS_E_VOLUME_MIRRORED
367 return "This operation is not supported on a mirrored volume.";
368 case 0x80042589: // VDS_E_VOLUME_SIMPLE_SPANNED
369 return "The operation is only supported on simple or spanned volumes.";
370 case 0x8004258C: // VDS_E_PARTITION_MSR
371 case 0x8004258D: // VDS_E_PARTITION_LDM
372 return "The operation is not supported on this type of partitions.";
373 case 0x0004258E: // VDS_S_WINPE_BOOTENTRY
374 return "The boot entries cannot be updated automatically on WinPE.";
375 case 0x8004258F: // VDS_E_ALIGN_NOT_A_POWER_OF_TWO
376 return "The alignment is not a power of two.";
377 case 0x80042590: // VDS_E_ALIGN_IS_ZERO
378 return "The alignment is zero.";
379 case 0x80042593: // VDS_E_FS_NOT_DETERMINED
380 return "The default file system could not be determined.";
381 case 0x80042595: // VDS_E_DISK_NOT_OFFLINE
382 return "This disk is already online.";
383 case 0x80042596: // VDS_E_FAILED_TO_ONLINE_DISK
384 return "The online operation failed.";
385 case 0x80042597: // VDS_E_FAILED_TO_OFFLINE_DISK
386 return "The offline operation failed.";
387 case 0x80042598: // VDS_E_BAD_REVISION_NUMBER
388 return "The operation could not be completed because the specified revision number is not supported.";
389 case 0x00042700: // VDS_S_NAME_TRUNCATED
390 return "The name was set successfully but had to be truncated.";
391 case 0x80042701: // VDS_E_NAME_NOT_UNIQUE
392 return "The specified name is not unique.";
393 case 0x8004270F: // VDS_E_NO_DISK_PATHNAME
394 return "The disk's path could not be retrieved. Some operations on the disk might fail.";
395 case 0x80042711: // VDS_E_NO_VOLUME_PATHNAME
396 return "The path could not be retrieved for one or more volumes.";
397 case 0x80042712: // VDS_E_PROVIDER_CACHE_OUTOFSYNC
398 return "The provider's cache is not in sync with the driver cache.";
399 case 0x80042713: // VDS_E_NO_IMPORT_TARGET
400 return "No import target was set for the subsystem.";
401 case 0x00042714: // VDS_S_ALREADY_EXISTS
402 return "The object already exists.";
403 case 0x00042715: // VDS_S_PROPERTIES_INCOMPLETE
404 return "Some, but not all, of the properties were successfully retrieved.";
405 case 0x80042803: // VDS_E_UNABLE_TO_FIND_BOOT_DISK
406 return "Volume disk extent information could not be retrieved for the boot volume.";
407 case 0x80042807: // VDS_E_BOOT_DISK
408 return "Disk attributes cannot be changed on the boot disk.";
409 case 0x00042808: // VDS_S_DISK_MOUNT_FAILED
410 case 0x00042809: // VDS_S_DISK_DISMOUNT_FAILED
411 return "One or more of the volumes on the disk could not be mounted/dismounted.";
412 case 0x8004280A: // VDS_E_DISK_IS_OFFLINE
413 case 0x8004280B: // VDS_E_DISK_IS_READ_ONLY
414 return "The operation cannot be performed on a disk that is offline or read-only.";
415 case 0x8004280C: // VDS_E_PAGEFILE_DISK
416 case 0x8004280D: // VDS_E_HIBERNATION_FILE_DISK
417 case 0x8004280E: // VDS_E_CRASHDUMP_DISK
418 return "The operation cannot be performed on a disk that contains a pagefile, hibernation or crashdump volume.";
419 case 0x8004280F: // VDS_E_UNABLE_TO_FIND_SYSTEM_DISK
420 return "A system error occurred while retrieving the system disk information.";
421 case 0x80042810: // VDS_E_INCORRECT_SYSTEM_VOLUME_EXTENT_INFO
422 return "Multiple disk extents reported for the system volume - system error.";
423 case 0x80042811: // VDS_E_SYSTEM_DISK
424 return "Disk attributes cannot be changed on the current system disk or BIOS disk 0.";
425 case 0x80042823: // VDS_E_SECTOR_SIZE_ERROR
426 return "The sector size MUST be non-zero, a power of 2, and less than the maximum sector size.";
427 case 0x80042907: // VDS_E_SUBSYSTEM_ID_IS_NULL
428 return "The provider returned a NULL subsystem identification string.";
429 case 0x8004290C: // VDS_E_REBOOT_REQUIRED
430 return "A reboot is required before any further operations are initiated.";
431 case 0x8004290D: // VDS_E_VOLUME_GUID_PATHNAME_NOT_ALLOWED
432 return "Volume GUID pathnames are not valid input to this method.";
433 case 0x8004290E: // VDS_E_BOOT_PAGEFILE_DRIVE_LETTER
434 return "Assigning or removing drive letters on the current boot or pagefile volume is not allowed.";
435 case 0x8004290F: // VDS_E_DELETE_WITH_CRITICAL
436 return "Delete is not allowed on a critical volume.";
437 case 0x80042910: // VDS_E_CLEAN_WITH_DATA
438 case 0x80042911: // VDS_E_CLEAN_WITH_OEM
439 return "The FORCE parameter MUST be set to TRUE in order to clean a disk that contains a data or OEM volume.";
440 case 0x80042912: // VDS_E_CLEAN_WITH_CRITICAL
441 return "Clean is not allowed on a critical disk.";
442 case 0x80042913: // VDS_E_FORMAT_CRITICAL
443 return "Format is not allowed on a critical volume.";
444 case 0x80042914: // VDS_E_NTFS_FORMAT_NOT_SUPPORTED
445 case 0x80042915: // VDS_E_FAT32_FORMAT_NOT_SUPPORTED
446 case 0x80042916: // VDS_E_FAT_FORMAT_NOT_SUPPORTED
447 return "The requested file system format is not supported on this volume.";
448 case 0x80042917: // VDS_E_FORMAT_NOT_SUPPORTED
449 return "The volume is not formattable.";
450 case 0x80042918: // VDS_E_COMPRESSION_NOT_SUPPORTED
451 return "The specified file system does not support compression.";
452 default:
453 return NULL;
454 }
455 }
456
457 static const char* GetVimError(DWORD error_code)
458 {
459 switch (error_code) {
460 case 0xC1420127:
461 return "The specified image in the specified wim is already mounted for read and write access.";
462 default:
463 return NULL;
464 }
465 }
466
467 #define sfree(p) do {if (p != NULL) {free((void*)(p)); p = NULL;}} while(0)
468 #define wconvert(p) wchar_t* w ## p = utf8_to_wchar(p)
469 #define walloc(p, size) wchar_t* w ## p = (p == NULL)?NULL:(wchar_t*)calloc(size, sizeof(wchar_t))
470 #define wfree(p) sfree(w ## p)
471 #define wchar_to_utf8_no_alloc(wsrc, dest, dest_size) \
472 WideCharToMultiByte(CP_UTF8, 0, wsrc, -1, dest, dest_size, NULL, NULL)
473
474 static __inline DWORD FormatMessageU(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId,
475 DWORD dwLanguageId, char* lpBuffer, DWORD nSize, va_list *Arguments)
476 {
477 DWORD ret = 0, err = ERROR_INVALID_DATA;
478 // coverity[returned_null]
479 walloc(lpBuffer, nSize);
480 ret = FormatMessageW(dwFlags, lpSource, dwMessageId, dwLanguageId, wlpBuffer, nSize, Arguments);
481 err = GetLastError();
482 if ((ret != 0) && ((ret = wchar_to_utf8_no_alloc(wlpBuffer, lpBuffer, nSize)) == 0)) {
483 err = GetLastError();
484 ret = 0;
485 }
486 wfree(lpBuffer);
487 SetLastError(err);
488 return ret;
489 }
490
491
492 // Convert a windows error to human readable string
493 const char *WindowsErrorString(DWORD error_code)
494 {
495 static char err_string[256] = { 0 };
496
497 DWORD size, presize;
498 DWORD format_error;
499
500 // Check for VDS error codes
501 if ((HRESULT_FACILITY(error_code) == FACILITY_ITF) && (GetVdsError(error_code) != NULL)) {
502 sprintf_s(err_string, sizeof(err_string), "[0x%08lX] %s", error_code, GetVdsError(error_code));
503 return err_string;
504 }
505 if ((HRESULT_FACILITY(error_code) == 322) && (GetVimError(error_code) != NULL)) {
506 sprintf_s(err_string, sizeof(err_string), "[0x%08lX] %s", error_code, GetVimError(error_code));
507 return err_string;
508 }
509 sprintf_s(err_string, sizeof(err_string), "[0x%08lX] ", error_code);
510 presize = (DWORD)strlen(err_string);
511
512 size = FormatMessageU(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL,
513 HRESULT_CODE(error_code), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
514 &err_string[presize], sizeof(err_string)-(DWORD)strlen(err_string), NULL);
515 if (size == 0) {
516 format_error = GetLastError();
517 if ((format_error) && (format_error != ERROR_MR_MID_NOT_FOUND) && (format_error != ERROR_MUI_FILE_NOT_LOADED))
518 sprintf_s(err_string, sizeof(err_string), "Windows error code 0x%08lX (FormatMessage error code 0x%08lX)",
519 error_code, format_error);
520 else
521 sprintf_s(err_string, sizeof(err_string), "Windows error code 0x%08lX", error_code);
522 }
523 else {
524 // Microsoft may suffix CRLF to error messages, which we need to remove...
525 size += presize - 2;
526 // Cannot underflow if the above assert passed since our first char is neither of the following
527 while ((err_string[size] == 0x0D) || (err_string[size] == 0x0A) || (err_string[size] == 0x20))
528 err_string[size--] = 0;
529 }
530
531 return err_string;
532 }
533
534
535
536 #define INTF_ADVANCEDDISK 1
537 #define INTF_ADVANCEDDISK2 2
538 #define INTF_CREATEPARTITIONEX 3
539 #define INTF_PARTITIONMF 4
540
541 /*
542 * Some code and functions in the file are copied from rufus.
543 * https://github.com/pbatard/rufus
544 */
545 #define VDS_SET_ERROR SetLastError
546 #define IVdsServiceLoader_LoadService(This, pwszMachineName, ppService) (This)->lpVtbl->LoadService(This, pwszMachineName, ppService)
547 #define IVdsServiceLoader_Release(This) (This)->lpVtbl->Release(This)
548 #define IVdsService_QueryProviders(This, masks, ppEnum) (This)->lpVtbl->QueryProviders(This, masks, ppEnum)
549 #define IVdsService_WaitForServiceReady(This) ((This)->lpVtbl->WaitForServiceReady(This))
550 #define IVdsService_CleanupObsoleteMountPoints(This) ((This)->lpVtbl->CleanupObsoleteMountPoints(This))
551 #define IVdsService_Refresh(This) ((This)->lpVtbl->Refresh(This))
552 #define IVdsService_Reenumerate(This) ((This)->lpVtbl->Reenumerate(This))
553 #define IVdsSwProvider_QueryInterface(This, riid, ppvObject) (This)->lpVtbl->QueryInterface(This, riid, ppvObject)
554 #define IVdsProvider_Release(This) (This)->lpVtbl->Release(This)
555 #define IVdsSwProvider_QueryPacks(This, ppEnum) (This)->lpVtbl->QueryPacks(This, ppEnum)
556 #define IVdsSwProvider_Release(This) (This)->lpVtbl->Release(This)
557 #define IVdsPack_QueryDisks(This, ppEnum) (This)->lpVtbl->QueryDisks(This, ppEnum)
558 #define IVdsDisk_GetProperties(This, pDiskProperties) (This)->lpVtbl->GetProperties(This, pDiskProperties)
559 #define IVdsDisk_Release(This) (This)->lpVtbl->Release(This)
560 #define IVdsDisk_QueryInterface(This, riid, ppvObject) (This)->lpVtbl->QueryInterface(This, riid, ppvObject)
561 #define IVdsAdvancedDisk_QueryPartitions(This, ppPartitionPropArray, plNumberOfPartitions) (This)->lpVtbl->QueryPartitions(This, ppPartitionPropArray, plNumberOfPartitions)
562 #define IVdsAdvancedDisk_DeletePartition(This, ullOffset, bForce, bForceProtected) (This)->lpVtbl->DeletePartition(This, ullOffset, bForce, bForceProtected)
563 #define IVdsAdvancedDisk_ChangeAttributes(This, ullOffset, para) (This)->lpVtbl->ChangeAttributes(This, ullOffset, para)
564 #define IVdsAdvancedDisk_CreatePartition(This, ullOffset, ullSize, para, ppAsync) (This)->lpVtbl->CreatePartition(This, ullOffset, ullSize, para, ppAsync)
565 #define IVdsAdvancedDisk_Clean(This, bForce, bForceOEM, bFullClean, ppAsync) (This)->lpVtbl->Clean(This, bForce, bForceOEM, bFullClean, ppAsync)
566 #define IVdsAdvancedDisk_Release(This) (This)->lpVtbl->Release(This)
567
568 #define IVdsAdvancedDisk2_ChangePartitionType(This, ullOffset, bForce, para) (This)->lpVtbl->ChangePartitionType(This, ullOffset, bForce, para)
569 #define IVdsAdvancedDisk2_Release(This) (This)->lpVtbl->Release(This)
570
571 #define IVdsCreatePartitionEx_CreatePartitionEx(This, ullOffset, ullSize, ulAlign, para, ppAsync) (This)->lpVtbl->CreatePartitionEx(This, ullOffset, ullSize, ulAlign, para, ppAsync)
572 #define IVdsCreatePartitionEx_Release(This) (This)->lpVtbl->Release(This)
573
574 #define IVdsPartitionMF_FormatPartitionEx(This, ullOffset, pwszFileSystemTypeName, usFileSystemRevision, ulDesiredUnitAllocationSize, pwszLabel, bForce, bQuickFormat, bEnableCompression, ppAsync) \
575 (This)->lpVtbl->FormatPartitionEx(This, ullOffset, pwszFileSystemTypeName, usFileSystemRevision, ulDesiredUnitAllocationSize, pwszLabel, bForce, bQuickFormat, bEnableCompression, ppAsync)
576 #define IVdsPartitionMF_Release(This) (This)->lpVtbl->Release(This)
577
578 #define IEnumVdsObject_Next(This, celt, ppObjectArray, pcFetched) (This)->lpVtbl->Next(This, celt, ppObjectArray, pcFetched)
579 #define IVdsPack_QueryVolumes(This, ppEnum) (This)->lpVtbl->QueryVolumes(This, ppEnum)
580 #define IVdsVolume_QueryInterface(This, riid, ppvObject) (This)->lpVtbl->QueryInterface(This, riid, ppvObject)
581 #define IVdsVolume_Release(This) (This)->lpVtbl->Release(This)
582 #define IVdsVolumeMF3_QueryVolumeGuidPathnames(This, pwszPathArray, pulNumberOfPaths) (This)->lpVtbl->QueryVolumeGuidPathnames(This,pwszPathArray,pulNumberOfPaths)
583 #define IVdsVolumeMF3_FormatEx2(This, pwszFileSystemTypeName, usFileSystemRevision, ulDesiredUnitAllocationSize, pwszLabel, Options, ppAsync) (This)->lpVtbl->FormatEx2(This, pwszFileSystemTypeName, usFileSystemRevision, ulDesiredUnitAllocationSize, pwszLabel, Options, ppAsync)
584 #define IVdsVolumeMF3_Release(This) (This)->lpVtbl->Release(This)
585 #define IVdsVolume_GetProperties(This, pVolumeProperties) (This)->lpVtbl->GetProperties(This,pVolumeProperties)
586 #define IVdsAsync_Cancel(This) (This)->lpVtbl->Cancel(This)
587 #define IVdsAsync_QueryStatus(This,pHrResult,pulPercentCompleted) (This)->lpVtbl->QueryStatus(This,pHrResult,pulPercentCompleted)
588 #define IVdsAsync_Wait(This,pHrResult,pAsyncOut) (This)->lpVtbl->Wait(This,pHrResult,pAsyncOut)
589 #define IVdsAsync_Release(This) (This)->lpVtbl->Release(This)
590
591 #define IUnknown_QueryInterface(This, a, b) (This)->lpVtbl->QueryInterface(This,a,b)
592 #define IUnknown_Release(This) (This)->lpVtbl->Release(This)
593
594 typedef BOOL(*VDS_Callback_PF)(void *pInterface, VDS_DISK_PROP *pDiskProp, UINT64 data);
595
596 STATIC IVdsService * VDS_InitService(void)
597 {
598 HRESULT hr;
599 IVdsServiceLoader *pLoader;
600 IVdsService *pService;
601
602 // Initialize COM
603 CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
604 CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_CONNECT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, 0, NULL);
605
606 // Create a VDS Loader Instance
607 hr = CoCreateInstance(&CLSID_VdsLoader, NULL, CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER, &IID_IVdsServiceLoader, (void **)&pLoader);
608 if (hr != S_OK)
609 {
610 VDS_SET_ERROR(hr);
611 Log("Could not create VDS Loader Instance: 0x%x", LASTERR);
612 return NULL;
613 }
614
615 // Load the VDS Service
616 hr = IVdsServiceLoader_LoadService(pLoader, L"", &pService);
617 IVdsServiceLoader_Release(pLoader);
618 if (hr != S_OK)
619 {
620 VDS_SET_ERROR(hr);
621 Log("Could not load VDS Service: 0x%x", LASTERR);
622 return NULL;
623 }
624
625 // Wait for the Service to become ready if needed
626 hr = IVdsService_WaitForServiceReady(pService);
627 if (hr != S_OK)
628 {
629 VDS_SET_ERROR(hr);
630 Log("VDS Service is not ready: 0x%x", LASTERR);
631 return NULL;
632 }
633
634 Log("VDS init OK, service %p", pService);
635 return pService;
636 }
637
638
639 STATIC BOOL VDS_DiskCommProc(int intf, int DriveIndex, VDS_Callback_PF callback, UINT64 data)
640 {
641 BOOL r = FALSE;
642 HRESULT hr;
643 ULONG ulFetched;
644 IUnknown *pUnk = NULL;
645 IEnumVdsObject *pEnum = NULL;
646 IVdsService *pService = NULL;
647 wchar_t wPhysicalName[48];
648
649 swprintf_s(wPhysicalName, ARRAYSIZE(wPhysicalName), L"\\\\?\\PhysicalDrive%d", DriveIndex);
650
651 pService = VDS_InitService();
652 if (!pService)
653 {
654 Log("Could not query VDS Service");
655 goto out;
656 }
657
658 // Query the VDS Service Providers
659 hr = IVdsService_QueryProviders(pService, VDS_QUERY_SOFTWARE_PROVIDERS, &pEnum);
660 if (hr != S_OK)
661 {
662 VDS_SET_ERROR(hr);
663 Log("Could not query VDS Service Providers: 0x%lx %u", hr, LASTERR);
664 goto out;
665 }
666
667 while (IEnumVdsObject_Next(pEnum, 1, &pUnk, &ulFetched) == S_OK)
668 {
669 IVdsProvider *pProvider;
670 IVdsSwProvider *pSwProvider;
671 IEnumVdsObject *pEnumPack;
672 IUnknown *pPackUnk;
673
674 // Get VDS Provider
675 hr = IUnknown_QueryInterface(pUnk, &IID_IVdsProvider, (void **)&pProvider);
676 IUnknown_Release(pUnk);
677 if (hr != S_OK)
678 {
679 VDS_SET_ERROR(hr);
680 Log("Could not get VDS Provider: %u", LASTERR);
681 goto out;
682 }
683
684 // Get VDS Software Provider
685 hr = IVdsSwProvider_QueryInterface(pProvider, &IID_IVdsSwProvider, (void **)&pSwProvider);
686 IVdsProvider_Release(pProvider);
687 if (hr != S_OK)
688 {
689 VDS_SET_ERROR(hr);
690 Log("Could not get VDS Software Provider: %u", LASTERR);
691 goto out;
692 }
693
694 // Get VDS Software Provider Packs
695 hr = IVdsSwProvider_QueryPacks(pSwProvider, &pEnumPack);
696 IVdsSwProvider_Release(pSwProvider);
697 if (hr != S_OK)
698 {
699 VDS_SET_ERROR(hr);
700 Log("Could not get VDS Software Provider Packs: %u", LASTERR);
701 goto out;
702 }
703
704 // Enumerate Provider Packs
705 while (IEnumVdsObject_Next(pEnumPack, 1, &pPackUnk, &ulFetched) == S_OK)
706 {
707 IVdsPack *pPack;
708 IEnumVdsObject *pEnumDisk;
709 IUnknown *pDiskUnk;
710
711 hr = IUnknown_QueryInterface(pPackUnk, &IID_IVdsPack, (void **)&pPack);
712 IUnknown_Release(pPackUnk);
713 if (hr != S_OK)
714 {
715 VDS_SET_ERROR(hr);
716 Log("Could not query VDS Software Provider Pack: %u", LASTERR);
717 goto out;
718 }
719
720 // Use the pack interface to access the disks
721 hr = IVdsPack_QueryDisks(pPack, &pEnumDisk);
722 if (hr != S_OK) {
723 VDS_SET_ERROR(hr);
724 Log("Could not query VDS disks: %u", LASTERR);
725 goto out;
726 }
727
728 // List disks
729 while (IEnumVdsObject_Next(pEnumDisk, 1, &pDiskUnk, &ulFetched) == S_OK)
730 {
731 VDS_DISK_PROP diskprop;
732 IVdsDisk *pDisk;
733 IVdsAdvancedDisk *pAdvancedDisk;
734 IVdsAdvancedDisk2 *pAdvancedDisk2;
735 IVdsCreatePartitionEx *pCreatePartitionEx;
736 IVdsDiskPartitionMF *pPartitionMP;
737
738 // Get the disk interface.
739 hr = IUnknown_QueryInterface(pDiskUnk, &IID_IVdsDisk, (void **)&pDisk);
740 if (hr != S_OK) {
741 VDS_SET_ERROR(hr);
742 Log("Could not query VDS Disk Interface: %u", LASTERR);
743 goto out;
744 }
745
746 // Get the disk properties
747 hr = IVdsDisk_GetProperties(pDisk, &diskprop);
748 if (hr != S_OK) {
749 VDS_SET_ERROR(hr);
750 Log("Could not query VDS Disk Properties: %u", LASTERR);
751 goto out;
752 }
753
754 // Isolate the disk we want
755 if (_wcsicmp(wPhysicalName, diskprop.pwszName) != 0)
756 {
757 IVdsDisk_Release(pDisk);
758 continue;
759 }
760
761 if (intf == INTF_ADVANCEDDISK)
762 {
763 // Instantiate the AdvanceDisk interface for our disk.
764 hr = IVdsDisk_QueryInterface(pDisk, &IID_IVdsAdvancedDisk, (void **)&pAdvancedDisk);
765 IVdsDisk_Release(pDisk);
766 if (hr != S_OK)
767 {
768 VDS_SET_ERROR(hr);
769 Log("Could not access VDS Advanced Disk interface: %u", LASTERR);
770 goto out;
771 }
772 else
773 {
774 Log("Callback %d process for disk <%S>", intf, diskprop.pwszName);
775 r = callback(pAdvancedDisk, &diskprop, data);
776 }
777 IVdsAdvancedDisk_Release(pAdvancedDisk);
778 }
779 else if (intf == INTF_ADVANCEDDISK2)
780 {
781 // Instantiate the AdvanceDisk interface for our disk.
782 hr = IVdsDisk_QueryInterface(pDisk, &IID_IVdsAdvancedDisk2, (void **)&pAdvancedDisk2);
783 IVdsDisk_Release(pDisk);
784 if (hr != S_OK)
785 {
786 VDS_SET_ERROR(hr);
787 Log("Could not access VDS Advanced Disk2 interface: %u", LASTERR);
788 goto out;
789 }
790 else
791 {
792 Log("Callback %d process for disk2 <%S>", intf, diskprop.pwszName);
793 r = callback(pAdvancedDisk2, &diskprop, data);
794 }
795 IVdsAdvancedDisk2_Release(pAdvancedDisk2);
796 }
797 else if (intf == INTF_CREATEPARTITIONEX)
798 {
799 // Instantiate the CreatePartitionEx interface for our disk.
800 hr = IVdsDisk_QueryInterface(pDisk, &IID_IVdsCreatePartitionEx, (void **)&pCreatePartitionEx);
801 IVdsDisk_Release(pDisk);
802 if (hr != S_OK)
803 {
804 VDS_SET_ERROR(hr);
805 Log("Could not access VDS CreatePartitionEx interface: %u", LASTERR);
806 goto out;
807 }
808 else
809 {
810 Log("Callback %d process for disk <%S>", intf, diskprop.pwszName);
811 r = callback(pCreatePartitionEx, &diskprop, data);
812 }
813 IVdsCreatePartitionEx_Release(pCreatePartitionEx);
814 }
815 else if (intf == INTF_PARTITIONMF)
816 {
817 // Instantiate the DiskPartitionMF interface for our disk.
818 hr = IVdsDisk_QueryInterface(pDisk, &IID_IVdsDiskPartitionMF, (void **)&pPartitionMP);
819 IVdsDisk_Release(pDisk);
820 if (hr != S_OK)
821 {
822 VDS_SET_ERROR(hr);
823 Log("Could not access VDS PartitionMF interface: %u", LASTERR);
824 goto out;
825 }
826 else
827 {
828 Log("Callback %d process for disk <%S>", intf, diskprop.pwszName);
829 r = callback(pPartitionMP, &diskprop, data);
830 }
831 IVdsPartitionMF_Release(pPartitionMP);
832 }
833
834 goto out;
835 }
836 }
837 }
838
839 out:
840 return r;
841 }
842
843 STATIC BOOL VDS_CallBack_CleanDisk(void *pInterface, VDS_DISK_PROP *pDiskProp, UINT64 data)
844 {
845 HRESULT hr, hr2;
846 ULONG completed;
847 IVdsAsync* pAsync;
848 IVdsAdvancedDisk *pAdvancedDisk = (IVdsAdvancedDisk *)pInterface;
849
850 (void)pDiskProp;
851 (void)data;
852
853 hr = IVdsAdvancedDisk_Clean(pAdvancedDisk, TRUE, TRUE, FALSE, &pAsync);
854 while (SUCCEEDED(hr))
855 {
856 hr = IVdsAsync_QueryStatus(pAsync, &hr2, &completed);
857 if (SUCCEEDED(hr))
858 {
859 hr = hr2;
860 if (hr == S_OK)
861 {
862 Log("Disk clean QueryStatus OK");
863 break;
864 }
865 else if (hr == VDS_E_OPERATION_PENDING)
866 {
867 hr = S_OK;
868 }
869 else
870 {
871 Log("QueryStatus invalid status:%u", hr);
872 }
873 }
874 Sleep(500);
875 }
876
877 if (hr != S_OK)
878 {
879 VDS_SET_ERROR(hr);
880 Log("Could not clean disk 0x%lx err:%u", hr, LASTERR);
881 return FALSE;
882 }
883
884 return TRUE;
885 }
886
887 BOOL VDS_CleanDisk(int DriveIndex)
888 {
889 BOOL ret = VDS_DiskCommProc(INTF_ADVANCEDDISK, DriveIndex, VDS_CallBack_CleanDisk, 0);
890 Log("VDS_CleanDisk %d ret:%d (%s)", DriveIndex, ret, ret ? "SUCCESS" : "FAIL");
891 return ret;
892 }
893
894 STATIC BOOL VDS_CallBack_DeletePartition(void *pInterface, VDS_DISK_PROP *pDiskProp, UINT64 data)
895 {
896 BOOL r = FALSE;
897 HRESULT hr;
898 VDS_PARTITION_PROP* prop_array = NULL;
899 LONG i, prop_array_size;
900 ULONG PartNumber = (ULONG)data;
901 IVdsAdvancedDisk *pAdvancedDisk = (IVdsAdvancedDisk *)pInterface;
902
903 if (PartNumber == 0)
904 {
905 Log("Deleting ALL partitions from disk '%S':", pDiskProp->pwszName);
906 }
907 else
908 {
909 Log("Deleting partition(%ld) from disk '%S':", PartNumber, pDiskProp->pwszName);
910 }
911
912 // Query the partition data, so we can get the start offset, which we need for deletion
913 hr = IVdsAdvancedDisk_QueryPartitions(pAdvancedDisk, &prop_array, &prop_array_size);
914 if (hr == S_OK)
915 {
916 r = TRUE;
917 for (i = 0; i < prop_array_size; i++)
918 {
919 if (PartNumber == 0 || PartNumber == prop_array[i].ulPartitionNumber)
920 {
921 Log("* Partition %d (offset: %lld, size: %llu) delete it.",
922 prop_array[i].ulPartitionNumber, prop_array[i].ullOffset, (ULONGLONG)prop_array[i].ullSize);
923 }
924 else
925 {
926 Log(" Partition %d (offset: %lld, size: %llu) skip it.",
927 prop_array[i].ulPartitionNumber, prop_array[i].ullOffset, (ULONGLONG)prop_array[i].ullSize);
928 continue;
929 }
930
931 hr = IVdsAdvancedDisk_DeletePartition(pAdvancedDisk, prop_array[i].ullOffset, TRUE, TRUE);
932 if (hr != S_OK)
933 {
934 r = FALSE;
935 VDS_SET_ERROR(hr);
936 Log("Could not delete partitions: 0x%x", LASTERR);
937 break;
938 }
939 else
940 {
941 Log("Delete this partitions success");
942 }
943 }
944 }
945 else
946 {
947 Log("No partition to delete on disk '%S'", pDiskProp->pwszName);
948 r = TRUE;
949 }
950
951 if (prop_array)
952 {
953 CoTaskMemFree(prop_array);
954 }
955
956 return r;
957 }
958
959 BOOL VDS_DeleteAllPartitions(int DriveIndex)
960 {
961 BOOL ret = VDS_DiskCommProc(INTF_ADVANCEDDISK, DriveIndex, VDS_CallBack_DeletePartition, 0);
962 Log("VDS_DeleteAllPartitions %d ret:%d (%s)", DriveIndex, ret, ret ? "SUCCESS" : "FAIL");
963 return ret;
964 }
965
966 BOOL VDS_DeleteVtoyEFIPartition(int DriveIndex)
967 {
968 BOOL ret = VDS_DiskCommProc(INTF_ADVANCEDDISK, DriveIndex, VDS_CallBack_DeletePartition, 2);
969 Log("VDS_DeleteVtoyEFIPartition %d ret:%d (%s)", DriveIndex, ret, ret ? "SUCCESS" : "FAIL");
970 return ret;
971 }
972
973 STATIC BOOL VDS_CallBack_ChangeEFIAttr(void *pInterface, VDS_DISK_PROP *pDiskProp, UINT64 data)
974 {
975 BOOL r = FALSE;
976 HRESULT hr;
977 VDS_PARTITION_PROP* prop_array = NULL;
978 LONG i, prop_array_size;
979 CHANGE_ATTRIBUTES_PARAMETERS AttrPara;
980 IVdsAdvancedDisk *pAdvancedDisk = (IVdsAdvancedDisk *)pInterface;
981
982 // Query the partition data, so we can get the start offset, which we need for deletion
983 hr = IVdsAdvancedDisk_QueryPartitions(pAdvancedDisk, &prop_array, &prop_array_size);
984 if (hr == S_OK)
985 {
986 for (i = 0; i < prop_array_size; i++)
987 {
988 if (prop_array[i].ullSize == VENTOY_EFI_PART_SIZE &&
989 prop_array[i].PartitionStyle == VDS_PST_GPT &&
990 memcmp(prop_array[i].Gpt.name, L"VTOYEFI", 7 * 2) == 0)
991 {
992 Log("* Partition %d (offset: %lld, size: %llu, Attr:0x%llx)", prop_array[i].ulPartitionNumber,
993 prop_array[i].ullOffset, (ULONGLONG)prop_array[i].ullSize, prop_array[i].Gpt.attributes);
994
995 if (prop_array[i].Gpt.attributes == data)
996 {
997 Log("Attribute match, No need to change.");
998 r = TRUE;
999 }
1000 else
1001 {
1002 AttrPara.style = VDS_PST_GPT;
1003 AttrPara.GptPartInfo.attributes = data;
1004 hr = IVdsAdvancedDisk_ChangeAttributes(pAdvancedDisk, prop_array[i].ullOffset, &AttrPara);
1005 if (hr == S_OK)
1006 {
1007 r = TRUE;
1008 Log("Change this partitions attribute success");
1009 }
1010 else
1011 {
1012 r = FALSE;
1013 VDS_SET_ERROR(hr);
1014 Log("Could not change partitions attr: %u", LASTERR);
1015 }
1016 }
1017 break;
1018 }
1019 }
1020 }
1021 else
1022 {
1023 Log("No partition found on disk '%S'", pDiskProp->pwszName);
1024 }
1025 CoTaskMemFree(prop_array);
1026
1027 return r;
1028 }
1029
1030 BOOL VDS_ChangeVtoyEFIAttr(int DriveIndex, UINT64 Attr)
1031 {
1032 BOOL ret = VDS_DiskCommProc(INTF_ADVANCEDDISK, DriveIndex, VDS_CallBack_ChangeEFIAttr, Attr);
1033 Log("VDS_ChangeVtoyEFIAttr %d ret:%d (%s)", DriveIndex, ret, ret ? "SUCCESS" : "FAIL");
1034 return ret;
1035 }
1036
1037
1038
1039 STATIC BOOL VDS_CallBack_ChangeEFIType(void *pInterface, VDS_DISK_PROP *pDiskProp, UINT64 data)
1040 {
1041 BOOL r = FALSE;
1042 HRESULT hr;
1043 IVdsAdvancedDisk2 *pAdvancedDisk2 = (IVdsAdvancedDisk2 *)pInterface;
1044 VDS_PARA *VdsPara = (VDS_PARA *)(ULONG)data;
1045 CHANGE_PARTITION_TYPE_PARAMETERS para;
1046
1047 para.style = VDS_PST_GPT;
1048 memcpy(&(para.GptPartInfo.partitionType), &VdsPara->Type, sizeof(GUID));
1049
1050 hr = IVdsAdvancedDisk2_ChangePartitionType(pAdvancedDisk2, VdsPara->Offset, TRUE, &para);
1051 if (hr == S_OK)
1052 {
1053 r = TRUE;
1054 }
1055 else
1056 {
1057 Log("Failed to change partition type 0x%lx(%s)", hr, WindowsErrorString(hr));
1058 }
1059
1060 return r;
1061 }
1062
1063
1064 BOOL VDS_ChangeVtoyEFI2ESP(int DriveIndex, UINT64 Offset)
1065 {
1066 VDS_PARA Para;
1067 GUID EspPartType = { 0xc12a7328, 0xf81f, 0x11d2, { 0xba, 0x4b, 0x00, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b } };
1068
1069 memcpy(&(Para.Type), &EspPartType, sizeof(GUID));
1070 Para.Offset = Offset;
1071
1072 BOOL ret = VDS_DiskCommProc(INTF_ADVANCEDDISK2, DriveIndex, VDS_CallBack_ChangeEFIType, (ULONG)&Para);
1073 Log("VDS_ChangeVtoyEFI2ESP %d ret:%d (%s)", DriveIndex, ret, ret ? "SUCCESS" : "FAIL");
1074 return ret;
1075 }
1076
1077 BOOL VDS_ChangeVtoyEFI2Basic(int DriveIndex, UINT64 Offset)
1078 {
1079 VDS_PARA Para;
1080 GUID WindowsDataPartType = { 0xebd0a0a2, 0xb9e5, 0x4433, { 0x87, 0xc0, 0x68, 0xb6, 0xb7, 0x26, 0x99, 0xc7 } };
1081
1082 memcpy(&(Para.Type), &WindowsDataPartType, sizeof(GUID));
1083 Para.Offset = Offset;
1084
1085 BOOL ret = VDS_DiskCommProc(INTF_ADVANCEDDISK2, DriveIndex, VDS_CallBack_ChangeEFIType, (ULONG)&Para);
1086 Log("VDS_ChangeVtoyEFI2Basic %d ret:%d (%s)", DriveIndex, ret, ret ? "SUCCESS" : "FAIL");
1087 return ret;
1088 }
1089
1090
1091 STATIC BOOL VDS_CallBack_CreateVtoyEFI(void *pInterface, VDS_DISK_PROP *pDiskProp, UINT64 data)
1092 {
1093 HRESULT hr, hr2;
1094 ULONG completed;
1095 IVdsAsync* pAsync;
1096 CREATE_PARTITION_PARAMETERS para;
1097 IVdsCreatePartitionEx *pCreatePartitionEx = (IVdsCreatePartitionEx *)pInterface;
1098 VDS_PARA *VdsPara = (VDS_PARA *)(ULONG)data;
1099
1100 (void)pDiskProp;
1101
1102 memset(&para, 0, sizeof(para));
1103 para.style = VDS_PST_GPT;
1104 memcpy(&(para.GptPartInfo.partitionType), &VdsPara->Type, sizeof(GUID));
1105 memcpy(&(para.GptPartInfo.partitionId), &VdsPara->Id, sizeof(GUID));
1106 para.GptPartInfo.attributes = VdsPara->Attr;
1107 memcpy(para.GptPartInfo.name, VdsPara->Name, sizeof(WCHAR)* VdsPara->NameLen);
1108
1109 hr = IVdsCreatePartitionEx_CreatePartitionEx(pCreatePartitionEx, VdsPara->Offset, VENTOY_EFI_PART_SIZE, 512, &para, &pAsync);
1110 while (SUCCEEDED(hr))
1111 {
1112 hr = IVdsAsync_QueryStatus(pAsync, &hr2, &completed);
1113 if (SUCCEEDED(hr))
1114 {
1115 hr = hr2;
1116 if (hr == S_OK)
1117 {
1118 Log("Disk create partition QueryStatus OK, %lu%%", completed);
1119 break;
1120 }
1121 else if (hr == VDS_E_OPERATION_PENDING)
1122 {
1123 Log("Disk partition finish: %lu%%", completed);
1124 hr = S_OK;
1125 }
1126 else
1127 {
1128 Log("QueryStatus invalid status:0x%lx", hr);
1129 }
1130 }
1131 Sleep(1000);
1132 }
1133
1134 if (hr != S_OK)
1135 {
1136 VDS_SET_ERROR(hr);
1137 Log("Could not create partition, err:0x%lx(%s)", LASTERR, WindowsErrorString(hr));
1138 return FALSE;
1139 }
1140
1141 return TRUE;
1142 }
1143
1144 BOOL VDS_CreateVtoyEFIPart(int DriveIndex, UINT64 Offset)
1145 {
1146 VDS_PARA Para;
1147 GUID WindowsDataPartType = { 0xebd0a0a2, 0xb9e5, 0x4433, { 0x87, 0xc0, 0x68, 0xb6, 0xb7, 0x26, 0x99, 0xc7 } };
1148 GUID EspPartType = { 0xc12a7328, 0xf81f, 0x11d2, { 0xba, 0x4b, 0x00, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b } };
1149
1150 Log("VDS_CreateVtoyEFIPart %u Offset:%llu Sector:%llu", DriveIndex, Offset, Offset / 512);
1151
1152 memset(&Para, 0, sizeof(Para));
1153 Para.Attr = 0x8000000000000000ULL;
1154 Para.Offset = Offset;
1155 memcpy(Para.Name, L"VTOYEFI", 7 * 2);
1156 Para.NameLen = 7;
1157 memcpy(&(Para.Type), &EspPartType, sizeof(GUID));
1158 CoCreateGuid(&(Para.Id));
1159
1160 BOOL ret = VDS_DiskCommProc(INTF_CREATEPARTITIONEX, DriveIndex, VDS_CallBack_CreateVtoyEFI, (ULONG)&Para);
1161 Log("VDS_CreateVtoyEFIPart %d ret:%d (%s)", DriveIndex, ret, ret ? "SUCCESS" : "FAIL");
1162 return ret;
1163 }
1164
1165
1166 STATIC BOOL VDS_CallBack_FormatVtoyEFI(void *pInterface, VDS_DISK_PROP *pDiskProp, UINT64 data)
1167 {
1168 HRESULT hr, hr2;
1169 ULONG completed;
1170 IVdsAsync* pAsync;
1171 IVdsDiskPartitionMF *pPartitionMF = (IVdsDiskPartitionMF *)pInterface;
1172 VDS_PARA *VdsPara = (VDS_PARA *)(ULONG)data;
1173
1174 (void)pDiskProp;
1175
1176 hr = IVdsPartitionMF_FormatPartitionEx(pPartitionMF, VdsPara->Offset, L"FAT", 0x0100, 0, VdsPara->Name, TRUE, TRUE, FALSE, &pAsync);
1177 while (SUCCEEDED(hr))
1178 {
1179 hr = IVdsAsync_QueryStatus(pAsync, &hr2, &completed);
1180 if (SUCCEEDED(hr))
1181 {
1182 hr = hr2;
1183 if (hr == S_OK)
1184 {
1185 Log("Disk format partition QueryStatus OK, %lu%%", completed);
1186 break;
1187 }
1188 else if (hr == VDS_E_OPERATION_PENDING)
1189 {
1190 Log("Disk format finish: %lu%%", completed);
1191 hr = S_OK;
1192 }
1193 else
1194 {
1195 Log("QueryStatus invalid status:0x%lx", hr);
1196 }
1197 }
1198 Sleep(1000);
1199 }
1200
1201 if (hr != S_OK)
1202 {
1203 VDS_SET_ERROR(hr);
1204 Log("Could not format partition, err:0x%lx (%s)", LASTERR, WindowsErrorString(hr));
1205 return FALSE;
1206 }
1207
1208 return TRUE;
1209 }
1210
1211 // Not supported for removable disk
1212 BOOL VDS_FormatVtoyEFIPart(int DriveIndex, UINT64 Offset)
1213 {
1214 VDS_PARA Para;
1215
1216 memset(&Para, 0, sizeof(Para));
1217 Para.Offset = Offset;
1218 memcpy(Para.Name, L"VTOYEFI", 7 * 2);
1219
1220 BOOL ret = VDS_DiskCommProc(INTF_PARTITIONMF, DriveIndex, VDS_CallBack_FormatVtoyEFI, (ULONG)&Para);
1221 Log("VDS_FormatVtoyEFIPart %d ret:%d (%s)", DriveIndex, ret, ret ? "SUCCESS" : "FAIL");
1222 return ret;
1223 }
1224