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