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.
45731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// TODO: 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
903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickbool Win32Filesystem::CreatePrivateFile(const Pathname &filename) {
913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // To make the file private to the current user, we first must construct a
923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // SECURITY_DESCRIPTOR specifying an ACL. This code is mostly based upon
933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // http://msdn.microsoft.com/en-us/library/ms707085%28VS.85%29.aspx
943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Get the current process token.
963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  HANDLE process_token = INVALID_HANDLE_VALUE;
973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!::OpenProcessToken(GetCurrentProcess(),
983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                          TOKEN_QUERY,
993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                          &process_token)) {
1003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    LOG_ERR(LS_ERROR) << "OpenProcessToken() failed";
1013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return false;
1023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
1033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Get the size of its TOKEN_USER structure. Return value is not checked
1053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // because we expect it to fail.
1063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DWORD token_user_size = 0;
1073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  (void)::GetTokenInformation(process_token,
1083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                              TokenUser,
1093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                              NULL,
1103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                              0,
1113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                              &token_user_size);
1123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Get the TOKEN_USER structure.
1143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  scoped_array<char> token_user_bytes(new char[token_user_size]);
1153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  PTOKEN_USER token_user = reinterpret_cast<PTOKEN_USER>(
1163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      token_user_bytes.get());
1173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  memset(token_user, 0, token_user_size);
1183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  BOOL success = ::GetTokenInformation(process_token,
1193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                       TokenUser,
1203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                       token_user,
1213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                       token_user_size,
1223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                       &token_user_size);
1233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // We're now done with this.
1243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  ::CloseHandle(process_token);
1253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!success) {
1263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    LOG_ERR(LS_ERROR) << "GetTokenInformation() failed";
1273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return false;
1283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
1293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!IsValidSid(token_user->User.Sid)) {
1313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    LOG_ERR(LS_ERROR) << "Current process has invalid user SID";
1323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return false;
1333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
1343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Compute size needed for an ACL that allows access to just this user.
1363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  int acl_size = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) +
1373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      GetLengthSid(token_user->User.Sid);
1383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Allocate it.
1403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  scoped_array<char> acl_bytes(new char[acl_size]);
1413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  PACL acl = reinterpret_cast<PACL>(acl_bytes.get());
1423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  memset(acl, 0, acl_size);
1433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!::InitializeAcl(acl, acl_size, ACL_REVISION)) {
1443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    LOG_ERR(LS_ERROR) << "InitializeAcl() failed";
1453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return false;
1463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
1473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Allow access to only the current user.
1493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!::AddAccessAllowedAce(acl,
1503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                             ACL_REVISION,
1513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                             GENERIC_READ | GENERIC_WRITE | STANDARD_RIGHTS_ALL,
1523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                             token_user->User.Sid)) {
1533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    LOG_ERR(LS_ERROR) << "AddAccessAllowedAce() failed";
1543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return false;
1553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
1563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Now make the security descriptor.
1583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  SECURITY_DESCRIPTOR security_descriptor;
1593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!::InitializeSecurityDescriptor(&security_descriptor,
1603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                      SECURITY_DESCRIPTOR_REVISION)) {
1613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    LOG_ERR(LS_ERROR) << "InitializeSecurityDescriptor() failed";
1623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return false;
1633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
1643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Put the ACL in it.
1663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!::SetSecurityDescriptorDacl(&security_descriptor,
1673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                   TRUE,
1683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                   acl,
1693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                   FALSE)) {
1703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    LOG_ERR(LS_ERROR) << "SetSecurityDescriptorDacl() failed";
1713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return false;
1723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
1733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Finally create the file.
1753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  SECURITY_ATTRIBUTES security_attributes;
1763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  security_attributes.nLength = sizeof(security_attributes);
1773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  security_attributes.lpSecurityDescriptor = &security_descriptor;
1783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  security_attributes.bInheritHandle = FALSE;
1793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  HANDLE handle = ::CreateFile(
1803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      ToUtf16(filename.pathname()).c_str(),
1813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      GENERIC_READ | GENERIC_WRITE,
1823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
1833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      &security_attributes,
1843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      CREATE_NEW,
1853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      0,
1863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      NULL);
1873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (INVALID_HANDLE_VALUE == handle) {
1883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    LOG_ERR(LS_ERROR) << "CreateFile() failed";
1893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return false;
1903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
1913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!::CloseHandle(handle)) {
1923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    LOG_ERR(LS_ERROR) << "CloseFile() failed";
1933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // Continue.
1943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
1953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return true;
1963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
1973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
198f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool Win32Filesystem::DeleteFile(const Pathname &filename) {
199f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  LOG(LS_INFO) << "Deleting file " << filename.pathname();
200f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (!IsFile(filename)) {
201f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    ASSERT(IsFile(filename));
202f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return false;
203f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
204f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return ::DeleteFile(ToUtf16(filename.pathname()).c_str()) != 0;
205f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
206f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
207f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool Win32Filesystem::DeleteEmptyFolder(const Pathname &folder) {
208f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  LOG(LS_INFO) << "Deleting folder " << folder.pathname();
209f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
210f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  std::string no_slash(folder.pathname(), 0, folder.pathname().length()-1);
211f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return ::RemoveDirectory(ToUtf16(no_slash).c_str()) != 0;
212f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
213f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
214f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool Win32Filesystem::GetTemporaryFolder(Pathname &pathname, bool create,
215f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                                         const std::string *append) {
216f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  wchar_t buffer[MAX_PATH + 1];
217f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (!::GetTempPath(ARRAY_SIZE(buffer), buffer))
218f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return false;
219f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (!IsCurrentProcessLowIntegrity() &&
220f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      !::GetLongPathName(buffer, buffer, ARRAY_SIZE(buffer)))
221f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return false;
222f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  size_t len = strlen(buffer);
223f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if ((len > 0) && (buffer[len-1] != '\\')) {
224f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    len += strcpyn(buffer + len, ARRAY_SIZE(buffer) - len, L"\\");
225f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
226f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (len >= ARRAY_SIZE(buffer) - 1)
227f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return false;
228f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  pathname.clear();
229f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  pathname.SetFolder(ToUtf8(buffer));
230f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (append != NULL) {
231f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    ASSERT(!append->empty());
232f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    pathname.AppendFolder(*append);
233f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
234f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return !create || CreateFolder(pathname);
235f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
236f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
237f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochstd::string Win32Filesystem::TempFilename(const Pathname &dir,
238f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                                          const std::string &prefix) {
239f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  wchar_t filename[MAX_PATH];
240f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (::GetTempFileName(ToUtf16(dir.pathname()).c_str(),
241f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                        ToUtf16(prefix).c_str(), 0, filename) != 0)
242f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return ToUtf8(filename);
243f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  ASSERT(false);
244f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return "";
245f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
246f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
247f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool Win32Filesystem::MoveFile(const Pathname &old_path,
248f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                               const Pathname &new_path) {
249f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (!IsFile(old_path)) {
250f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    ASSERT(IsFile(old_path));
251f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return false;
252f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
253f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  LOG(LS_INFO) << "Moving " << old_path.pathname()
254f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch               << " to " << new_path.pathname();
255f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return ::MoveFile(ToUtf16(old_path.pathname()).c_str(),
256f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                    ToUtf16(new_path.pathname()).c_str()) != 0;
257f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
258f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
259f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool Win32Filesystem::MoveFolder(const Pathname &old_path,
260f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                                 const Pathname &new_path) {
261f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (!IsFolder(old_path)) {
262f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    ASSERT(IsFolder(old_path));
263f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return false;
264f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
265f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  LOG(LS_INFO) << "Moving " << old_path.pathname()
266f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch               << " to " << new_path.pathname();
267f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (::MoveFile(ToUtf16(old_path.pathname()).c_str(),
268f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch               ToUtf16(new_path.pathname()).c_str()) == 0) {
269f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if (::GetLastError() != ERROR_NOT_SAME_DEVICE) {
270f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      LOG_GLE(LS_ERROR) << "Failed to move file";
271f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      return false;
272f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    }
273f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if (!CopyFolder(old_path, new_path))
274f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      return false;
275f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if (!DeleteFolderAndContents(old_path))
276f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      return false;
277f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
278f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return true;
279f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
280f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
281f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool Win32Filesystem::IsFolder(const Pathname &path) {
282f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  WIN32_FILE_ATTRIBUTE_DATA data = {0};
283f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (0 == ::GetFileAttributesEx(ToUtf16(path.pathname()).c_str(),
284f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                                 GetFileExInfoStandard, &data))
285f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return false;
286f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ==
287f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      FILE_ATTRIBUTE_DIRECTORY;
288f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
289f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
290f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool Win32Filesystem::IsFile(const Pathname &path) {
291f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  WIN32_FILE_ATTRIBUTE_DATA data = {0};
292f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (0 == ::GetFileAttributesEx(ToUtf16(path.pathname()).c_str(),
293f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                                 GetFileExInfoStandard, &data))
294f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return false;
295f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0;
296f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
297f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
298f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool Win32Filesystem::IsAbsent(const Pathname& path) {
299f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  WIN32_FILE_ATTRIBUTE_DATA data = {0};
300f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (0 != ::GetFileAttributesEx(ToUtf16(path.pathname()).c_str(),
301f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                                 GetFileExInfoStandard, &data))
302f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return false;
303f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  DWORD err = ::GetLastError();
304f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return (ERROR_FILE_NOT_FOUND == err || ERROR_PATH_NOT_FOUND == err);
305f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
306f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
307f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool Win32Filesystem::CopyFile(const Pathname &old_path,
308f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                               const Pathname &new_path) {
309f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return ::CopyFile(ToUtf16(old_path.pathname()).c_str(),
310f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                    ToUtf16(new_path.pathname()).c_str(), TRUE) != 0;
311f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
312f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
313f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool Win32Filesystem::IsTemporaryPath(const Pathname& pathname) {
314f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  TCHAR buffer[MAX_PATH + 1];
315f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (!::GetTempPath(ARRAY_SIZE(buffer), buffer))
316f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return false;
317f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (!IsCurrentProcessLowIntegrity() &&
318f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      !::GetLongPathName(buffer, buffer, ARRAY_SIZE(buffer)))
319f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return false;
320f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return (::strnicmp(ToUtf16(pathname.pathname()).c_str(),
321f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                     buffer, strlen(buffer)) == 0);
322f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
323f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
324f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool Win32Filesystem::GetFileSize(const Pathname &pathname, size_t *size) {
325f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  WIN32_FILE_ATTRIBUTE_DATA data = {0};
326f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (::GetFileAttributesEx(ToUtf16(pathname.pathname()).c_str(),
327f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                            GetFileExInfoStandard, &data) == 0)
328f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return false;
329f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  *size = data.nFileSizeLow;
330f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return true;
331f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
332f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
333f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool Win32Filesystem::GetFileTime(const Pathname& path, FileTimeType which,
334f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                                  time_t* time) {
335f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  WIN32_FILE_ATTRIBUTE_DATA data = {0};
336f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (::GetFileAttributesEx(ToUtf16(path.pathname()).c_str(),
337f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                            GetFileExInfoStandard, &data) == 0)
338f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return false;
339f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  switch (which) {
340f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  case FTT_CREATED:
341f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    FileTimeToUnixTime(data.ftCreationTime, time);
342f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    break;
343f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  case FTT_MODIFIED:
344f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    FileTimeToUnixTime(data.ftLastWriteTime, time);
345f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    break;
346f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  case FTT_ACCESSED:
347f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    FileTimeToUnixTime(data.ftLastAccessTime, time);
348f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    break;
349f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  default:
350f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return false;
351f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
352f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return true;
353f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
354f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
355f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool Win32Filesystem::GetAppPathname(Pathname* path) {
356f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  TCHAR buffer[MAX_PATH + 1];
357f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (0 == ::GetModuleFileName(NULL, buffer, ARRAY_SIZE(buffer)))
358f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return false;
359f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  path->SetPathname(ToUtf8(buffer));
360f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return true;
361f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
362f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
363f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool Win32Filesystem::GetAppDataFolder(Pathname* path, bool per_user) {
364f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  ASSERT(!organization_name_.empty());
365f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  ASSERT(!application_name_.empty());
366f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  TCHAR buffer[MAX_PATH + 1];
367f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  int csidl = per_user ? CSIDL_LOCAL_APPDATA : CSIDL_COMMON_APPDATA;
368f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (!::SHGetSpecialFolderPath(NULL, buffer, csidl, TRUE))
369f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return false;
370f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (!IsCurrentProcessLowIntegrity() &&
371f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      !::GetLongPathName(buffer, buffer, ARRAY_SIZE(buffer)))
372f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return false;
373f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  size_t len = strcatn(buffer, ARRAY_SIZE(buffer), __T("\\"));
374f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  len += strcpyn(buffer + len, ARRAY_SIZE(buffer) - len,
375f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                 ToUtf16(organization_name_).c_str());
376f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if ((len > 0) && (buffer[len-1] != __T('\\'))) {
377f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    len += strcpyn(buffer + len, ARRAY_SIZE(buffer) - len, __T("\\"));
378f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
379f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  len += strcpyn(buffer + len, ARRAY_SIZE(buffer) - len,
380f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                 ToUtf16(application_name_).c_str());
381f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if ((len > 0) && (buffer[len-1] != __T('\\'))) {
382f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    len += strcpyn(buffer + len, ARRAY_SIZE(buffer) - len, __T("\\"));
383f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
384f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (len >= ARRAY_SIZE(buffer) - 1)
385f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return false;
386f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  path->clear();
387f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  path->SetFolder(ToUtf8(buffer));
388f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return CreateFolder(*path);
389f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
390f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
391f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool Win32Filesystem::GetAppTempFolder(Pathname* path) {
392f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (!GetAppPathname(path))
393f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return false;
394f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  std::string filename(path->filename());
395f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return GetTemporaryFolder(*path, true, &filename);
396f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
397f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
398f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool Win32Filesystem::GetDiskFreeSpace(const Pathname& path, int64 *freebytes) {
399f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (!freebytes) {
400f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return false;
401f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
402f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  char drive[4];
403f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  std::wstring drive16;
404f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  const wchar_t* target_drive = NULL;
405f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (path.GetDrive(drive, sizeof(drive))) {
406f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    drive16 = ToUtf16(drive);
407f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    target_drive = drive16.c_str();
408f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  } else if (path.folder().substr(0, 2) == "\\\\") {
409f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    // UNC path, fail.
410f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    // TODO: Handle UNC paths.
411f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return false;
412f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  } else {
413f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    // The path is probably relative.  GetDriveType and GetDiskFreeSpaceEx
414f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    // use the current drive if NULL is passed as the drive name.
415f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    // TODO: Add method to Pathname to determine if the path is relative.
416f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    // TODO: Add method to Pathname to convert a path to absolute.
417f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
418f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  UINT driveType = ::GetDriveType(target_drive);
419f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if ( (driveType & DRIVE_REMOTE) || (driveType & DRIVE_UNKNOWN) ) {
420f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    LOG(LS_VERBOSE) << " remove or unknown drive " << drive;
421f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return false;
422f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
423f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
424f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  int64 totalNumberOfBytes;  // receives the number of bytes on disk
425f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  int64 totalNumberOfFreeBytes;  // receives the free bytes on disk
426f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // make sure things won't change in 64 bit machine
427f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // TODO replace with compile time assert
428f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  ASSERT(sizeof(ULARGE_INTEGER) == sizeof(uint64));  //NOLINT
429f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (::GetDiskFreeSpaceEx(target_drive,
430f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                           (PULARGE_INTEGER)freebytes,
431f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                           (PULARGE_INTEGER)&totalNumberOfBytes,
432f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                           (PULARGE_INTEGER)&totalNumberOfFreeBytes)) {
433f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return true;
434f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  } else {
435f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    LOG(LS_VERBOSE) << " GetDiskFreeSpaceEx returns error ";
436f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return false;
437f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
438f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
439f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
440f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochPathname Win32Filesystem::GetCurrentDirectory() {
441f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  Pathname cwd;
442f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  int path_len = 0;
443f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  scoped_array<wchar_t> path;
444f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  do {
445f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    int needed = ::GetCurrentDirectory(path_len, path.get());
446f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if (needed == 0) {
447f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      // Error.
448f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      LOG_GLE(LS_ERROR) << "::GetCurrentDirectory() failed";
449f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      return cwd;  // returns empty pathname
450f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    }
451f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if (needed <= path_len) {
452f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      // It wrote successfully.
453f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      break;
454f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    }
455f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    // Else need to re-alloc for "needed".
456f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    path.reset(new wchar_t[needed]);
457f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    path_len = needed;
458f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  } while (true);
459f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  cwd.SetFolder(ToUtf8(path.get()));
460f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return cwd;
461f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
462f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
463f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// TODO: Consider overriding DeleteFolderAndContents for speed and potentially
464f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// better OS integration (recycle bin?)
465f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch/*
466f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  std::wstring temp_path16 = ToUtf16(temp_path.pathname());
467f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  temp_path16.append(1, '*');
468f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  temp_path16.append(1, '\0');
469f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
470f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  SHFILEOPSTRUCT file_op = { 0 };
471f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  file_op.wFunc = FO_DELETE;
472f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  file_op.pFrom = temp_path16.c_str();
473f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  file_op.fFlags = FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_SILENT;
474f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return (0 == SHFileOperation(&file_op));
475f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch*/
476f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
477f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}  // namespace talk_base
478