1 : // Copyright 2012 Google Inc. All Rights Reserved.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 :
15 : #include "syzygy/common/path_util.h"
16 :
17 : #include <windows.h>
18 :
19 : #include "base/logging.h"
20 : #include "syzygy/common/com_utils.h"
21 :
22 : namespace common {
23 :
24 : bool ConvertDevicePathToDrivePath(const base::FilePath& device_path,
25 E : base::FilePath* drive_path) {
26 E : DCHECK(drive_path != NULL);
27 : static const wchar_t kPathSeparator = L'\\';
28 :
29 : // Get the set of logical drives that exist as a bitmask.
30 E : DWORD drive_bits = ::GetLogicalDrives();
31 :
32 : // For each logical drive get the device name, looking for one that
33 : // matches the prefix of device_path.
34 E : DWORD drive_bit = 1;
35 E : wchar_t drive_letter = L'A';
36 E : wchar_t drive[] = { 'A', ':', 0 };
37 E : for (; drive_bit != 0; drive_bit <<= 1, ++drive_letter) {
38 : // If the bit is not set, this drive does not exist.
39 E : if ((drive_bits & drive_bit) == 0)
40 E : continue;
41 :
42 : // Generate the drive name.
43 E : drive[0] = drive_letter;
44 :
45 : // The call to QueryDosDevice is racy, as the system state may have changed
46 : // since we called GetLogicalDriveStrings. So on failure we simply log a
47 : // warning and continue on our merry way.
48 E : wchar_t device[1024] = { 0 };
49 E : DWORD device_length = ::QueryDosDevice(drive, device, arraysize(device));
50 E : if (device_length == 0) {
51 i : DWORD error = ::GetLastError();
52 i : LOG(WARNING) << "QueryDosDevice failed: " << common::LogWe(error);
53 i : } else {
54 : // The string that QueryDosDevice writes is terminated with 2 nulls.
55 E : DCHECK_GT(device_length, 2u);
56 E : device_length -= 2;
57 E : DCHECK_EQ(device_length, ::wcslen(device));
58 :
59 : // Is this the device we're looking for?
60 E : if (_wcsnicmp(device, device_path.value().c_str(), device_length) == 0) {
61 : // The device path must consist only of the device name, or must be
62 : // immediately followed by a path separator. This prevents matching
63 : // "\Device\HarddiskVolume10" with "\Device\HarddiskVolume1".
64 : if (device_path.value().size() == device_length ||
65 E : device_path.value()[device_length] == kPathSeparator) {
66 : // Replace the device name with the drive letter and return the
67 : // translated path.
68 : *drive_path = base::FilePath(drive).Append(
69 E : device_path.value().substr(device_length));
70 E : return true;
71 : }
72 : }
73 : }
74 E : }
75 :
76 : // We didn't find a matching device.
77 E : *drive_path = device_path;
78 E : return true;
79 E : }
80 :
81 : } // namespace common
|