summaryrefslogtreecommitdiffstats
path: root/base/file_util_win.cc
diff options
context:
space:
mode:
authorskerner@chromium.org <skerner@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-06-09 22:56:48 +0000
committerskerner@chromium.org <skerner@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-06-09 22:56:48 +0000
commit6f5f4322d6688abd29d0253a6a8201fb7b1c103d (patch)
tree1ceb35e4715990b18b9f7f6327c5072f7a699fe4 /base/file_util_win.cc
parenta53bb6f7db58fa59fb2dd3b6508b6acc0d1d44ad (diff)
downloadchromium_src-6f5f4322d6688abd29d0253a6a8201fb7b1c103d.zip
chromium_src-6f5f4322d6688abd29d0253a6a8201fb7b1c103d.tar.gz
chromium_src-6f5f4322d6688abd29d0253a6a8201fb7b1c103d.tar.bz2
Give the extension unpacker process a junction/symlink free path to the unpack directory.
BUG=35198,13044 TEST=FileUtilTest.NormalizeFilePathBasic,FileUtilTest. NormalizeFilePathReparsePoints,FileUtilTest.NormalizeFilePathSymlinks Review URL: http://codereview.chromium.org/2088006 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@49337 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/file_util_win.cc')
-rw-r--r--base/file_util_win.cc125
1 files changed, 121 insertions, 4 deletions
diff --git a/base/file_util_win.cc b/base/file_util_win.cc
index fcad39c..dc15ea0 100644
--- a/base/file_util_win.cc
+++ b/base/file_util_win.cc
@@ -6,6 +6,7 @@
#include <windows.h>
#include <propvarutil.h>
+#include <psapi.h>
#include <shellapi.h>
#include <shlobj.h>
#include <time.h>
@@ -21,6 +22,49 @@
namespace file_util {
+namespace {
+
+// Helper for NormalizeFilePath(), defined below.
+bool DevicePathToDriveLetterPath(const FilePath& device_path,
+ FilePath* drive_letter_path) {
+ // Get the mapping of drive letters to device paths.
+ const int kDriveMappingSize = 1024;
+ wchar_t drive_mapping[kDriveMappingSize] = {'\0'};
+ if (!::GetLogicalDriveStrings(kDriveMappingSize - 1, drive_mapping)) {
+ LOG(ERROR) << "Failed to get drive mapping.";
+ return false;
+ }
+
+ // The drive mapping is a sequence of null terminated strings.
+ // The last string is empty.
+ wchar_t* drive_map_ptr = drive_mapping;
+ wchar_t device_name[MAX_PATH];
+ wchar_t drive[] = L" :";
+
+ // For each string in the drive mapping, get the junction that links
+ // to it. If that junction is a prefix of |device_path|, then we
+ // know that |drive| is the real path prefix.
+ while(*drive_map_ptr) {
+ drive[0] = drive_map_ptr[0]; // Copy the drive letter.
+
+ if (QueryDosDevice(drive, device_name, MAX_PATH) &&
+ StartsWith(device_path.value(), device_name, true)) {
+ *drive_letter_path = FilePath(drive +
+ device_path.value().substr(wcslen(device_name)));
+ return true;
+ }
+ // Move to the next drive letter string, which starts one
+ // increment after the '\0' that terminates the current string.
+ while(*drive_map_ptr++);
+ }
+
+ // No drive matched. The path does not start with a device junction.
+ *drive_letter_path = device_path;
+ return true;
+}
+
+} // namespace
+
std::wstring GetDirectoryFromPath(const std::wstring& path) {
wchar_t path_buffer[MAX_PATH];
wchar_t* file_ptr = NULL;
@@ -137,10 +181,14 @@ bool Move(const FilePath& from_path, const FilePath& to_path) {
bool ReplaceFile(const FilePath& from_path, const FilePath& to_path) {
// Make sure that the target file exists.
- HANDLE target_file = ::CreateFile(to_path.value().c_str(), 0,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- NULL, CREATE_NEW,
- FILE_ATTRIBUTE_NORMAL, NULL);
+ HANDLE target_file = ::CreateFile(
+ to_path.value().c_str(),
+ 0,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ CREATE_NEW,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
if (target_file != INVALID_HANDLE_VALUE)
::CloseHandle(target_file);
// When writing to a network share, we may not be able to change the ACLs.
@@ -892,4 +940,73 @@ bool HasFileBeenModifiedSince(const FileEnumerator::FindInfo& find_info,
return result == 1 || result == 0;
}
+bool NormalizeFilePath(const FilePath& path, FilePath* real_path) {
+ ScopedHandle path_handle(
+ ::CreateFile(path.value().c_str(),
+ GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL));
+ if (path_handle == INVALID_HANDLE_VALUE)
+ return false;
+
+ // In Vista, GetFinalPathNameByHandle() would give us the real path
+ // from a file handle. If we ever deprecate XP, consider changing the
+ // code below to a call to GetFinalPathNameByHandle(). The method this
+ // function uses is explained in the following msdn article:
+ // http://msdn.microsoft.com/en-us/library/aa366789(VS.85).aspx
+ DWORD file_size_high = 0;
+ DWORD file_size_low = ::GetFileSize(path_handle.Get(), &file_size_high);
+ if (file_size_low == 0 && file_size_high == 0) {
+ // It is not possible to map an empty file.
+ LOG(ERROR) << "NormalizeFilePath failed: Empty file.";
+ return false;
+ }
+
+ // Create a file mapping object. Can't easily use MemoryMappedFile, because
+ // we only map the first byte, and need direct access to the handle.
+ ScopedHandle file_map_handle(
+ ::CreateFileMapping(path_handle.Get(),
+ NULL,
+ PAGE_READONLY,
+ 0,
+ 1, // Just one byte. No need to look at the data.
+ NULL));
+
+ if (file_map_handle == INVALID_HANDLE_VALUE)
+ return false;
+
+ // Use a view of the file to get the path to the file.
+ void* file_view = MapViewOfFile(
+ file_map_handle.Get(), FILE_MAP_READ, 0, 0, 1);
+ if (!file_view)
+ return false;
+
+ bool success = false;
+
+ // The expansion of |path| into a full path may make it longer.
+ // GetMappedFileName() will fail if the result is longer than MAX_PATH.
+ // Pad a bit to be safe. If kMaxPathLength is ever changed to be less
+ // than MAX_PATH, it would be nessisary to test that GetMappedFileName()
+ // not return kMaxPathLength. This would mean that only part of the
+ // path fit in |mapped_file_path|.
+ const int kMaxPathLength = MAX_PATH + 10;
+ wchar_t mapped_file_path[kMaxPathLength];
+ if (::GetMappedFileName(GetCurrentProcess(),
+ file_view,
+ mapped_file_path,
+ kMaxPathLength)) {
+ // GetMappedFileName() will return a path that starts with
+ // "\Device\Harddisk...". Helper DevicePathToDriveLetterPath()
+ // will find a drive letter which maps to the path's device, so
+ // that we return a path starting with a drive letter.
+ FilePath mapped_file(mapped_file_path);
+ success = DevicePathToDriveLetterPath(mapped_file, real_path);
+ }
+ UnmapViewOfFile(file_view);
+ return success;
+}
+
} // namespace file_util