Home | History | Annotate | Download | only in file_system
      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 "chrome/browser/chromeos/drive/file_system/create_directory_operation.h"
      6 
      7 #include "chrome/browser/chromeos/drive/drive.pb.h"
      8 #include "chrome/browser/chromeos/drive/file_system/operation_observer.h"
      9 #include "chrome/browser/chromeos/drive/file_system_util.h"
     10 #include "chrome/browser/chromeos/drive/resource_metadata.h"
     11 #include "content/public/browser/browser_thread.h"
     12 
     13 using content::BrowserThread;
     14 
     15 namespace drive {
     16 namespace file_system {
     17 
     18 namespace {
     19 
     20 FileError CreateDirectoryRecursively(
     21     internal::ResourceMetadata* metadata,
     22     const std::string& parent_local_id,
     23     const base::FilePath& relative_file_path,
     24     std::set<std::string>* updated_local_ids,
     25     std::set<base::FilePath>* changed_directories) {
     26   // Split the first component and remaining ones of |relative_file_path|.
     27   std::vector<base::FilePath::StringType> components;
     28   relative_file_path.GetComponents(&components);
     29   DCHECK(!components.empty());
     30   base::FilePath title(components[0]);
     31   base::FilePath remaining_path;
     32   title.AppendRelativePath(relative_file_path, &remaining_path);
     33 
     34   ResourceEntry entry;
     35   const base::Time now = base::Time::Now();
     36   entry.set_title(title.AsUTF8Unsafe());
     37   entry.mutable_file_info()->set_is_directory(true);
     38   entry.mutable_file_info()->set_last_modified(now.ToInternalValue());
     39   entry.mutable_file_info()->set_last_accessed(now.ToInternalValue());
     40   entry.set_parent_local_id(parent_local_id);
     41   entry.set_metadata_edit_state(ResourceEntry::DIRTY);
     42   entry.set_modification_date(base::Time::Now().ToInternalValue());
     43 
     44   std::string local_id;
     45   FileError error = metadata->AddEntry(entry, &local_id);
     46   if (error != FILE_ERROR_OK)
     47     return error;
     48 
     49   base::FilePath path;
     50   error = metadata->GetFilePath(local_id, &path);
     51   if (error != FILE_ERROR_OK)
     52     return error;
     53 
     54   updated_local_ids->insert(local_id);
     55   changed_directories->insert(path.DirName());
     56 
     57   if (remaining_path.empty())  // All directories are created successfully.
     58     return FILE_ERROR_OK;
     59 
     60   // Create descendant directories.
     61   return CreateDirectoryRecursively(metadata, local_id, remaining_path,
     62                                     updated_local_ids, changed_directories);
     63 }
     64 
     65 FileError UpdateLocalState(internal::ResourceMetadata* metadata,
     66                            const base::FilePath& directory_path,
     67                            bool is_exclusive,
     68                            bool is_recursive,
     69                            std::set<std::string>* updated_local_ids,
     70                            std::set<base::FilePath>* changed_directories) {
     71   // Get the existing deepest entry.
     72   std::vector<base::FilePath::StringType> components;
     73   directory_path.GetComponents(&components);
     74 
     75   if (components.empty() || components[0] != util::kDriveGrandRootDirName)
     76     return FILE_ERROR_NOT_FOUND;
     77 
     78   base::FilePath existing_deepest_path(components[0]);
     79   std::string local_id = util::kDriveGrandRootLocalId;
     80   for (size_t i = 1; i < components.size(); ++i) {
     81     std::string child_local_id;
     82     FileError error =
     83         metadata->GetChildId(local_id, components[i], &child_local_id);
     84     if (error == FILE_ERROR_NOT_FOUND)
     85       break;
     86     if (error != FILE_ERROR_OK)
     87       return error;
     88     existing_deepest_path = existing_deepest_path.Append(components[i]);
     89     local_id = child_local_id;
     90   }
     91 
     92   ResourceEntry entry;
     93   FileError error = metadata->GetResourceEntryById(local_id, &entry);
     94   if (error != FILE_ERROR_OK)
     95     return error;
     96 
     97   if (!entry.file_info().is_directory())
     98     return FILE_ERROR_NOT_A_DIRECTORY;
     99 
    100   if (directory_path == existing_deepest_path)
    101     return is_exclusive ? FILE_ERROR_EXISTS : FILE_ERROR_OK;
    102 
    103   // If it is not recursive creation, the found directory must be the direct
    104   // parent of |directory_path| to ensure creating exact one directory.
    105   if (!is_recursive && existing_deepest_path != directory_path.DirName())
    106     return FILE_ERROR_NOT_FOUND;
    107 
    108   // Create directories under the found directory.
    109   base::FilePath remaining_path;
    110   existing_deepest_path.AppendRelativePath(directory_path, &remaining_path);
    111   return CreateDirectoryRecursively(metadata, entry.local_id(), remaining_path,
    112                                     updated_local_ids, changed_directories);
    113 }
    114 
    115 }  // namespace
    116 
    117 CreateDirectoryOperation::CreateDirectoryOperation(
    118     base::SequencedTaskRunner* blocking_task_runner,
    119     OperationObserver* observer,
    120     internal::ResourceMetadata* metadata)
    121     : blocking_task_runner_(blocking_task_runner),
    122       observer_(observer),
    123       metadata_(metadata),
    124       weak_ptr_factory_(this) {
    125   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    126 }
    127 
    128 CreateDirectoryOperation::~CreateDirectoryOperation() {
    129   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    130 }
    131 
    132 void CreateDirectoryOperation::CreateDirectory(
    133     const base::FilePath& directory_path,
    134     bool is_exclusive,
    135     bool is_recursive,
    136     const FileOperationCallback& callback) {
    137   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    138   DCHECK(!callback.is_null());
    139 
    140   std::set<std::string>* updated_local_ids = new std::set<std::string>;
    141   std::set<base::FilePath>* changed_directories = new std::set<base::FilePath>;
    142   base::PostTaskAndReplyWithResult(
    143       blocking_task_runner_.get(),
    144       FROM_HERE,
    145       base::Bind(&UpdateLocalState,
    146                  metadata_, directory_path, is_exclusive, is_recursive,
    147                  updated_local_ids, changed_directories),
    148       base::Bind(&CreateDirectoryOperation::
    149                      CreateDirectoryAfterUpdateLocalState,
    150                  weak_ptr_factory_.GetWeakPtr(),
    151                  callback,
    152                  base::Owned(updated_local_ids),
    153                  base::Owned(changed_directories)));
    154 }
    155 
    156 void CreateDirectoryOperation::CreateDirectoryAfterUpdateLocalState(
    157       const FileOperationCallback& callback,
    158       const std::set<std::string>* updated_local_ids,
    159       const std::set<base::FilePath>* changed_directories,
    160       FileError error) {
    161   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    162   DCHECK(!callback.is_null());
    163 
    164   for (std::set<std::string>::const_iterator it = updated_local_ids->begin();
    165        it != updated_local_ids->end(); ++it)
    166     observer_->OnEntryUpdatedByOperation(*it);
    167 
    168   for (std::set<base::FilePath>::const_iterator it =
    169            changed_directories->begin(); it != changed_directories->end(); ++it)
    170     observer_->OnDirectoryChangedByOperation(*it);
    171 
    172   callback.Run(error);
    173 }
    174 
    175 }  // namespace file_system
    176 }  // namespace drive
    177