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