2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS FS utility tool
4 * FILE: modules/rosapps/applications/cmdutils/vcdcli/vcdcli.c
5 * PURPOSE: Virtual CD-ROM management application
6 * PROGRAMMERS: Pierre Schweitzer <pierre@reactos.org>
9 #define WIN32_NO_STATUS
13 #include <ndk/rtltypes.h>
14 #include <ndk/rtlfuncs.h>
20 #define IOCTL_CDROM_BASE FILE_DEVICE_CD_ROM
21 #define IOCTL_CDROM_EJECT_MEDIA CTL_CODE(IOCTL_CDROM_BASE, 0x0202, METHOD_BUFFERED, FILE_READ_ACCESS)
28 _ftprintf(stdout
, _T("vcdcli usage:\n"));
29 _ftprintf(stdout
, _T("\tlist [/a]: list all the virtual drives\n"));
30 _ftprintf(stdout
, _T("\tcreate: create a virtual drive\n"));
31 _ftprintf(stdout
, _T("\tmount X path: mount path image on X virtual drive\n"));
32 _ftprintf(stdout
, _T("\tremount X: remount image on X virtual drive\n"));
33 _ftprintf(stdout
, _T("\tremount X: remount image on X virtual drive\n"));
34 _ftprintf(stdout
, _T("\teject X: eject image on X virtual drive\n"));
35 _ftprintf(stdout
, _T("\tremove X: remove virtual drive X\n"));
39 _ftprintf(stdout
, _T("mount usage:\n"));
40 _ftprintf(stdout
, _T("\tmount <drive letter> <path.iso> [/u] [/j]\n"));
41 _ftprintf(stdout
, _T("\tMount the ISO image given in <path.iso> on the previously created virtual drive <drive letter>\n"));
42 _ftprintf(stdout
, _T("\t\tDo not use colon for drive letter\n"));
43 _ftprintf(stdout
, _T("\t\tUse /u to make UDF volumes not appear as such\n"));
44 _ftprintf(stdout
, _T("\t\tUse /j to make Joliet volumes not appear as such\n"));
48 _ftprintf(stdout
, _T("remount usage:\n"));
49 _ftprintf(stdout
, _T("\tremount <drive letter>\n"));
50 _ftprintf(stdout
, _T("\tRemount the ISO image that was previously mounted on the virtual drive <drive letter>\n"));
51 _ftprintf(stdout
, _T("\t\tDo not use colon for drive letter\n"));
55 _ftprintf(stdout
, _T("eject usage:\n"));
56 _ftprintf(stdout
, _T("\teject <drive letter>\n"));
57 _ftprintf(stdout
, _T("\tEjects the ISO image that is mounted on the virtual drive <drive letter>\n"));
58 _ftprintf(stdout
, _T("\t\tDo not use colon for drive letter\n"));
62 _ftprintf(stdout
, _T("remove usage:\n"));
63 _ftprintf(stdout
, _T("\tremove <drive letter>\n"));
64 _ftprintf(stdout
, _T("\tRemoves the virtual drive <drive letter> making it no longer usable\n"));
65 _ftprintf(stdout
, _T("\t\tDo not use colon for drive letter\n"));
70 OpenLetter(WCHAR Letter
)
75 _stprintf(Device
, _T("\\\\.\\%c:"), Letter
);
78 return CreateFile(Device
, GENERIC_READ
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
79 NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
87 /* Open the SC manager */
88 hMgr
= OpenSCManager(NULL
, NULL
, SC_MANAGER_CREATE_SERVICE
);
91 _ftprintf(stderr
, _T("Failed opening service manager: %x\n"), GetLastError());
95 /* Open the service matching our driver */
96 hSvc
= OpenService(hMgr
, _T("Vcdrom"), SERVICE_START
);
99 _ftprintf(stderr
, _T("Failed opening service: %x\n"), GetLastError());
100 CloseServiceHandle(hMgr
);
106 StartService(hSvc
, 0, NULL
);
109 CloseServiceHandle(hSvc
);
110 CloseServiceHandle(hMgr
);
112 /* Always return true when service exists
113 * We don't care whether it was running or not
122 /* We'll always talk to master first, so we start it here */
125 return INVALID_HANDLE_VALUE
;
128 /* And then, open it */
129 return CreateFile(_T("\\\\.\\\\VirtualCdRom"), GENERIC_READ
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
130 NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
134 IsLetterOwned(WCHAR Letter
)
141 /* We've to deal with driver */
143 if (hDev
== INVALID_HANDLE_VALUE
)
145 _ftprintf(stderr
, _T("Failed to open VCD: %x\n"), GetLastError());
149 /* Get the list of the managed drives */
150 Res
= DeviceIoControl(hDev
, IOCTL_VCDROM_ENUMERATE_DRIVES
, NULL
, 0, &Drives
, sizeof(Drives
), &BytesRead
, NULL
);
153 _ftprintf(stderr
, _T("Failed to enumerate drives: %x\n"), GetLastError());
161 /* Do we find our letter in the list? */
162 for (i
= 0; i
< Drives
.Count
; ++i
)
164 if (Drives
.Drives
[i
] == Letter
)
171 if (i
== Drives
.Count
)
173 _ftprintf(stderr
, _T("%c is not a drive owned by VCD\n"), Letter
);
177 /* Otherwise, that's fine! */
183 Min(DWORD a
, DWORD b
)
185 return (a
> b
? b
: a
);
190 _tmain(int argc
, const TCHAR
*argv
[])
196 /* We need a command, at least */
203 /* List will display all the managed drives */
204 if (_tcscmp(argv
[1], _T("list")) == 0)
210 /* Open the driver for query */
212 if (hDev
== INVALID_HANDLE_VALUE
)
214 _ftprintf(stderr
, _T("Failed to open VCD: %x\n"), GetLastError());
218 /* Query the virtual drives */
219 Res
= DeviceIoControl(hDev
, IOCTL_VCDROM_ENUMERATE_DRIVES
, NULL
, 0, &Drives
, sizeof(Drives
), &BytesRead
, NULL
);
222 _ftprintf(stderr
, _T("Failed to create VCD: %x\n"), GetLastError());
227 /* Done with master */
230 /* No drives? Display a pretty message */
231 if (Drives
.Count
== 0)
233 _ftprintf(stdout
, _T("No virtual drives\n"));
237 /* Do we have to display all the information? That's '/a' */
241 if (_tcscmp(argv
[2], _T("/a")) == 0)
249 _ftprintf(stdout
, _T("Managed drives:\n"));
250 /* For each virtual drive... */
251 for (i
= 0; i
< Drives
.Count
; ++i
)
256 /* Display its letter */
257 _ftprintf(stdout
, _T("%c: "), Drives
.Drives
[i
]);
259 /* And open it to query more data */
260 hLet
= OpenLetter(Drives
.Drives
[i
]);
261 if (hLet
!= INVALID_HANDLE_VALUE
)
263 /* Get the image path along with mount status */
264 Res
= DeviceIoControl(hLet
, IOCTL_VCDROM_GET_IMAGE_PATH
, NULL
, 0, &Image
, sizeof(Image
), &BytesRead
, NULL
);
270 /* Display image if any, otherwise display "no image" */
271 if (Image
.Length
!= 0)
273 Path
.Length
= Image
.Length
;
274 Path
.MaximumLength
= Image
.Length
;
275 Path
.Buffer
= Image
.Path
;
279 Path
.Length
= sizeof(L
"no image") - sizeof(UNICODE_NULL
);
280 Path
.MaximumLength
= sizeof(L
"no image");
281 Path
.Buffer
= L
"no image";
284 /* Print everything including mount status */
285 _ftprintf(stdout
, _T("%wZ, %s"), &Path
, (Image
.Mounted
== 0 ? _T("not mounted") : _T("mounted")));
288 /* Close drive and move to the next one */
293 _ftprintf(stdout
, _T("\n"));
298 /* Basic display, just display drives on a single line */
299 _ftprintf(stdout
, _T("Virtual drives:\n"));
300 for (i
= 0; i
< Drives
.Count
; ++i
)
302 _ftprintf(stdout
, _T("%c: "), Drives
.Drives
[i
]);
304 _ftprintf(stdout
, _T("\n"));
308 else if (_tcscmp(argv
[1], _T("create")) == 0)
314 if (hDev
== INVALID_HANDLE_VALUE
)
316 _ftprintf(stderr
, _T("Failed to open VCD: %x\n"), GetLastError());
320 /* Issue the IOCTL */
321 Res
= DeviceIoControl(hDev
, IOCTL_VCDROM_CREATE_DRIVE
, NULL
, 0, &Letter
, sizeof(WCHAR
), &BytesRead
, NULL
);
324 _ftprintf(stderr
, _T("Failed to create drive: %x\n"), GetLastError());
329 /* And display the create drive letter to the user */
330 _ftprintf(stdout
, _T("The virtual drive '%c' has been created\n"), Letter
);
334 else if (_tcscmp(argv
[1], _T("mount")) == 0)
339 UNICODE_STRING NtPathName
;
340 MOUNT_PARAMETERS MountParams
;
342 /* We need two args */
349 /* First, check letter is OK */
350 if (!_istalpha(argv
[2][0]) || argv
[2][1] != 0)
356 /* Now, check the ISO image is OK and reachable by the user */
357 hFile
= CreateFile(argv
[3], FILE_READ_DATA
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
358 if (hFile
== INVALID_HANDLE_VALUE
)
360 _ftprintf(stderr
, _T("Failed to open file: %s\n"), GetLastError());
364 /* Validate the drive is owned by vcdrom */
365 Letter
= _totupper(argv
[2][0]);
366 if (!IsLetterOwned(Letter
))
372 /* Get NT path for the driver */
373 if (!RtlDosPathNameToNtPathName_U(argv
[3], &NtPathName
, NULL
, NULL
))
375 _ftprintf(stderr
, _T("Failed to convert path\n"));
380 /* Copy it in the parameter structure */
381 _tcsncpy(MountParams
.Path
, NtPathName
.Buffer
, 255);
382 MountParams
.Length
= Min(NtPathName
.Length
, 255 * sizeof(WCHAR
));
383 MountParams
.Flags
= 0;
385 /* Do we have to suppress anything? */
386 for (i
= 4; i
< argc
; ++i
)
388 /* Make UDF uneffective */
389 if (_tcscmp(argv
[i
], _T("/u")) == 0)
391 MountParams
.Flags
|= MOUNT_FLAG_SUPP_UDF
;
393 /* Make Joliet uneffective */
394 else if (_tcscmp(argv
[i
], _T("/j")) == 0)
396 MountParams
.Flags
|= MOUNT_FLAG_SUPP_JOLIET
;
400 /* No longer needed */
401 RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathName
.Buffer
);
404 hDev
= OpenLetter(Letter
);
405 if (hDev
== INVALID_HANDLE_VALUE
)
407 _ftprintf(stderr
, _T("Failed to open VCD %c: %x\n"), Letter
, GetLastError());
412 /* We have to release image now, the driver will attempt to open it */
415 /* Issue the mount IOCTL */
416 Res
= DeviceIoControl(hDev
, IOCTL_VCDROM_MOUNT_IMAGE
, &MountParams
, sizeof(MountParams
), NULL
, 0, &BytesRead
, NULL
);
419 _ftprintf(stderr
, _T("Failed to mount %s on %c: %x\n"), argv
[3], Letter
, GetLastError());
424 /* Pretty print in case of a success */
425 _ftprintf(stdout
, _T("%s mounted on %c\n"), argv
[3], Letter
);
429 else if (_tcscmp(argv
[1], _T("remount")) == 0)
440 /* First, check letter is OK */
441 if (!_istalpha(argv
[2][0]) || argv
[2][1] != 0)
447 /* Validate the drive is owned by vcdrom */
448 Letter
= _totupper(argv
[2][0]);
449 if (!IsLetterOwned(Letter
))
455 hDev
= OpenLetter(Letter
);
456 if (hDev
== INVALID_HANDLE_VALUE
)
458 _ftprintf(stderr
, _T("Failed to open VCD %c: %x\n"), Letter
, GetLastError());
462 /* Issue the remount IOCTL */
463 Res
= DeviceIoControl(hDev
, IOCTL_STORAGE_LOAD_MEDIA
, NULL
, 0, NULL
, 0, &BytesRead
, NULL
);
466 _ftprintf(stderr
, _T("Failed to remount media on %c: %x\n"), Letter
, GetLastError());
471 /* Pretty print in case of a success */
472 _ftprintf(stdout
, _T("Media remounted on %c\n"), Letter
);
476 else if (_tcscmp(argv
[1], _T("eject")) == 0)
487 /* First, check letter is OK */
488 if (!_istalpha(argv
[2][0]) || argv
[2][1] != 0)
494 /* Validate the drive is owned by vcdrom */
495 Letter
= _totupper(argv
[2][0]);
496 if (!IsLetterOwned(Letter
))
502 hDev
= OpenLetter(Letter
);
503 if (hDev
== INVALID_HANDLE_VALUE
)
505 _ftprintf(stderr
, _T("Failed to open VCD %c: %x\n"), Letter
, GetLastError());
509 /* Issue the eject IOCTL */
510 Res
= DeviceIoControl(hDev
, IOCTL_CDROM_EJECT_MEDIA
, NULL
, 0, NULL
, 0, &BytesRead
, NULL
);
513 _ftprintf(stderr
, _T("Failed to eject media on %c: %x\n"), Letter
, GetLastError());
518 /* Pretty print in case of a success */
519 _ftprintf(stdout
, _T("Media ejected on %c\n"), Letter
);
523 else if (_tcscmp(argv
[1], _T("remove")) == 0)
534 /* First, check letter is OK */
535 if (!_istalpha(argv
[2][0]) || argv
[2][1] != 0)
541 /* Validate the drive is owned by vcdrom */
542 Letter
= _totupper(argv
[2][0]);
543 if (!IsLetterOwned(Letter
))
549 hDev
= OpenLetter(Letter
);
550 if (hDev
== INVALID_HANDLE_VALUE
)
552 _ftprintf(stderr
, _T("Failed to open VCD %c: %x\n"), Letter
, GetLastError());
556 /* Issue the remove IOCTL */
557 Res
= DeviceIoControl(hDev
, IOCTL_VCDROM_DELETE_DRIVE
, NULL
, 0, NULL
, 0, &BytesRead
, NULL
);
560 _ftprintf(stderr
, _T("Failed to remove virtual drive %c: %x\n"), Letter
, GetLastError());
565 /* Pretty print in case of a success */
566 _ftprintf(stdout
, _T("Virtual drive %c removed\n"), Letter
);