create_directory_operation.cc revision 5f1c94371a64b3196d4be9466099bb892df9b88e
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_change.h" 9#include "chrome/browser/chromeos/drive/file_system/operation_delegate.h" 10#include "chrome/browser/chromeos/drive/file_system_util.h" 11#include "chrome/browser/chromeos/drive/resource_metadata.h" 12#include "content/public/browser/browser_thread.h" 13 14using content::BrowserThread; 15 16namespace drive { 17namespace file_system { 18 19namespace { 20 21FileError CreateDirectoryRecursively(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 FileChange* changed_files) { 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 DCHECK(changed_files); 56 changed_files->Update( 57 path, FileChange::FILE_TYPE_DIRECTORY, FileChange::ADD_OR_UPDATE); 58 59 if (remaining_path.empty()) // All directories are created successfully. 60 return FILE_ERROR_OK; 61 62 // Create descendant directories. 63 return CreateDirectoryRecursively( 64 metadata, local_id, remaining_path, updated_local_ids, changed_files); 65} 66 67FileError UpdateLocalState(internal::ResourceMetadata* metadata, 68 const base::FilePath& directory_path, 69 bool is_exclusive, 70 bool is_recursive, 71 std::set<std::string>* updated_local_ids, 72 FileChange* changed_files) { 73 // Get the existing deepest entry. 74 std::vector<base::FilePath::StringType> components; 75 directory_path.GetComponents(&components); 76 77 if (components.empty() || components[0] != util::kDriveGrandRootDirName) 78 return FILE_ERROR_NOT_FOUND; 79 80 base::FilePath existing_deepest_path(components[0]); 81 std::string local_id = util::kDriveGrandRootLocalId; 82 for (size_t i = 1; i < components.size(); ++i) { 83 std::string child_local_id; 84 FileError error = 85 metadata->GetChildId(local_id, components[i], &child_local_id); 86 if (error == FILE_ERROR_NOT_FOUND) 87 break; 88 if (error != FILE_ERROR_OK) 89 return error; 90 existing_deepest_path = existing_deepest_path.Append(components[i]); 91 local_id = child_local_id; 92 } 93 94 ResourceEntry entry; 95 FileError error = metadata->GetResourceEntryById(local_id, &entry); 96 if (error != FILE_ERROR_OK) 97 return error; 98 99 if (!entry.file_info().is_directory()) 100 return FILE_ERROR_NOT_A_DIRECTORY; 101 102 if (directory_path == existing_deepest_path) 103 return is_exclusive ? FILE_ERROR_EXISTS : FILE_ERROR_OK; 104 105 // If it is not recursive creation, the found directory must be the direct 106 // parent of |directory_path| to ensure creating exact one directory. 107 if (!is_recursive && existing_deepest_path != directory_path.DirName()) 108 return FILE_ERROR_NOT_FOUND; 109 110 // Create directories under the found directory. 111 base::FilePath remaining_path; 112 existing_deepest_path.AppendRelativePath(directory_path, &remaining_path); 113 return CreateDirectoryRecursively(metadata, 114 entry.local_id(), 115 remaining_path, 116 updated_local_ids, 117 changed_files); 118} 119 120} // namespace 121 122CreateDirectoryOperation::CreateDirectoryOperation( 123 base::SequencedTaskRunner* blocking_task_runner, 124 OperationDelegate* delegate, 125 internal::ResourceMetadata* metadata) 126 : blocking_task_runner_(blocking_task_runner), 127 delegate_(delegate), 128 metadata_(metadata), 129 weak_ptr_factory_(this) { 130 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 131} 132 133CreateDirectoryOperation::~CreateDirectoryOperation() { 134 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 135} 136 137void CreateDirectoryOperation::CreateDirectory( 138 const base::FilePath& directory_path, 139 bool is_exclusive, 140 bool is_recursive, 141 const FileOperationCallback& callback) { 142 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 143 DCHECK(!callback.is_null()); 144 145 std::set<std::string>* updated_local_ids = new std::set<std::string>; 146 FileChange* changed_files(new FileChange); 147 base::PostTaskAndReplyWithResult( 148 blocking_task_runner_.get(), 149 FROM_HERE, 150 base::Bind(&UpdateLocalState, 151 metadata_, 152 directory_path, 153 is_exclusive, 154 is_recursive, 155 updated_local_ids, 156 changed_files), 157 base::Bind( 158 &CreateDirectoryOperation::CreateDirectoryAfterUpdateLocalState, 159 weak_ptr_factory_.GetWeakPtr(), 160 callback, 161 base::Owned(updated_local_ids), 162 base::Owned(changed_files))); 163} 164 165void CreateDirectoryOperation::CreateDirectoryAfterUpdateLocalState( 166 const FileOperationCallback& callback, 167 const std::set<std::string>* updated_local_ids, 168 const FileChange* changed_files, 169 FileError error) { 170 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 171 DCHECK(!callback.is_null()); 172 173 for (std::set<std::string>::const_iterator it = updated_local_ids->begin(); 174 it != updated_local_ids->end(); ++it) 175 delegate_->OnEntryUpdatedByOperation(*it); 176 177 delegate_->OnFileChangedByOperation(*changed_files); 178 179 callback.Run(error); 180} 181 182} // namespace file_system 183} // namespace drive 184