Home | History | Annotate | Download | only in fileapi
      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/recursive_operation_delegate.h"
      6 
      7 #include "base/bind.h"
      8 #include "webkit/browser/fileapi/file_system_context.h"
      9 #include "webkit/browser/fileapi/file_system_operation_runner.h"
     10 
     11 namespace fileapi {
     12 
     13 namespace {
     14 // Don't start too many inflight operations.
     15 const int kMaxInflightOperations = 5;
     16 }
     17 
     18 RecursiveOperationDelegate::RecursiveOperationDelegate(
     19     FileSystemContext* file_system_context)
     20     : file_system_context_(file_system_context),
     21       inflight_operations_(0) {
     22 }
     23 
     24 RecursiveOperationDelegate::~RecursiveOperationDelegate() {
     25 }
     26 
     27 void RecursiveOperationDelegate::StartRecursiveOperation(
     28     const FileSystemURL& root,
     29     const StatusCallback& callback) {
     30   callback_ = callback;
     31   pending_directories_.push(root);
     32   ProcessNextDirectory();
     33 }
     34 
     35 FileSystemOperationRunner* RecursiveOperationDelegate::operation_runner() {
     36   return file_system_context_->operation_runner();
     37 }
     38 
     39 void RecursiveOperationDelegate::ProcessNextDirectory() {
     40   DCHECK(pending_files_.empty());
     41   if (inflight_operations_ > 0)
     42     return;
     43   if (pending_directories_.empty()) {
     44     callback_.Run(base::PLATFORM_FILE_OK);
     45     return;
     46   }
     47   FileSystemURL url = pending_directories_.front();
     48   pending_directories_.pop();
     49   inflight_operations_++;
     50   ProcessDirectory(
     51       url, base::Bind(&RecursiveOperationDelegate::DidProcessDirectory,
     52                       AsWeakPtr(), url));
     53 }
     54 
     55 void RecursiveOperationDelegate::ProcessPendingFiles() {
     56   if (pending_files_.empty()) {
     57     ProcessNextDirectory();
     58     return;
     59   }
     60   while (!pending_files_.empty() &&
     61          inflight_operations_ < kMaxInflightOperations) {
     62     FileSystemURL url = pending_files_.front();
     63     pending_files_.pop();
     64     inflight_operations_++;
     65     base::MessageLoopProxy::current()->PostTask(
     66         FROM_HERE,
     67         base::Bind(&RecursiveOperationDelegate::ProcessFile,
     68                    AsWeakPtr(), url,
     69                    base::Bind(&RecursiveOperationDelegate::DidProcessFile,
     70                               AsWeakPtr())));
     71   }
     72 }
     73 
     74 void RecursiveOperationDelegate::DidProcessFile(base::PlatformFileError error) {
     75   inflight_operations_--;
     76   DCHECK_GE(inflight_operations_, 0);
     77   if (error != base::PLATFORM_FILE_OK) {
     78     callback_.Run(error);
     79     return;
     80   }
     81   ProcessPendingFiles();
     82 }
     83 
     84 void RecursiveOperationDelegate::DidProcessDirectory(
     85     const FileSystemURL& url,
     86     base::PlatformFileError error) {
     87   if (error != base::PLATFORM_FILE_OK) {
     88     callback_.Run(error);
     89     return;
     90   }
     91   operation_runner()->ReadDirectory(
     92       url, base::Bind(&RecursiveOperationDelegate::DidReadDirectory,
     93                       AsWeakPtr(), url));
     94 }
     95 
     96 void RecursiveOperationDelegate::DidReadDirectory(
     97     const FileSystemURL& parent,
     98     base::PlatformFileError error,
     99     const FileEntryList& entries,
    100     bool has_more) {
    101   if (error != base::PLATFORM_FILE_OK) {
    102     if (error == base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY) {
    103       // The given path may have been a file, so try RemoveFile now.
    104       ProcessFile(parent,
    105                   base::Bind(&RecursiveOperationDelegate::DidTryProcessFile,
    106                              AsWeakPtr(), error));
    107       return;
    108     }
    109     callback_.Run(error);
    110     return;
    111   }
    112   for (size_t i = 0; i < entries.size(); i++) {
    113     FileSystemURL url = file_system_context_->CreateCrackedFileSystemURL(
    114         parent.origin(),
    115         parent.mount_type(),
    116         parent.virtual_path().Append(entries[i].name));
    117     if (entries[i].is_directory)
    118       pending_directories_.push(url);
    119     else
    120       pending_files_.push(url);
    121   }
    122   if (has_more)
    123     return;
    124 
    125   inflight_operations_--;
    126   DCHECK_GE(inflight_operations_, 0);
    127   ProcessPendingFiles();
    128 }
    129 
    130 void RecursiveOperationDelegate::DidTryProcessFile(
    131     base::PlatformFileError previous_error,
    132     base::PlatformFileError error) {
    133   if (error == base::PLATFORM_FILE_ERROR_NOT_A_FILE) {
    134     // It wasn't a file either; returns with the previous error.
    135     callback_.Run(previous_error);
    136     return;
    137   }
    138   DidProcessFile(error);
    139 }
    140 
    141 }  // namespace fileapi
    142