win32filesystem.cc revision f74420b3285b9fe04a7e00aa3b8c0ab07ea344bc
1f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch/* 2f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * libjingle 3f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * Copyright 2004--2006, Google Inc. 4f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * 5f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * Redistribution and use in source and binary forms, with or without 6f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * modification, are permitted provided that the following conditions are met: 7f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * 8f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * 1. Redistributions of source code must retain the above copyright notice, 9f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * this list of conditions and the following disclaimer. 10f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * 2. Redistributions in binary form must reproduce the above copyright notice, 11f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * this list of conditions and the following disclaimer in the documentation 12f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * and/or other materials provided with the distribution. 13f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * 3. The name of the author may not be used to endorse or promote products 14f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * derived from this software without specific prior written permission. 15f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * 16f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch */ 27f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 28f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/win32filesystem.h" 29f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 30f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/win32.h" 31f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include <shellapi.h> 32f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include <shlobj.h> 33f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include <tchar.h> 34f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 35f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/fileutils.h" 36f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/pathutils.h" 37f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/scoped_ptr.h" 38f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/stream.h" 39f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/stringutils.h" 40f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 41f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// In several places in this file, we test the integrity level of the process 42f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// before calling GetLongPathName. We do this because calling GetLongPathName 43f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// when running under protected mode IE (a low integrity process) can result in 44f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// a virtualized path being returned, which is wrong if you only plan to read. 45f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// TODO(juberti): Waiting to hear back from IE team on whether this is the 46f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// best approach; IEIsProtectedModeProcess is another possible solution. 47f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 48f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochnamespace talk_base { 49f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 50f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool Win32Filesystem::CreateFolder(const Pathname &pathname) { 51f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (pathname.pathname().empty() || !pathname.filename().empty()) 52f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return false; 53f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 54f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch std::wstring path16; 55f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!Utf8ToWindowsFilename(pathname.pathname(), &path16)) 56f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return false; 57f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 58f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch DWORD res = ::GetFileAttributes(path16.c_str()); 59f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (res != INVALID_FILE_ATTRIBUTES) { 60f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Something exists at this location, check if it is a directory 61f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return ((res & FILE_ATTRIBUTE_DIRECTORY) != 0); 62f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else if ((GetLastError() != ERROR_FILE_NOT_FOUND) 63f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch && (GetLastError() != ERROR_PATH_NOT_FOUND)) { 64f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Unexpected error 65f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return false; 66f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 67f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 68f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Directory doesn't exist, look up one directory level 69f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!pathname.parent_folder().empty()) { 70f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch Pathname parent(pathname); 71f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch parent.SetFolder(pathname.parent_folder()); 72f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!CreateFolder(parent)) { 73f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return false; 74f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 75f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 76f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 77f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return (::CreateDirectory(path16.c_str(), NULL) != 0); 78f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 79f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 80f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochFileStream *Win32Filesystem::OpenFile(const Pathname &filename, 81f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch const std::string &mode) { 82f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch FileStream *fs = new FileStream(); 83f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (fs && !fs->Open(filename.pathname().c_str(), mode.c_str())) { 84f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch delete fs; 85f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch fs = NULL; 86f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 87f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return fs; 88f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 89f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 90f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool Win32Filesystem::DeleteFile(const Pathname &filename) { 91f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG(LS_INFO) << "Deleting file " << filename.pathname(); 92f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!IsFile(filename)) { 93f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ASSERT(IsFile(filename)); 94f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return false; 95f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 96f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return ::DeleteFile(ToUtf16(filename.pathname()).c_str()) != 0; 97f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 98f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 99f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool Win32Filesystem::DeleteEmptyFolder(const Pathname &folder) { 100f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG(LS_INFO) << "Deleting folder " << folder.pathname(); 101f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 102f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch std::string no_slash(folder.pathname(), 0, folder.pathname().length()-1); 103f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return ::RemoveDirectory(ToUtf16(no_slash).c_str()) != 0; 104f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 105f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 106f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool Win32Filesystem::GetTemporaryFolder(Pathname &pathname, bool create, 107f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch const std::string *append) { 108f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch wchar_t buffer[MAX_PATH + 1]; 109f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!::GetTempPath(ARRAY_SIZE(buffer), buffer)) 110f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return false; 111f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!IsCurrentProcessLowIntegrity() && 112f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch !::GetLongPathName(buffer, buffer, ARRAY_SIZE(buffer))) 113f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return false; 114f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch size_t len = strlen(buffer); 115f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if ((len > 0) && (buffer[len-1] != '\\')) { 116f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch len += strcpyn(buffer + len, ARRAY_SIZE(buffer) - len, L"\\"); 117f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 118f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (len >= ARRAY_SIZE(buffer) - 1) 119f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return false; 120f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch pathname.clear(); 121f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch pathname.SetFolder(ToUtf8(buffer)); 122f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (append != NULL) { 123f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ASSERT(!append->empty()); 124f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch pathname.AppendFolder(*append); 125f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 126f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return !create || CreateFolder(pathname); 127f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 128f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 129f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochstd::string Win32Filesystem::TempFilename(const Pathname &dir, 130f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch const std::string &prefix) { 131f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch wchar_t filename[MAX_PATH]; 132f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (::GetTempFileName(ToUtf16(dir.pathname()).c_str(), 133f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ToUtf16(prefix).c_str(), 0, filename) != 0) 134f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return ToUtf8(filename); 135f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ASSERT(false); 136f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return ""; 137f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 138f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 139f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool Win32Filesystem::MoveFile(const Pathname &old_path, 140f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch const Pathname &new_path) { 141f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!IsFile(old_path)) { 142f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ASSERT(IsFile(old_path)); 143f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return false; 144f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 145f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG(LS_INFO) << "Moving " << old_path.pathname() 146f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch << " to " << new_path.pathname(); 147f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return ::MoveFile(ToUtf16(old_path.pathname()).c_str(), 148f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ToUtf16(new_path.pathname()).c_str()) != 0; 149f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 150f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 151f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool Win32Filesystem::MoveFolder(const Pathname &old_path, 152f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch const Pathname &new_path) { 153f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!IsFolder(old_path)) { 154f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ASSERT(IsFolder(old_path)); 155f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return false; 156f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 157f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG(LS_INFO) << "Moving " << old_path.pathname() 158f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch << " to " << new_path.pathname(); 159f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (::MoveFile(ToUtf16(old_path.pathname()).c_str(), 160f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ToUtf16(new_path.pathname()).c_str()) == 0) { 161f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (::GetLastError() != ERROR_NOT_SAME_DEVICE) { 162f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG_GLE(LS_ERROR) << "Failed to move file"; 163f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return false; 164f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 165f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!CopyFolder(old_path, new_path)) 166f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return false; 167f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!DeleteFolderAndContents(old_path)) 168f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return false; 169f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 170f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return true; 171f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 172f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 173f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool Win32Filesystem::IsFolder(const Pathname &path) { 174f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch WIN32_FILE_ATTRIBUTE_DATA data = {0}; 175f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (0 == ::GetFileAttributesEx(ToUtf16(path.pathname()).c_str(), 176f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch GetFileExInfoStandard, &data)) 177f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return false; 178f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 179f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch FILE_ATTRIBUTE_DIRECTORY; 180f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 181f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 182f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool Win32Filesystem::IsFile(const Pathname &path) { 183f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch WIN32_FILE_ATTRIBUTE_DATA data = {0}; 184f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (0 == ::GetFileAttributesEx(ToUtf16(path.pathname()).c_str(), 185f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch GetFileExInfoStandard, &data)) 186f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return false; 187f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0; 188f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 189f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 190f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool Win32Filesystem::IsAbsent(const Pathname& path) { 191f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch WIN32_FILE_ATTRIBUTE_DATA data = {0}; 192f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (0 != ::GetFileAttributesEx(ToUtf16(path.pathname()).c_str(), 193f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch GetFileExInfoStandard, &data)) 194f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return false; 195f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch DWORD err = ::GetLastError(); 196f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return (ERROR_FILE_NOT_FOUND == err || ERROR_PATH_NOT_FOUND == err); 197f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 198f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 199f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool Win32Filesystem::CopyFile(const Pathname &old_path, 200f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch const Pathname &new_path) { 201f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return ::CopyFile(ToUtf16(old_path.pathname()).c_str(), 202f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ToUtf16(new_path.pathname()).c_str(), TRUE) != 0; 203f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 204f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 205f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool Win32Filesystem::IsTemporaryPath(const Pathname& pathname) { 206f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch TCHAR buffer[MAX_PATH + 1]; 207f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!::GetTempPath(ARRAY_SIZE(buffer), buffer)) 208f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return false; 209f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!IsCurrentProcessLowIntegrity() && 210f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch !::GetLongPathName(buffer, buffer, ARRAY_SIZE(buffer))) 211f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return false; 212f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return (::strnicmp(ToUtf16(pathname.pathname()).c_str(), 213f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch buffer, strlen(buffer)) == 0); 214f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 215f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 216f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool Win32Filesystem::GetFileSize(const Pathname &pathname, size_t *size) { 217f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch WIN32_FILE_ATTRIBUTE_DATA data = {0}; 218f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (::GetFileAttributesEx(ToUtf16(pathname.pathname()).c_str(), 219f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch GetFileExInfoStandard, &data) == 0) 220f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return false; 221f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *size = data.nFileSizeLow; 222f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return true; 223f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 224f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 225f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool Win32Filesystem::GetFileTime(const Pathname& path, FileTimeType which, 226f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch time_t* time) { 227f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch WIN32_FILE_ATTRIBUTE_DATA data = {0}; 228f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (::GetFileAttributesEx(ToUtf16(path.pathname()).c_str(), 229f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch GetFileExInfoStandard, &data) == 0) 230f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return false; 231f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch switch (which) { 232f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch case FTT_CREATED: 233f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch FileTimeToUnixTime(data.ftCreationTime, time); 234f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch break; 235f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch case FTT_MODIFIED: 236f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch FileTimeToUnixTime(data.ftLastWriteTime, time); 237f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch break; 238f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch case FTT_ACCESSED: 239f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch FileTimeToUnixTime(data.ftLastAccessTime, time); 240f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch break; 241f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch default: 242f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return false; 243f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 244f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return true; 245f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 246f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 247f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool Win32Filesystem::GetAppPathname(Pathname* path) { 248f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch TCHAR buffer[MAX_PATH + 1]; 249f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (0 == ::GetModuleFileName(NULL, buffer, ARRAY_SIZE(buffer))) 250f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return false; 251f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch path->SetPathname(ToUtf8(buffer)); 252f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return true; 253f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 254f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 255f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool Win32Filesystem::GetAppDataFolder(Pathname* path, bool per_user) { 256f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ASSERT(!organization_name_.empty()); 257f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ASSERT(!application_name_.empty()); 258f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch TCHAR buffer[MAX_PATH + 1]; 259f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch int csidl = per_user ? CSIDL_LOCAL_APPDATA : CSIDL_COMMON_APPDATA; 260f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!::SHGetSpecialFolderPath(NULL, buffer, csidl, TRUE)) 261f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return false; 262f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!IsCurrentProcessLowIntegrity() && 263f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch !::GetLongPathName(buffer, buffer, ARRAY_SIZE(buffer))) 264f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return false; 265f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch size_t len = strcatn(buffer, ARRAY_SIZE(buffer), __T("\\")); 266f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch len += strcpyn(buffer + len, ARRAY_SIZE(buffer) - len, 267f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ToUtf16(organization_name_).c_str()); 268f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if ((len > 0) && (buffer[len-1] != __T('\\'))) { 269f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch len += strcpyn(buffer + len, ARRAY_SIZE(buffer) - len, __T("\\")); 270f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 271f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch len += strcpyn(buffer + len, ARRAY_SIZE(buffer) - len, 272f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ToUtf16(application_name_).c_str()); 273f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if ((len > 0) && (buffer[len-1] != __T('\\'))) { 274f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch len += strcpyn(buffer + len, ARRAY_SIZE(buffer) - len, __T("\\")); 275f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 276f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (len >= ARRAY_SIZE(buffer) - 1) 277f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return false; 278f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch path->clear(); 279f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch path->SetFolder(ToUtf8(buffer)); 280f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return CreateFolder(*path); 281f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 282f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 283f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool Win32Filesystem::GetAppTempFolder(Pathname* path) { 284f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!GetAppPathname(path)) 285f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return false; 286f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch std::string filename(path->filename()); 287f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return GetTemporaryFolder(*path, true, &filename); 288f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 289f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 290f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool Win32Filesystem::GetDiskFreeSpace(const Pathname& path, int64 *freebytes) { 291f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!freebytes) { 292f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return false; 293f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 294f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch char drive[4]; 295f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch std::wstring drive16; 296f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch const wchar_t* target_drive = NULL; 297f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (path.GetDrive(drive, sizeof(drive))) { 298f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch drive16 = ToUtf16(drive); 299f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch target_drive = drive16.c_str(); 300f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else if (path.folder().substr(0, 2) == "\\\\") { 301f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // UNC path, fail. 302f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // TODO: Handle UNC paths. 303f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return false; 304f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else { 305f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // The path is probably relative. GetDriveType and GetDiskFreeSpaceEx 306f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // use the current drive if NULL is passed as the drive name. 307f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // TODO: Add method to Pathname to determine if the path is relative. 308f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // TODO: Add method to Pathname to convert a path to absolute. 309f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 310f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch UINT driveType = ::GetDriveType(target_drive); 311f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if ( (driveType & DRIVE_REMOTE) || (driveType & DRIVE_UNKNOWN) ) { 312f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG(LS_VERBOSE) << " remove or unknown drive " << drive; 313f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return false; 314f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 315f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 316f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch int64 totalNumberOfBytes; // receives the number of bytes on disk 317f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch int64 totalNumberOfFreeBytes; // receives the free bytes on disk 318f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // make sure things won't change in 64 bit machine 319f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // TODO replace with compile time assert 320f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ASSERT(sizeof(ULARGE_INTEGER) == sizeof(uint64)); //NOLINT 321f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (::GetDiskFreeSpaceEx(target_drive, 322f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch (PULARGE_INTEGER)freebytes, 323f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch (PULARGE_INTEGER)&totalNumberOfBytes, 324f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch (PULARGE_INTEGER)&totalNumberOfFreeBytes)) { 325f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return true; 326f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else { 327f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG(LS_VERBOSE) << " GetDiskFreeSpaceEx returns error "; 328f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return false; 329f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 330f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 331f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 332f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochPathname Win32Filesystem::GetCurrentDirectory() { 333f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch Pathname cwd; 334f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch int path_len = 0; 335f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch scoped_array<wchar_t> path; 336f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch do { 337f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch int needed = ::GetCurrentDirectory(path_len, path.get()); 338f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (needed == 0) { 339f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Error. 340f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG_GLE(LS_ERROR) << "::GetCurrentDirectory() failed"; 341f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return cwd; // returns empty pathname 342f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 343f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (needed <= path_len) { 344f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // It wrote successfully. 345f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch break; 346f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 347f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Else need to re-alloc for "needed". 348f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch path.reset(new wchar_t[needed]); 349f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch path_len = needed; 350f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } while (true); 351f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch cwd.SetFolder(ToUtf8(path.get())); 352f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return cwd; 353f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 354f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 355f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// TODO: Consider overriding DeleteFolderAndContents for speed and potentially 356f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// better OS integration (recycle bin?) 357f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch/* 358f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch std::wstring temp_path16 = ToUtf16(temp_path.pathname()); 359f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch temp_path16.append(1, '*'); 360f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch temp_path16.append(1, '\0'); 361f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 362f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch SHFILEOPSTRUCT file_op = { 0 }; 363f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch file_op.wFunc = FO_DELETE; 364f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch file_op.pFrom = temp_path16.c_str(); 365f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch file_op.fFlags = FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_SILENT; 366f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return (0 == SHFileOperation(&file_op)); 367f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch*/ 368f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 369f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} // namespace talk_base 370