1// Copyright 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_file_operation.h" 6 7#include <string> 8 9#include "base/files/file_util.h" 10#include "chrome/browser/chromeos/drive/drive.pb.h" 11#include "chrome/browser/chromeos/drive/file_change.h" 12#include "chrome/browser/chromeos/drive/file_system/operation_delegate.h" 13#include "chrome/browser/chromeos/drive/resource_metadata.h" 14#include "content/public/browser/browser_thread.h" 15#include "net/base/mime_util.h" 16 17using content::BrowserThread; 18 19namespace drive { 20namespace file_system { 21 22namespace { 23 24const char kMimeTypeOctetStream[] = "application/octet-stream"; 25 26// Updates local state. 27FileError UpdateLocalState(internal::ResourceMetadata* metadata, 28 const base::FilePath& file_path, 29 const std::string& mime_type_in, 30 ResourceEntry* entry) { 31 DCHECK(metadata); 32 33 FileError error = metadata->GetResourceEntryByPath(file_path, entry); 34 if (error == FILE_ERROR_OK) 35 return FILE_ERROR_EXISTS; 36 37 if (error != FILE_ERROR_NOT_FOUND) 38 return error; 39 40 // If parent path is not a directory, it is an error. 41 ResourceEntry parent; 42 if (metadata->GetResourceEntryByPath( 43 file_path.DirName(), &parent) != FILE_ERROR_OK || 44 !parent.file_info().is_directory()) 45 return FILE_ERROR_NOT_A_DIRECTORY; 46 47 // If mime_type is not set or "application/octet-stream", guess from the 48 // |file_path|. If it is still unsure, use octet-stream by default. 49 std::string mime_type = mime_type_in; 50 if ((mime_type.empty() || mime_type == kMimeTypeOctetStream) && 51 !net::GetMimeTypeFromFile(file_path, &mime_type)) 52 mime_type = kMimeTypeOctetStream; 53 54 // Add the entry to the local resource metadata. 55 const base::Time now = base::Time::Now(); 56 entry->mutable_file_info()->set_last_modified(now.ToInternalValue()); 57 entry->mutable_file_info()->set_last_accessed(now.ToInternalValue()); 58 entry->set_title(file_path.BaseName().AsUTF8Unsafe()); 59 entry->set_parent_local_id(parent.local_id()); 60 entry->set_metadata_edit_state(ResourceEntry::DIRTY); 61 entry->set_modification_date(base::Time::Now().ToInternalValue()); 62 entry->mutable_file_specific_info()->set_content_mime_type(mime_type); 63 64 std::string local_id; 65 error = metadata->AddEntry(*entry, &local_id); 66 entry->set_local_id(local_id); 67 return error; 68} 69 70} // namespace 71 72CreateFileOperation::CreateFileOperation( 73 base::SequencedTaskRunner* blocking_task_runner, 74 OperationDelegate* delegate, 75 internal::ResourceMetadata* metadata) 76 : blocking_task_runner_(blocking_task_runner), 77 delegate_(delegate), 78 metadata_(metadata), 79 weak_ptr_factory_(this) { 80 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 81} 82 83CreateFileOperation::~CreateFileOperation() { 84 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 85} 86 87void CreateFileOperation::CreateFile(const base::FilePath& file_path, 88 bool is_exclusive, 89 const std::string& mime_type, 90 const FileOperationCallback& callback) { 91 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 92 DCHECK(!callback.is_null()); 93 94 ResourceEntry* entry = new ResourceEntry; 95 base::PostTaskAndReplyWithResult( 96 blocking_task_runner_.get(), 97 FROM_HERE, 98 base::Bind(&UpdateLocalState, 99 metadata_, 100 file_path, 101 mime_type, 102 entry), 103 base::Bind(&CreateFileOperation::CreateFileAfterUpdateLocalState, 104 weak_ptr_factory_.GetWeakPtr(), 105 callback, 106 file_path, 107 is_exclusive, 108 base::Owned(entry))); 109} 110 111void CreateFileOperation::CreateFileAfterUpdateLocalState( 112 const FileOperationCallback& callback, 113 const base::FilePath& file_path, 114 bool is_exclusive, 115 ResourceEntry* entry, 116 FileError error) { 117 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 118 DCHECK(!callback.is_null()); 119 120 if (error == FILE_ERROR_EXISTS) { 121 // Error if an exclusive mode is requested, or the entry is not a file. 122 error = (is_exclusive || 123 entry->file_info().is_directory() || 124 entry->file_specific_info().is_hosted_document()) ? 125 FILE_ERROR_EXISTS : FILE_ERROR_OK; 126 } else if (error == FILE_ERROR_OK) { 127 DCHECK(!entry->file_info().is_directory()); 128 129 // Notify delegate if the file was newly created. 130 FileChange changed_file; 131 changed_file.Update( 132 file_path, FileChange::FILE_TYPE_FILE, FileChange::ADD_OR_UPDATE); 133 delegate_->OnFileChangedByOperation(changed_file); 134 delegate_->OnEntryUpdatedByOperation(entry->local_id()); 135 } 136 callback.Run(error); 137} 138 139} // namespace file_system 140} // namespace drive 141