eject.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. /*
  2. * Eject CDs
  3. *
  4. * Copyright 2005 Alexandre Julliard for CodeWeavers
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2.1 of the License, or (at your option) any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this library; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  19. */
  20. #define WIN32_LEAN_AND_MEAN
  21. #include <windows.h>
  22. #include <winioctl.h>
  23. #include <ntddstor.h>
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include "wine/debug.h"
  27. WINE_DEFAULT_DEBUG_CHANNEL(eject);
  28. /* options */
  29. static BOOL unmount_only;
  30. static BOOL eject_all;
  31. /* wrapper for GetDriveTypeW */
  32. static DWORD get_drive_type( WCHAR drive )
  33. {
  34. WCHAR path[16];
  35. lstrcpyW( path, L"a:\\" );
  36. path[0] = drive;
  37. return GetDriveTypeW( path );
  38. }
  39. static BOOL eject_cd( WCHAR drive )
  40. {
  41. PREVENT_MEDIA_REMOVAL removal;
  42. WCHAR buffer[16];
  43. HANDLE handle;
  44. DWORD result;
  45. if (get_drive_type( drive ) != DRIVE_CDROM)
  46. {
  47. WINE_MESSAGE( "Drive %c: is not a CD or is not mounted\n", (char)drive );
  48. return FALSE;
  49. }
  50. lstrcpyW( buffer, L"\\\\.\\a:" );
  51. buffer[4] = drive;
  52. handle = CreateFileW( buffer, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
  53. NULL, OPEN_EXISTING, 0, 0 );
  54. if (handle == INVALID_HANDLE_VALUE)
  55. {
  56. WINE_MESSAGE( "Cannot open device for drive %c:\n", (char)drive );
  57. return FALSE;
  58. }
  59. WINE_TRACE( "ejecting %c:\n", (char)drive );
  60. if (!DeviceIoControl( handle, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0, &result, NULL ))
  61. WINE_WARN( "FSCTL_DISMOUNT_VOLUME failed with err %d\n", GetLastError() );
  62. removal.PreventMediaRemoval = FALSE;
  63. if (!DeviceIoControl( handle, IOCTL_STORAGE_MEDIA_REMOVAL, &removal, sizeof(removal), NULL, 0, &result, NULL ))
  64. WINE_WARN( "IOCTL_STORAGE_MEDIA_REMOVAL failed with err %d\n", GetLastError() );
  65. if (!unmount_only)
  66. {
  67. if (!DeviceIoControl( handle, IOCTL_STORAGE_EJECT_MEDIA, NULL, 0, NULL, 0, &result, NULL ))
  68. WINE_WARN( "IOCTL_STORAGE_EJECT_MEDIA failed with err %d\n", GetLastError() );
  69. }
  70. CloseHandle( handle );
  71. return TRUE;
  72. }
  73. /* find the CD drive, and die if we find more than one */
  74. static WCHAR find_cd_drive(void)
  75. {
  76. WCHAR ret = 0, drive;
  77. for (drive = 'c'; drive <= 'z'; drive++)
  78. {
  79. if (get_drive_type( drive ) != DRIVE_CDROM) continue;
  80. if (ret)
  81. {
  82. WINE_MESSAGE( "Multiple CD drives found (%c: and %c:), you need to specify the one you want.\n",
  83. (char)ret, (char)drive );
  84. exit(1);
  85. }
  86. ret = drive;
  87. }
  88. return ret;
  89. }
  90. static void usage(void)
  91. {
  92. WINE_MESSAGE( "Usage: eject [-u] [-a] [-h] [x:]...\n" );
  93. WINE_MESSAGE( " -a Eject all the CD drives we find\n" );
  94. WINE_MESSAGE( " -h Display this help message\n" );
  95. WINE_MESSAGE( " -u Unmount only, don't eject the CD\n" );
  96. WINE_MESSAGE( " x: Eject drive x:\n" );
  97. exit(1);
  98. }
  99. static void parse_options( int *argc, char *argv[] )
  100. {
  101. int i;
  102. char *opt;
  103. for (i = 1; i < *argc; i++)
  104. {
  105. if (argv[i][0] != '-')
  106. {
  107. /* check for valid drive argument */
  108. if (strlen(argv[i]) != 2 || argv[i][1] != ':') usage();
  109. continue;
  110. }
  111. for (opt = argv[i] + 1; *opt; opt++) switch(*opt)
  112. {
  113. case 'a': eject_all = TRUE; break;
  114. case 'u': unmount_only = TRUE; break;
  115. case 'h': usage(); break;
  116. default:
  117. WINE_MESSAGE( "Unknown option -%c\n", *opt );
  118. usage();
  119. }
  120. memmove( argv + i, argv + i + 1, (*argc - i) * sizeof(*argv) );
  121. (*argc)--;
  122. i--;
  123. }
  124. }
  125. int __cdecl main( int argc, char *argv[] )
  126. {
  127. parse_options( &argc, argv );
  128. if (eject_all)
  129. {
  130. WCHAR drive;
  131. for (drive = 'c'; drive <= 'z'; drive++)
  132. {
  133. if (get_drive_type( drive ) != DRIVE_CDROM) continue;
  134. if (!eject_cd( drive )) exit(1);
  135. }
  136. }
  137. else if (argc > 1)
  138. {
  139. int i;
  140. for (i = 1; i < argc; i++)
  141. if (!eject_cd( argv[i][0] )) exit(1);
  142. }
  143. else
  144. {
  145. WCHAR drive = find_cd_drive();
  146. if (!drive)
  147. {
  148. WINE_MESSAGE( "No CD drive found\n" );
  149. exit(1);
  150. }
  151. if (!eject_cd( drive )) exit(1);
  152. }
  153. exit(0);
  154. }