1// Copyright 2014 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/file_system_provider/provided_file_system.h"
6
7#include <vector>
8
9#include "base/debug/trace_event.h"
10#include "base/files/file.h"
11#include "chrome/browser/chromeos/file_system_provider/notification_manager.h"
12#include "chrome/browser/chromeos/file_system_provider/operations/abort.h"
13#include "chrome/browser/chromeos/file_system_provider/operations/close_file.h"
14#include "chrome/browser/chromeos/file_system_provider/operations/copy_entry.h"
15#include "chrome/browser/chromeos/file_system_provider/operations/create_directory.h"
16#include "chrome/browser/chromeos/file_system_provider/operations/create_file.h"
17#include "chrome/browser/chromeos/file_system_provider/operations/delete_entry.h"
18#include "chrome/browser/chromeos/file_system_provider/operations/get_metadata.h"
19#include "chrome/browser/chromeos/file_system_provider/operations/move_entry.h"
20#include "chrome/browser/chromeos/file_system_provider/operations/open_file.h"
21#include "chrome/browser/chromeos/file_system_provider/operations/read_directory.h"
22#include "chrome/browser/chromeos/file_system_provider/operations/read_file.h"
23#include "chrome/browser/chromeos/file_system_provider/operations/truncate.h"
24#include "chrome/browser/chromeos/file_system_provider/operations/unmount.h"
25#include "chrome/browser/chromeos/file_system_provider/operations/write_file.h"
26#include "chrome/browser/chromeos/file_system_provider/request_manager.h"
27#include "chrome/browser/profiles/profile.h"
28#include "chrome/common/extensions/api/file_system_provider.h"
29#include "extensions/browser/event_router.h"
30
31namespace net {
32class IOBuffer;
33}  // namespace net
34
35namespace chromeos {
36namespace file_system_provider {
37namespace {
38
39// Dicards the result of Abort() when called from the destructor.
40void EmptyStatusCallback(base::File::Error /* result */) {
41}
42
43}  // namespace
44
45ProvidedFileSystem::ProvidedFileSystem(
46    Profile* profile,
47    const ProvidedFileSystemInfo& file_system_info)
48    : profile_(profile),
49      event_router_(extensions::EventRouter::Get(profile)),  // May be NULL.
50      file_system_info_(file_system_info),
51      notification_manager_(
52          new NotificationManager(profile_, file_system_info_)),
53      request_manager_(notification_manager_.get()),
54      weak_ptr_factory_(this) {
55}
56
57ProvidedFileSystem::~ProvidedFileSystem() {
58  const std::vector<int> request_ids = request_manager_.GetActiveRequestIds();
59  for (size_t i = 0; i < request_ids.size(); ++i) {
60    Abort(request_ids[i], base::Bind(&EmptyStatusCallback));
61  }
62}
63
64ProvidedFileSystem::AbortCallback ProvidedFileSystem::RequestUnmount(
65    const storage::AsyncFileUtil::StatusCallback& callback) {
66  const int request_id = request_manager_.CreateRequest(
67      REQUEST_UNMOUNT,
68      scoped_ptr<RequestManager::HandlerInterface>(
69          new operations::Unmount(event_router_, file_system_info_, callback)));
70  if (!request_id) {
71    callback.Run(base::File::FILE_ERROR_SECURITY);
72    return AbortCallback();
73  }
74
75  return base::Bind(
76      &ProvidedFileSystem::Abort, weak_ptr_factory_.GetWeakPtr(), request_id);
77}
78
79ProvidedFileSystem::AbortCallback ProvidedFileSystem::GetMetadata(
80    const base::FilePath& entry_path,
81    MetadataFieldMask fields,
82    const GetMetadataCallback& callback) {
83  const int request_id = request_manager_.CreateRequest(
84      GET_METADATA,
85      scoped_ptr<RequestManager::HandlerInterface>(new operations::GetMetadata(
86          event_router_, file_system_info_, entry_path, fields, callback)));
87  if (!request_id) {
88    callback.Run(make_scoped_ptr<EntryMetadata>(NULL),
89                 base::File::FILE_ERROR_SECURITY);
90    return AbortCallback();
91  }
92
93  return base::Bind(
94      &ProvidedFileSystem::Abort, weak_ptr_factory_.GetWeakPtr(), request_id);
95}
96
97ProvidedFileSystem::AbortCallback ProvidedFileSystem::ReadDirectory(
98    const base::FilePath& directory_path,
99    const storage::AsyncFileUtil::ReadDirectoryCallback& callback) {
100  const int request_id = request_manager_.CreateRequest(
101      READ_DIRECTORY,
102      scoped_ptr<RequestManager::HandlerInterface>(
103          new operations::ReadDirectory(
104              event_router_, file_system_info_, directory_path, callback)));
105  if (!request_id) {
106    callback.Run(base::File::FILE_ERROR_SECURITY,
107                 storage::AsyncFileUtil::EntryList(),
108                 false /* has_more */);
109    return AbortCallback();
110  }
111
112  return base::Bind(
113      &ProvidedFileSystem::Abort, weak_ptr_factory_.GetWeakPtr(), request_id);
114}
115
116ProvidedFileSystem::AbortCallback ProvidedFileSystem::ReadFile(
117    int file_handle,
118    net::IOBuffer* buffer,
119    int64 offset,
120    int length,
121    const ReadChunkReceivedCallback& callback) {
122  TRACE_EVENT1(
123      "file_system_provider", "ProvidedFileSystem::ReadFile", "length", length);
124  const int request_id = request_manager_.CreateRequest(
125      READ_FILE,
126      make_scoped_ptr<RequestManager::HandlerInterface>(
127          new operations::ReadFile(event_router_,
128                                   file_system_info_,
129                                   file_handle,
130                                   buffer,
131                                   offset,
132                                   length,
133                                   callback)));
134  if (!request_id) {
135    callback.Run(0 /* chunk_length */,
136                 false /* has_more */,
137                 base::File::FILE_ERROR_SECURITY);
138    return AbortCallback();
139  }
140
141  return base::Bind(
142      &ProvidedFileSystem::Abort, weak_ptr_factory_.GetWeakPtr(), request_id);
143}
144
145ProvidedFileSystem::AbortCallback ProvidedFileSystem::OpenFile(
146    const base::FilePath& file_path,
147    OpenFileMode mode,
148    const OpenFileCallback& callback) {
149  const int request_id = request_manager_.CreateRequest(
150      OPEN_FILE,
151      scoped_ptr<RequestManager::HandlerInterface>(new operations::OpenFile(
152          event_router_, file_system_info_, file_path, mode, callback)));
153  if (!request_id) {
154    callback.Run(0 /* file_handle */, base::File::FILE_ERROR_SECURITY);
155    return AbortCallback();
156  }
157
158  return base::Bind(
159      &ProvidedFileSystem::Abort, weak_ptr_factory_.GetWeakPtr(), request_id);
160}
161
162ProvidedFileSystem::AbortCallback ProvidedFileSystem::CloseFile(
163    int file_handle,
164    const storage::AsyncFileUtil::StatusCallback& callback) {
165  const int request_id = request_manager_.CreateRequest(
166      CLOSE_FILE,
167      scoped_ptr<RequestManager::HandlerInterface>(new operations::CloseFile(
168          event_router_, file_system_info_, file_handle, callback)));
169  if (!request_id) {
170    callback.Run(base::File::FILE_ERROR_SECURITY);
171    return AbortCallback();
172  }
173
174  return base::Bind(
175      &ProvidedFileSystem::Abort, weak_ptr_factory_.GetWeakPtr(), request_id);
176}
177
178ProvidedFileSystem::AbortCallback ProvidedFileSystem::CreateDirectory(
179    const base::FilePath& directory_path,
180    bool recursive,
181    const storage::AsyncFileUtil::StatusCallback& callback) {
182  const int request_id = request_manager_.CreateRequest(
183      CREATE_DIRECTORY,
184      scoped_ptr<RequestManager::HandlerInterface>(
185          new operations::CreateDirectory(event_router_,
186                                          file_system_info_,
187                                          directory_path,
188                                          recursive,
189                                          callback)));
190  if (!request_id) {
191    callback.Run(base::File::FILE_ERROR_SECURITY);
192    return AbortCallback();
193  }
194
195  return base::Bind(
196      &ProvidedFileSystem::Abort, weak_ptr_factory_.GetWeakPtr(), request_id);
197}
198
199ProvidedFileSystem::AbortCallback ProvidedFileSystem::DeleteEntry(
200    const base::FilePath& entry_path,
201    bool recursive,
202    const storage::AsyncFileUtil::StatusCallback& callback) {
203  const int request_id = request_manager_.CreateRequest(
204      DELETE_ENTRY,
205      scoped_ptr<RequestManager::HandlerInterface>(new operations::DeleteEntry(
206          event_router_, file_system_info_, entry_path, recursive, callback)));
207  if (!request_id) {
208    callback.Run(base::File::FILE_ERROR_SECURITY);
209    return AbortCallback();
210  }
211
212  return base::Bind(
213      &ProvidedFileSystem::Abort, weak_ptr_factory_.GetWeakPtr(), request_id);
214}
215
216ProvidedFileSystem::AbortCallback ProvidedFileSystem::CreateFile(
217    const base::FilePath& file_path,
218    const storage::AsyncFileUtil::StatusCallback& callback) {
219  const int request_id = request_manager_.CreateRequest(
220      CREATE_FILE,
221      scoped_ptr<RequestManager::HandlerInterface>(new operations::CreateFile(
222          event_router_, file_system_info_, file_path, callback)));
223  if (!request_id) {
224    callback.Run(base::File::FILE_ERROR_SECURITY);
225    return AbortCallback();
226  }
227
228  return base::Bind(
229      &ProvidedFileSystem::Abort, weak_ptr_factory_.GetWeakPtr(), request_id);
230}
231
232ProvidedFileSystem::AbortCallback ProvidedFileSystem::CopyEntry(
233    const base::FilePath& source_path,
234    const base::FilePath& target_path,
235    const storage::AsyncFileUtil::StatusCallback& callback) {
236  const int request_id = request_manager_.CreateRequest(
237      COPY_ENTRY,
238      scoped_ptr<RequestManager::HandlerInterface>(
239          new operations::CopyEntry(event_router_,
240                                    file_system_info_,
241                                    source_path,
242                                    target_path,
243                                    callback)));
244  if (!request_id) {
245    callback.Run(base::File::FILE_ERROR_SECURITY);
246    return AbortCallback();
247  }
248
249  return base::Bind(
250      &ProvidedFileSystem::Abort, weak_ptr_factory_.GetWeakPtr(), request_id);
251}
252
253ProvidedFileSystem::AbortCallback ProvidedFileSystem::WriteFile(
254    int file_handle,
255    net::IOBuffer* buffer,
256    int64 offset,
257    int length,
258    const storage::AsyncFileUtil::StatusCallback& callback) {
259  TRACE_EVENT1("file_system_provider",
260               "ProvidedFileSystem::WriteFile",
261               "length",
262               length);
263  const int request_id = request_manager_.CreateRequest(
264      WRITE_FILE,
265      make_scoped_ptr<RequestManager::HandlerInterface>(
266          new operations::WriteFile(event_router_,
267                                    file_system_info_,
268                                    file_handle,
269                                    make_scoped_refptr(buffer),
270                                    offset,
271                                    length,
272                                    callback)));
273  if (!request_id) {
274    callback.Run(base::File::FILE_ERROR_SECURITY);
275    return AbortCallback();
276  }
277
278  return base::Bind(
279      &ProvidedFileSystem::Abort, weak_ptr_factory_.GetWeakPtr(), request_id);
280}
281
282ProvidedFileSystem::AbortCallback ProvidedFileSystem::MoveEntry(
283    const base::FilePath& source_path,
284    const base::FilePath& target_path,
285    const storage::AsyncFileUtil::StatusCallback& callback) {
286  const int request_id = request_manager_.CreateRequest(
287      MOVE_ENTRY,
288      scoped_ptr<RequestManager::HandlerInterface>(
289          new operations::MoveEntry(event_router_,
290                                    file_system_info_,
291                                    source_path,
292                                    target_path,
293                                    callback)));
294  if (!request_id) {
295    callback.Run(base::File::FILE_ERROR_SECURITY);
296    return AbortCallback();
297  }
298
299  return base::Bind(
300      &ProvidedFileSystem::Abort, weak_ptr_factory_.GetWeakPtr(), request_id);
301}
302
303ProvidedFileSystem::AbortCallback ProvidedFileSystem::Truncate(
304    const base::FilePath& file_path,
305    int64 length,
306    const storage::AsyncFileUtil::StatusCallback& callback) {
307  const int request_id = request_manager_.CreateRequest(
308      TRUNCATE,
309      scoped_ptr<RequestManager::HandlerInterface>(new operations::Truncate(
310          event_router_, file_system_info_, file_path, length, callback)));
311  if (!request_id) {
312    callback.Run(base::File::FILE_ERROR_SECURITY);
313    return AbortCallback();
314  }
315
316  return base::Bind(
317      &ProvidedFileSystem::Abort, weak_ptr_factory_.GetWeakPtr(), request_id);
318}
319
320const ProvidedFileSystemInfo& ProvidedFileSystem::GetFileSystemInfo() const {
321  return file_system_info_;
322}
323
324RequestManager* ProvidedFileSystem::GetRequestManager() {
325  return &request_manager_;
326}
327
328base::WeakPtr<ProvidedFileSystemInterface> ProvidedFileSystem::GetWeakPtr() {
329  return weak_ptr_factory_.GetWeakPtr();
330}
331
332void ProvidedFileSystem::Abort(
333    int operation_request_id,
334    const storage::AsyncFileUtil::StatusCallback& callback) {
335  request_manager_.RejectRequest(operation_request_id,
336                                 make_scoped_ptr(new RequestValue()),
337                                 base::File::FILE_ERROR_ABORT);
338  if (!request_manager_.CreateRequest(
339          ABORT,
340          scoped_ptr<RequestManager::HandlerInterface>(
341              new operations::Abort(event_router_,
342                                    file_system_info_,
343                                    operation_request_id,
344                                    callback)))) {
345    callback.Run(base::File::FILE_ERROR_SECURITY);
346  }
347}
348
349}  // namespace file_system_provider
350}  // namespace chromeos
351