1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "webkit/browser/fileapi/native_file_util.h" 6 7 #include "base/file_util.h" 8 #include "base/files/file_enumerator.h" 9 #include "base/memory/scoped_ptr.h" 10 #include "webkit/browser/fileapi/file_system_operation_context.h" 11 12 namespace fileapi { 13 14 namespace { 15 16 // Sets permissions on directory at |dir_path| based on the target platform. 17 // Returns true on success, or false otherwise. 18 // 19 // TODO(benchan): Find a better place outside webkit to host this function. 20 bool SetPlatformSpecificDirectoryPermissions(const base::FilePath& dir_path) { 21 #if defined(OS_CHROMEOS) 22 // System daemons on Chrome OS may run as a user different than the Chrome 23 // process but need to access files under the directories created here. 24 // Because of that, grant the execute permission on the created directory 25 // to group and other users. 26 if (HANDLE_EINTR(chmod(dir_path.value().c_str(), 27 S_IRWXU | S_IXGRP | S_IXOTH)) != 0) { 28 return false; 29 } 30 #endif 31 // Keep the directory permissions unchanged on non-Chrome OS platforms. 32 return true; 33 } 34 35 } // namespace 36 37 using base::PlatformFile; 38 using base::PlatformFileError; 39 40 class NativeFileEnumerator : public FileSystemFileUtil::AbstractFileEnumerator { 41 public: 42 NativeFileEnumerator(const base::FilePath& root_path, 43 bool recursive, 44 int file_type) 45 : file_enum_(root_path, recursive, file_type) { 46 } 47 48 virtual ~NativeFileEnumerator() {} 49 50 virtual base::FilePath Next() OVERRIDE; 51 virtual int64 Size() OVERRIDE; 52 virtual base::Time LastModifiedTime() OVERRIDE; 53 virtual bool IsDirectory() OVERRIDE; 54 55 private: 56 base::FileEnumerator file_enum_; 57 base::FileEnumerator::FileInfo file_util_info_; 58 }; 59 60 base::FilePath NativeFileEnumerator::Next() { 61 base::FilePath rv = file_enum_.Next(); 62 if (!rv.empty()) 63 file_util_info_ = file_enum_.GetInfo(); 64 return rv; 65 } 66 67 int64 NativeFileEnumerator::Size() { 68 return file_util_info_.GetSize(); 69 } 70 71 base::Time NativeFileEnumerator::LastModifiedTime() { 72 return file_util_info_.GetLastModifiedTime(); 73 } 74 75 bool NativeFileEnumerator::IsDirectory() { 76 return file_util_info_.IsDirectory(); 77 } 78 79 PlatformFileError NativeFileUtil::CreateOrOpen( 80 const base::FilePath& path, int file_flags, 81 PlatformFile* file_handle, bool* created) { 82 if (!base::DirectoryExists(path.DirName())) { 83 // If its parent does not exist, should return NOT_FOUND error. 84 return base::PLATFORM_FILE_ERROR_NOT_FOUND; 85 } 86 if (base::DirectoryExists(path)) 87 return base::PLATFORM_FILE_ERROR_NOT_A_FILE; 88 PlatformFileError error_code = base::PLATFORM_FILE_OK; 89 *file_handle = base::CreatePlatformFile(path, file_flags, 90 created, &error_code); 91 return error_code; 92 } 93 94 PlatformFileError NativeFileUtil::Close(PlatformFile file_handle) { 95 if (!base::ClosePlatformFile(file_handle)) 96 return base::PLATFORM_FILE_ERROR_FAILED; 97 return base::PLATFORM_FILE_OK; 98 } 99 100 PlatformFileError NativeFileUtil::EnsureFileExists( 101 const base::FilePath& path, 102 bool* created) { 103 if (!base::DirectoryExists(path.DirName())) 104 // If its parent does not exist, should return NOT_FOUND error. 105 return base::PLATFORM_FILE_ERROR_NOT_FOUND; 106 PlatformFileError error_code = base::PLATFORM_FILE_OK; 107 // Tries to create the |path| exclusively. This should fail 108 // with base::PLATFORM_FILE_ERROR_EXISTS if the path already exists. 109 PlatformFile handle = base::CreatePlatformFile( 110 path, 111 base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_READ, 112 created, &error_code); 113 if (error_code == base::PLATFORM_FILE_ERROR_EXISTS) { 114 // Make sure created_ is false. 115 if (created) 116 *created = false; 117 error_code = base::PLATFORM_FILE_OK; 118 } 119 if (handle != base::kInvalidPlatformFileValue) 120 base::ClosePlatformFile(handle); 121 return error_code; 122 } 123 124 PlatformFileError NativeFileUtil::CreateDirectory( 125 const base::FilePath& path, 126 bool exclusive, 127 bool recursive) { 128 // If parent dir of file doesn't exist. 129 if (!recursive && !base::PathExists(path.DirName())) 130 return base::PLATFORM_FILE_ERROR_NOT_FOUND; 131 132 bool path_exists = base::PathExists(path); 133 if (exclusive && path_exists) 134 return base::PLATFORM_FILE_ERROR_EXISTS; 135 136 // If file exists at the path. 137 if (path_exists && !base::DirectoryExists(path)) 138 return base::PLATFORM_FILE_ERROR_EXISTS; 139 140 if (!file_util::CreateDirectory(path)) 141 return base::PLATFORM_FILE_ERROR_FAILED; 142 143 if (!SetPlatformSpecificDirectoryPermissions(path)) 144 return base::PLATFORM_FILE_ERROR_FAILED; 145 146 return base::PLATFORM_FILE_OK; 147 } 148 149 PlatformFileError NativeFileUtil::GetFileInfo( 150 const base::FilePath& path, 151 base::PlatformFileInfo* file_info) { 152 if (!base::PathExists(path)) 153 return base::PLATFORM_FILE_ERROR_NOT_FOUND; 154 if (!file_util::GetFileInfo(path, file_info)) 155 return base::PLATFORM_FILE_ERROR_FAILED; 156 return base::PLATFORM_FILE_OK; 157 } 158 159 scoped_ptr<FileSystemFileUtil::AbstractFileEnumerator> 160 NativeFileUtil::CreateFileEnumerator(const base::FilePath& root_path, 161 bool recursive) { 162 return make_scoped_ptr(new NativeFileEnumerator( 163 root_path, recursive, 164 base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES)) 165 .PassAs<FileSystemFileUtil::AbstractFileEnumerator>(); 166 } 167 168 PlatformFileError NativeFileUtil::Touch( 169 const base::FilePath& path, 170 const base::Time& last_access_time, 171 const base::Time& last_modified_time) { 172 if (!file_util::TouchFile( 173 path, last_access_time, last_modified_time)) 174 return base::PLATFORM_FILE_ERROR_FAILED; 175 return base::PLATFORM_FILE_OK; 176 } 177 178 PlatformFileError NativeFileUtil::Truncate( 179 const base::FilePath& path, int64 length) { 180 PlatformFileError error_code(base::PLATFORM_FILE_ERROR_FAILED); 181 PlatformFile file = 182 base::CreatePlatformFile( 183 path, 184 base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_WRITE, 185 NULL, 186 &error_code); 187 if (error_code != base::PLATFORM_FILE_OK) { 188 return error_code; 189 } 190 DCHECK_NE(base::kInvalidPlatformFileValue, file); 191 if (!base::TruncatePlatformFile(file, length)) 192 error_code = base::PLATFORM_FILE_ERROR_FAILED; 193 base::ClosePlatformFile(file); 194 return error_code; 195 } 196 197 bool NativeFileUtil::PathExists(const base::FilePath& path) { 198 return base::PathExists(path); 199 } 200 201 bool NativeFileUtil::DirectoryExists(const base::FilePath& path) { 202 return base::DirectoryExists(path); 203 } 204 205 PlatformFileError NativeFileUtil::CopyOrMoveFile( 206 const base::FilePath& src_path, 207 const base::FilePath& dest_path, 208 bool copy) { 209 base::PlatformFileInfo info; 210 base::PlatformFileError error = NativeFileUtil::GetFileInfo(src_path, &info); 211 if (error != base::PLATFORM_FILE_OK) 212 return error; 213 if (info.is_directory) 214 return base::PLATFORM_FILE_ERROR_NOT_A_FILE; 215 216 error = NativeFileUtil::GetFileInfo(dest_path, &info); 217 if (error != base::PLATFORM_FILE_OK && 218 error != base::PLATFORM_FILE_ERROR_NOT_FOUND) 219 return error; 220 if (info.is_directory) 221 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION; 222 if (error == base::PLATFORM_FILE_ERROR_NOT_FOUND) { 223 error = NativeFileUtil::GetFileInfo(dest_path.DirName(), &info); 224 if (error != base::PLATFORM_FILE_OK) 225 return error; 226 if (!info.is_directory) 227 return base::PLATFORM_FILE_ERROR_NOT_FOUND; 228 } 229 230 if (copy) { 231 if (base::CopyFile(src_path, dest_path)) 232 return base::PLATFORM_FILE_OK; 233 } else { 234 if (base::Move(src_path, dest_path)) 235 return base::PLATFORM_FILE_OK; 236 } 237 return base::PLATFORM_FILE_ERROR_FAILED; 238 } 239 240 PlatformFileError NativeFileUtil::DeleteFile(const base::FilePath& path) { 241 if (!base::PathExists(path)) 242 return base::PLATFORM_FILE_ERROR_NOT_FOUND; 243 if (base::DirectoryExists(path)) 244 return base::PLATFORM_FILE_ERROR_NOT_A_FILE; 245 if (!base::DeleteFile(path, false)) 246 return base::PLATFORM_FILE_ERROR_FAILED; 247 return base::PLATFORM_FILE_OK; 248 } 249 250 PlatformFileError NativeFileUtil::DeleteDirectory(const base::FilePath& path) { 251 if (!base::PathExists(path)) 252 return base::PLATFORM_FILE_ERROR_NOT_FOUND; 253 if (!base::DirectoryExists(path)) 254 return base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY; 255 if (!file_util::IsDirectoryEmpty(path)) 256 return base::PLATFORM_FILE_ERROR_NOT_EMPTY; 257 if (!base::DeleteFile(path, false)) 258 return base::PLATFORM_FILE_ERROR_FAILED; 259 return base::PLATFORM_FILE_OK; 260 } 261 262 } // namespace fileapi 263