Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(689)

Side by Side Diff: base/file_util_win.cc

Issue 2088006: Give the extension unpacker process a junction/symlink free path to the unpack directory. (Closed)
Patch Set: Rebase for commit. Created 10 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « base/file_util_unittest.cc ('k') | chrome/browser/extensions/sandboxed_extension_unpacker.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/file_util.h" 5 #include "base/file_util.h"
6 6
7 #include <windows.h> 7 #include <windows.h>
8 #include <propvarutil.h> 8 #include <propvarutil.h>
9 #include <psapi.h>
9 #include <shellapi.h> 10 #include <shellapi.h>
10 #include <shlobj.h> 11 #include <shlobj.h>
11 #include <time.h> 12 #include <time.h>
12 #include <string> 13 #include <string>
13 14
14 #include "base/file_path.h" 15 #include "base/file_path.h"
15 #include "base/logging.h" 16 #include "base/logging.h"
16 #include "base/scoped_comptr_win.h" 17 #include "base/scoped_comptr_win.h"
17 #include "base/scoped_handle.h" 18 #include "base/scoped_handle.h"
18 #include "base/string_util.h" 19 #include "base/string_util.h"
19 #include "base/time.h" 20 #include "base/time.h"
20 #include "base/win_util.h" 21 #include "base/win_util.h"
21 22
22 namespace file_util { 23 namespace file_util {
23 24
25 namespace {
26
27 // Helper for NormalizeFilePath(), defined below.
28 bool DevicePathToDriveLetterPath(const FilePath& device_path,
29 FilePath* drive_letter_path) {
30 // Get the mapping of drive letters to device paths.
31 const int kDriveMappingSize = 1024;
32 wchar_t drive_mapping[kDriveMappingSize] = {'\0'};
33 if (!::GetLogicalDriveStrings(kDriveMappingSize - 1, drive_mapping)) {
34 LOG(ERROR) << "Failed to get drive mapping.";
35 return false;
36 }
37
38 // The drive mapping is a sequence of null terminated strings.
39 // The last string is empty.
40 wchar_t* drive_map_ptr = drive_mapping;
41 wchar_t device_name[MAX_PATH];
42 wchar_t drive[] = L" :";
43
44 // For each string in the drive mapping, get the junction that links
45 // to it. If that junction is a prefix of |device_path|, then we
46 // know that |drive| is the real path prefix.
47 while(*drive_map_ptr) {
48 drive[0] = drive_map_ptr[0]; // Copy the drive letter.
49
50 if (QueryDosDevice(drive, device_name, MAX_PATH) &&
51 StartsWith(device_path.value(), device_name, true)) {
52 *drive_letter_path = FilePath(drive +
53 device_path.value().substr(wcslen(device_name)));
54 return true;
55 }
56 // Move to the next drive letter string, which starts one
57 // increment after the '\0' that terminates the current string.
58 while(*drive_map_ptr++);
59 }
60
61 // No drive matched. The path does not start with a device junction.
62 *drive_letter_path = device_path;
63 return true;
64 }
65
66 } // namespace
67
24 std::wstring GetDirectoryFromPath(const std::wstring& path) { 68 std::wstring GetDirectoryFromPath(const std::wstring& path) {
25 wchar_t path_buffer[MAX_PATH]; 69 wchar_t path_buffer[MAX_PATH];
26 wchar_t* file_ptr = NULL; 70 wchar_t* file_ptr = NULL;
27 if (GetFullPathName(path.c_str(), MAX_PATH, path_buffer, &file_ptr) == 0) 71 if (GetFullPathName(path.c_str(), MAX_PATH, path_buffer, &file_ptr) == 0)
28 return L""; 72 return L"";
29 73
30 std::wstring::size_type length = 74 std::wstring::size_type length =
31 file_ptr ? file_ptr - path_buffer : path.length(); 75 file_ptr ? file_ptr - path_buffer : path.length();
32 std::wstring directory(path, 0, length); 76 std::wstring directory(path, 0, length);
33 return FilePath(directory).StripTrailingSeparators().value(); 77 return FilePath(directory).StripTrailingSeparators().value();
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
130 // MoveFileEx fails if moving directory across volumes. We will simulate 174 // MoveFileEx fails if moving directory across volumes. We will simulate
131 // the move by using Copy and Delete. Ideally we could check whether 175 // the move by using Copy and Delete. Ideally we could check whether
132 // from_path and to_path are indeed in different volumes. 176 // from_path and to_path are indeed in different volumes.
133 return CopyAndDeleteDirectory(from_path, to_path); 177 return CopyAndDeleteDirectory(from_path, to_path);
134 } 178 }
135 return false; 179 return false;
136 } 180 }
137 181
138 bool ReplaceFile(const FilePath& from_path, const FilePath& to_path) { 182 bool ReplaceFile(const FilePath& from_path, const FilePath& to_path) {
139 // Make sure that the target file exists. 183 // Make sure that the target file exists.
140 HANDLE target_file = ::CreateFile(to_path.value().c_str(), 0, 184 HANDLE target_file = ::CreateFile(
141 FILE_SHARE_READ | FILE_SHARE_WRITE, 185 to_path.value().c_str(),
142 NULL, CREATE_NEW, 186 0,
143 FILE_ATTRIBUTE_NORMAL, NULL); 187 FILE_SHARE_READ | FILE_SHARE_WRITE,
188 NULL,
189 CREATE_NEW,
190 FILE_ATTRIBUTE_NORMAL,
191 NULL);
144 if (target_file != INVALID_HANDLE_VALUE) 192 if (target_file != INVALID_HANDLE_VALUE)
145 ::CloseHandle(target_file); 193 ::CloseHandle(target_file);
146 // When writing to a network share, we may not be able to change the ACLs. 194 // When writing to a network share, we may not be able to change the ACLs.
147 // Ignore ACL errors then (REPLACEFILE_IGNORE_MERGE_ERRORS). 195 // Ignore ACL errors then (REPLACEFILE_IGNORE_MERGE_ERRORS).
148 return ::ReplaceFile(to_path.value().c_str(), 196 return ::ReplaceFile(to_path.value().c_str(),
149 from_path.value().c_str(), NULL, 197 from_path.value().c_str(), NULL,
150 REPLACEFILE_IGNORE_MERGE_ERRORS, NULL, NULL) ? true : false; 198 REPLACEFILE_IGNORE_MERGE_ERRORS, NULL, NULL) ? true : false;
151 } 199 }
152 200
153 bool CopyFile(const FilePath& from_path, const FilePath& to_path) { 201 bool CopyFile(const FilePath& from_path, const FilePath& to_path) {
(...skipping 731 matching lines...) Expand 10 before | Expand all | Expand 10 after
885 length_ = INVALID_FILE_SIZE; 933 length_ = INVALID_FILE_SIZE;
886 } 934 }
887 935
888 bool HasFileBeenModifiedSince(const FileEnumerator::FindInfo& find_info, 936 bool HasFileBeenModifiedSince(const FileEnumerator::FindInfo& find_info,
889 const base::Time& cutoff_time) { 937 const base::Time& cutoff_time) {
890 long result = CompareFileTime(&find_info.ftLastWriteTime, 938 long result = CompareFileTime(&find_info.ftLastWriteTime,
891 &cutoff_time.ToFileTime()); 939 &cutoff_time.ToFileTime());
892 return result == 1 || result == 0; 940 return result == 1 || result == 0;
893 } 941 }
894 942
943 bool NormalizeFilePath(const FilePath& path, FilePath* real_path) {
944 ScopedHandle path_handle(
945 ::CreateFile(path.value().c_str(),
946 GENERIC_READ,
947 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
948 NULL,
949 OPEN_EXISTING,
950 FILE_ATTRIBUTE_NORMAL,
951 NULL));
952 if (path_handle == INVALID_HANDLE_VALUE)
953 return false;
954
955 // In Vista, GetFinalPathNameByHandle() would give us the real path
956 // from a file handle. If we ever deprecate XP, consider changing the
957 // code below to a call to GetFinalPathNameByHandle(). The method this
958 // function uses is explained in the following msdn article:
959 // http://msdn.microsoft.com/en-us/library/aa366789(VS.85).aspx
960 DWORD file_size_high = 0;
961 DWORD file_size_low = ::GetFileSize(path_handle.Get(), &file_size_high);
962 if (file_size_low == 0 && file_size_high == 0) {
963 // It is not possible to map an empty file.
964 LOG(ERROR) << "NormalizeFilePath failed: Empty file.";
965 return false;
966 }
967
968 // Create a file mapping object. Can't easily use MemoryMappedFile, because
969 // we only map the first byte, and need direct access to the handle.
970 ScopedHandle file_map_handle(
971 ::CreateFileMapping(path_handle.Get(),
972 NULL,
973 PAGE_READONLY,
974 0,
975 1, // Just one byte. No need to look at the data.
976 NULL));
977
978 if (file_map_handle == INVALID_HANDLE_VALUE)
979 return false;
980
981 // Use a view of the file to get the path to the file.
982 void* file_view = MapViewOfFile(
983 file_map_handle.Get(), FILE_MAP_READ, 0, 0, 1);
984 if (!file_view)
985 return false;
986
987 bool success = false;
988
989 // The expansion of |path| into a full path may make it longer.
990 // GetMappedFileName() will fail if the result is longer than MAX_PATH.
991 // Pad a bit to be safe. If kMaxPathLength is ever changed to be less
992 // than MAX_PATH, it would be nessisary to test that GetMappedFileName()
993 // not return kMaxPathLength. This would mean that only part of the
994 // path fit in |mapped_file_path|.
995 const int kMaxPathLength = MAX_PATH + 10;
996 wchar_t mapped_file_path[kMaxPathLength];
997 if (::GetMappedFileName(GetCurrentProcess(),
998 file_view,
999 mapped_file_path,
1000 kMaxPathLength)) {
1001 // GetMappedFileName() will return a path that starts with
1002 // "\Device\Harddisk...". Helper DevicePathToDriveLetterPath()
1003 // will find a drive letter which maps to the path's device, so
1004 // that we return a path starting with a drive letter.
1005 FilePath mapped_file(mapped_file_path);
1006 success = DevicePathToDriveLetterPath(mapped_file, real_path);
1007 }
1008 UnmapViewOfFile(file_view);
1009 return success;
1010 }
1011
895 } // namespace file_util 1012 } // namespace file_util
OLDNEW
« no previous file with comments | « base/file_util_unittest.cc ('k') | chrome/browser/extensions/sandboxed_extension_unpacker.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698