blob: 3b73e3429b72164a6bdc8e4af90aebbe3687e7ae [file] [log] [blame]
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01001// Copyright (c) 2012 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/media_galleries/fileapi/native_media_file_util.h"
6
Ben Murdocheb525c52013-07-10 11:40:50 +01007#include <string>
8
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01009#include "base/bind.h"
Ben Murdocheb525c52013-07-10 11:40:50 +010010#include "base/bind_helpers.h"
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +010011#include "base/file_util.h"
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010012#include "base/files/file_enumerator.h"
Ben Murdoch558790d2013-07-30 15:19:42 +010013#include "base/files/scoped_platform_file_closer.h"
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010014#include "base/strings/string_util.h"
15#include "base/task_runner_util.h"
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010016#include "chrome/browser/media_galleries/fileapi/media_path_filter.h"
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010017#include "content/public/browser/browser_thread.h"
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +010018#include "net/base/mime_sniffer.h"
Ben Murdocheb525c52013-07-10 11:40:50 +010019#include "url/gurl.h"
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +010020#include "webkit/browser/fileapi/file_system_context.h"
21#include "webkit/browser/fileapi/file_system_operation_context.h"
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +010022#include "webkit/browser/fileapi/native_file_util.h"
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010023#include "webkit/common/blob/shareable_file_reference.h"
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010024
25namespace chrome {
26
27namespace {
28
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010029// Used to skip the hidden folders and files. Returns true if the file specified
30// by |path| should be skipped.
31bool ShouldSkip(const base::FilePath& path) {
32 const base::FilePath::StringType base_name = path.BaseName().value();
33 if (base_name.empty())
34 return false;
35
36 // Dot files (aka hidden files)
37 if (base_name[0] == '.')
38 return true;
39
40 // Mac OS X file.
41 if (base_name == FILE_PATH_LITERAL("__MACOSX"))
42 return true;
43
44#if defined(OS_WIN)
45 DWORD file_attributes = ::GetFileAttributes(path.value().c_str());
46 if ((file_attributes != INVALID_FILE_ATTRIBUTES) &&
47 ((file_attributes & FILE_ATTRIBUTE_HIDDEN) != 0))
48 return true;
49#else
50 // Windows always creates a recycle bin folder in the attached device to store
51 // all the deleted contents. On non-windows operating systems, there is no way
52 // to get the hidden attribute of windows recycle bin folders that are present
53 // on the attached device. Therefore, compare the file path name to the
54 // recycle bin name and exclude those folders. For more details, please refer
55 // to http://support.microsoft.com/kb/171694.
56 const char win_98_recycle_bin_name[] = "RECYCLED";
57 const char win_xp_recycle_bin_name[] = "RECYCLER";
58 const char win_vista_recycle_bin_name[] = "$Recycle.bin";
59 if ((base::strncasecmp(base_name.c_str(),
60 win_98_recycle_bin_name,
61 strlen(win_98_recycle_bin_name)) == 0) ||
62 (base::strncasecmp(base_name.c_str(),
63 win_xp_recycle_bin_name,
64 strlen(win_xp_recycle_bin_name)) == 0) ||
65 (base::strncasecmp(base_name.c_str(),
66 win_vista_recycle_bin_name,
67 strlen(win_vista_recycle_bin_name)) == 0))
68 return true;
69#endif
70 return false;
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +010071}
72
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010073// Returns true if the current thread is capable of doing IO.
74bool IsOnTaskRunnerThread(fileapi::FileSystemOperationContext* context) {
75 return context->task_runner()->RunsTasksOnCurrentThread();
76}
77
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010078} // namespace
79
Ben Murdochbb1529c2013-08-08 10:24:53 +010080NativeMediaFileUtil::NativeMediaFileUtil(MediaPathFilter* media_path_filter)
81 : weak_factory_(this),
82 media_path_filter_(media_path_filter) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010083}
84
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010085NativeMediaFileUtil::~NativeMediaFileUtil() {
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +010086}
87
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +010088// static
89base::PlatformFileError NativeMediaFileUtil::IsMediaFile(
90 const base::FilePath& path) {
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +010091 base::PlatformFile file_handle;
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +010092 const int flags = base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ;
93 base::PlatformFileError error =
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010094 fileapi::NativeFileUtil::CreateOrOpen(path, flags, &file_handle, NULL);
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +010095 if (error != base::PLATFORM_FILE_OK)
96 return error;
97
Ben Murdoch558790d2013-07-30 15:19:42 +010098 base::ScopedPlatformFileCloser scoped_platform_file(&file_handle);
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +010099 char buffer[net::kMaxBytesToSniff];
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100100
101 // Read as much as net::SniffMimeTypeFromLocalData() will bother looking at.
102 int64 len =
103 base::ReadPlatformFile(file_handle, 0, buffer, net::kMaxBytesToSniff);
104 if (len < 0)
105 return base::PLATFORM_FILE_ERROR_FAILED;
106 if (len == 0)
107 return base::PLATFORM_FILE_ERROR_SECURITY;
108
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100109 std::string mime_type;
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100110 if (!net::SniffMimeTypeFromLocalData(buffer, len, &mime_type))
111 return base::PLATFORM_FILE_ERROR_SECURITY;
112
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100113 if (StartsWithASCII(mime_type, "image/", true) ||
114 StartsWithASCII(mime_type, "audio/", true) ||
115 StartsWithASCII(mime_type, "video/", true) ||
116 mime_type == "application/x-shockwave-flash") {
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100117 return base::PLATFORM_FILE_OK;
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100118 }
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100119 return base::PLATFORM_FILE_ERROR_SECURITY;
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100120}
121
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100122void NativeMediaFileUtil::CreateOrOpen(
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100123 scoped_ptr<fileapi::FileSystemOperationContext> context,
124 const fileapi::FileSystemURL& url,
125 int file_flags,
126 const CreateOrOpenCallback& callback) {
127 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
128 // Only called by NaCl, which should not have access to media file systems.
129 base::PlatformFile invalid_file(base::kInvalidPlatformFileValue);
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100130 callback.Run(base::PLATFORM_FILE_ERROR_SECURITY,
131 base::PassPlatformFile(&invalid_file),
132 base::Closure());
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100133}
134
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100135void NativeMediaFileUtil::EnsureFileExists(
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100136 scoped_ptr<fileapi::FileSystemOperationContext> context,
137 const fileapi::FileSystemURL& url,
138 const EnsureFileExistsCallback& callback) {
139 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100140 callback.Run(base::PLATFORM_FILE_ERROR_SECURITY, false);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100141}
142
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100143void NativeMediaFileUtil::CreateDirectory(
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100144 scoped_ptr<fileapi::FileSystemOperationContext> context,
145 const fileapi::FileSystemURL& url,
146 bool exclusive,
147 bool recursive,
148 const StatusCallback& callback) {
149 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
Ben Murdocheb525c52013-07-10 11:40:50 +0100150 fileapi::FileSystemOperationContext* context_ptr = context.get();
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100151 const bool success = context_ptr->task_runner()->PostTask(
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100152 FROM_HERE,
153 base::Bind(&NativeMediaFileUtil::CreateDirectoryOnTaskRunnerThread,
Ben Murdocheb525c52013-07-10 11:40:50 +0100154 weak_factory_.GetWeakPtr(), base::Passed(&context),
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100155 url, exclusive, recursive, callback));
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100156 DCHECK(success);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100157}
158
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100159void NativeMediaFileUtil::GetFileInfo(
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100160 scoped_ptr<fileapi::FileSystemOperationContext> context,
161 const fileapi::FileSystemURL& url,
162 const GetFileInfoCallback& callback) {
163 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
Ben Murdocheb525c52013-07-10 11:40:50 +0100164 fileapi::FileSystemOperationContext* context_ptr = context.get();
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100165 const bool success = context_ptr->task_runner()->PostTask(
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100166 FROM_HERE,
167 base::Bind(&NativeMediaFileUtil::GetFileInfoOnTaskRunnerThread,
Ben Murdocheb525c52013-07-10 11:40:50 +0100168 weak_factory_.GetWeakPtr(), base::Passed(&context),
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100169 url, callback));
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100170 DCHECK(success);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100171}
172
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100173void NativeMediaFileUtil::ReadDirectory(
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100174 scoped_ptr<fileapi::FileSystemOperationContext> context,
175 const fileapi::FileSystemURL& url,
176 const ReadDirectoryCallback& callback) {
177 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
Ben Murdocheb525c52013-07-10 11:40:50 +0100178 fileapi::FileSystemOperationContext* context_ptr = context.get();
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100179 const bool success = context_ptr->task_runner()->PostTask(
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100180 FROM_HERE,
181 base::Bind(&NativeMediaFileUtil::ReadDirectoryOnTaskRunnerThread,
Ben Murdocheb525c52013-07-10 11:40:50 +0100182 weak_factory_.GetWeakPtr(), base::Passed(&context),
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100183 url, callback));
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100184 DCHECK(success);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100185}
186
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100187void NativeMediaFileUtil::Touch(
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100188 scoped_ptr<fileapi::FileSystemOperationContext> context,
189 const fileapi::FileSystemURL& url,
190 const base::Time& last_access_time,
191 const base::Time& last_modified_time,
192 const StatusCallback& callback) {
193 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100194 callback.Run(base::PLATFORM_FILE_ERROR_SECURITY);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100195}
196
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100197void NativeMediaFileUtil::Truncate(
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100198 scoped_ptr<fileapi::FileSystemOperationContext> context,
199 const fileapi::FileSystemURL& url,
200 int64 length,
201 const StatusCallback& callback) {
202 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100203 callback.Run(base::PLATFORM_FILE_ERROR_SECURITY);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100204}
205
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100206void NativeMediaFileUtil::CopyFileLocal(
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100207 scoped_ptr<fileapi::FileSystemOperationContext> context,
208 const fileapi::FileSystemURL& src_url,
209 const fileapi::FileSystemURL& dest_url,
210 const StatusCallback& callback) {
211 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
Ben Murdocheb525c52013-07-10 11:40:50 +0100212 fileapi::FileSystemOperationContext* context_ptr = context.get();
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100213 const bool success = context_ptr->task_runner()->PostTask(
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100214 FROM_HERE,
215 base::Bind(&NativeMediaFileUtil::CopyOrMoveFileLocalOnTaskRunnerThread,
Ben Murdocheb525c52013-07-10 11:40:50 +0100216 weak_factory_.GetWeakPtr(), base::Passed(&context),
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100217 src_url, dest_url, true /* copy */, callback));
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100218 DCHECK(success);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100219}
220
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100221void NativeMediaFileUtil::MoveFileLocal(
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100222 scoped_ptr<fileapi::FileSystemOperationContext> context,
223 const fileapi::FileSystemURL& src_url,
224 const fileapi::FileSystemURL& dest_url,
225 const StatusCallback& callback) {
226 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
Ben Murdocheb525c52013-07-10 11:40:50 +0100227 fileapi::FileSystemOperationContext* context_ptr = context.get();
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100228 const bool success = context_ptr->task_runner()->PostTask(
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100229 FROM_HERE,
230 base::Bind(&NativeMediaFileUtil::CopyOrMoveFileLocalOnTaskRunnerThread,
Ben Murdocheb525c52013-07-10 11:40:50 +0100231 weak_factory_.GetWeakPtr(), base::Passed(&context),
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100232 src_url, dest_url, false /* copy */, callback));
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100233 DCHECK(success);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100234}
235
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100236void NativeMediaFileUtil::CopyInForeignFile(
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100237 scoped_ptr<fileapi::FileSystemOperationContext> context,
238 const base::FilePath& src_file_path,
239 const fileapi::FileSystemURL& dest_url,
240 const StatusCallback& callback) {
241 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
Ben Murdocheb525c52013-07-10 11:40:50 +0100242 fileapi::FileSystemOperationContext* context_ptr = context.get();
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100243 const bool success = context_ptr->task_runner()->PostTask(
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100244 FROM_HERE,
245 base::Bind(&NativeMediaFileUtil::CopyInForeignFileOnTaskRunnerThread,
Ben Murdocheb525c52013-07-10 11:40:50 +0100246 weak_factory_.GetWeakPtr(), base::Passed(&context),
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100247 src_file_path, dest_url, callback));
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100248 DCHECK(success);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100249}
250
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100251void NativeMediaFileUtil::DeleteFile(
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100252 scoped_ptr<fileapi::FileSystemOperationContext> context,
253 const fileapi::FileSystemURL& url,
254 const StatusCallback& callback) {
255 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100256 callback.Run(base::PLATFORM_FILE_ERROR_SECURITY);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100257}
258
259// This is needed to support Copy and Move.
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100260void NativeMediaFileUtil::DeleteDirectory(
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100261 scoped_ptr<fileapi::FileSystemOperationContext> context,
262 const fileapi::FileSystemURL& url,
263 const StatusCallback& callback) {
264 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
Ben Murdocheb525c52013-07-10 11:40:50 +0100265 fileapi::FileSystemOperationContext* context_ptr = context.get();
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100266 const bool success = context_ptr->task_runner()->PostTask(
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100267 FROM_HERE,
268 base::Bind(&NativeMediaFileUtil::DeleteDirectoryOnTaskRunnerThread,
Ben Murdocheb525c52013-07-10 11:40:50 +0100269 weak_factory_.GetWeakPtr(), base::Passed(&context),
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100270 url, callback));
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100271 DCHECK(success);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100272}
273
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100274void NativeMediaFileUtil::DeleteRecursively(
Ben Murdocheb525c52013-07-10 11:40:50 +0100275 scoped_ptr<fileapi::FileSystemOperationContext> context,
276 const fileapi::FileSystemURL& url,
277 const StatusCallback& callback) {
278 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100279 callback.Run(base::PLATFORM_FILE_ERROR_INVALID_OPERATION);
Ben Murdocheb525c52013-07-10 11:40:50 +0100280}
281
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100282void NativeMediaFileUtil::CreateSnapshotFile(
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100283 scoped_ptr<fileapi::FileSystemOperationContext> context,
284 const fileapi::FileSystemURL& url,
285 const CreateSnapshotFileCallback& callback) {
286 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
Ben Murdocheb525c52013-07-10 11:40:50 +0100287 fileapi::FileSystemOperationContext* context_ptr = context.get();
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100288 const bool success = context_ptr->task_runner()->PostTask(
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100289 FROM_HERE,
290 base::Bind(&NativeMediaFileUtil::CreateSnapshotFileOnTaskRunnerThread,
Ben Murdocheb525c52013-07-10 11:40:50 +0100291 weak_factory_.GetWeakPtr(), base::Passed(&context),
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100292 url, callback));
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100293 DCHECK(success);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100294}
295
296void NativeMediaFileUtil::CreateDirectoryOnTaskRunnerThread(
Ben Murdocheb525c52013-07-10 11:40:50 +0100297 scoped_ptr<fileapi::FileSystemOperationContext> context,
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100298 const fileapi::FileSystemURL& url,
299 bool exclusive,
300 bool recursive,
301 const StatusCallback& callback) {
Ben Murdocheb525c52013-07-10 11:40:50 +0100302 DCHECK(IsOnTaskRunnerThread(context.get()));
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100303 base::PlatformFileError error =
Ben Murdocheb525c52013-07-10 11:40:50 +0100304 CreateDirectorySync(context.get(), url, exclusive, recursive);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100305 content::BrowserThread::PostTask(
306 content::BrowserThread::IO,
307 FROM_HERE,
308 base::Bind(callback, error));
309}
310
311void NativeMediaFileUtil::GetFileInfoOnTaskRunnerThread(
Ben Murdocheb525c52013-07-10 11:40:50 +0100312 scoped_ptr<fileapi::FileSystemOperationContext> context,
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100313 const fileapi::FileSystemURL& url,
314 const GetFileInfoCallback& callback) {
Ben Murdocheb525c52013-07-10 11:40:50 +0100315 DCHECK(IsOnTaskRunnerThread(context.get()));
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100316 base::PlatformFileInfo file_info;
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100317 base::PlatformFileError error =
Ben Murdochbbcdd452013-07-25 10:06:34 +0100318 GetFileInfoSync(context.get(), url, &file_info, NULL);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100319 content::BrowserThread::PostTask(
320 content::BrowserThread::IO,
321 FROM_HERE,
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100322 base::Bind(callback, error, file_info));
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100323}
324
325void NativeMediaFileUtil::ReadDirectoryOnTaskRunnerThread(
Ben Murdocheb525c52013-07-10 11:40:50 +0100326 scoped_ptr<fileapi::FileSystemOperationContext> context,
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100327 const fileapi::FileSystemURL& url,
328 const ReadDirectoryCallback& callback) {
Ben Murdocheb525c52013-07-10 11:40:50 +0100329 DCHECK(IsOnTaskRunnerThread(context.get()));
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100330 EntryList entry_list;
331 base::PlatformFileError error =
Ben Murdocheb525c52013-07-10 11:40:50 +0100332 ReadDirectorySync(context.get(), url, &entry_list);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100333 content::BrowserThread::PostTask(
334 content::BrowserThread::IO,
335 FROM_HERE,
336 base::Bind(callback, error, entry_list, false /* has_more */));
337}
338
339void NativeMediaFileUtil::CopyOrMoveFileLocalOnTaskRunnerThread(
Ben Murdocheb525c52013-07-10 11:40:50 +0100340 scoped_ptr<fileapi::FileSystemOperationContext> context,
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100341 const fileapi::FileSystemURL& src_url,
342 const fileapi::FileSystemURL& dest_url,
343 bool copy,
344 const StatusCallback& callback) {
Ben Murdocheb525c52013-07-10 11:40:50 +0100345 DCHECK(IsOnTaskRunnerThread(context.get()));
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100346 base::PlatformFileError error =
Ben Murdocheb525c52013-07-10 11:40:50 +0100347 CopyOrMoveFileSync(context.get(), src_url, dest_url, copy);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100348 content::BrowserThread::PostTask(
349 content::BrowserThread::IO,
350 FROM_HERE,
351 base::Bind(callback, error));
352}
353
354void NativeMediaFileUtil::CopyInForeignFileOnTaskRunnerThread(
Ben Murdocheb525c52013-07-10 11:40:50 +0100355 scoped_ptr<fileapi::FileSystemOperationContext> context,
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100356 const base::FilePath& src_file_path,
357 const fileapi::FileSystemURL& dest_url,
358 const StatusCallback& callback) {
Ben Murdocheb525c52013-07-10 11:40:50 +0100359 DCHECK(IsOnTaskRunnerThread(context.get()));
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100360 base::PlatformFileError error =
Ben Murdocheb525c52013-07-10 11:40:50 +0100361 CopyInForeignFileSync(context.get(), src_file_path, dest_url);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100362 content::BrowserThread::PostTask(
363 content::BrowserThread::IO,
364 FROM_HERE,
365 base::Bind(callback, error));
366}
367
368void NativeMediaFileUtil::DeleteDirectoryOnTaskRunnerThread(
Ben Murdocheb525c52013-07-10 11:40:50 +0100369 scoped_ptr<fileapi::FileSystemOperationContext> context,
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100370 const fileapi::FileSystemURL& url,
371 const StatusCallback& callback) {
Ben Murdocheb525c52013-07-10 11:40:50 +0100372 DCHECK(IsOnTaskRunnerThread(context.get()));
373 base::PlatformFileError error = DeleteDirectorySync(context.get(), url);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100374 content::BrowserThread::PostTask(
375 content::BrowserThread::IO,
376 FROM_HERE,
377 base::Bind(callback, error));
378}
379
380void NativeMediaFileUtil::CreateSnapshotFileOnTaskRunnerThread(
Ben Murdocheb525c52013-07-10 11:40:50 +0100381 scoped_ptr<fileapi::FileSystemOperationContext> context,
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100382 const fileapi::FileSystemURL& url,
383 const CreateSnapshotFileCallback& callback) {
Ben Murdocheb525c52013-07-10 11:40:50 +0100384 DCHECK(IsOnTaskRunnerThread(context.get()));
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100385 base::PlatformFileInfo file_info;
386 base::FilePath platform_path;
387 scoped_refptr<webkit_blob::ShareableFileReference> file_ref;
388 base::PlatformFileError error =
Ben Murdocheb525c52013-07-10 11:40:50 +0100389 CreateSnapshotFileSync(context.get(), url, &file_info, &platform_path,
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100390 &file_ref);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100391 content::BrowserThread::PostTask(
392 content::BrowserThread::IO,
393 FROM_HERE,
394 base::Bind(callback, error, file_info, platform_path, file_ref));
395}
396
397base::PlatformFileError NativeMediaFileUtil::CreateDirectorySync(
398 fileapi::FileSystemOperationContext* context,
399 const fileapi::FileSystemURL& url,
400 bool exclusive,
401 bool recursive) {
402 base::FilePath file_path;
403 base::PlatformFileError error = GetLocalFilePath(context, url, &file_path);
404 if (error != base::PLATFORM_FILE_OK)
405 return error;
406 return fileapi::NativeFileUtil::CreateDirectory(file_path, exclusive,
407 recursive);
408}
409
410base::PlatformFileError NativeMediaFileUtil::CopyOrMoveFileSync(
411 fileapi::FileSystemOperationContext* context,
412 const fileapi::FileSystemURL& src_url,
413 const fileapi::FileSystemURL& dest_url,
414 bool copy) {
415 DCHECK(IsOnTaskRunnerThread(context));
416 base::FilePath src_file_path;
417 base::PlatformFileError error =
418 GetFilteredLocalFilePathForExistingFileOrDirectory(
419 context, src_url,
420 base::PLATFORM_FILE_ERROR_NOT_FOUND,
421 &src_file_path);
422 if (error != base::PLATFORM_FILE_OK)
423 return error;
424 if (fileapi::NativeFileUtil::DirectoryExists(src_file_path))
425 return base::PLATFORM_FILE_ERROR_NOT_A_FILE;
426
427 base::FilePath dest_file_path;
428 error = GetLocalFilePath(context, dest_url, &dest_file_path);
429 if (error != base::PLATFORM_FILE_OK)
430 return error;
431 base::PlatformFileInfo file_info;
432 error = fileapi::NativeFileUtil::GetFileInfo(dest_file_path, &file_info);
433 if (error != base::PLATFORM_FILE_OK &&
434 error != base::PLATFORM_FILE_ERROR_NOT_FOUND)
435 return error;
436 if (error == base::PLATFORM_FILE_OK && file_info.is_directory)
437 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION;
Ben Murdochbb1529c2013-08-08 10:24:53 +0100438 if (!media_path_filter_->Match(dest_file_path))
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100439 return base::PLATFORM_FILE_ERROR_SECURITY;
440
441 return fileapi::NativeFileUtil::CopyOrMoveFile(src_file_path, dest_file_path,
442 copy);
443}
444
445base::PlatformFileError NativeMediaFileUtil::CopyInForeignFileSync(
446 fileapi::FileSystemOperationContext* context,
447 const base::FilePath& src_file_path,
448 const fileapi::FileSystemURL& dest_url) {
449 DCHECK(IsOnTaskRunnerThread(context));
450 if (src_file_path.empty())
451 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION;
452
453 base::FilePath dest_file_path;
454 base::PlatformFileError error =
455 GetFilteredLocalFilePath(context, dest_url, &dest_file_path);
456 if (error != base::PLATFORM_FILE_OK)
457 return error;
458 return fileapi::NativeFileUtil::CopyOrMoveFile(src_file_path, dest_file_path,
459 true);
460}
461
462base::PlatformFileError NativeMediaFileUtil::GetFileInfoSync(
463 fileapi::FileSystemOperationContext* context,
464 const fileapi::FileSystemURL& url,
465 base::PlatformFileInfo* file_info,
466 base::FilePath* platform_path) {
467 DCHECK(context);
468 DCHECK(IsOnTaskRunnerThread(context));
469 DCHECK(file_info);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100470
471 base::FilePath file_path;
472 base::PlatformFileError error = GetLocalFilePath(context, url, &file_path);
473 if (error != base::PLATFORM_FILE_OK)
474 return error;
475 if (file_util::IsLink(file_path))
476 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
477 error = fileapi::NativeFileUtil::GetFileInfo(file_path, file_info);
478 if (error != base::PLATFORM_FILE_OK)
479 return error;
480
481 if (platform_path)
482 *platform_path = file_path;
483 if (file_info->is_directory ||
Ben Murdochbb1529c2013-08-08 10:24:53 +0100484 media_path_filter_->Match(file_path)) {
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100485 return base::PLATFORM_FILE_OK;
486 }
487 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
488}
489
490base::PlatformFileError NativeMediaFileUtil::GetLocalFilePath(
491 fileapi::FileSystemOperationContext* context,
492 const fileapi::FileSystemURL& url,
493 base::FilePath* local_file_path) {
494 DCHECK(local_file_path);
495 DCHECK(url.is_valid());
496 if (url.path().empty()) {
497 // Root direcory case, which should not be accessed.
498 return base::PLATFORM_FILE_ERROR_ACCESS_DENIED;
499 }
500 *local_file_path = url.path();
501 return base::PLATFORM_FILE_OK;
502}
503
504base::PlatformFileError NativeMediaFileUtil::ReadDirectorySync(
505 fileapi::FileSystemOperationContext* context,
506 const fileapi::FileSystemURL& url,
507 EntryList* file_list) {
508 DCHECK(IsOnTaskRunnerThread(context));
509 DCHECK(file_list);
510 DCHECK(file_list->empty());
511 base::PlatformFileInfo file_info;
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100512 base::FilePath dir_path;
513 base::PlatformFileError error =
514 GetFileInfoSync(context, url, &file_info, &dir_path);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100515
516 if (error != base::PLATFORM_FILE_OK)
517 return error;
518
519 if (!file_info.is_directory)
520 return base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY;
521
522 base::FileEnumerator file_enum(
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100523 dir_path,
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100524 false /* recursive */,
525 base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES);
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100526 for (base::FilePath enum_path = file_enum.Next();
527 !enum_path.empty();
528 enum_path = file_enum.Next()) {
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100529 // Skip symlinks.
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100530 if (file_util::IsLink(enum_path))
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100531 continue;
532
533 base::FileEnumerator::FileInfo info = file_enum.GetInfo();
534
535 // NativeMediaFileUtil skip criteria.
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100536 if (ShouldSkip(enum_path))
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100537 continue;
Ben Murdochbb1529c2013-08-08 10:24:53 +0100538 if (!info.IsDirectory() && !media_path_filter_->Match(enum_path))
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100539 continue;
540
541 fileapi::DirectoryEntry entry;
542 entry.is_directory = info.IsDirectory();
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100543 entry.name = enum_path.BaseName().value();
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100544 entry.size = info.GetSize();
545 entry.last_modified_time = info.GetLastModifiedTime();
546
547 file_list->push_back(entry);
548 }
549
550 return base::PLATFORM_FILE_OK;
551}
552
553base::PlatformFileError NativeMediaFileUtil::DeleteDirectorySync(
554 fileapi::FileSystemOperationContext* context,
555 const fileapi::FileSystemURL& url) {
556 DCHECK(IsOnTaskRunnerThread(context));
557 base::FilePath file_path;
558 base::PlatformFileError error = GetLocalFilePath(context, url, &file_path);
559 if (error != base::PLATFORM_FILE_OK)
560 return error;
561 return fileapi::NativeFileUtil::DeleteDirectory(file_path);
562}
563
564base::PlatformFileError NativeMediaFileUtil::CreateSnapshotFileSync(
565 fileapi::FileSystemOperationContext* context,
566 const fileapi::FileSystemURL& url,
567 base::PlatformFileInfo* file_info,
568 base::FilePath* platform_path,
569 scoped_refptr<webkit_blob::ShareableFileReference>* file_ref) {
570 DCHECK(IsOnTaskRunnerThread(context));
571 base::PlatformFileError error =
572 GetFileInfoSync(context, url, file_info, platform_path);
573 if (error == base::PLATFORM_FILE_OK && file_info->is_directory)
574 error = base::PLATFORM_FILE_ERROR_NOT_A_FILE;
575 if (error == base::PLATFORM_FILE_OK)
576 error = NativeMediaFileUtil::IsMediaFile(*platform_path);
577
578 // We're just returning the local file information.
579 *file_ref = scoped_refptr<webkit_blob::ShareableFileReference>();
580
581 return error;
582}
583
584base::PlatformFileError NativeMediaFileUtil::GetFilteredLocalFilePath(
585 fileapi::FileSystemOperationContext* context,
586 const fileapi::FileSystemURL& file_system_url,
587 base::FilePath* local_file_path) {
588 DCHECK(IsOnTaskRunnerThread(context));
589 base::FilePath file_path;
590 base::PlatformFileError error =
591 GetLocalFilePath(context, file_system_url, &file_path);
592 if (error != base::PLATFORM_FILE_OK)
593 return error;
Ben Murdochbb1529c2013-08-08 10:24:53 +0100594 if (!media_path_filter_->Match(file_path))
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100595 return base::PLATFORM_FILE_ERROR_SECURITY;
596
597 *local_file_path = file_path;
598 return base::PLATFORM_FILE_OK;
599}
600
601base::PlatformFileError
602NativeMediaFileUtil::GetFilteredLocalFilePathForExistingFileOrDirectory(
603 fileapi::FileSystemOperationContext* context,
604 const fileapi::FileSystemURL& file_system_url,
605 base::PlatformFileError failure_error,
606 base::FilePath* local_file_path) {
607 DCHECK(IsOnTaskRunnerThread(context));
608 base::FilePath file_path;
609 base::PlatformFileError error =
610 GetLocalFilePath(context, file_system_url, &file_path);
611 if (error != base::PLATFORM_FILE_OK)
612 return error;
613
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100614 if (!base::PathExists(file_path))
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100615 return failure_error;
616 base::PlatformFileInfo file_info;
617 if (!file_util::GetFileInfo(file_path, &file_info))
618 return base::PLATFORM_FILE_ERROR_FAILED;
619
620 if (!file_info.is_directory &&
Ben Murdochbb1529c2013-08-08 10:24:53 +0100621 !media_path_filter_->Match(file_path)) {
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100622 return failure_error;
623 }
624
625 *local_file_path = file_path;
626 return base::PLATFORM_FILE_OK;
627}
628
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100629} // namespace chrome