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 "storage/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 "base/thread_task_runner_handle.h" 13#include "storage/browser/fileapi/file_system_context.h" 14#include "storage/browser/fileapi/file_system_file_util.h" 15#include "storage/browser/fileapi/file_system_operation_context.h" 16#include "storage/browser/fileapi/file_system_url.h" 17#include "storage/common/blob/shareable_file_reference.h" 18#include "storage/common/fileapi/file_system_util.h" 19 20using base::Bind; 21using base::Callback; 22using base::Owned; 23using base::Unretained; 24using storage::ShareableFileReference; 25 26namespace storage { 27 28namespace { 29 30class EnsureFileExistsHelper { 31 public: 32 EnsureFileExistsHelper() : error_(base::File::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::File::Error error_; 46 bool created_; 47 DISALLOW_COPY_AND_ASSIGN(EnsureFileExistsHelper); 48}; 49 50class GetFileInfoHelper { 51 public: 52 GetFileInfoHelper() 53 : error_(base::File::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::File::Error error_; 80 base::File::Info file_info_; 81 base::FilePath platform_path_; 82 storage::ScopedFile scoped_file_; 83 DISALLOW_COPY_AND_ASSIGN(GetFileInfoHelper); 84}; 85 86void ReadDirectoryHelper(FileSystemFileUtil* file_util, 87 FileSystemOperationContext* context, 88 const FileSystemURL& url, 89 base::SingleThreadTaskRunner* origin_loop, 90 const AsyncFileUtil::ReadDirectoryCallback& callback) { 91 base::File::Info file_info; 92 base::FilePath platform_path; 93 base::File::Error error = file_util->GetFileInfo( 94 context, url, &file_info, &platform_path); 95 96 if (error == base::File::FILE_OK && !file_info.is_directory) 97 error = base::File::FILE_ERROR_NOT_A_DIRECTORY; 98 99 std::vector<DirectoryEntry> entries; 100 if (error != base::File::FILE_OK) { 101 origin_loop->PostTask( 102 FROM_HERE, base::Bind(callback, error, entries, false /* has_more */)); 103 return; 104 } 105 106 // Note: Increasing this value may make some tests in LayoutTests meaningless. 107 // (Namely, read-directory-many.html and read-directory-sync-many.html are 108 // assuming that they are reading much more entries than this constant.) 109 const size_t kResultChunkSize = 100; 110 111 scoped_ptr<FileSystemFileUtil::AbstractFileEnumerator> file_enum( 112 file_util->CreateFileEnumerator(context, url)); 113 114 base::FilePath current; 115 while (!(current = file_enum->Next()).empty()) { 116 DirectoryEntry entry; 117 entry.is_directory = file_enum->IsDirectory(); 118 entry.name = VirtualPath::BaseName(current).value(); 119 entry.size = file_enum->Size(); 120 entry.last_modified_time = file_enum->LastModifiedTime(); 121 entries.push_back(entry); 122 123 if (entries.size() == kResultChunkSize) { 124 origin_loop->PostTask( 125 FROM_HERE, base::Bind(callback, base::File::FILE_OK, entries, 126 true /* has_more */)); 127 entries.clear(); 128 } 129 } 130 origin_loop->PostTask( 131 FROM_HERE, base::Bind(callback, base::File::FILE_OK, entries, 132 false /* has_more */)); 133} 134 135void RunCreateOrOpenCallback( 136 FileSystemOperationContext* context, 137 const AsyncFileUtil::CreateOrOpenCallback& callback, 138 base::File file) { 139 callback.Run(file.Pass(), base::Closure()); 140} 141 142} // namespace 143 144AsyncFileUtilAdapter::AsyncFileUtilAdapter( 145 FileSystemFileUtil* sync_file_util) 146 : sync_file_util_(sync_file_util) { 147 DCHECK(sync_file_util_.get()); 148} 149 150AsyncFileUtilAdapter::~AsyncFileUtilAdapter() { 151} 152 153void AsyncFileUtilAdapter::CreateOrOpen( 154 scoped_ptr<FileSystemOperationContext> context, 155 const FileSystemURL& url, 156 int file_flags, 157 const CreateOrOpenCallback& callback) { 158 FileSystemOperationContext* context_ptr = context.release(); 159 base::PostTaskAndReplyWithResult( 160 context_ptr->task_runner(), 161 FROM_HERE, 162 Bind(&FileSystemFileUtil::CreateOrOpen, Unretained(sync_file_util_.get()), 163 context_ptr, url, file_flags), 164 Bind(&RunCreateOrOpenCallback, base::Owned(context_ptr), callback)); 165} 166 167void AsyncFileUtilAdapter::EnsureFileExists( 168 scoped_ptr<FileSystemOperationContext> context, 169 const FileSystemURL& url, 170 const EnsureFileExistsCallback& callback) { 171 EnsureFileExistsHelper* helper = new EnsureFileExistsHelper; 172 FileSystemOperationContext* context_ptr = context.release(); 173 const bool success = context_ptr->task_runner()->PostTaskAndReply( 174 FROM_HERE, 175 Bind(&EnsureFileExistsHelper::RunWork, Unretained(helper), 176 sync_file_util_.get(), base::Owned(context_ptr), url), 177 Bind(&EnsureFileExistsHelper::Reply, Owned(helper), callback)); 178 DCHECK(success); 179} 180 181void AsyncFileUtilAdapter::CreateDirectory( 182 scoped_ptr<FileSystemOperationContext> context, 183 const FileSystemURL& url, 184 bool exclusive, 185 bool recursive, 186 const StatusCallback& callback) { 187 FileSystemOperationContext* context_ptr = context.release(); 188 const bool success = base::PostTaskAndReplyWithResult( 189 context_ptr->task_runner(), FROM_HERE, 190 Bind(&FileSystemFileUtil::CreateDirectory, 191 Unretained(sync_file_util_.get()), 192 base::Owned(context_ptr), url, exclusive, recursive), 193 callback); 194 DCHECK(success); 195} 196 197void AsyncFileUtilAdapter::GetFileInfo( 198 scoped_ptr<FileSystemOperationContext> context, 199 const FileSystemURL& url, 200 const GetFileInfoCallback& callback) { 201 FileSystemOperationContext* context_ptr = context.release(); 202 GetFileInfoHelper* helper = new GetFileInfoHelper; 203 const bool success = context_ptr->task_runner()->PostTaskAndReply( 204 FROM_HERE, 205 Bind(&GetFileInfoHelper::GetFileInfo, Unretained(helper), 206 sync_file_util_.get(), base::Owned(context_ptr), url), 207 Bind(&GetFileInfoHelper::ReplyFileInfo, Owned(helper), callback)); 208 DCHECK(success); 209} 210 211void AsyncFileUtilAdapter::ReadDirectory( 212 scoped_ptr<FileSystemOperationContext> context, 213 const FileSystemURL& url, 214 const ReadDirectoryCallback& callback) { 215 FileSystemOperationContext* context_ptr = context.release(); 216 const bool success = context_ptr->task_runner()->PostTask( 217 FROM_HERE, 218 Bind(&ReadDirectoryHelper, 219 sync_file_util_.get(), base::Owned(context_ptr), url, 220 base::ThreadTaskRunnerHandle::Get(), callback)); 221 DCHECK(success); 222} 223 224void 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 240void 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 254void 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 272void 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 288void 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 303void 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 317void 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 331void AsyncFileUtilAdapter::DeleteRecursively( 332 scoped_ptr<FileSystemOperationContext> context, 333 const FileSystemURL& url, 334 const StatusCallback& callback) { 335 callback.Run(base::File::FILE_ERROR_INVALID_OPERATION); 336} 337 338void 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 storage 353