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