- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / drive / fileapi_worker.cc
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/fileapi_worker.h"
6
7 #include "base/files/file_path.h"
8 #include "base/logging.h"
9 #include "base/task_runner_util.h"
10 #include "base/threading/sequenced_worker_pool.h"
11 #include "chrome/browser/chromeos/drive/drive.pb.h"
12 #include "chrome/browser/chromeos/drive/file_errors.h"
13 #include "chrome/browser/chromeos/drive/file_system_interface.h"
14 #include "chrome/browser/chromeos/drive/file_system_util.h"
15 #include "chrome/browser/chromeos/drive/resource_entry_conversion.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "webkit/common/fileapi/directory_entry.h"
18
19 using content::BrowserThread;
20
21 namespace drive {
22 namespace fileapi_internal {
23 namespace {
24
25 // The summary of opening mode is:
26 // - PLATFORM_FILE_OPEN: Open the existing file. Fail if not exists.
27 // - PLATFORM_FILE_CREATE: Create the file if not exists. Fail if exists.
28 // - PLATFORM_FILE_OPEN_ALWAYS: Open the existing file. Create a new file
29 //     if not exists.
30 // - PLATFORM_FILE_CREATE_ALWAYS: Create a new file if not exists. If exists
31 //     open it with truncate.
32 // - PLATFORM_FILE_OPEN_TRUNCATE: Open the existing file with truncate.
33 //     Fail if not exists.
34 OpenMode GetOpenMode(int file_flag) {
35   if (file_flag & (base::PLATFORM_FILE_OPEN |
36                    base::PLATFORM_FILE_OPEN_TRUNCATED))
37     return OPEN_FILE;
38
39   if (file_flag & base::PLATFORM_FILE_CREATE)
40     return CREATE_FILE;
41
42   DCHECK(file_flag & (base::PLATFORM_FILE_OPEN_ALWAYS |
43                       base::PLATFORM_FILE_CREATE_ALWAYS));
44   return OPEN_OR_CREATE_FILE;
45 }
46
47 // Runs |callback| with the PlatformFileError converted from |error|.
48 void RunStatusCallbackByFileError(const StatusCallback& callback,
49                                   FileError error) {
50   callback.Run(FileErrorToPlatformError(error));
51 }
52
53 // Runs |callback| with arguments converted from |error| and |entry|.
54 void RunGetFileInfoCallback(const GetFileInfoCallback& callback,
55                             FileError error,
56                             scoped_ptr<ResourceEntry> entry) {
57   if (error != FILE_ERROR_OK) {
58     callback.Run(FileErrorToPlatformError(error), base::PlatformFileInfo());
59     return;
60   }
61
62   DCHECK(entry);
63   base::PlatformFileInfo file_info;
64   ConvertResourceEntryToPlatformFileInfo(*entry, &file_info);
65   callback.Run(base::PLATFORM_FILE_OK, file_info);
66 }
67
68 // Runs |callback| with arguments converted from |error| and |resource_entries|.
69 void RunReadDirectoryCallback(
70     const ReadDirectoryCallback& callback,
71     FileError error,
72     scoped_ptr<ResourceEntryVector> resource_entries) {
73   if (error != FILE_ERROR_OK) {
74     callback.Run(FileErrorToPlatformError(error),
75                  std::vector<fileapi::DirectoryEntry>(), false);
76     return;
77   }
78
79   DCHECK(resource_entries);
80
81   std::vector<fileapi::DirectoryEntry> entries;
82   // Convert drive files to File API's directory entry.
83   entries.reserve(resource_entries->size());
84   for (size_t i = 0; i < resource_entries->size(); ++i) {
85     const ResourceEntry& resource_entry = (*resource_entries)[i];
86     fileapi::DirectoryEntry entry;
87     entry.name = resource_entry.base_name();
88
89     const PlatformFileInfoProto& file_info = resource_entry.file_info();
90     entry.is_directory = file_info.is_directory();
91     entry.size = file_info.size();
92     entry.last_modified_time =
93         base::Time::FromInternalValue(file_info.last_modified());
94     entries.push_back(entry);
95   }
96
97   callback.Run(base::PLATFORM_FILE_OK, entries, false);
98 }
99
100 // Runs |callback| with arguments based on |error|, |local_path| and |entry|.
101 void RunCreateSnapshotFileCallback(const CreateSnapshotFileCallback& callback,
102                                    FileError error,
103                                    const base::FilePath& local_path,
104                                    scoped_ptr<ResourceEntry> entry) {
105   if (error != FILE_ERROR_OK) {
106     callback.Run(
107         FileErrorToPlatformError(error),
108         base::PlatformFileInfo(), base::FilePath(),
109         webkit_blob::ScopedFile::ScopeOutPolicy());
110     return;
111   }
112
113   DCHECK(entry);
114
115   // When reading file, last modified time specified in file info will be
116   // compared to the last modified time of the local version of the drive file.
117   // Since those two values don't generally match (last modification time on the
118   // drive server vs. last modification time of the local, downloaded file), so
119   // we have to opt out from this check. We do this by unsetting last_modified
120   // value in the file info passed to the CreateSnapshot caller.
121   base::PlatformFileInfo file_info;
122   ConvertResourceEntryToPlatformFileInfo(*entry, &file_info);
123   file_info.last_modified = base::Time();
124
125   // If the file is a hosted document, a temporary JSON file is created to
126   // represent the document. The JSON file is not cached and its lifetime
127   // is managed by ShareableFileReference.
128   webkit_blob::ScopedFile::ScopeOutPolicy scope_out_policy =
129       entry->file_specific_info().is_hosted_document() ?
130       webkit_blob::ScopedFile::DELETE_ON_SCOPE_OUT :
131       webkit_blob::ScopedFile::DONT_DELETE_ON_SCOPE_OUT;
132
133   callback.Run(base::PLATFORM_FILE_OK, file_info, local_path, scope_out_policy);
134 }
135
136 // Runs |callback| with arguments converted from |error| and |local_path|.
137 void RunCreateWritableSnapshotFileCallback(
138     const CreateWritableSnapshotFileCallback& callback,
139     FileError error,
140     const base::FilePath& local_path,
141     const base::Closure& close_callback) {
142   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
143   callback.Run(FileErrorToPlatformError(error), local_path, close_callback);
144 }
145
146 // Runs |callback| with |error| and |platform_file|.
147 void RunOpenFileCallback(const OpenFileCallback& callback,
148                          const base::Closure& close_callback,
149                          base::PlatformFileError* error,
150                          base::PlatformFile platform_file) {
151   callback.Run(*error, platform_file, close_callback);
152 }
153
154 // Part of OpenFile(). Called after FileSystem::OpenFile().
155 void OpenFileAfterFileSystemOpenFile(int file_flags,
156                                      const OpenFileCallback& callback,
157                                      FileError error,
158                                      const base::FilePath& local_path,
159                                      const base::Closure& close_callback) {
160   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
161
162   if (error != FILE_ERROR_OK) {
163     callback.Run(FileErrorToPlatformError(error),
164                  base::kInvalidPlatformFileValue,
165                  base::Closure());
166     return;
167   }
168
169   // Here, the file should be at |local_path|, but there may be timing issue.
170   // Because the file is managed by Drive file system, so, in order to avoid
171   // unexpected file creation, CREATE, OPEN_ALWAYS and CREATE_ALWAYS are
172   // translated into OPEN or OPEN_TRUNCATED, here. Keep OPEN and OPEN_TRUNCATED
173   // as is.
174   if (file_flags & (base::PLATFORM_FILE_CREATE |
175                     base::PLATFORM_FILE_OPEN_ALWAYS)) {
176     file_flags &= ~(base::PLATFORM_FILE_CREATE |
177                     base::PLATFORM_FILE_OPEN_ALWAYS);
178     file_flags |= base::PLATFORM_FILE_OPEN;
179   } else if (file_flags & base::PLATFORM_FILE_CREATE_ALWAYS) {
180     file_flags &= ~base::PLATFORM_FILE_CREATE_ALWAYS;
181     file_flags |= base::PLATFORM_FILE_OPEN_TRUNCATED;
182   }
183
184   // Cache file prepared for modification is available. Open it locally.
185   base::PlatformFileError* result =
186       new base::PlatformFileError(base::PLATFORM_FILE_ERROR_FAILED);
187   bool posted = base::PostTaskAndReplyWithResult(
188       BrowserThread::GetBlockingPool(), FROM_HERE,
189       base::Bind(&base::CreatePlatformFile,
190                  local_path, file_flags, static_cast<bool*>(NULL), result),
191       base::Bind(&RunOpenFileCallback,
192                  callback, close_callback, base::Owned(result)));
193   DCHECK(posted);
194 }
195
196 }  // namespace
197
198 void RunFileSystemCallback(
199     const FileSystemGetter& file_system_getter,
200     const base::Callback<void(FileSystemInterface*)>& callback,
201     const base::Closure& on_error_callback) {
202   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
203   FileSystemInterface* file_system = file_system_getter.Run();
204
205   if (!file_system) {
206     if (!on_error_callback.is_null())
207       on_error_callback.Run();
208     return;
209   }
210
211   callback.Run(file_system);
212 }
213
214 void GetFileInfo(const base::FilePath& file_path,
215                  const GetFileInfoCallback& callback,
216                  FileSystemInterface* file_system) {
217   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
218   file_system->GetResourceEntryByPath(
219       file_path,
220       base::Bind(&RunGetFileInfoCallback, callback));
221 }
222
223 void Copy(const base::FilePath& src_file_path,
224           const base::FilePath& dest_file_path,
225           bool preserve_last_modified,
226           const StatusCallback& callback,
227           FileSystemInterface* file_system) {
228   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
229   file_system->Copy(src_file_path, dest_file_path, preserve_last_modified,
230                     base::Bind(&RunStatusCallbackByFileError, callback));
231 }
232
233 void Move(const base::FilePath& src_file_path,
234           const base::FilePath& dest_file_path,
235           bool preserve_last_modified,
236           const StatusCallback& callback,
237           FileSystemInterface* file_system) {
238   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
239   file_system->Move(src_file_path, dest_file_path, preserve_last_modified,
240                     base::Bind(&RunStatusCallbackByFileError, callback));
241 }
242
243 void CopyInForeignFile(const base::FilePath& src_foreign_file_path,
244                        const base::FilePath& dest_file_path,
245                        const StatusCallback& callback,
246                        FileSystemInterface* file_system) {
247   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
248   file_system->TransferFileFromLocalToRemote(
249       src_foreign_file_path, dest_file_path,
250       base::Bind(&RunStatusCallbackByFileError, callback));
251 }
252
253 void ReadDirectory(const base::FilePath& file_path,
254                    const ReadDirectoryCallback& callback,
255                    FileSystemInterface* file_system) {
256   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
257   file_system->ReadDirectoryByPath(
258       file_path,
259       base::Bind(&RunReadDirectoryCallback, callback));
260 }
261
262 void Remove(const base::FilePath& file_path,
263             bool is_recursive,
264             const StatusCallback& callback,
265             FileSystemInterface* file_system) {
266   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
267   file_system->Remove(file_path, is_recursive,
268                       base::Bind(&RunStatusCallbackByFileError, callback));
269 }
270
271 void CreateDirectory(const base::FilePath& file_path,
272                      bool is_exclusive,
273                      bool is_recursive,
274                      const StatusCallback& callback,
275                      FileSystemInterface* file_system) {
276   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
277   file_system->CreateDirectory(
278       file_path, is_exclusive, is_recursive,
279       base::Bind(&RunStatusCallbackByFileError, callback));
280 }
281
282 void CreateFile(const base::FilePath& file_path,
283                 bool is_exclusive,
284                 const StatusCallback& callback,
285                 FileSystemInterface* file_system) {
286   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
287   file_system->CreateFile(file_path, is_exclusive,
288                           std::string(),  // no mime type; guess from file_path
289                           base::Bind(&RunStatusCallbackByFileError, callback));
290 }
291
292 void Truncate(const base::FilePath& file_path,
293               int64 length,
294               const StatusCallback& callback,
295               FileSystemInterface* file_system) {
296   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
297   file_system->TruncateFile(
298       file_path, length,
299       base::Bind(&RunStatusCallbackByFileError, callback));
300 }
301
302 void CreateSnapshotFile(const base::FilePath& file_path,
303                         const CreateSnapshotFileCallback& callback,
304                         FileSystemInterface* file_system) {
305   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
306   file_system->GetFileByPath(
307       file_path,
308       base::Bind(&RunCreateSnapshotFileCallback, callback));
309 }
310
311 void CreateWritableSnapshotFile(
312     const base::FilePath& file_path,
313     const CreateWritableSnapshotFileCallback& callback,
314     FileSystemInterface* file_system) {
315   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
316   file_system->OpenFile(
317       file_path,
318       OPEN_FILE,
319       std::string(),  // no mime type; we never create a new file here.
320       base::Bind(&RunCreateWritableSnapshotFileCallback, callback));
321 }
322
323 void OpenFile(const base::FilePath& file_path,
324               int file_flags,
325               const OpenFileCallback& callback,
326               FileSystemInterface* file_system) {
327   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
328
329   // Returns an error if any unsupported flag is found.
330   if (file_flags & ~(base::PLATFORM_FILE_OPEN |
331                      base::PLATFORM_FILE_CREATE |
332                      base::PLATFORM_FILE_OPEN_ALWAYS |
333                      base::PLATFORM_FILE_CREATE_ALWAYS |
334                      base::PLATFORM_FILE_OPEN_TRUNCATED |
335                      base::PLATFORM_FILE_READ |
336                      base::PLATFORM_FILE_WRITE |
337                      base::PLATFORM_FILE_WRITE_ATTRIBUTES |
338                      base::PLATFORM_FILE_APPEND)) {
339     base::MessageLoopProxy::current()->PostTask(
340         FROM_HERE,
341         base::Bind(callback,
342                    base::PLATFORM_FILE_ERROR_FAILED,
343                    base::kInvalidPlatformFileValue,
344                    base::Closure()));
345     return;
346   }
347
348   file_system->OpenFile(
349       file_path, GetOpenMode(file_flags),
350       std::string(),  // no mime type; guess from file_path
351       base::Bind(&OpenFileAfterFileSystemOpenFile, file_flags, callback));
352 }
353
354 void TouchFile(const base::FilePath& file_path,
355                const base::Time& last_access_time,
356                const base::Time& last_modified_time,
357                const StatusCallback& callback,
358                FileSystemInterface* file_system) {
359   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
360   file_system->TouchFile(file_path, last_access_time, last_modified_time,
361                          base::Bind(&RunStatusCallbackByFileError, callback));
362
363 }
364
365 }  // namespace fileapi_internal
366 }  // namespace drive