| Index: base/disk.cc
|
| diff --git a/base/disk.cc b/base/disk.cc
|
| deleted file mode 100644
|
| index ef09e87bfa55113bec17b45f48c707ebdc08fd47..0000000000000000000000000000000000000000
|
| --- a/base/disk.cc
|
| +++ /dev/null
|
| @@ -1,401 +0,0 @@
|
| -// Copyright 2004-2009 Google Inc.
|
| -//
|
| -// Licensed under the Apache License, Version 2.0 (the "License");
|
| -// you may not use this file except in compliance with the License.
|
| -// You may obtain a copy of the License at
|
| -//
|
| -// http://www.apache.org/licenses/LICENSE-2.0
|
| -//
|
| -// Unless required by applicable law or agreed to in writing, software
|
| -// distributed under the License is distributed on an "AS IS" BASIS,
|
| -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| -// See the License for the specific language governing permissions and
|
| -// limitations under the License.
|
| -// ========================================================================
|
| -//
|
| -// Disk functions
|
| -
|
| -#include "omaha/base/disk.h"
|
| -
|
| -#include <winioctl.h>
|
| -#include "omaha/base/commontypes.h"
|
| -#include "omaha/base/const_config.h"
|
| -#include "omaha/base/debug.h"
|
| -#include "omaha/base/error.h"
|
| -#include "omaha/base/file.h"
|
| -#include "omaha/base/localization.h"
|
| -#include "omaha/base/logging.h"
|
| -#include "omaha/base/shell.h"
|
| -#include "omaha/base/string.h"
|
| -#include "omaha/base/synchronized.h"
|
| -#include "omaha/base/system.h"
|
| -#include "omaha/base/timer.h"
|
| -#include "omaha/base/utils.h"
|
| -
|
| -namespace omaha {
|
| -
|
| -#define kNetdiskVendorId "netdisk"
|
| -
|
| -// see also: http://support.microsoft.com/default.aspx?scid=kb;EN-US;Q264203
|
| -
|
| -#if _MSC_VER < 1400
|
| -// Not defined in the headers we have; from MSDN:
|
| -#define IOCTL_STORAGE_QUERY_PROPERTY \
|
| - CTL_CODE(IOCTL_STORAGE_BASE, 0x0500, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
| -
|
| -typedef struct _STORAGE_DEVICE_DESCRIPTOR {
|
| - ULONG Version;
|
| - ULONG Size;
|
| - UCHAR DeviceType;
|
| - UCHAR DeviceTypeModifier;
|
| - BOOLEAN RemovableMedia;
|
| - BOOLEAN CommandQueueing;
|
| - ULONG VendorIdOffset;
|
| - ULONG ProductIdOffset;
|
| - ULONG ProductRevisionOffset;
|
| - ULONG SerialNumberOffset;
|
| - STORAGE_BUS_TYPE BusType;
|
| - ULONG RawPropertiesLength;
|
| - UCHAR RawDeviceProperties[1];
|
| -} STORAGE_DEVICE_DESCRIPTOR, *PSTORAGE_DEVICE_DESCRIPTOR;
|
| -
|
| -typedef enum _STORAGE_QUERY_TYPE {
|
| - PropertyStandardQuery = 0,
|
| - PropertyExistsQuery,
|
| - PropertyMaskQuery,
|
| - PropertyQueryMaxDefined
|
| -} STORAGE_QUERY_TYPE, *PSTORAGE_QUERY_TYPE;
|
| -
|
| -typedef enum _STORAGE_PROPERTY_ID {
|
| - StorageDeviceProperty = 0,
|
| - StorageAdapterProperty,
|
| - StorageDeviceIdProperty
|
| -} STORAGE_PROPERTY_ID, *PSTORAGE_PROPERTY_ID;
|
| -
|
| -typedef struct _STORAGE_PROPERTY_QUERY {
|
| - STORAGE_PROPERTY_ID PropertyId;
|
| - STORAGE_QUERY_TYPE QueryType;
|
| - UCHAR AdditionalParameters[1];
|
| -} STORAGE_PROPERTY_QUERY, *PSTORAGE_PROPERTY_QUERY;
|
| -
|
| -// -------
|
| -#endif
|
| -
|
| -#define kIoctlBufferSize 1024
|
| -
|
| -#define kMaxDrivesCached 3
|
| -#define kMaxDriveLen 20
|
| -static TCHAR g_cache_drive[kMaxDrivesCached][kMaxDriveLen+1];
|
| -static bool g_cache_external[kMaxDrivesCached];
|
| -static int g_cache_pos;
|
| -static LLock g_cache_lock;
|
| -
|
| -bool IsDiskExternal(const TCHAR *drive) {
|
| - ASSERT(drive, (L""));
|
| - ASSERT(lstrlen(drive) < kMaxDriveLen, (L""));
|
| -
|
| - DisableThreadErrorUI disable_error_dialog_box;
|
| -
|
| - {
|
| - __mutexScope(g_cache_lock);
|
| - for (int i = 0; i < kMaxDrivesCached; i++)
|
| - if (!lstrcmp(drive, g_cache_drive[i])) {
|
| - UTIL_LOG(L1, (L"cached disk ext %s %d", drive, g_cache_external[i]));
|
| - return g_cache_external[i];
|
| - }
|
| - }
|
| -
|
| -#ifdef _DEBUG
|
| - Timer timer(true);
|
| -#endif
|
| -
|
| - byte buffer[kIoctlBufferSize+1];
|
| -
|
| - bool external = false;
|
| - HANDLE device = ::CreateFile(drive,
|
| - GENERIC_READ,
|
| - FILE_SHARE_READ | FILE_SHARE_WRITE,
|
| - NULL,
|
| - OPEN_EXISTING,
|
| - NULL,
|
| - NULL);
|
| - if (device == INVALID_HANDLE_VALUE) {
|
| - UTIL_LOG(L1, (L"disk external could not open drive %s", drive));
|
| - goto done;
|
| - }
|
| - STORAGE_DEVICE_DESCRIPTOR *device_desc;
|
| - STORAGE_PROPERTY_QUERY query;
|
| - DWORD out_bytes;
|
| - query.PropertyId = StorageDeviceProperty;
|
| - query.QueryType = PropertyStandardQuery;
|
| - *(query.AdditionalParameters) = 0;
|
| -
|
| - device_desc = reinterpret_cast<STORAGE_DEVICE_DESCRIPTOR*>(buffer);
|
| - // should not be needed, but just to be safer
|
| - ZeroMemory(buffer, kIoctlBufferSize);
|
| -
|
| - BOOL ok = ::DeviceIoControl(device,
|
| - IOCTL_STORAGE_QUERY_PROPERTY,
|
| - &query,
|
| - sizeof(STORAGE_PROPERTY_QUERY),
|
| - buffer,
|
| - kIoctlBufferSize,
|
| - &out_bytes,
|
| - (LPOVERLAPPED)NULL);
|
| -
|
| - if (ok &&
|
| - device_desc->VendorIdOffset &&
|
| - stristr(reinterpret_cast<char*>(buffer + device_desc->VendorIdOffset),
|
| - kNetdiskVendorId)) {
|
| - external = true;
|
| - UTIL_LOG(L1, (L"ximeta netdisk %s", drive));
|
| - }
|
| -
|
| - if (ok &&
|
| - (device_desc->BusType == BusTypeUsb ||
|
| - device_desc->BusType == BusType1394)) {
|
| - external = true;
|
| - }
|
| - if (!ok) {
|
| - UTIL_LOG(L1, (L"disk external ioctl failed %s", drive));
|
| - }
|
| - CloseHandle(device);
|
| - done:
|
| - UTIL_LOG(L1, (L"disk external %s %d time %s",
|
| - drive, external, String_DoubleToString(timer.GetMilliseconds(), 3)));
|
| -
|
| - {
|
| - __mutexScope(g_cache_lock);
|
| - lstrcpyn(g_cache_drive[g_cache_pos], drive, kMaxDriveLen+1);
|
| - g_cache_external[g_cache_pos] = external;
|
| - if (++g_cache_pos >= kMaxDrivesCached) g_cache_pos = 0;
|
| - }
|
| -
|
| - return external;
|
| -}
|
| -
|
| -// find the first fixed local disk with at least the space requested
|
| -// confirms that we can create a directory on the drive
|
| -// returns the drive in the drive parameter
|
| -// returns E_FAIL if no drive with enough space could be found
|
| -HRESULT FindFirstLocalDriveWithEnoughSpace(const uint64 space_required,
|
| - CString *drive) {
|
| - ASSERT1(drive);
|
| -
|
| - DisableThreadErrorUI disable_error_dialog_box;
|
| -
|
| - const int kMaxNumDrives = 26;
|
| - static const size_t kBufLen = (STR_SIZE("c:\\\0") * kMaxNumDrives) + 1;
|
| -
|
| - // obtain the fixed system drives
|
| - TCHAR buf[kBufLen];
|
| - DWORD str_len = ::GetLogicalDriveStrings(kBufLen, buf);
|
| - if (str_len > 0 && str_len < kBufLen) {
|
| - for (TCHAR* ptr = buf; *ptr != L'\0'; ptr += (lstrlen(ptr) + 1)) {
|
| - UINT drive_type = GetDriveType(ptr);
|
| - if (drive_type == DRIVE_FIXED) {
|
| - CString test_drive(ptr);
|
| - if (!IsDiskExternal(CString(L"\\\\?\\") + test_drive.Left(2))) {
|
| - uint64 free_disk_space = 0;
|
| - HRESULT hr = GetFreeDiskSpace(test_drive, &free_disk_space);
|
| -
|
| - if (SUCCEEDED(hr) && space_required <= free_disk_space) {
|
| - CString temp_dir;
|
| - // confirm that we can create a directory on this drive
|
| - bool found = false;
|
| - while (!found) {
|
| - temp_dir = test_drive +
|
| - NOTRANSL(L"test") +
|
| - itostr(static_cast<uint32>(::GetTickCount()));
|
| - if (!File::Exists (temp_dir)) found = true;
|
| - }
|
| -
|
| - if (SUCCEEDED(CreateDir(temp_dir, NULL))) {
|
| - VERIFY1(SUCCEEDED(DeleteDirectory(temp_dir)));
|
| - *drive = test_drive;
|
| - UTIL_LOG(L1, (L"drive %s enough space %d", test_drive.GetString(),
|
| - free_disk_space));
|
| - return S_OK;
|
| - }
|
| - }
|
| - }
|
| - }
|
| - }
|
| - }
|
| -
|
| - return E_FAIL;
|
| -}
|
| -
|
| -// Get free disk space of a drive containing the specified folder
|
| -HRESULT GetFreeDiskSpace(uint32 csidl, uint64* free_disk_space) {
|
| - ASSERT1(free_disk_space);
|
| -
|
| - CString path;
|
| - RET_IF_FAILED(Shell::GetSpecialFolder(csidl, false, &path));
|
| -
|
| - return GetFreeDiskSpace(path, free_disk_space);
|
| -}
|
| -
|
| -// Get free disk space of a drive containing the specified folder
|
| -HRESULT GetFreeDiskSpace(const TCHAR* folder, uint64* free_disk_space) {
|
| - ASSERT1(folder && *folder);
|
| - ASSERT1(free_disk_space);
|
| -
|
| - DisableThreadErrorUI disable_error_dialog_box;
|
| -
|
| - CString drive(folder);
|
| -
|
| - // (Stupid API used by System::GetDiskStatistics will work with any folder -
|
| - // as long as it EXISTS. Since the data storage folder might not exist yet
|
| - // (e.g., on a clean install) we'll just truncate it down to a drive letter.)
|
| - drive = drive.Left(3); // "X:\"
|
| - ASSERT1(String_EndsWith(drive, _T(":\\"), false));
|
| -
|
| - // Get the free disk space available to this user on this drive
|
| - uint64 free_bytes_current_user = 0LL;
|
| - uint64 total_bytes_current_user = 0LL;
|
| - uint64 free_bytes_all_users = 0LL;
|
| - RET_IF_FAILED(System::GetDiskStatistics(drive,
|
| - &free_bytes_current_user,
|
| - &total_bytes_current_user,
|
| - &free_bytes_all_users));
|
| -
|
| - *free_disk_space = std::min(free_bytes_current_user, free_bytes_all_users);
|
| -
|
| - return S_OK;
|
| -}
|
| -
|
| -// Has enough free disk space on a drive containing the specified folder
|
| -HRESULT HasEnoughFreeDiskSpace(uint32 csidl, uint64 disk_space_needed) {
|
| - uint64 free_disk_space = 0;
|
| - if (SUCCEEDED(GetFreeDiskSpace(csidl, &free_disk_space))) {
|
| - return (disk_space_needed <= free_disk_space) ?
|
| - S_OK : CI_E_NOT_ENOUGH_DISK_SPACE;
|
| - }
|
| - return S_OK;
|
| -}
|
| -
|
| -// Has enough free disk space on a drive containing the specified folder
|
| -HRESULT HasEnoughFreeDiskSpace(const TCHAR* folder, uint64 disk_space_needed) {
|
| - uint64 free_disk_space = 0;
|
| - if (SUCCEEDED(GetFreeDiskSpace(folder, &free_disk_space))) {
|
| - return (disk_space_needed <= free_disk_space) ?
|
| - S_OK : CI_E_NOT_ENOUGH_DISK_SPACE;
|
| - }
|
| - return S_OK;
|
| -}
|
| -
|
| -// The ::CreateFile() call will fail for mapped local drives (subst).
|
| -bool IsHotPluggable(const TCHAR* drive) {
|
| - ASSERT(drive, (L""));
|
| -
|
| - // Disable potential error dialogs during this check
|
| - DisableThreadErrorUI disable_error_dialog_box;
|
| -
|
| - //
|
| - // We set the default return value to true so that
|
| - // we treat the disk as hot-pluggable in case we
|
| - // don't know.
|
| - //
|
| - bool ret = true;
|
| -
|
| - if (drive && lstrlen(drive) >= 2) {
|
| - CString volume_path(_T("\\\\.\\"));
|
| - // We don't want the trailing backslash.
|
| - volume_path.Append(drive, 2);
|
| -
|
| - CHandle volume(::CreateFile(volume_path, GENERIC_READ,
|
| - FILE_SHARE_READ | FILE_SHARE_WRITE,
|
| - NULL, OPEN_EXISTING, 0, NULL));
|
| -
|
| - if (volume != INVALID_HANDLE_VALUE) {
|
| - STORAGE_HOTPLUG_INFO shi = {0};
|
| - shi.Size = sizeof(shi);
|
| - DWORD bytes_returned = 0;
|
| - if (::DeviceIoControl(volume, IOCTL_STORAGE_GET_HOTPLUG_INFO, NULL, 0,
|
| - &shi, sizeof(STORAGE_HOTPLUG_INFO), &bytes_returned,
|
| - NULL)) {
|
| - ret = (shi.DeviceHotplug != false);
|
| - } else {
|
| - UTIL_LOG(LW, (_T("[::DeviceIoControl failed][%u]"), ::GetLastError()));
|
| - }
|
| - } else {
|
| - UTIL_LOG(LW, (_T("[::CreateFile failed][%u]"), ::GetLastError()));
|
| - }
|
| - } else {
|
| - ASSERT(false, (L"Invalid path"));
|
| - }
|
| -
|
| - return ret;
|
| -}
|
| -
|
| -bool IsLargeDrive(const TCHAR* drive) {
|
| - ASSERT1(drive && *drive);
|
| -
|
| - DisableThreadErrorUI disable_error_dialog_box;
|
| -
|
| - ULARGE_INTEGER caller_free_bytes = {0};
|
| - ULARGE_INTEGER total_bytes = {0};
|
| - ULARGE_INTEGER total_free_bytes = {0};
|
| -
|
| - if (!::GetDiskFreeSpaceEx(drive,
|
| - &caller_free_bytes,
|
| - &total_bytes,
|
| - &total_free_bytes)) {
|
| - HRESULT hr = HRESULTFromLastError();
|
| - UTIL_LOG(LEVEL_ERROR,
|
| - (_T("[IsLargeDrive - failed to GetDiskFreeSpaceEx][0x%x]"), hr));
|
| - return false;
|
| - }
|
| -
|
| - return (total_bytes.QuadPart > kLargeDriveSize);
|
| -}
|
| -
|
| -HRESULT DevicePathToDosPath(const TCHAR* device_path, CString* dos_path) {
|
| - ASSERT1(device_path);
|
| - ASSERT1(dos_path);
|
| - UTIL_LOG(L4, (_T("[DevicePathToDosPath][device_path=%s]"), device_path));
|
| -
|
| - dos_path->Empty();
|
| -
|
| - TCHAR drive_strings[MAX_PATH] = _T("");
|
| - if (!::GetLogicalDriveStrings(arraysize(drive_strings), drive_strings)) {
|
| - UTIL_LOG(L4, (_T("[DevicePathToDosPath-GetLogicalDriveStrings fail][0x%x]"),
|
| - HRESULTFromLastError()));
|
| - return HRESULTFromLastError();
|
| - }
|
| -
|
| - // Drive strings are stored as a set of null terminated strings, with an
|
| - // extra null after the last string. Each drive string is of the form "C:\".
|
| - // We convert it to the form "C:", which is the format expected by
|
| - // ::QueryDosDevice().
|
| - TCHAR drive_colon[3] = _T(" :");
|
| - for (const TCHAR* next_drive_letter = drive_strings;
|
| - *next_drive_letter;
|
| - next_drive_letter += _tcslen(next_drive_letter) + 1) {
|
| - // Dos device of the form "C:".
|
| - *drive_colon = *next_drive_letter;
|
| - TCHAR device_name[MAX_PATH] = _T("");
|
| - if (!::QueryDosDevice(drive_colon, device_name, arraysize(device_name))) {
|
| - UTIL_LOG(LEVEL_ERROR, (_T("[QueryDosDevice failed][0x%x]"),
|
| - HRESULTFromLastError()));
|
| - continue;
|
| - }
|
| -
|
| - UTIL_LOG(L4, (_T("[DevicePathToDosPath found drive]")
|
| - _T("[logical drive %s][device name %s]"),
|
| - drive_colon, device_name));
|
| -
|
| - size_t name_length = _tcslen(device_name);
|
| - if (_tcsnicmp(device_path, device_name, name_length) == 0) {
|
| - // Construct DOS path.
|
| - dos_path->Format(_T("%s%s"), drive_colon, device_path + name_length);
|
| - UTIL_LOG(L4, (_T("[DevicePathToDosPath][dos_path=%s]"), *dos_path));
|
| - return S_OK;
|
| - }
|
| - }
|
| -
|
| - return HRESULT_FROM_WIN32(ERROR_INVALID_DRIVE);
|
| -}
|
| -
|
| -} // namespace omaha
|
|
|