1 // Copyright (c) 2013 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/async_file_util_adapter.h" 6 7 #include <vector> 8 9 #include "base/bind.h" 10 #include "base/sequenced_task_runner.h" 11 #include "base/task_runner_util.h" 12 #include "webkit/browser/fileapi/file_system_context.h" 13 #include "webkit/browser/fileapi/file_system_file_util.h" 14 #include "webkit/browser/fileapi/file_system_operation_context.h" 15 #include "webkit/browser/fileapi/file_system_url.h" 16 #include "webkit/common/blob/shareable_file_reference.h" 17 #include "webkit/common/fileapi/file_system_util.h" 18 19 using base::Bind; 20 using base::Callback; 21 using base::Owned; 22 using base::PlatformFileError; 23 using base::Unretained; 24 using webkit_blob::ShareableFileReference; 25 26 namespace fileapi { 27 28 namespace { 29 30 class EnsureFileExistsHelper { 31 public: 32 EnsureFileExistsHelper() : error_(base::PLATFORM_FILE_OK), created_(false) {} 33 34 void RunWork(FileSystemFileUtil* file_util, 35 FileSystemOperationContext* context, 36 const FileSystemURL& url) { 37 error_ = file_util->EnsureFileExists(context, url, &created_); 38 } 39 40 void Reply(const AsyncFileUtil::EnsureFileExistsCallback& callback) { 41 callback.Run(error_, created_); 42 } 43 44 private: 45 base::PlatformFileError error_; 46 bool created_; 47 DISALLOW_COPY_AND_ASSIGN(EnsureFileExistsHelper); 48 }; 49 50 class GetFileInfoHelper { 51 public: 52 GetFileInfoHelper() 53 : error_(base::PLATFORM_FILE_OK) {} 54 55 void GetFileInfo(FileSystemFileUtil* file_util, 56 FileSystemOperationContext* context, 57 const FileSystemURL& url) { 58 error_ = file_util->GetFileInfo(context, url, &file_info_, &platform_path_); 59 } 60 61 void CreateSnapshotFile(FileSystemFileUtil* file_util, 62 FileSystemOperationContext* context, 63 const FileSystemURL& url) { 64 scoped_file_ = file_util->CreateSnapshotFile( 65 context, url, &error_, &file_info_, &platform_path_); 66 } 67 68 void ReplyFileInfo(const AsyncFileUtil::GetFileInfoCallback& callback) { 69 callback.Run(error_, file_info_); 70 } 71 72 void ReplySnapshotFile( 73 const AsyncFileUtil::CreateSnapshotFileCallback& callback) { 74 callback.Run(error_, file_info_, platform_path_, 75 ShareableFileReference::GetOrCreate(scoped_file_.Pass())); 76 } 77 78 private: 79 base::PlatformFileError error_; 80 base::PlatformFileInfo file_info_; 81 base::FilePath platform_path_; 82 webkit_blob::ScopedFile scoped_file_; 83 DISALLOW_COPY_AND_ASSIGN(GetFileInfoHelper); 84 }; 85 86 class ReadDirectoryHelper { 87 public: 88 ReadDirectoryHelper() : error_(base::PLATFORM_FILE_OK) {} 89 90 void RunWork(FileSystemFileUtil* file_util, 91 FileSystemOperationContext* context, 92 const FileSystemURL& url) { 93 base::PlatformFileInfo file_info; 94 base::FilePath platform_path; 95 PlatformFileError error = file_util->GetFileInfo( 96 context, url, &file_info, &platform_path); 97 if (error != base::PLATFORM_FILE_OK) { 98 error_ = error; 99 return; 100 } 101 if (!file_info.is_directory) { 102 error_ = base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY; 103 return; 104 } 105 106 scoped_ptr<FileSystemFileUtil::AbstractFileEnumerator> file_enum( 107 file_util->CreateFileEnumerator(context, url)); 108 109 base::FilePath current; 110 while (!(current = file_enum->Next()).empty()) { 111 DirectoryEntry entry; 112 entry.is_directory = file_enum->IsDirectory(); 113 entry.name = VirtualPath::BaseName(current).value(); 114 entry.size = file_enum->Size(); 115 entry.last_modified_time = file_enum->LastModifiedTime(); 116 entries_.push_back(entry); 117 } 118 error_ = base::PLATFORM_FILE_OK; 119 } 120 121 void Reply(const AsyncFileUtil::ReadDirectoryCallback& callback) { 122 callback.Run(error_, entries_, false /* has_more */); 123 } 124 125 private: 126 base::PlatformFileError error_; 127 std::vector<DirectoryEntry> entries_; 128 DISALLOW_COPY_AND_ASSIGN(ReadDirectoryHelper); 129 }; 130 131 void RunCreateOrOpenCallback( 132 const AsyncFileUtil::CreateOrOpenCallback& callback, 133 base::PlatformFileError result, 134 base::PassPlatformFile file, 135 bool created) { 136 callback.Run(result, file, base::Closure()); 137 } 138 139 } // namespace 140 141 AsyncFileUtilAdapter::AsyncFileUtilAdapter( 142 FileSystemFileUtil* sync_file_util) 143 : sync_file_util_(sync_file_util) { 144 DCHECK(sync_file_util_.get()); 145 } 146 147 AsyncFileUtilAdapter::~AsyncFileUtilAdapter() { 148 } 149 150 void AsyncFileUtilAdapter::CreateOrOpen( 151 scoped_ptr<FileSystemOperationContext> context, 152 const FileSystemURL& url, 153 int file_flags, 154 const CreateOrOpenCallback& callback) { 155 FileSystemOperationContext* context_ptr = context.release(); 156 const bool success = base::FileUtilProxy::RelayCreateOrOpen( 157 context_ptr->task_runner(), 158 Bind(&FileSystemFileUtil::CreateOrOpen, Unretained(sync_file_util_.get()), 159 context_ptr, url, file_flags), 160 Bind(&FileSystemFileUtil::Close, Unretained(sync_file_util_.get()), 161 base::Owned(context_ptr)), 162 Bind(&RunCreateOrOpenCallback, callback)); 163 DCHECK(success); 164 } 165 166 void AsyncFileUtilAdapter::EnsureFileExists( 167 scoped_ptr<FileSystemOperationContext> context, 168 const FileSystemURL& url, 169 const EnsureFileExistsCallback& callback) { 170 EnsureFileExistsHelper* helper = new EnsureFileExistsHelper; 171 FileSystemOperationContext* context_ptr = context.release(); 172 const bool success = context_ptr->task_runner()->PostTaskAndReply( 173 FROM_HERE, 174 Bind(&EnsureFileExistsHelper::RunWork, Unretained(helper), 175 sync_file_util_.get(), base::Owned(context_ptr), url), 176 Bind(&EnsureFileExistsHelper::Reply, Owned(helper), callback)); 177 DCHECK(success); 178 } 179 180 void AsyncFileUtilAdapter::CreateDirectory( 181 scoped_ptr<FileSystemOperationContext> context, 182 const FileSystemURL& url, 183 bool exclusive, 184 bool recursive, 185 const StatusCallback& callback) { 186 FileSystemOperationContext* context_ptr = context.release(); 187 const bool success = base::PostTaskAndReplyWithResult( 188 context_ptr->task_runner(), FROM_HERE, 189 Bind(&FileSystemFileUtil::CreateDirectory, 190 Unretained(sync_file_util_.get()), 191 base::Owned(context_ptr), url, exclusive, recursive), 192 callback); 193 DCHECK(success); 194 } 195 196 void AsyncFileUtilAdapter::GetFileInfo( 197 scoped_ptr<FileSystemOperationContext> context, 198 const FileSystemURL& url, 199 const GetFileInfoCallback& callback) { 200 FileSystemOperationContext* context_ptr = context.release(); 201 GetFileInfoHelper* helper = new GetFileInfoHelper; 202 const bool success = context_ptr->task_runner()->PostTaskAndReply( 203 FROM_HERE, 204 Bind(&GetFileInfoHelper::GetFileInfo, Unretained(helper), 205 sync_file_util_.get(), base::Owned(context_ptr), url), 206 Bind(&GetFileInfoHelper::ReplyFileInfo, Owned(helper), callback)); 207 DCHECK(success); 208 } 209 210 void AsyncFileUtilAdapter::ReadDirectory( 211 scoped_ptr<FileSystemOperationContext> context, 212 const FileSystemURL& url, 213 const ReadDirectoryCallback& callback) { 214 FileSystemOperationContext* context_ptr = context.release(); 215 ReadDirectoryHelper* helper = new ReadDirectoryHelper; 216 const bool success = context_ptr->task_runner()->PostTaskAndReply( 217 FROM_HERE, 218 Bind(&ReadDirectoryHelper::RunWork, Unretained(helper), 219 sync_file_util_.get(), base::Owned(context_ptr), url), 220 Bind(&ReadDirectoryHelper::Reply, Owned(helper), callback)); 221 DCHECK(success); 222 } 223 224 void AsyncFileUtilAdapter::Touch( 225 scoped_ptr<FileSystemOperationContext> context, 226 const FileSystemURL& url, 227 const base::Time& last_access_time, 228 const base::Time& last_modified_time, 229 const StatusCallback& callback) { 230 FileSystemOperationContext* context_ptr = context.release(); 231 const bool success = base::PostTaskAndReplyWithResult( 232 context_ptr->task_runner(), FROM_HERE, 233 Bind(&FileSystemFileUtil::Touch, Unretained(sync_file_util_.get()), 234 base::Owned(context_ptr), url, 235 last_access_time, last_modified_time), 236 callback); 237 DCHECK(success); 238 } 239 240 void AsyncFileUtilAdapter::Truncate( 241 scoped_ptr<FileSystemOperationContext> context, 242 const FileSystemURL& url, 243 int64 length, 244 const StatusCallback& callback) { 245 FileSystemOperationContext* context_ptr = context.release(); 246 const bool success = base::PostTaskAndReplyWithResult( 247 context_ptr->task_runner(), FROM_HERE, 248 Bind(&FileSystemFileUtil::Truncate, Unretained(sync_file_util_.get()), 249 base::Owned(context_ptr), url, length), 250 callback); 251 DCHECK(success); 252 } 253 254 void AsyncFileUtilAdapter::CopyFileLocal( 255 scoped_ptr<FileSystemOperationContext> context, 256 const FileSystemURL& src_url, 257 const FileSystemURL& dest_url, 258 CopyOrMoveOption option, 259 const CopyFileProgressCallback& progress_callback, 260 const StatusCallback& callback) { 261 // TODO(hidehiko): Support progress_callback. 262 FileSystemOperationContext* context_ptr = context.release(); 263 const bool success = base::PostTaskAndReplyWithResult( 264 context_ptr->task_runner(), FROM_HERE, 265 Bind(&FileSystemFileUtil::CopyOrMoveFile, 266 Unretained(sync_file_util_.get()), base::Owned(context_ptr), 267 src_url, dest_url, option, true /* copy */), 268 callback); 269 DCHECK(success); 270 } 271 272 void AsyncFileUtilAdapter::MoveFileLocal( 273 scoped_ptr<FileSystemOperationContext> context, 274 const FileSystemURL& src_url, 275 const FileSystemURL& dest_url, 276 CopyOrMoveOption option, 277 const StatusCallback& callback) { 278 FileSystemOperationContext* context_ptr = context.release(); 279 const bool success = base::PostTaskAndReplyWithResult( 280 context_ptr->task_runner(), FROM_HERE, 281 Bind(&FileSystemFileUtil::CopyOrMoveFile, 282 Unretained(sync_file_util_.get()), base::Owned(context_ptr), 283 src_url, dest_url, option, false /* copy */), 284 callback); 285 DCHECK(success); 286 } 287 288 void AsyncFileUtilAdapter::CopyInForeignFile( 289 scoped_ptr<FileSystemOperationContext> context, 290 const base::FilePath& src_file_path, 291 const FileSystemURL& dest_url, 292 const StatusCallback& callback) { 293 FileSystemOperationContext* context_ptr = context.release(); 294 const bool success = base::PostTaskAndReplyWithResult( 295 context_ptr->task_runner(), FROM_HERE, 296 Bind(&FileSystemFileUtil::CopyInForeignFile, 297 Unretained(sync_file_util_.get()), 298 base::Owned(context_ptr), src_file_path, dest_url), 299 callback); 300 DCHECK(success); 301 } 302 303 void AsyncFileUtilAdapter::DeleteFile( 304 scoped_ptr<FileSystemOperationContext> context, 305 const FileSystemURL& url, 306 const StatusCallback& callback) { 307 FileSystemOperationContext* context_ptr = context.release(); 308 const bool success = base::PostTaskAndReplyWithResult( 309 context_ptr->task_runner(), FROM_HERE, 310 Bind(&FileSystemFileUtil::DeleteFile, 311 Unretained(sync_file_util_.get()), 312 base::Owned(context_ptr), url), 313 callback); 314 DCHECK(success); 315 } 316 317 void AsyncFileUtilAdapter::DeleteDirectory( 318 scoped_ptr<FileSystemOperationContext> context, 319 const FileSystemURL& url, 320 const StatusCallback& callback) { 321 FileSystemOperationContext* context_ptr = context.release(); 322 const bool success = base::PostTaskAndReplyWithResult( 323 context_ptr->task_runner(), FROM_HERE, 324 Bind(&FileSystemFileUtil::DeleteDirectory, 325 Unretained(sync_file_util_.get()), 326 base::Owned(context_ptr), url), 327 callback); 328 DCHECK(success); 329 } 330 331 void AsyncFileUtilAdapter::DeleteRecursively( 332 scoped_ptr<FileSystemOperationContext> context, 333 const FileSystemURL& url, 334 const StatusCallback& callback) { 335 callback.Run(base::PLATFORM_FILE_ERROR_INVALID_OPERATION); 336 } 337 338 void AsyncFileUtilAdapter::CreateSnapshotFile( 339 scoped_ptr<FileSystemOperationContext> context, 340 const FileSystemURL& url, 341 const CreateSnapshotFileCallback& callback) { 342 FileSystemOperationContext* context_ptr = context.release(); 343 GetFileInfoHelper* helper = new GetFileInfoHelper; 344 const bool success = context_ptr->task_runner()->PostTaskAndReply( 345 FROM_HERE, 346 Bind(&GetFileInfoHelper::CreateSnapshotFile, Unretained(helper), 347 sync_file_util_.get(), base::Owned(context_ptr), url), 348 Bind(&GetFileInfoHelper::ReplySnapshotFile, Owned(helper), callback)); 349 DCHECK(success); 350 } 351 352 } // namespace fileapi 353