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