sbWindowsStorageDeviceUtils.cpp
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set sw=2 :miv */
3 /*
4  *=BEGIN SONGBIRD GPL
5  *
6  * This file is part of the Songbird web player.
7  *
8  * Copyright(c) 2005-2010 POTI, Inc.
9  * http://www.songbirdnest.com
10  *
11  * This file may be licensed under the terms of of the
12  * GNU General Public License Version 2 (the ``GPL'').
13  *
14  * Software distributed under the License is distributed
15  * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
16  * express or implied. See the GPL for the specific language
17  * governing rights and limitations.
18  *
19  * You should have received a copy of the GPL along with this
20  * program. If not, go to http://www.gnu.org/licenses/gpl.html
21  * or write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23  *
24  *=END SONGBIRD GPL
25  */
26 
27 //------------------------------------------------------------------------------
28 //
29 // Songbird Windows storage device utilities services.
30 //
31 //------------------------------------------------------------------------------
32 
38 //------------------------------------------------------------------------------
39 //
40 // Songbird Windows storage device utilities imported services.
41 //
42 //------------------------------------------------------------------------------
43 
44 // Self import.
46 
47 // Local imports.
48 #include "sbWindowsDeviceUtils.h"
49 
50 // Songbird imports.
51 #include <sbWindowsUtils.h>
52 
53 // Windows imports.
54 #include <ntddscsi.h>
55 
56 
57 //------------------------------------------------------------------------------
58 //
59 // Songbird Windows device storage services.
60 //
61 //------------------------------------------------------------------------------
62 
78 nsresult
79 sbWinFindDevicesByStorageDevNum(STORAGE_DEVICE_NUMBER* aStorageDevNum,
80  PRBool aMatchPartitionNumber,
81  const GUID* aGUID,
82  nsTArray<DEVINST>& aDevInstList)
83 {
84  // Validate arguments.
85  NS_ENSURE_ARG_POINTER(aStorageDevNum);
86  NS_ENSURE_ARG_POINTER(aGUID);
87 
88  // Function variables.
89  nsresult rv;
90 
91  // Get the interface device class info and set up for auto-disposal.
92  HDEVINFO devInfo =
93  SetupDiGetClassDevsW(aGUID,
94  NULL,
95  NULL,
96  DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
97  NS_ENSURE_TRUE(devInfo != INVALID_HANDLE_VALUE, NS_ERROR_FAILURE);
98  sbAutoHDEVINFO autoDevInfo(devInfo);
99 
100  // Search for device instances with a matching storage device number.
101  aDevInstList.Clear();
102  DWORD devIndex = 0;
103  while (1) {
104  // Get the next device detail data and set it up for auto-disposal.
105  PSP_DEVICE_INTERFACE_DETAIL_DATA devIfDetailData;
106  SP_DEVINFO_DATA devInfoData;
107  rv = sbWinGetDevDetail(&devIfDetailData,
108  &devInfoData,
109  devInfo,
110  aGUID,
111  devIndex++);
112  if (rv == NS_ERROR_NOT_AVAILABLE)
113  break;
114  NS_ENSURE_SUCCESS(rv, rv);
116  autoDevIfDetailData(devIfDetailData);
117 
118  // Get the next storage device number.
119  STORAGE_DEVICE_NUMBER storageDevNum;
120  rv = sbWinGetStorageDevNum(devIfDetailData->DevicePath, &storageDevNum);
121  if (NS_FAILED(rv))
122  continue;
123 
124  // Skip device instance if it doesn't match the target storage device
125  // number.
126  if (storageDevNum.DeviceType != aStorageDevNum->DeviceType)
127  continue;
128  if (storageDevNum.DeviceNumber != aStorageDevNum->DeviceNumber)
129  continue;
130  if (aMatchPartitionNumber &&
131  (storageDevNum.PartitionNumber != aStorageDevNum->PartitionNumber)) {
132  continue;
133  }
134 
135  // Add device instance to list.
136  NS_ENSURE_TRUE(aDevInstList.AppendElement(devInfoData.DevInst),
137  NS_ERROR_OUT_OF_MEMORY);
138  }
139 
140  return NS_OK;
141 }
142 
143 
156 nsresult
157 sbWinGetStorageDevNum(DEVINST aDevInst,
158  const GUID* aGUID,
159  STORAGE_DEVICE_NUMBER* aStorageDevNum)
160 {
161  // Validate arguments.
162  NS_ENSURE_ARG_POINTER(aStorageDevNum);
163  NS_ENSURE_ARG_POINTER(aGUID);
164 
165  // Function variables.
166  nsresult rv;
167 
168  // Get the device interface path.
169  nsAutoString deviceInterfacePath;
170  rv = sbWinGetDevicePath(aDevInst, aGUID, deviceInterfacePath);
171  NS_ENSURE_SUCCESS(rv, rv);
172 
173  return sbWinGetStorageDevNum(deviceInterfacePath.get(), aStorageDevNum);
174 }
175 
176 
188 nsresult
189 sbWinGetStorageDevNum(LPCTSTR aDevPath,
190  STORAGE_DEVICE_NUMBER* aStorageDevNum)
191 {
192  // Validate arguments.
193  NS_ENSURE_ARG_POINTER(aDevPath);
194  NS_ENSURE_ARG_POINTER(aStorageDevNum);
195 
196  // Function variables.
197  PRBool hasDevNum = PR_TRUE;
198  BOOL success;
199 
200  // Create a device file and set it up for auto-disposal.
201  HANDLE devFile = CreateFileW(aDevPath,
202  0,
203  FILE_SHARE_READ | FILE_SHARE_WRITE,
204  NULL,
205  OPEN_EXISTING,
206  0,
207  NULL);
208  if (devFile == INVALID_HANDLE_VALUE)
209  return NS_ERROR_NOT_AVAILABLE;
210  sbAutoHANDLE autoDevFile(devFile);
211 
212  // Get the device number.
213  STORAGE_DEVICE_NUMBER getDevNumParams;
214  DWORD byteCount;
215  success = DeviceIoControl(devFile,
216  IOCTL_STORAGE_GET_DEVICE_NUMBER,
217  NULL,
218  0,
219  &getDevNumParams,
220  sizeof(getDevNumParams),
221  &byteCount,
222  NULL);
223  if (!success)
224  return NS_ERROR_NOT_AVAILABLE;
225  NS_ENSURE_TRUE(getDevNumParams.DeviceNumber != 0xFFFFFFFF,
226  NS_ERROR_FAILURE);
227 
228  // Return results.
229  CopyMemory(aStorageDevNum, &getDevNumParams, sizeof(STORAGE_DEVICE_NUMBER));
230 
231  return NS_OK;
232 }
233 
234 
235 //------------------------------------------------------------------------------
236 //
237 // Songbird Windows volume device services.
238 //
239 //------------------------------------------------------------------------------
240 
249 nsresult
250 sbWinVolumeIsReady(DEVINST aDevInst,
251  PRBool* aIsReady)
252 {
253  // Validate arguments.
254  NS_ENSURE_ARG_POINTER(aIsReady);
255 
256  // Function variables.
257  PRBool success;
258  nsresult rv;
259 
260  // Get the volume device interface path.
261  GUID guid = GUID_DEVINTERFACE_VOLUME;
262  nsAutoString volumeDeviceInterfacePath;
263  rv = sbWinGetDevicePath(aDevInst, &guid, volumeDeviceInterfacePath);
264  NS_ENSURE_SUCCESS(rv, rv);
265 
266  // Try getting the volume GUID path. If this fails, the volume is not ready.
267  static const DWORD volumeGUIDPathLength = 51;
268  WCHAR volumeGUIDPath[volumeGUIDPathLength];
269  volumeDeviceInterfacePath.AppendLiteral("\\");
270  success = GetVolumeNameForVolumeMountPointW(volumeDeviceInterfacePath.get(),
271  volumeGUIDPath,
272  volumeGUIDPathLength);
273  if (!success) {
274  *aIsReady = PR_FALSE;
275  return NS_OK;
276  }
277 
278  // Try getting the volume information. If this fails, the volume is not
279  // ready.
280  DWORD fileSystemFlags;
281  WCHAR volumeLabel[MAX_PATH+1];
282  WCHAR fileSystemName[MAX_PATH+1];
283  success = GetVolumeInformationW(volumeDeviceInterfacePath.BeginReading(),
284  volumeLabel,
285  NS_ARRAY_LENGTH(volumeLabel),
286  NULL,
287  NULL,
288  &fileSystemFlags,
289  fileSystemName,
290  NS_ARRAY_LENGTH(fileSystemName));
291  if (!success) {
292  *aIsReady = PR_FALSE;
293  return NS_OK;
294  }
295 
296  // The volume is ready.
297  *aIsReady = PR_TRUE;
298 
299  return NS_OK;
300 }
301 
302 
311 nsresult
312 sbWinVolumeGetIsReadOnly(const nsAString& aVolumeMountPath,
313  PRBool* aIsReadOnly)
314 {
315  // Validate arguments.
316  NS_ENSURE_ARG_POINTER(aIsReadOnly);
317 
318  // Function variables.
319  BOOL success;
320 
321  // Get the file system flags.
322  DWORD fileSystemFlags;
323  WCHAR volumeLabel[MAX_PATH+1];
324  WCHAR fileSystemName[MAX_PATH+1];
325  success = GetVolumeInformationW(aVolumeMountPath.BeginReading(),
326  volumeLabel,
327  NS_ARRAY_LENGTH(volumeLabel),
328  NULL,
329  NULL,
330  &fileSystemFlags,
331  fileSystemName,
332  NS_ARRAY_LENGTH(fileSystemName));
333  NS_ENSURE_TRUE(success, NS_ERROR_FAILURE);
334 
335  // Return results.
336  if (fileSystemFlags & FILE_READ_ONLY_VOLUME)
337  *aIsReadOnly = PR_TRUE;
338  else
339  *aIsReadOnly = PR_FALSE;
340 
341  return NS_OK;
342 }
343 
344 
355 nsresult
356 sbWinGetVolumeGUIDPath(DEVINST aDevInst,
357  nsAString& aVolumeGUIDPath)
358 {
359  BOOL success;
360  nsresult rv;
361 
362  // Get the volume device interface path.
363  GUID guid = GUID_DEVINTERFACE_VOLUME;
364  nsAutoString volumeDeviceInterfacePath;
365  rv = sbWinGetDevicePath(aDevInst, &guid, volumeDeviceInterfacePath);
366  NS_ENSURE_SUCCESS(rv, rv);
367 
368  // Get the volume GUID path. The mount point must end with "\\".
369  static const DWORD volumeGUIDPathLength = 51;
370  WCHAR volumeGUIDPath[volumeGUIDPathLength];
371  volumeDeviceInterfacePath.AppendLiteral("\\");
372  success = GetVolumeNameForVolumeMountPointW(volumeDeviceInterfacePath.get(),
373  volumeGUIDPath,
374  volumeGUIDPathLength);
375  NS_ENSURE_TRUE(success, NS_ERROR_FAILURE);
376 
377  // Return results.
378  aVolumeGUIDPath.Assign(volumeGUIDPath);
379 
380  return NS_OK;
381 }
382 
383 
394 nsresult
395 sbWinGetVolumeGUID(DEVINST aDevInst,
396  nsAString& aVolumeGUID)
397 {
398  nsresult rv;
399 
400  // Start with the volume GUID path.
401  rv = sbWinGetVolumeGUIDPath(aDevInst, aVolumeGUID);
402  NS_ENSURE_SUCCESS(rv, rv);
403 
404  // Strip everything but the volume GUID. Transform
405  // "\\?\Volume{26a21bda-a627-11d7-9931-806e6f6e6963}\" to
406  // "{26a21bda-a627-11d7-9931-806e6f6e6963}".
407  PRInt32 index;
408  index = aVolumeGUID.Find("{");
409  NS_ENSURE_TRUE(index >= 0, NS_ERROR_UNEXPECTED);
410  aVolumeGUID.Cut(0, index);
411  index = aVolumeGUID.Find("}");
412  NS_ENSURE_TRUE(index >= 0, NS_ERROR_UNEXPECTED);
413  aVolumeGUID.SetLength(index + 1);
414 
415  return NS_OK;
416 }
417 
418 
427 nsresult
428 sbWinGetVolumePathNames(DEVINST aDevInst,
429  nsTArray<nsString>& aPathNames)
430 {
431  nsresult rv;
432 
433  // Get the volume GUID path.
434  nsAutoString volumeGUIDPath;
435  rv = sbWinGetVolumeGUIDPath(aDevInst, volumeGUIDPath);
436  NS_ENSURE_SUCCESS(rv, rv);
437 
438  // Get the volume path names.
439  rv = sbWinGetVolumePathNames(volumeGUIDPath, aPathNames);
440  NS_ENSURE_SUCCESS(rv, rv);
441 
442  return NS_OK;
443 }
444 
445 
454 nsresult
455 sbWinGetVolumePathNames(nsAString& aVolumeGUIDPath,
456  nsTArray<nsString>& aPathNames)
457 {
458  BOOL success;
459 
460  // Clear the list of path names.
461  aPathNames.Clear();
462 
463  // Get the total length of all of the path names. Do nothing more if the
464  // length is zero.
465  DWORD pathNamesLength;
466  success = GetVolumePathNamesForVolumeNameW(aVolumeGUIDPath.BeginReading(),
467  NULL,
468  0,
469  &pathNamesLength);
470  if (!success)
471  NS_ENSURE_TRUE(GetLastError() == ERROR_MORE_DATA, NS_ERROR_FAILURE);
472  if (pathNamesLength == 0)
473  return NS_OK;
474 
475  // Allocate memory for the path names and set it up for auto-disposal.
476  WCHAR* pathNames =
477  static_cast<WCHAR*>(malloc(pathNamesLength * sizeof(WCHAR)));
478  NS_ENSURE_TRUE(pathNames, NS_ERROR_OUT_OF_MEMORY);
479  sbAutoMemPtr<WCHAR> autoPathNames(pathNames);
480 
481  // Get the volume path names.
482  success = GetVolumePathNamesForVolumeNameW(aVolumeGUIDPath.BeginReading(),
483  pathNames,
484  pathNamesLength,
485  &pathNamesLength);
486  NS_ENSURE_TRUE(success, NS_ERROR_FAILURE);
487 
488  // Add the names to the volume path name list.
489  DWORD pathNameIndex = 0;
490  while (pathNameIndex < pathNamesLength) {
491  // Get the next path name. Exit loop if no more paths.
492  WCHAR* pathName = pathNames + pathNameIndex;
493  if (pathName[0] == L'\0')
494  break;
495 
496  // Add the path name to the list.
497  aPathNames.AppendElement(pathName);
498 
499  // Add the next path name.
500  pathNameIndex += wcslen(pathName) + 1;
501  }
502 
503  return NS_OK;
504 }
505 
506 
515 nsresult
516 sbWinGetVolumeLabel(const nsAString& aVolumeMountPath,
517  nsACString& aVolumeLabel)
518 {
519  BOOL success;
520 
521  // Get the volume label.
522  WCHAR volumeLabel[MAX_PATH+1];
523  WCHAR fileSystemName[MAX_PATH+1];
524  success = GetVolumeInformationW(aVolumeMountPath.BeginReading(),
525  volumeLabel,
526  NS_ARRAY_LENGTH(volumeLabel),
527  NULL,
528  NULL,
529  NULL,
530  fileSystemName,
531  NS_ARRAY_LENGTH(fileSystemName));
532  NS_ENSURE_TRUE(success, NS_ERROR_FAILURE);
533 
534  // Return results.
535  aVolumeLabel.Assign(NS_ConvertUTF16toUTF8(volumeLabel));
536 
537  return NS_OK;
538 }
539 
540 
549 nsresult
550 sbWinSetVolumeLabel(const nsAString& aVolumeMountPath,
551  const nsACString& aVolumeLabel)
552 {
553  BOOL success;
554 
555  // Set the volume label.
556  success = SetVolumeLabelW(aVolumeMountPath.BeginReading(),
557  NS_ConvertUTF8toUTF16(aVolumeLabel).get());
558  NS_ENSURE_TRUE(success, NS_ERROR_FAILURE);
559 
560  return NS_OK;
561 }
562 
563 
564 //------------------------------------------------------------------------------
565 //
566 // Songbird Windows SCSI device utilities services.
567 //
568 //------------------------------------------------------------------------------
569 
570 //
571 // Songbird Windows SCSI device utilities defs.
572 //
573 
574 #define CDB6GENERIC_LENGTH 6
575 
577  SCSI_PASS_THROUGH Spt;
578  ULONG Filler; // realign buffers to double word boundary
579  UCHAR SenseBuf[32];
580  UCHAR DataBuf[512];
582 
583 #define SCSIOP_INQUIRY 0x12
584 
585 
595 nsresult
596 sbWinGetSCSIProductInfo(DEVINST aDevInst,
597  nsAString& aVendorID,
598  nsAString& aProductID)
599 {
600  DWORD byteCount;
601  BOOL success;
602  errno_t errno;
603  nsresult rv;
604 
605  // Create a disk interface device file.
606  sbAutoHANDLE diskHandle;
607  GUID guid = GUID_DEVINTERFACE_DISK;
608  rv = sbWinCreateDeviceFile(diskHandle.StartAssignment(),
609  aDevInst,
610  &guid,
611  0,
612  FILE_SHARE_READ | FILE_SHARE_WRITE,
613  NULL,
614  OPEN_EXISTING,
615  0,
616  NULL);
617  NS_ENSURE_SUCCESS(rv, rv);
618 
619  // Set up a storage property query to get the storage device descriptor.
620  STORAGE_PROPERTY_QUERY storagePropertyQuery;
621  memset(&storagePropertyQuery, 0, sizeof(storagePropertyQuery));
622  storagePropertyQuery.PropertyId = StorageDeviceProperty;
623  storagePropertyQuery.QueryType = PropertyStandardQuery;
624 
625  // Determine how many bytes are required to hold the full storage device
626  // descriptor.
627  STORAGE_DESCRIPTOR_HEADER storageDescriptorHeader;
628  success = DeviceIoControl(diskHandle,
629  IOCTL_STORAGE_QUERY_PROPERTY,
630  &storagePropertyQuery,
631  sizeof(storagePropertyQuery),
632  &storageDescriptorHeader,
633  sizeof(storageDescriptorHeader),
634  &byteCount,
635  NULL);
636  NS_ENSURE_TRUE(success, NS_ERROR_FAILURE);
637  NS_ENSURE_TRUE(byteCount == sizeof(storageDescriptorHeader),
638  NS_ERROR_FAILURE);
639 
640  // Allocate the storage device descriptor.
642  storageDeviceDescriptor = static_cast<PSTORAGE_DEVICE_DESCRIPTOR>
643  (malloc(storageDescriptorHeader.Size));
644  NS_ENSURE_TRUE(storageDeviceDescriptor, NS_ERROR_OUT_OF_MEMORY);
645 
646  // Get the storage device descriptor.
647  success = DeviceIoControl(diskHandle,
648  IOCTL_STORAGE_QUERY_PROPERTY,
649  &storagePropertyQuery,
650  sizeof(storagePropertyQuery),
651  storageDeviceDescriptor,
652  storageDescriptorHeader.Size,
653  &byteCount,
654  NULL);
655  NS_ENSURE_TRUE(success, NS_ERROR_FAILURE);
656  NS_ENSURE_TRUE(byteCount == storageDescriptorHeader.Size, NS_ERROR_FAILURE);
657 
658  // Return results with trailing spaces trimmed. SCSI inquiry vendor and
659  // product IDs have trailing spaces as filler.
660  aVendorID.AssignLiteral
661  (reinterpret_cast<char*>(storageDeviceDescriptor.get()) +
662  storageDeviceDescriptor->VendorIdOffset);
663  aVendorID.Trim(" ", PR_FALSE, PR_TRUE);
664  aProductID.AssignLiteral
665  (reinterpret_cast<char*>(storageDeviceDescriptor.get()) +
666  storageDeviceDescriptor->ProductIdOffset);
667  aProductID.Trim(" ", PR_FALSE, PR_TRUE);
668 
669  return NS_OK;
670 }
671 
nsresult sbWinCreateDeviceFile(HANDLE *aDevFile, DEVINST aDevInst, const GUID *aGUID, DWORD aDesiredAccess, DWORD aShareMode, LPSECURITY_ATTRIBUTES aSecurityAttributes, DWORD aCreationDisposition, DWORD aFlagsAndAttributes, HANDLE aTemplateFile)
return NS_OK
nsresult sbWinVolumeIsReady(DEVINST aDevInst, PRBool *aIsReady)
Songbird Windows Device Utilities Definitions.
nsresult sbWinGetDevDetail(PSP_DEVICE_INTERFACE_DETAIL_DATA *aDevIfDetailData, SP_DEVINFO_DATA *aDevInfoData, HDEVINFO aDevInfo, const GUID *aGUID, DWORD aDevIndex)
nsresult sbWinGetVolumeGUID(DEVINST aDevInst, nsAString &aVolumeGUID)
nsresult sbWinFindDevicesByStorageDevNum(STORAGE_DEVICE_NUMBER *aStorageDevNum, PRBool aMatchPartitionNumber, const GUID *aGUID, nsTArray< DEVINST > &aDevInstList)
nsresult sbWinSetVolumeLabel(const nsAString &aVolumeMountPath, const nsACString &aVolumeLabel)
nsresult sbWinGetStorageDevNum(DEVINST aDevInst, const GUID *aGUID, STORAGE_DEVICE_NUMBER *aStorageDevNum)
nsresult sbWinVolumeGetIsReadOnly(const nsAString &aVolumeMountPath, PRBool *aIsReadOnly)
nsresult sbWinGetSCSIProductInfo(DEVINST aDevInst, nsAString &aVendorID, nsAString &aProductID)
nsresult sbWinGetVolumePathNames(DEVINST aDevInst, nsTArray< nsString > &aPathNames)
nsresult sbWinGetVolumeLabel(const nsAString &aVolumeMountPath, nsACString &aVolumeLabel)
Songbird Windows Storage Device Utilities Definitions.
nsresult sbWinGetVolumeGUIDPath(DEVINST aDevInst, nsAString &aVolumeGUIDPath)
struct _SCSI_PASS_THROUGH_WITH_BUFFERS * PSCSI_PASS_THROUGH_WITH_BUFFERS
struct _SCSI_PASS_THROUGH_WITH_BUFFERS SCSI_PASS_THROUGH_WITH_BUFFERS
nsresult sbWinGetDevicePath(DEVINST aDevInst, const GUID *aGUID, nsAString &aDevicePath)
T * get() const