Revert of Add button to add new FSP services to Files app. (patchset #8 id:140001...
[chromium-blink-merge.git] / chrome / browser / chromeos / drive / fileapi / fileapi_worker.cc
blobceb34fe47f60201780378b7718dca19c26eb8d4a
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.
5 #include "chrome/browser/chromeos/drive/fileapi/fileapi_worker.h"
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"
20 using content::BrowserThread;
22 namespace drive {
23 namespace fileapi_internal {
24 namespace {
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;
39 if (file_flag & base::File::FLAG_CREATE)
40 return CREATE_FILE;
42 DCHECK(file_flag &
43 (base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_CREATE_ALWAYS));
44 return OPEN_OR_CREATE_FILE;
47 // Runs |callback| with the File::Error converted from |error|.
48 void RunStatusCallbackByFileError(const StatusCallback& callback,
49 FileError error) {
50 callback.Run(FileErrorToBaseFileError(error));
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;
62 DCHECK(entry);
63 base::File::Info file_info;
64 ConvertResourceEntryToFileInfo(*entry, &file_info);
65 callback.Run(base::File::FILE_OK, file_info);
68 // Runs |callback| with entries.
69 void RunReadDirectoryCallbackWithEntries(
70 const ReadDirectoryCallback& callback,
71 scoped_ptr<ResourceEntryVector> resource_entries) {
72 DCHECK(resource_entries);
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();
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);
90 callback.Run(base::File::FILE_OK, entries, true /*has_more*/);
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*/);
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;
114 DCHECK(entry);
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();
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;
134 callback.Run(base::File::FILE_OK, file_info, local_path, scope_out_policy);
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_CURRENTLY_ON(BrowserThread::UI);
144 callback.Run(FileErrorToBaseFileError(error), local_path, close_callback);
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);
154 base::File OpenFile(const base::FilePath& path, int flags) {
155 return base::File(path, flags);
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_CURRENTLY_ON(BrowserThread::UI);
166 if (error != FILE_ERROR_OK) {
167 callback.Run(base::File(FileErrorToBaseFileError(error)), base::Closure());
168 return;
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;
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);
194 } // namespace
196 FileSystemInterface* GetFileSystemFromUrl(const storage::FileSystemURL& url) {
197 DCHECK_CURRENTLY_ON(BrowserThread::UI);
199 Profile* profile = util::ExtractProfileFromPath(url.path());
200 return profile ? util::GetFileSystemByProfile(profile) : NULL;
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_CURRENTLY_ON(BrowserThread::UI);
208 FileSystemInterface* file_system = file_system_getter.Run();
210 if (!file_system) {
211 if (!on_error_callback.is_null())
212 on_error_callback.Run();
213 return;
216 callback.Run(file_system);
219 void GetFileInfo(const base::FilePath& file_path,
220 const GetFileInfoCallback& callback,
221 FileSystemInterface* file_system) {
222 DCHECK_CURRENTLY_ON(BrowserThread::UI);
223 file_system->GetResourceEntry(
224 file_path,
225 base::Bind(&RunGetFileInfoCallback, callback));
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_CURRENTLY_ON(BrowserThread::UI);
234 file_system->Copy(src_file_path, dest_file_path, preserve_last_modified,
235 base::Bind(&RunStatusCallbackByFileError, callback));
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_CURRENTLY_ON(BrowserThread::UI);
243 file_system->Move(src_file_path, dest_file_path,
244 base::Bind(&RunStatusCallbackByFileError, callback));
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_CURRENTLY_ON(BrowserThread::UI);
252 file_system->TransferFileFromLocalToRemote(
253 src_foreign_file_path, dest_file_path,
254 base::Bind(&RunStatusCallbackByFileError, callback));
257 void ReadDirectory(const base::FilePath& file_path,
258 const ReadDirectoryCallback& callback,
259 FileSystemInterface* file_system) {
260 DCHECK_CURRENTLY_ON(BrowserThread::UI);
261 file_system->ReadDirectory(
262 file_path,
263 base::Bind(&RunReadDirectoryCallbackWithEntries, callback),
264 base::Bind(&RunReadDirectoryCallbackOnCompletion, callback));
267 void Remove(const base::FilePath& file_path,
268 bool is_recursive,
269 const StatusCallback& callback,
270 FileSystemInterface* file_system) {
271 DCHECK_CURRENTLY_ON(BrowserThread::UI);
272 file_system->Remove(file_path, is_recursive,
273 base::Bind(&RunStatusCallbackByFileError, callback));
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_CURRENTLY_ON(BrowserThread::UI);
282 file_system->CreateDirectory(
283 file_path, is_exclusive, is_recursive,
284 base::Bind(&RunStatusCallbackByFileError, callback));
287 void CreateFile(const base::FilePath& file_path,
288 bool is_exclusive,
289 const StatusCallback& callback,
290 FileSystemInterface* file_system) {
291 DCHECK_CURRENTLY_ON(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));
297 void Truncate(const base::FilePath& file_path,
298 int64 length,
299 const StatusCallback& callback,
300 FileSystemInterface* file_system) {
301 DCHECK_CURRENTLY_ON(BrowserThread::UI);
302 file_system->TruncateFile(
303 file_path, length,
304 base::Bind(&RunStatusCallbackByFileError, callback));
307 void CreateSnapshotFile(const base::FilePath& file_path,
308 const CreateSnapshotFileCallback& callback,
309 FileSystemInterface* file_system) {
310 DCHECK_CURRENTLY_ON(BrowserThread::UI);
311 file_system->GetFile(file_path,
312 base::Bind(&RunCreateSnapshotFileCallback, callback));
315 void CreateWritableSnapshotFile(
316 const base::FilePath& file_path,
317 const CreateWritableSnapshotFileCallback& callback,
318 FileSystemInterface* file_system) {
319 DCHECK_CURRENTLY_ON(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));
327 void OpenFile(const base::FilePath& file_path,
328 int file_flags,
329 const OpenFileCallback& callback,
330 FileSystemInterface* file_system) {
331 DCHECK_CURRENTLY_ON(BrowserThread::UI);
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;
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));
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_CURRENTLY_ON(BrowserThread::UI);
363 file_system->TouchFile(file_path, last_access_time, last_modified_time,
364 base::Bind(&RunStatusCallbackByFileError, callback));
368 } // namespace fileapi_internal
369 } // namespace drive