15ca58a0aca0320b8980921e8ee55112668817939Adrian Prantl// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25ca58a0aca0320b8980921e8ee55112668817939Adrian Prantl// Use of this source code is governed by a BSD-style license that can be 35ca58a0aca0320b8980921e8ee55112668817939Adrian Prantl// found in the LICENSE file. 45ca58a0aca0320b8980921e8ee55112668817939Adrian Prantl 55ca58a0aca0320b8980921e8ee55112668817939Adrian Prantl#include "storage/browser/fileapi/native_file_util.h" 600df5eaa9f4f7cc0809fd47c95311b532fbe63c6Adrian Prantl 700df5eaa9f4f7cc0809fd47c95311b532fbe63c6Adrian Prantl#include "base/files/file.h" 800df5eaa9f4f7cc0809fd47c95311b532fbe63c6Adrian Prantl#include "base/files/file_enumerator.h" 900df5eaa9f4f7cc0809fd47c95311b532fbe63c6Adrian Prantl#include "base/files/file_util.h" 1000df5eaa9f4f7cc0809fd47c95311b532fbe63c6Adrian Prantl#include "base/memory/scoped_ptr.h" 1100df5eaa9f4f7cc0809fd47c95311b532fbe63c6Adrian Prantl#include "storage/browser/fileapi/file_system_operation_context.h" 1200df5eaa9f4f7cc0809fd47c95311b532fbe63c6Adrian Prantl#include "storage/browser/fileapi/file_system_url.h" 1300df5eaa9f4f7cc0809fd47c95311b532fbe63c6Adrian Prantl 1400df5eaa9f4f7cc0809fd47c95311b532fbe63c6Adrian Prantlnamespace storage { 1500df5eaa9f4f7cc0809fd47c95311b532fbe63c6Adrian Prantl 1600df5eaa9f4f7cc0809fd47c95311b532fbe63c6Adrian Prantlnamespace { 1700df5eaa9f4f7cc0809fd47c95311b532fbe63c6Adrian Prantl 1800df5eaa9f4f7cc0809fd47c95311b532fbe63c6Adrian Prantl// Sets permissions on directory at |dir_path| based on the target platform. 1900df5eaa9f4f7cc0809fd47c95311b532fbe63c6Adrian Prantl// Returns true on success, or false otherwise. 2000df5eaa9f4f7cc0809fd47c95311b532fbe63c6Adrian Prantl// 2100df5eaa9f4f7cc0809fd47c95311b532fbe63c6Adrian Prantl// TODO(benchan): Find a better place outside webkit to host this function. 2200df5eaa9f4f7cc0809fd47c95311b532fbe63c6Adrian Prantlbool SetPlatformSpecificDirectoryPermissions(const base::FilePath& dir_path) { 2300df5eaa9f4f7cc0809fd47c95311b532fbe63c6Adrian Prantl#if defined(OS_CHROMEOS) 2400df5eaa9f4f7cc0809fd47c95311b532fbe63c6Adrian Prantl // System daemons on Chrome OS may run as a user different than the Chrome 2500df5eaa9f4f7cc0809fd47c95311b532fbe63c6Adrian Prantl // process but need to access files under the directories created here. 2600df5eaa9f4f7cc0809fd47c95311b532fbe63c6Adrian Prantl // Because of that, grant the execute permission on the created directory 2700df5eaa9f4f7cc0809fd47c95311b532fbe63c6Adrian Prantl // to group and other users. 2800df5eaa9f4f7cc0809fd47c95311b532fbe63c6Adrian Prantl if (HANDLE_EINTR(chmod(dir_path.value().c_str(), 2900df5eaa9f4f7cc0809fd47c95311b532fbe63c6Adrian Prantl S_IRWXU | S_IXGRP | S_IXOTH)) != 0) { 3000df5eaa9f4f7cc0809fd47c95311b532fbe63c6Adrian Prantl return false; 3100df5eaa9f4f7cc0809fd47c95311b532fbe63c6Adrian Prantl } 3200df5eaa9f4f7cc0809fd47c95311b532fbe63c6Adrian Prantl#endif 3300df5eaa9f4f7cc0809fd47c95311b532fbe63c6Adrian Prantl // Keep the directory permissions unchanged on non-Chrome OS platforms. 3400df5eaa9f4f7cc0809fd47c95311b532fbe63c6Adrian Prantl return true; 3500df5eaa9f4f7cc0809fd47c95311b532fbe63c6Adrian Prantl} 3600df5eaa9f4f7cc0809fd47c95311b532fbe63c6Adrian Prantl 3700df5eaa9f4f7cc0809fd47c95311b532fbe63c6Adrian Prantl// Copies a file |from| to |to|, and ensure the written content is synced to 3800df5eaa9f4f7cc0809fd47c95311b532fbe63c6Adrian Prantl// the disk. This is essentially base::CopyFile followed by fsync(). 3900df5eaa9f4f7cc0809fd47c95311b532fbe63c6Adrian Prantlbool CopyFileAndSync(const base::FilePath& from, const base::FilePath& to) { 4000df5eaa9f4f7cc0809fd47c95311b532fbe63c6Adrian Prantl base::File infile(from, base::File::FLAG_OPEN | base::File::FLAG_READ); 4100df5eaa9f4f7cc0809fd47c95311b532fbe63c6Adrian Prantl if (!infile.IsValid()) { 4200df5eaa9f4f7cc0809fd47c95311b532fbe63c6Adrian Prantl return false; 4300df5eaa9f4f7cc0809fd47c95311b532fbe63c6Adrian Prantl } 4400df5eaa9f4f7cc0809fd47c95311b532fbe63c6Adrian Prantl 4500df5eaa9f4f7cc0809fd47c95311b532fbe63c6Adrian Prantl base::File outfile(to, 4600df5eaa9f4f7cc0809fd47c95311b532fbe63c6Adrian Prantl base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE); 4700df5eaa9f4f7cc0809fd47c95311b532fbe63c6Adrian Prantl if (!outfile.IsValid()) { 4800df5eaa9f4f7cc0809fd47c95311b532fbe63c6Adrian Prantl return false; 4900df5eaa9f4f7cc0809fd47c95311b532fbe63c6Adrian Prantl } 5000df5eaa9f4f7cc0809fd47c95311b532fbe63c6Adrian Prantl 5100df5eaa9f4f7cc0809fd47c95311b532fbe63c6Adrian Prantl const int kBufferSize = 32768; 5200df5eaa9f4f7cc0809fd47c95311b532fbe63c6Adrian Prantl std::vector<char> buffer(kBufferSize); 5300df5eaa9f4f7cc0809fd47c95311b532fbe63c6Adrian Prantl 5400df5eaa9f4f7cc0809fd47c95311b532fbe63c6Adrian Prantl for (;;) { 5500df5eaa9f4f7cc0809fd47c95311b532fbe63c6Adrian Prantl int bytes_read = infile.ReadAtCurrentPos(&buffer[0], kBufferSize); 5600df5eaa9f4f7cc0809fd47c95311b532fbe63c6Adrian Prantl if (bytes_read < 0) 5700df5eaa9f4f7cc0809fd47c95311b532fbe63c6Adrian Prantl return false; 585ca58a0aca0320b8980921e8ee55112668817939Adrian Prantl if (bytes_read == 0) 595ca58a0aca0320b8980921e8ee55112668817939Adrian Prantl break; 605ca58a0aca0320b8980921e8ee55112668817939Adrian Prantl for (int bytes_written = 0; bytes_written < bytes_read; ) { 615ca58a0aca0320b8980921e8ee55112668817939Adrian Prantl int bytes_written_partial = outfile.WriteAtCurrentPos( 625ca58a0aca0320b8980921e8ee55112668817939Adrian Prantl &buffer[bytes_written], bytes_read - bytes_written); 635ca58a0aca0320b8980921e8ee55112668817939Adrian Prantl if (bytes_written_partial < 0) 645ca58a0aca0320b8980921e8ee55112668817939Adrian Prantl return false; 655ca58a0aca0320b8980921e8ee55112668817939Adrian Prantl bytes_written += bytes_written_partial; 665ca58a0aca0320b8980921e8ee55112668817939Adrian Prantl } 675ca58a0aca0320b8980921e8ee55112668817939Adrian Prantl } 685ca58a0aca0320b8980921e8ee55112668817939Adrian Prantl 695ca58a0aca0320b8980921e8ee55112668817939Adrian Prantl return outfile.Flush(); 705ca58a0aca0320b8980921e8ee55112668817939Adrian Prantl} 715ca58a0aca0320b8980921e8ee55112668817939Adrian Prantl 725ca58a0aca0320b8980921e8ee55112668817939Adrian Prantl} // namespace 735ca58a0aca0320b8980921e8ee55112668817939Adrian Prantl 745ca58a0aca0320b8980921e8ee55112668817939Adrian Prantlusing base::PlatformFile; 755ca58a0aca0320b8980921e8ee55112668817939Adrian Prantl 765ca58a0aca0320b8980921e8ee55112668817939Adrian Prantlclass NativeFileEnumerator : public FileSystemFileUtil::AbstractFileEnumerator { 775ca58a0aca0320b8980921e8ee55112668817939Adrian Prantl public: 785ca58a0aca0320b8980921e8ee55112668817939Adrian Prantl NativeFileEnumerator(const base::FilePath& root_path, 795ca58a0aca0320b8980921e8ee55112668817939Adrian Prantl bool recursive, 805ca58a0aca0320b8980921e8ee55112668817939Adrian Prantl int file_type) 815ca58a0aca0320b8980921e8ee55112668817939Adrian Prantl : file_enum_(root_path, recursive, file_type) { 82 } 83 84 virtual ~NativeFileEnumerator() {} 85 86 virtual base::FilePath Next() OVERRIDE; 87 virtual int64 Size() OVERRIDE; 88 virtual base::Time LastModifiedTime() OVERRIDE; 89 virtual bool IsDirectory() OVERRIDE; 90 91 private: 92 base::FileEnumerator file_enum_; 93 base::FileEnumerator::FileInfo file_util_info_; 94}; 95 96base::FilePath NativeFileEnumerator::Next() { 97 base::FilePath rv = file_enum_.Next(); 98 if (!rv.empty()) 99 file_util_info_ = file_enum_.GetInfo(); 100 return rv; 101} 102 103int64 NativeFileEnumerator::Size() { 104 return file_util_info_.GetSize(); 105} 106 107base::Time NativeFileEnumerator::LastModifiedTime() { 108 return file_util_info_.GetLastModifiedTime(); 109} 110 111bool NativeFileEnumerator::IsDirectory() { 112 return file_util_info_.IsDirectory(); 113} 114 115NativeFileUtil::CopyOrMoveMode NativeFileUtil::CopyOrMoveModeForDestination( 116 const FileSystemURL& dest_url, bool copy) { 117 if (copy) { 118 return dest_url.mount_option().copy_sync_option() == COPY_SYNC_OPTION_SYNC ? 119 COPY_SYNC : COPY_NOSYNC; 120 } 121 return MOVE; 122} 123 124base::File NativeFileUtil::CreateOrOpen(const base::FilePath& path, 125 int file_flags) { 126 if (!base::DirectoryExists(path.DirName())) { 127 // If its parent does not exist, should return NOT_FOUND error. 128 return base::File(base::File::FILE_ERROR_NOT_FOUND); 129 } 130 131 // TODO(rvargas): Check |file_flags| instead. See bug 356358. 132 if (base::DirectoryExists(path)) 133 return base::File(base::File::FILE_ERROR_NOT_A_FILE); 134 135 return base::File(path, file_flags); 136} 137 138base::File::Error NativeFileUtil::EnsureFileExists( 139 const base::FilePath& path, 140 bool* created) { 141 if (!base::DirectoryExists(path.DirName())) 142 // If its parent does not exist, should return NOT_FOUND error. 143 return base::File::FILE_ERROR_NOT_FOUND; 144 145 // Tries to create the |path| exclusively. This should fail 146 // with base::File::FILE_ERROR_EXISTS if the path already exists. 147 base::File file(path, base::File::FLAG_CREATE | base::File::FLAG_READ); 148 149 if (file.IsValid()) { 150 if (created) 151 *created = file.created(); 152 return base::File::FILE_OK; 153 } 154 155 base::File::Error error_code = file.error_details(); 156 if (error_code == base::File::FILE_ERROR_EXISTS) { 157 // Make sure created_ is false. 158 if (created) 159 *created = false; 160 error_code = base::File::FILE_OK; 161 } 162 return error_code; 163} 164 165base::File::Error NativeFileUtil::CreateDirectory( 166 const base::FilePath& path, 167 bool exclusive, 168 bool recursive) { 169 // If parent dir of file doesn't exist. 170 if (!recursive && !base::PathExists(path.DirName())) 171 return base::File::FILE_ERROR_NOT_FOUND; 172 173 bool path_exists = base::PathExists(path); 174 if (exclusive && path_exists) 175 return base::File::FILE_ERROR_EXISTS; 176 177 // If file exists at the path. 178 if (path_exists && !base::DirectoryExists(path)) 179 return base::File::FILE_ERROR_EXISTS; 180 181 if (!base::CreateDirectory(path)) 182 return base::File::FILE_ERROR_FAILED; 183 184 if (!SetPlatformSpecificDirectoryPermissions(path)) { 185 // Since some file systems don't support permission setting, we do not treat 186 // an error from the function as the failure of copying. Just log it. 187 LOG(WARNING) << "Setting directory permission failed: " 188 << path.AsUTF8Unsafe(); 189 } 190 191 return base::File::FILE_OK; 192} 193 194base::File::Error NativeFileUtil::GetFileInfo( 195 const base::FilePath& path, 196 base::File::Info* file_info) { 197 if (!base::PathExists(path)) 198 return base::File::FILE_ERROR_NOT_FOUND; 199 200 if (!base::GetFileInfo(path, file_info)) 201 return base::File::FILE_ERROR_FAILED; 202 return base::File::FILE_OK; 203} 204 205scoped_ptr<FileSystemFileUtil::AbstractFileEnumerator> 206 NativeFileUtil::CreateFileEnumerator(const base::FilePath& root_path, 207 bool recursive) { 208 return make_scoped_ptr(new NativeFileEnumerator( 209 root_path, recursive, 210 base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES)) 211 .PassAs<FileSystemFileUtil::AbstractFileEnumerator>(); 212} 213 214base::File::Error NativeFileUtil::Touch( 215 const base::FilePath& path, 216 const base::Time& last_access_time, 217 const base::Time& last_modified_time) { 218 if (!base::TouchFile(path, last_access_time, last_modified_time)) 219 return base::File::FILE_ERROR_FAILED; 220 return base::File::FILE_OK; 221} 222 223base::File::Error NativeFileUtil::Truncate(const base::FilePath& path, 224 int64 length) { 225 base::File file(path, base::File::FLAG_OPEN | base::File::FLAG_WRITE); 226 if (!file.IsValid()) 227 return file.error_details(); 228 229 if (!file.SetLength(length)) 230 return base::File::FILE_ERROR_FAILED; 231 232 return base::File::FILE_OK; 233} 234 235bool NativeFileUtil::PathExists(const base::FilePath& path) { 236 return base::PathExists(path); 237} 238 239bool NativeFileUtil::DirectoryExists(const base::FilePath& path) { 240 return base::DirectoryExists(path); 241} 242 243base::File::Error NativeFileUtil::CopyOrMoveFile( 244 const base::FilePath& src_path, 245 const base::FilePath& dest_path, 246 FileSystemOperation::CopyOrMoveOption option, 247 CopyOrMoveMode mode) { 248 base::File::Info info; 249 base::File::Error error = NativeFileUtil::GetFileInfo(src_path, &info); 250 if (error != base::File::FILE_OK) 251 return error; 252 if (info.is_directory) 253 return base::File::FILE_ERROR_NOT_A_FILE; 254 base::Time last_modified = info.last_modified; 255 256 error = NativeFileUtil::GetFileInfo(dest_path, &info); 257 if (error != base::File::FILE_OK && 258 error != base::File::FILE_ERROR_NOT_FOUND) 259 return error; 260 if (info.is_directory) 261 return base::File::FILE_ERROR_INVALID_OPERATION; 262 if (error == base::File::FILE_ERROR_NOT_FOUND) { 263 error = NativeFileUtil::GetFileInfo(dest_path.DirName(), &info); 264 if (error != base::File::FILE_OK) 265 return error; 266 if (!info.is_directory) 267 return base::File::FILE_ERROR_NOT_FOUND; 268 } 269 270 switch (mode) { 271 case COPY_NOSYNC: 272 if (!base::CopyFile(src_path, dest_path)) 273 return base::File::FILE_ERROR_FAILED; 274 break; 275 case COPY_SYNC: 276 if (!CopyFileAndSync(src_path, dest_path)) 277 return base::File::FILE_ERROR_FAILED; 278 break; 279 case MOVE: 280 if (!base::Move(src_path, dest_path)) 281 return base::File::FILE_ERROR_FAILED; 282 break; 283 } 284 285 // Preserve the last modified time. Do not return error here even if 286 // the setting is failed, because the copy itself is successfully done. 287 if (option == FileSystemOperation::OPTION_PRESERVE_LAST_MODIFIED) 288 base::TouchFile(dest_path, last_modified, last_modified); 289 290 return base::File::FILE_OK; 291} 292 293base::File::Error NativeFileUtil::DeleteFile(const base::FilePath& path) { 294 if (!base::PathExists(path)) 295 return base::File::FILE_ERROR_NOT_FOUND; 296 if (base::DirectoryExists(path)) 297 return base::File::FILE_ERROR_NOT_A_FILE; 298 if (!base::DeleteFile(path, false)) 299 return base::File::FILE_ERROR_FAILED; 300 return base::File::FILE_OK; 301} 302 303base::File::Error NativeFileUtil::DeleteDirectory(const base::FilePath& path) { 304 if (!base::PathExists(path)) 305 return base::File::FILE_ERROR_NOT_FOUND; 306 if (!base::DirectoryExists(path)) 307 return base::File::FILE_ERROR_NOT_A_DIRECTORY; 308 if (!base::IsDirectoryEmpty(path)) 309 return base::File::FILE_ERROR_NOT_EMPTY; 310 if (!base::DeleteFile(path, false)) 311 return base::File::FILE_ERROR_FAILED; 312 return base::File::FILE_OK; 313} 314 315} // namespace storage 316