1 : // Copyright 2011 Google Inc.
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/core/file_util.h"
16 :
17 : #include "base/file_util.h"
18 : #include "base/win/scoped_handle.h"
19 : #include "sawbuck/common/com_utils.h"
20 :
21 : namespace core {
22 :
23 : namespace {
24 :
25 : enum FileInformationResult {
26 : kFileNotFound,
27 : kSuccess,
28 : kFailure
29 : };
30 :
31 : // Gets a handle to a file, and the file information for it. Leaves the handle
32 : // open.
33 : FileInformationResult GetFileInformation(
34 : const FilePath& path,
35 : base::win::ScopedHandle* handle,
36 E : BY_HANDLE_FILE_INFORMATION* file_info) {
37 : // Open the file in the least restrictive possible way.
38 : handle->Set(
39 : ::CreateFile(path.value().c_str(),
40 : SYNCHRONIZE,
41 : FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
42 : NULL,
43 : OPEN_EXISTING,
44 : FILE_ATTRIBUTE_NORMAL,
45 E : NULL));
46 E : if (!handle->IsValid()) {
47 : // The file not being found is a special case.
48 E : DWORD error = ::GetLastError();
49 E : if (error == ERROR_FILE_NOT_FOUND || error == ERROR_PATH_NOT_FOUND)
50 E : return kFileNotFound;
51 :
52 i : LOG(ERROR) << "Unable to open \"" << path.value() << "\": "
53 : << com::LogWe(error);
54 i : return kFailure;
55 : }
56 :
57 E : if (!::GetFileInformationByHandle(handle->Get(), file_info)) {
58 i : DWORD error = ::GetLastError();
59 i : LOG(ERROR) << "GetFileInformationByHandle failed for \"" << path.value()
60 : << "\": " << com::LogWe(error);
61 i : return kFailure;
62 : }
63 :
64 E : return kSuccess;
65 E : }
66 :
67 : } // namespace
68 :
69 : FilePathCompareResult CompareFilePaths(const FilePath& path1,
70 E : const FilePath& path2) {
71 : // Now we try opening both files for reading to see if they point to the same
72 : // underlying volume and file index. We open both files simultaneously to
73 : // avoid a race condition whereby the file could be moved/removed in between
74 : // the two calls to GetFileInformation.
75 :
76 E : base::win::ScopedHandle handle1;
77 E : BY_HANDLE_FILE_INFORMATION info1 = {};
78 E : FileInformationResult result1 = GetFileInformation(path1, &handle1, &info1);
79 E : if (result1 == kFailure)
80 i : return kFilePathCompareError;
81 :
82 E : base::win::ScopedHandle handle2;
83 E : BY_HANDLE_FILE_INFORMATION info2 = {};
84 E : FileInformationResult result2 = GetFileInformation(path2, &handle2, &info2);
85 E : if (result2 == kFailure)
86 i : return kFilePathCompareError;
87 :
88 : // If neither file exists we can't really compare them based on anything
89 : // other than the path itself.
90 E : if (result1 == kFileNotFound && result2 == kFileNotFound) {
91 E : FilePath abs1(path1);
92 E : FilePath abs2(path2);
93 :
94 : bool result = file_util::AbsolutePath(&abs1) &&
95 E : file_util::AbsolutePath(&abs2);
96 E : if (!result)
97 i : return kUnableToCompareFilePaths;
98 :
99 E : if (abs1 == abs2)
100 E : return kEquivalentFilePaths;
101 :
102 E : return kUnableToCompareFilePaths;
103 : }
104 :
105 : // If only one of them exists, then they can't possibly be the same file.
106 E : if (result1 == kFileNotFound || result2 == kFileNotFound)
107 E : return kDistinctFilePaths;
108 :
109 : // If they both exist we compare the details of where they live on disk.
110 : bool identical = info1.dwVolumeSerialNumber == info2.dwVolumeSerialNumber &&
111 : info1.nFileIndexLow == info2.nFileIndexLow &&
112 E : info1.nFileIndexHigh == info2.nFileIndexHigh;
113 :
114 E : return identical ? kEquivalentFilePaths : kDistinctFilePaths;
115 E : }
116 :
117 : } // namespace core
|