blob: 68e6322826924907ab35ce9278e3bc4a050ac593 [file] [log] [blame]
[email protected]e7e46732012-01-05 11:45:551// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]d4905e2e2011-05-13 21:56:322// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]28f051c32013-05-21 05:15:265#include "webkit/browser/fileapi/obfuscated_file_util.h"
[email protected]d4905e2e2011-05-13 21:56:326
7#include <queue>
[email protected]172205b2011-08-30 03:36:448#include <string>
[email protected]fcc2d5f2011-05-23 22:06:269#include <vector>
[email protected]d4905e2e2011-05-13 21:56:3210
11#include "base/file_util.h"
[email protected]6b931152011-05-20 21:02:3512#include "base/format_macros.h"
[email protected]d4905e2e2011-05-13 21:56:3213#include "base/logging.h"
[email protected]0a7328532011-05-13 23:54:4314#include "base/message_loop.h"
[email protected]58b7c5a62011-08-15 13:09:2715#include "base/stl_util.h"
[email protected]6b931152011-05-20 21:02:3516#include "base/stringprintf.h"
[email protected]4ce532f2013-03-27 22:03:4017#include "base/strings/string_number_conversions.h"
[email protected]13ac53532013-03-30 00:27:0018#include "base/strings/sys_string_conversions.h"
[email protected]906265872013-06-07 22:40:4519#include "base/strings/utf_string_conversions.h"
[email protected]17258682013-06-05 13:38:4020#include "base/time.h"
[email protected]d4905e2e2011-05-13 21:56:3221#include "googleurl/src/gurl.h"
[email protected]391550b2013-05-10 04:34:1222#include "webkit/base/origin_url_conversions.h"
[email protected]f25e1132013-05-24 13:58:0423#include "webkit/browser/fileapi/file_observers.h"
[email protected]c6f9203a2013-05-28 02:08:0724#include "webkit/browser/fileapi/file_system_context.h"
25#include "webkit/browser/fileapi/file_system_operation_context.h"
26#include "webkit/browser/fileapi/file_system_url.h"
[email protected]5a20d042013-05-22 12:54:1827#include "webkit/browser/fileapi/native_file_util.h"
[email protected]0b7fcc12013-05-30 13:04:1428#include "webkit/browser/fileapi/sandbox_isolated_origin_database.h"
[email protected]28f051c32013-05-21 05:15:2629#include "webkit/browser/fileapi/sandbox_mount_point_provider.h"
[email protected]0b7fcc12013-05-30 13:04:1430#include "webkit/browser/fileapi/sandbox_origin_database.h"
[email protected]7df9fe92013-05-28 06:49:4631#include "webkit/browser/fileapi/syncable/syncable_file_system_util.h"
[email protected]7660ec92013-05-30 05:12:3932#include "webkit/browser/quota/quota_manager.h"
[email protected]61d271f32013-05-28 04:59:2333#include "webkit/common/fileapi/file_system_util.h"
[email protected]d4905e2e2011-05-13 21:56:3234
[email protected]294dd0312012-05-11 07:35:1335// Example of various paths:
[email protected]949f25a2012-06-27 01:53:0936// void ObfuscatedFileUtil::DoSomething(const FileSystemURL& url) {
[email protected]a3ef4832013-02-02 05:12:3337// base::FilePath virtual_path = url.path();
38// base::FilePath local_path = GetLocalFilePath(url);
[email protected]294dd0312012-05-11 07:35:1339//
[email protected]95af7372012-05-28 07:51:2040// NativeFileUtil::DoSomething(local_path);
41// file_util::DoAnother(local_path);
[email protected]294dd0312012-05-11 07:35:1342// }
43
[email protected]08f8feb2012-02-26 11:53:5044namespace fileapi {
45
[email protected]d4905e2e2011-05-13 21:56:3246namespace {
47
[email protected]e6bbd9c2013-05-16 10:46:4548typedef SandboxDirectoryDatabase::FileId FileId;
49typedef SandboxDirectoryDatabase::FileInfo FileInfo;
[email protected]294dd0312012-05-11 07:35:1350
[email protected]d4905e2e2011-05-13 21:56:3251void InitFileInfo(
[email protected]e6bbd9c2013-05-16 10:46:4552 SandboxDirectoryDatabase::FileInfo* file_info,
53 SandboxDirectoryDatabase::FileId parent_id,
[email protected]a3ef4832013-02-02 05:12:3354 const base::FilePath::StringType& file_name) {
[email protected]d4905e2e2011-05-13 21:56:3255 DCHECK(file_info);
56 file_info->parent_id = parent_id;
[email protected]d4905e2e2011-05-13 21:56:3257 file_info->name = file_name;
[email protected]d4905e2e2011-05-13 21:56:3258}
59
[email protected]0c5ebe32011-08-19 22:37:1660// Costs computed as per crbug.com/86114, based on the LevelDB implementation of
61// path storage under Linux. It's not clear if that will differ on Windows, on
[email protected]a3ef4832013-02-02 05:12:3362// which base::FilePath uses wide chars [since they're converted to UTF-8 for storage
[email protected]0c5ebe32011-08-19 22:37:1663// anyway], but as long as the cost is high enough that one can't cheat on quota
64// by storing data in paths, it doesn't need to be all that accurate.
[email protected]172205b2011-08-30 03:36:4465const int64 kPathCreationQuotaCost = 146; // Bytes per inode, basically.
66const int64 kPathByteQuotaCost = 2; // Bytes per byte of path length in UTF-8.
[email protected]0c5ebe32011-08-19 22:37:1667
[email protected]f49dfc882012-04-05 15:02:0668int64 UsageForPath(size_t length) {
69 return kPathCreationQuotaCost +
70 static_cast<int64>(length) * kPathByteQuotaCost;
[email protected]0c5ebe32011-08-19 22:37:1671}
72
[email protected]f49dfc882012-04-05 15:02:0673bool AllocateQuota(FileSystemOperationContext* context, int64 growth) {
[email protected]294dd0312012-05-11 07:35:1374 if (context->allowed_bytes_growth() == quota::QuotaManager::kNoLimit)
75 return true;
76
[email protected]0c5ebe32011-08-19 22:37:1677 int64 new_quota = context->allowed_bytes_growth() - growth;
[email protected]f49dfc882012-04-05 15:02:0678 if (growth > 0 && new_quota < 0)
79 return false;
80 context->set_allowed_bytes_growth(new_quota);
[email protected]ecdfd6c52012-04-11 13:35:4481 return true;
[email protected]0c5ebe32011-08-19 22:37:1682}
83
[email protected]f49dfc882012-04-05 15:02:0684void UpdateUsage(
[email protected]08f8feb2012-02-26 11:53:5085 FileSystemOperationContext* context,
[email protected]caf66702012-09-07 07:02:2086 const FileSystemURL& url,
[email protected]f49dfc882012-04-05 15:02:0687 int64 growth) {
[email protected]caf66702012-09-07 07:02:2088 context->update_observers()->Notify(
89 &FileUpdateObserver::OnUpdate, MakeTuple(url, growth));
[email protected]0c5ebe32011-08-19 22:37:1690}
91
[email protected]e6bbd9c2013-05-16 10:46:4592void TouchDirectory(SandboxDirectoryDatabase* db, FileId dir_id) {
[email protected]fad625e2f2011-12-08 05:38:0393 DCHECK(db);
94 if (!db->UpdateModificationTime(dir_id, base::Time::Now()))
95 NOTREACHED();
96}
97
[email protected]17258682013-06-05 13:38:4098class Deleter {
99 public:
100 explicit Deleter(ObfuscatedFileUtil* util) : util_(util) {}
101
102 void operator()(bool* ptr) const {
103 if (*ptr)
104 util_->ResetObjectLifetimeTracker();
105 delete ptr;
106 }
107
108 private:
109 ObfuscatedFileUtil* util_;
110};
111
112void MaybeDropDatabases(
113 ObfuscatedFileUtil* util,
114 scoped_refptr<base::SequencedTaskRunner> file_task_runner,
115 scoped_ptr<bool, Deleter> object_still_alive,
116 int64 db_flush_delay_seconds) {
117 // If object isn't alive, DB has already been dropped by dtor.
118 if (!*object_still_alive)
119 return;
120
121 // Check to see if DB was recently used. If yes, restart timer so it triggers
122 // again in kFlushDelaySeconds from the last time it was used.
123 base::TimeDelta last_used_delta =
124 base::TimeTicks::Now() - util->db_last_use_time();
125 int64 next_timer_delta = db_flush_delay_seconds - last_used_delta.InSeconds();
126 if (next_timer_delta > 0) {
127 file_task_runner->PostDelayedTask(
128 FROM_HERE,
129 base::Bind(&MaybeDropDatabases,
130 base::Unretained(util),
131 file_task_runner,
132 base::Passed(&object_still_alive),
133 db_flush_delay_seconds),
134 base::TimeDelta::FromSeconds(next_timer_delta));
135 return;
136 }
137
138 util->DropDatabases();
139}
140
[email protected]a3ef4832013-02-02 05:12:33141const base::FilePath::CharType kTemporaryDirectoryName[] = FILE_PATH_LITERAL("t");
142const base::FilePath::CharType kPersistentDirectoryName[] = FILE_PATH_LITERAL("p");
143const base::FilePath::CharType kSyncableDirectoryName[] = FILE_PATH_LITERAL("s");
[email protected]6b931152011-05-20 21:02:35144
[email protected]d4905e2e2011-05-13 21:56:32145} // namespace
146
[email protected]d4905e2e2011-05-13 21:56:32147using base::PlatformFile;
148using base::PlatformFileError;
149
[email protected]7878ece2011-09-05 11:41:49150class ObfuscatedFileEnumerator
[email protected]d4905e2e2011-05-13 21:56:32151 : public FileSystemFileUtil::AbstractFileEnumerator {
152 public:
[email protected]7878ece2011-09-05 11:41:49153 ObfuscatedFileEnumerator(
[email protected]e6bbd9c2013-05-16 10:46:45154 SandboxDirectoryDatabase* db,
[email protected]172205b2011-08-30 03:36:44155 FileSystemOperationContext* context,
[email protected]294dd0312012-05-11 07:35:13156 ObfuscatedFileUtil* obfuscated_file_util,
[email protected]949f25a2012-06-27 01:53:09157 const FileSystemURL& root_url,
[email protected]566f223792012-03-07 03:24:28158 bool recursive)
[email protected]294dd0312012-05-11 07:35:13159 : db_(db),
[email protected]172205b2011-08-30 03:36:44160 context_(context),
[email protected]294dd0312012-05-11 07:35:13161 obfuscated_file_util_(obfuscated_file_util),
[email protected]949f25a2012-06-27 01:53:09162 origin_(root_url.origin()),
163 type_(root_url.type()),
[email protected]f1a9c522012-07-25 22:08:27164 recursive_(recursive),
165 current_file_id_(0) {
[email protected]a3ef4832013-02-02 05:12:33166 base::FilePath root_virtual_path = root_url.path();
[email protected]d4905e2e2011-05-13 21:56:32167 FileId file_id;
[email protected]294dd0312012-05-11 07:35:13168
169 if (!db_->GetFileWithPath(root_virtual_path, &file_id))
[email protected]d4905e2e2011-05-13 21:56:32170 return;
[email protected]294dd0312012-05-11 07:35:13171
172 FileRecord record = { file_id, root_virtual_path };
[email protected]566f223792012-03-07 03:24:28173 recurse_queue_.push(record);
[email protected]d4905e2e2011-05-13 21:56:32174 }
175
[email protected]294dd0312012-05-11 07:35:13176 virtual ~ObfuscatedFileEnumerator() {}
[email protected]d4905e2e2011-05-13 21:56:32177
[email protected]a3ef4832013-02-02 05:12:33178 virtual base::FilePath Next() OVERRIDE {
[email protected]d4905e2e2011-05-13 21:56:32179 ProcessRecurseQueue();
[email protected]294dd0312012-05-11 07:35:13180 if (display_stack_.empty())
[email protected]a3ef4832013-02-02 05:12:33181 return base::FilePath();
[email protected]a3938912012-03-27 14:00:55182
[email protected]294dd0312012-05-11 07:35:13183 current_file_id_ = display_stack_.back();
184 display_stack_.pop_back();
[email protected]a3938912012-03-27 14:00:55185
[email protected]294dd0312012-05-11 07:35:13186 FileInfo file_info;
[email protected]a3ef4832013-02-02 05:12:33187 base::FilePath platform_file_path;
[email protected]294dd0312012-05-11 07:35:13188 base::PlatformFileError error =
189 obfuscated_file_util_->GetFileInfoInternal(
190 db_, context_, origin_, type_, current_file_id_,
191 &file_info, &current_platform_file_info_, &platform_file_path);
192 if (error != base::PLATFORM_FILE_OK)
193 return Next();
194
[email protected]a3ef4832013-02-02 05:12:33195 base::FilePath virtual_path =
[email protected]294dd0312012-05-11 07:35:13196 current_parent_virtual_path_.Append(file_info.name);
197 if (recursive_ && file_info.is_directory()) {
198 FileRecord record = { current_file_id_, virtual_path };
199 recurse_queue_.push(record);
[email protected]a3938912012-03-27 14:00:55200 }
[email protected]294dd0312012-05-11 07:35:13201 return virtual_path;
[email protected]d4905e2e2011-05-13 21:56:32202 }
203
[email protected]172205b2011-08-30 03:36:44204 virtual int64 Size() OVERRIDE {
[email protected]294dd0312012-05-11 07:35:13205 return current_platform_file_info_.size;
[email protected]172205b2011-08-30 03:36:44206 }
207
[email protected]2c514f32012-03-14 05:58:13208 virtual base::Time LastModifiedTime() OVERRIDE {
[email protected]294dd0312012-05-11 07:35:13209 return current_platform_file_info_.last_modified;
[email protected]2c514f32012-03-14 05:58:13210 }
211
[email protected]172205b2011-08-30 03:36:44212 virtual bool IsDirectory() OVERRIDE {
[email protected]294dd0312012-05-11 07:35:13213 return current_platform_file_info_.is_directory;
[email protected]d4905e2e2011-05-13 21:56:32214 }
215
216 private:
[email protected]e6bbd9c2013-05-16 10:46:45217 typedef SandboxDirectoryDatabase::FileId FileId;
218 typedef SandboxDirectoryDatabase::FileInfo FileInfo;
[email protected]d4905e2e2011-05-13 21:56:32219
220 struct FileRecord {
221 FileId file_id;
[email protected]a3ef4832013-02-02 05:12:33222 base::FilePath virtual_path;
[email protected]d4905e2e2011-05-13 21:56:32223 };
224
225 void ProcessRecurseQueue() {
[email protected]294dd0312012-05-11 07:35:13226 while (display_stack_.empty() && !recurse_queue_.empty()) {
227 FileRecord entry = recurse_queue_.front();
[email protected]d4905e2e2011-05-13 21:56:32228 recurse_queue_.pop();
[email protected]294dd0312012-05-11 07:35:13229 if (!db_->ListChildren(entry.file_id, &display_stack_)) {
230 display_stack_.clear();
[email protected]d4905e2e2011-05-13 21:56:32231 return;
[email protected]d4905e2e2011-05-13 21:56:32232 }
[email protected]294dd0312012-05-11 07:35:13233 current_parent_virtual_path_ = entry.virtual_path;
[email protected]d4905e2e2011-05-13 21:56:32234 }
235 }
236
[email protected]e6bbd9c2013-05-16 10:46:45237 SandboxDirectoryDatabase* db_;
[email protected]172205b2011-08-30 03:36:44238 FileSystemOperationContext* context_;
[email protected]294dd0312012-05-11 07:35:13239 ObfuscatedFileUtil* obfuscated_file_util_;
240 GURL origin_;
241 FileSystemType type_;
[email protected]566f223792012-03-07 03:24:28242 bool recursive_;
[email protected]294dd0312012-05-11 07:35:13243
244 std::queue<FileRecord> recurse_queue_;
245 std::vector<FileId> display_stack_;
[email protected]a3ef4832013-02-02 05:12:33246 base::FilePath current_parent_virtual_path_;
[email protected]294dd0312012-05-11 07:35:13247
248 FileId current_file_id_;
249 base::PlatformFileInfo current_platform_file_info_;
[email protected]d4905e2e2011-05-13 21:56:32250};
251
[email protected]7878ece2011-09-05 11:41:49252class ObfuscatedOriginEnumerator
253 : public ObfuscatedFileUtil::AbstractOriginEnumerator {
[email protected]fcc2d5f2011-05-23 22:06:26254 public:
[email protected]e6bbd9c2013-05-16 10:46:45255 typedef SandboxOriginDatabase::OriginRecord OriginRecord;
[email protected]7878ece2011-09-05 11:41:49256 ObfuscatedOriginEnumerator(
[email protected]0b7fcc12013-05-30 13:04:14257 SandboxOriginDatabaseInterface* origin_database,
[email protected]a3ef4832013-02-02 05:12:33258 const base::FilePath& base_file_path)
[email protected]294dd0312012-05-11 07:35:13259 : base_file_path_(base_file_path) {
[email protected]fcc2d5f2011-05-23 22:06:26260 if (origin_database)
261 origin_database->ListAllOrigins(&origins_);
262 }
263
[email protected]7fd8fa4f2013-02-07 05:43:50264 virtual ~ObfuscatedOriginEnumerator() {}
[email protected]fcc2d5f2011-05-23 22:06:26265
266 // Returns the next origin. Returns empty if there are no more origins.
267 virtual GURL Next() OVERRIDE {
268 OriginRecord record;
269 if (!origins_.empty()) {
270 record = origins_.back();
271 origins_.pop_back();
272 }
273 current_ = record;
[email protected]391550b2013-05-10 04:34:12274 return webkit_base::GetOriginURLFromIdentifier(UTF8ToUTF16(record.origin));
[email protected]fcc2d5f2011-05-23 22:06:26275 }
276
277 // Returns the current origin's information.
278 virtual bool HasFileSystemType(FileSystemType type) const OVERRIDE {
279 if (current_.path.empty())
280 return false;
[email protected]a3ef4832013-02-02 05:12:33281 base::FilePath::StringType type_string =
[email protected]7878ece2011-09-05 11:41:49282 ObfuscatedFileUtil::GetDirectoryNameForType(type);
[email protected]fcc2d5f2011-05-23 22:06:26283 if (type_string.empty()) {
284 NOTREACHED();
285 return false;
286 }
[email protected]0b7fcc12013-05-30 13:04:14287 base::FilePath path =
288 base_file_path_.Append(current_.path).Append(type_string);
[email protected]fcc2d5f2011-05-23 22:06:26289 return file_util::DirectoryExists(path);
290 }
291
292 private:
293 std::vector<OriginRecord> origins_;
294 OriginRecord current_;
[email protected]a3ef4832013-02-02 05:12:33295 base::FilePath base_file_path_;
[email protected]fcc2d5f2011-05-23 22:06:26296};
297
[email protected]7878ece2011-09-05 11:41:49298ObfuscatedFileUtil::ObfuscatedFileUtil(
[email protected]0b7fcc12013-05-30 13:04:14299 quota::SpecialStoragePolicy* special_storage_policy,
[email protected]17258682013-06-05 13:38:40300 const base::FilePath& file_system_directory,
301 base::SequencedTaskRunner* file_task_runner)
[email protected]0b7fcc12013-05-30 13:04:14302 : special_storage_policy_(special_storage_policy),
[email protected]17258682013-06-05 13:38:40303 file_system_directory_(file_system_directory),
304 file_task_runner_(file_task_runner),
305 db_flush_delay_seconds_(10 * 60), // 10 mins.
306 object_lifetime_tracker_(NULL) {
[email protected]7878ece2011-09-05 11:41:49307}
[email protected]fcc2d5f2011-05-23 22:06:26308
[email protected]3cfc10f2012-05-24 01:20:41309ObfuscatedFileUtil::~ObfuscatedFileUtil() {
[email protected]17258682013-06-05 13:38:40310 // Mark as deleted so that the callback doesn't run on invalid object.
311 if (object_lifetime_tracker_)
312 *object_lifetime_tracker_ = false;
313
[email protected]3cfc10f2012-05-24 01:20:41314 DropDatabases();
315}
316
[email protected]7878ece2011-09-05 11:41:49317PlatformFileError ObfuscatedFileUtil::CreateOrOpen(
318 FileSystemOperationContext* context,
[email protected]949f25a2012-06-27 01:53:09319 const FileSystemURL& url, int file_flags,
[email protected]7878ece2011-09-05 11:41:49320 PlatformFile* file_handle, bool* created) {
[email protected]f7ac94e2013-04-30 08:34:50321 PlatformFileError error = CreateOrOpenInternal(context, url, file_flags,
322 file_handle, created);
323 if (*file_handle != base::kInvalidPlatformFileValue &&
324 file_flags & base::PLATFORM_FILE_WRITE &&
325 context->quota_limit_type() == quota::kQuotaLimitTypeUnlimited) {
326 DCHECK_EQ(base::PLATFORM_FILE_OK, error);
[email protected]f7ac94e2013-04-30 08:34:50327 context->file_system_context()->GetQuotaUtil(url.type())->
328 StickyInvalidateUsageCache(url.origin(), url.type());
[email protected]c4e6f9c2012-09-09 17:42:10329 }
[email protected]7878ece2011-09-05 11:41:49330 return error;
331}
332
[email protected]95af7372012-05-28 07:51:20333PlatformFileError ObfuscatedFileUtil::Close(
334 FileSystemOperationContext* context,
335 base::PlatformFile file) {
336 return NativeFileUtil::Close(file);
337}
338
[email protected]7878ece2011-09-05 11:41:49339PlatformFileError ObfuscatedFileUtil::EnsureFileExists(
340 FileSystemOperationContext* context,
[email protected]949f25a2012-06-27 01:53:09341 const FileSystemURL& url,
[email protected]7878ece2011-09-05 11:41:49342 bool* created) {
[email protected]e6bbd9c2013-05-16 10:46:45343 SandboxDirectoryDatabase* db = GetDirectoryDatabase(
[email protected]949f25a2012-06-27 01:53:09344 url.origin(), url.type(), true);
[email protected]7878ece2011-09-05 11:41:49345 if (!db)
346 return base::PLATFORM_FILE_ERROR_FAILED;
[email protected]294dd0312012-05-11 07:35:13347
[email protected]7878ece2011-09-05 11:41:49348 FileId file_id;
[email protected]949f25a2012-06-27 01:53:09349 if (db->GetFileWithPath(url.path(), &file_id)) {
[email protected]7878ece2011-09-05 11:41:49350 FileInfo file_info;
351 if (!db->GetFileInfo(file_id, &file_info)) {
352 NOTREACHED();
353 return base::PLATFORM_FILE_ERROR_FAILED;
354 }
355 if (file_info.is_directory())
356 return base::PLATFORM_FILE_ERROR_NOT_A_FILE;
357 if (created)
358 *created = false;
359 return base::PLATFORM_FILE_OK;
360 }
361 FileId parent_id;
[email protected]8a020f62013-02-18 08:05:44362 if (!db->GetFileWithPath(VirtualPath::DirName(url.path()), &parent_id))
[email protected]7878ece2011-09-05 11:41:49363 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
364
365 FileInfo file_info;
[email protected]08f8feb2012-02-26 11:53:50366 InitFileInfo(&file_info, parent_id,
[email protected]949f25a2012-06-27 01:53:09367 VirtualPath::BaseName(url.path()).value());
[email protected]f49dfc882012-04-05 15:02:06368
369 int64 growth = UsageForPath(file_info.name.size());
370 if (!AllocateQuota(context, growth))
[email protected]7878ece2011-09-05 11:41:49371 return base::PLATFORM_FILE_ERROR_NO_SPACE;
[email protected]294dd0312012-05-11 07:35:13372 PlatformFileError error = CreateFile(
[email protected]a3ef4832013-02-02 05:12:33373 context, base::FilePath(), url.origin(), url.type(), &file_info, 0, NULL);
[email protected]f49dfc882012-04-05 15:02:06374 if (created && base::PLATFORM_FILE_OK == error) {
[email protected]7878ece2011-09-05 11:41:49375 *created = true;
[email protected]caf66702012-09-07 07:02:20376 UpdateUsage(context, url, growth);
[email protected]c4e6f9c2012-09-09 17:42:10377 context->change_observers()->Notify(
378 &FileChangeObserver::OnCreateFile, MakeTuple(url));
[email protected]f49dfc882012-04-05 15:02:06379 }
[email protected]7878ece2011-09-05 11:41:49380 return error;
381}
382
383PlatformFileError ObfuscatedFileUtil::CreateDirectory(
384 FileSystemOperationContext* context,
[email protected]949f25a2012-06-27 01:53:09385 const FileSystemURL& url,
[email protected]7878ece2011-09-05 11:41:49386 bool exclusive,
387 bool recursive) {
[email protected]e6bbd9c2013-05-16 10:46:45388 SandboxDirectoryDatabase* db = GetDirectoryDatabase(
[email protected]949f25a2012-06-27 01:53:09389 url.origin(), url.type(), true);
[email protected]7878ece2011-09-05 11:41:49390 if (!db)
391 return base::PLATFORM_FILE_ERROR_FAILED;
[email protected]294dd0312012-05-11 07:35:13392
[email protected]8c5b3692012-11-20 09:56:49393 // TODO(kinuko): Remove this dirty hack when we fully support directory
394 // operations or clean up the code if we decided not to support directory
395 // operations. (http://crbug.com/161442)
[email protected]a11968d2013-06-04 23:54:44396 if ((url.type() == kFileSystemTypeSyncable ||
397 url.type() == kFileSystemTypeSyncableForInternalSync) &&
[email protected]0615243c2013-05-20 10:11:10398 !sync_file_system::IsSyncFSDirectoryOperationEnabled()) {
[email protected]8c5b3692012-11-20 09:56:49399 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION;
400 }
401
[email protected]7878ece2011-09-05 11:41:49402 FileId file_id;
[email protected]949f25a2012-06-27 01:53:09403 if (db->GetFileWithPath(url.path(), &file_id)) {
[email protected]7878ece2011-09-05 11:41:49404 FileInfo file_info;
405 if (exclusive)
406 return base::PLATFORM_FILE_ERROR_EXISTS;
407 if (!db->GetFileInfo(file_id, &file_info)) {
408 NOTREACHED();
409 return base::PLATFORM_FILE_ERROR_FAILED;
410 }
411 if (!file_info.is_directory())
412 return base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY;
413 return base::PLATFORM_FILE_OK;
414 }
415
[email protected]a3ef4832013-02-02 05:12:33416 std::vector<base::FilePath::StringType> components;
[email protected]949f25a2012-06-27 01:53:09417 VirtualPath::GetComponents(url.path(), &components);
[email protected]7878ece2011-09-05 11:41:49418 FileId parent_id = 0;
419 size_t index;
420 for (index = 0; index < components.size(); ++index) {
[email protected]a3ef4832013-02-02 05:12:33421 base::FilePath::StringType name = components[index];
[email protected]7878ece2011-09-05 11:41:49422 if (name == FILE_PATH_LITERAL("/"))
423 continue;
424 if (!db->GetChildWithName(parent_id, name, &parent_id))
425 break;
426 }
427 if (!recursive && components.size() - index > 1)
428 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
[email protected]fad625e2f2011-12-08 05:38:03429 bool first = true;
[email protected]7878ece2011-09-05 11:41:49430 for (; index < components.size(); ++index) {
431 FileInfo file_info;
432 file_info.name = components[index];
433 if (file_info.name == FILE_PATH_LITERAL("/"))
434 continue;
435 file_info.modification_time = base::Time::Now();
436 file_info.parent_id = parent_id;
[email protected]f49dfc882012-04-05 15:02:06437 int64 growth = UsageForPath(file_info.name.size());
438 if (!AllocateQuota(context, growth))
[email protected]7878ece2011-09-05 11:41:49439 return base::PLATFORM_FILE_ERROR_NO_SPACE;
440 if (!db->AddFileInfo(file_info, &parent_id)) {
441 NOTREACHED();
442 return base::PLATFORM_FILE_ERROR_FAILED;
443 }
[email protected]caf66702012-09-07 07:02:20444 UpdateUsage(context, url, growth);
[email protected]c4e6f9c2012-09-09 17:42:10445 context->change_observers()->Notify(
446 &FileChangeObserver::OnCreateDirectory, MakeTuple(url));
[email protected]fad625e2f2011-12-08 05:38:03447 if (first) {
448 first = false;
449 TouchDirectory(db, file_info.parent_id);
450 }
[email protected]7878ece2011-09-05 11:41:49451 }
452 return base::PLATFORM_FILE_OK;
453}
454
455PlatformFileError ObfuscatedFileUtil::GetFileInfo(
456 FileSystemOperationContext* context,
[email protected]949f25a2012-06-27 01:53:09457 const FileSystemURL& url,
[email protected]7878ece2011-09-05 11:41:49458 base::PlatformFileInfo* file_info,
[email protected]a3ef4832013-02-02 05:12:33459 base::FilePath* platform_file_path) {
[email protected]e6bbd9c2013-05-16 10:46:45460 SandboxDirectoryDatabase* db = GetDirectoryDatabase(
[email protected]949f25a2012-06-27 01:53:09461 url.origin(), url.type(), false);
[email protected]7878ece2011-09-05 11:41:49462 if (!db)
463 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
464 FileId file_id;
[email protected]949f25a2012-06-27 01:53:09465 if (!db->GetFileWithPath(url.path(), &file_id))
[email protected]7878ece2011-09-05 11:41:49466 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
467 FileInfo local_info;
[email protected]08f8feb2012-02-26 11:53:50468 return GetFileInfoInternal(db, context,
[email protected]949f25a2012-06-27 01:53:09469 url.origin(), url.type(),
[email protected]08f8feb2012-02-26 11:53:50470 file_id, &local_info,
471 file_info, platform_file_path);
[email protected]7878ece2011-09-05 11:41:49472}
473
[email protected]d109fcb2012-11-07 19:44:33474scoped_ptr<FileSystemFileUtil::AbstractFileEnumerator>
475 ObfuscatedFileUtil::CreateFileEnumerator(
[email protected]d4905e2e2011-05-13 21:56:32476 FileSystemOperationContext* context,
[email protected]5453ca052013-04-11 21:15:39477 const FileSystemURL& root_url) {
478 return CreateFileEnumerator(context, root_url, false /* recursive */);
[email protected]d4905e2e2011-05-13 21:56:32479}
480
[email protected]7878ece2011-09-05 11:41:49481PlatformFileError ObfuscatedFileUtil::GetLocalFilePath(
[email protected]f1ddaa42011-07-19 05:03:03482 FileSystemOperationContext* context,
[email protected]949f25a2012-06-27 01:53:09483 const FileSystemURL& url,
[email protected]a3ef4832013-02-02 05:12:33484 base::FilePath* local_path) {
[email protected]e6bbd9c2013-05-16 10:46:45485 SandboxDirectoryDatabase* db = GetDirectoryDatabase(
[email protected]949f25a2012-06-27 01:53:09486 url.origin(), url.type(), false);
[email protected]95af7372012-05-28 07:51:20487 if (!db)
[email protected]7878ece2011-09-05 11:41:49488 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
[email protected]95af7372012-05-28 07:51:20489 FileId file_id;
[email protected]949f25a2012-06-27 01:53:09490 if (!db->GetFileWithPath(url.path(), &file_id))
[email protected]95af7372012-05-28 07:51:20491 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
492 FileInfo file_info;
493 if (!db->GetFileInfo(file_id, &file_info) || file_info.is_directory()) {
494 NOTREACHED();
495 // Directories have no local file path.
496 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
497 }
498 *local_path = DataPathToLocalPath(
[email protected]949f25a2012-06-27 01:53:09499 url.origin(), url.type(), file_info.data_path);
[email protected]f1ddaa42011-07-19 05:03:03500
[email protected]95af7372012-05-28 07:51:20501 if (local_path->empty())
502 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
[email protected]d4905e2e2011-05-13 21:56:32503 return base::PLATFORM_FILE_OK;
504}
505
[email protected]7878ece2011-09-05 11:41:49506PlatformFileError ObfuscatedFileUtil::Touch(
507 FileSystemOperationContext* context,
[email protected]949f25a2012-06-27 01:53:09508 const FileSystemURL& url,
[email protected]7878ece2011-09-05 11:41:49509 const base::Time& last_access_time,
510 const base::Time& last_modified_time) {
[email protected]e6bbd9c2013-05-16 10:46:45511 SandboxDirectoryDatabase* db = GetDirectoryDatabase(
[email protected]949f25a2012-06-27 01:53:09512 url.origin(), url.type(), false);
[email protected]d4905e2e2011-05-13 21:56:32513 if (!db)
[email protected]7878ece2011-09-05 11:41:49514 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
[email protected]d4905e2e2011-05-13 21:56:32515 FileId file_id;
[email protected]949f25a2012-06-27 01:53:09516 if (!db->GetFileWithPath(url.path(), &file_id))
[email protected]7878ece2011-09-05 11:41:49517 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
518
519 FileInfo file_info;
520 if (!db->GetFileInfo(file_id, &file_info)) {
521 NOTREACHED();
522 return base::PLATFORM_FILE_ERROR_FAILED;
523 }
524 if (file_info.is_directory()) {
[email protected]fad625e2f2011-12-08 05:38:03525 if (!db->UpdateModificationTime(file_id, last_modified_time))
[email protected]7878ece2011-09-05 11:41:49526 return base::PLATFORM_FILE_ERROR_FAILED;
527 return base::PLATFORM_FILE_OK;
528 }
[email protected]a3ef4832013-02-02 05:12:33529 base::FilePath local_path = DataPathToLocalPath(
[email protected]949f25a2012-06-27 01:53:09530 url.origin(), url.type(), file_info.data_path);
[email protected]95af7372012-05-28 07:51:20531 return NativeFileUtil::Touch(
532 local_path, last_access_time, last_modified_time);
[email protected]7878ece2011-09-05 11:41:49533}
534
535PlatformFileError ObfuscatedFileUtil::Truncate(
536 FileSystemOperationContext* context,
[email protected]949f25a2012-06-27 01:53:09537 const FileSystemURL& url,
[email protected]7878ece2011-09-05 11:41:49538 int64 length) {
[email protected]ecdfd6c52012-04-11 13:35:44539 base::PlatformFileInfo file_info;
[email protected]a3ef4832013-02-02 05:12:33540 base::FilePath local_path;
[email protected]ecdfd6c52012-04-11 13:35:44541 base::PlatformFileError error =
[email protected]949f25a2012-06-27 01:53:09542 GetFileInfo(context, url, &file_info, &local_path);
[email protected]ecdfd6c52012-04-11 13:35:44543 if (error != base::PLATFORM_FILE_OK)
544 return error;
545
546 int64 growth = length - file_info.size;
547 if (!AllocateQuota(context, growth))
548 return base::PLATFORM_FILE_ERROR_NO_SPACE;
[email protected]95af7372012-05-28 07:51:20549 error = NativeFileUtil::Truncate(local_path, length);
[email protected]c4e6f9c2012-09-09 17:42:10550 if (error == base::PLATFORM_FILE_OK) {
[email protected]caf66702012-09-07 07:02:20551 UpdateUsage(context, url, growth);
[email protected]c4e6f9c2012-09-09 17:42:10552 context->change_observers()->Notify(
553 &FileChangeObserver::OnModifyFile, MakeTuple(url));
554 }
[email protected]ecdfd6c52012-04-11 13:35:44555 return error;
[email protected]7878ece2011-09-05 11:41:49556}
557
[email protected]7878ece2011-09-05 11:41:49558PlatformFileError ObfuscatedFileUtil::CopyOrMoveFile(
559 FileSystemOperationContext* context,
[email protected]949f25a2012-06-27 01:53:09560 const FileSystemURL& src_url,
561 const FileSystemURL& dest_url,
[email protected]7878ece2011-09-05 11:41:49562 bool copy) {
563 // Cross-filesystem copies and moves should be handled via CopyInForeignFile.
[email protected]949f25a2012-06-27 01:53:09564 DCHECK(src_url.origin() == dest_url.origin());
565 DCHECK(src_url.type() == dest_url.type());
[email protected]7878ece2011-09-05 11:41:49566
[email protected]e6bbd9c2013-05-16 10:46:45567 SandboxDirectoryDatabase* db = GetDirectoryDatabase(
[email protected]949f25a2012-06-27 01:53:09568 src_url.origin(), src_url.type(), true);
[email protected]7878ece2011-09-05 11:41:49569 if (!db)
570 return base::PLATFORM_FILE_ERROR_FAILED;
[email protected]294dd0312012-05-11 07:35:13571
[email protected]7878ece2011-09-05 11:41:49572 FileId src_file_id;
[email protected]949f25a2012-06-27 01:53:09573 if (!db->GetFileWithPath(src_url.path(), &src_file_id))
[email protected]7878ece2011-09-05 11:41:49574 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
[email protected]294dd0312012-05-11 07:35:13575
[email protected]7878ece2011-09-05 11:41:49576 FileId dest_file_id;
[email protected]949f25a2012-06-27 01:53:09577 bool overwrite = db->GetFileWithPath(dest_url.path(),
[email protected]08f8feb2012-02-26 11:53:50578 &dest_file_id);
[email protected]294dd0312012-05-11 07:35:13579
[email protected]7878ece2011-09-05 11:41:49580 FileInfo src_file_info;
[email protected]294dd0312012-05-11 07:35:13581 base::PlatformFileInfo src_platform_file_info;
[email protected]a3ef4832013-02-02 05:12:33582 base::FilePath src_local_path;
[email protected]294dd0312012-05-11 07:35:13583 base::PlatformFileError error = GetFileInfoInternal(
[email protected]949f25a2012-06-27 01:53:09584 db, context, src_url.origin(), src_url.type(), src_file_id,
[email protected]95af7372012-05-28 07:51:20585 &src_file_info, &src_platform_file_info, &src_local_path);
[email protected]294dd0312012-05-11 07:35:13586 if (error != base::PLATFORM_FILE_OK)
587 return error;
588 if (src_file_info.is_directory())
[email protected]bab213be2013-01-23 15:13:08589 return base::PLATFORM_FILE_ERROR_NOT_A_FILE;
[email protected]294dd0312012-05-11 07:35:13590
591 FileInfo dest_file_info;
592 base::PlatformFileInfo dest_platform_file_info; // overwrite case only
[email protected]a3ef4832013-02-02 05:12:33593 base::FilePath dest_local_path; // overwrite case only
[email protected]7878ece2011-09-05 11:41:49594 if (overwrite) {
[email protected]294dd0312012-05-11 07:35:13595 base::PlatformFileError error = GetFileInfoInternal(
[email protected]949f25a2012-06-27 01:53:09596 db, context, dest_url.origin(), dest_url.type(), dest_file_id,
[email protected]95af7372012-05-28 07:51:20597 &dest_file_info, &dest_platform_file_info, &dest_local_path);
[email protected]294dd0312012-05-11 07:35:13598 if (error == base::PLATFORM_FILE_ERROR_NOT_FOUND)
599 overwrite = false; // fallback to non-overwrite case
600 else if (error != base::PLATFORM_FILE_OK)
601 return error;
602 else if (dest_file_info.is_directory())
[email protected]bab213be2013-01-23 15:13:08603 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION;
[email protected]7878ece2011-09-05 11:41:49604 }
[email protected]294dd0312012-05-11 07:35:13605 if (!overwrite) {
606 FileId dest_parent_id;
[email protected]8a020f62013-02-18 08:05:44607 if (!db->GetFileWithPath(VirtualPath::DirName(dest_url.path()),
[email protected]294dd0312012-05-11 07:35:13608 &dest_parent_id)) {
[email protected]294dd0312012-05-11 07:35:13609 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
610 }
611
612 dest_file_info = src_file_info;
613 dest_file_info.parent_id = dest_parent_id;
614 dest_file_info.name =
[email protected]949f25a2012-06-27 01:53:09615 VirtualPath::BaseName(dest_url.path()).value();
[email protected]294dd0312012-05-11 07:35:13616 }
617
618 int64 growth = 0;
619 if (copy)
620 growth += src_platform_file_info.size;
621 else
622 growth -= UsageForPath(src_file_info.name.size());
623 if (overwrite)
624 growth -= dest_platform_file_info.size;
625 else
626 growth += UsageForPath(dest_file_info.name.size());
627 if (!AllocateQuota(context, growth))
628 return base::PLATFORM_FILE_ERROR_NO_SPACE;
629
[email protected]7878ece2011-09-05 11:41:49630 /*
631 * Copy-with-overwrite
632 * Just overwrite data file
633 * Copy-without-overwrite
634 * Copy backing file
635 * Create new metadata pointing to new backing file.
636 * Move-with-overwrite
637 * transaction:
638 * Remove source entry.
639 * Point target entry to source entry's backing file.
640 * Delete target entry's old backing file
641 * Move-without-overwrite
642 * Just update metadata
643 */
[email protected]294dd0312012-05-11 07:35:13644 error = base::PLATFORM_FILE_ERROR_FAILED;
[email protected]7878ece2011-09-05 11:41:49645 if (copy) {
[email protected]7878ece2011-09-05 11:41:49646 if (overwrite) {
[email protected]95af7372012-05-28 07:51:20647 error = NativeFileUtil::CopyOrMoveFile(
648 src_local_path,
649 dest_local_path,
[email protected]294dd0312012-05-11 07:35:13650 true /* copy */);
651 } else { // non-overwrite
[email protected]95af7372012-05-28 07:51:20652 error = CreateFile(context, src_local_path,
[email protected]949f25a2012-06-27 01:53:09653 dest_url.origin(), dest_url.type(),
[email protected]294dd0312012-05-11 07:35:13654 &dest_file_info, 0, NULL);
[email protected]7878ece2011-09-05 11:41:49655 }
[email protected]294dd0312012-05-11 07:35:13656 } else {
[email protected]7878ece2011-09-05 11:41:49657 if (overwrite) {
[email protected]294dd0312012-05-11 07:35:13658 if (db->OverwritingMoveFile(src_file_id, dest_file_id)) {
659 if (base::PLATFORM_FILE_OK !=
[email protected]95af7372012-05-28 07:51:20660 NativeFileUtil::DeleteFile(dest_local_path))
[email protected]294dd0312012-05-11 07:35:13661 LOG(WARNING) << "Leaked a backing file.";
662 error = base::PLATFORM_FILE_OK;
663 } else {
664 error = base::PLATFORM_FILE_ERROR_FAILED;
[email protected]7878ece2011-09-05 11:41:49665 }
[email protected]294dd0312012-05-11 07:35:13666 } else { // non-overwrite
667 if (db->UpdateFileInfo(src_file_id, dest_file_info))
668 error = base::PLATFORM_FILE_OK;
669 else
670 error = base::PLATFORM_FILE_ERROR_FAILED;
[email protected]7878ece2011-09-05 11:41:49671 }
672 }
[email protected]294dd0312012-05-11 07:35:13673
674 if (error != base::PLATFORM_FILE_OK)
675 return error;
676
[email protected]c4e6f9c2012-09-09 17:42:10677 if (overwrite) {
678 context->change_observers()->Notify(
679 &FileChangeObserver::OnModifyFile,
680 MakeTuple(dest_url));
681 } else {
682 context->change_observers()->Notify(
683 &FileChangeObserver::OnCreateFileFrom,
684 MakeTuple(dest_url, src_url));
685 }
686
687 if (!copy) {
688 context->change_observers()->Notify(
689 &FileChangeObserver::OnRemoveFile, MakeTuple(src_url));
[email protected]294dd0312012-05-11 07:35:13690 TouchDirectory(db, src_file_info.parent_id);
[email protected]c4e6f9c2012-09-09 17:42:10691 }
692
[email protected]294dd0312012-05-11 07:35:13693 TouchDirectory(db, dest_file_info.parent_id);
694
[email protected]caf66702012-09-07 07:02:20695 UpdateUsage(context, dest_url, growth);
[email protected]294dd0312012-05-11 07:35:13696 return error;
[email protected]7878ece2011-09-05 11:41:49697}
698
699PlatformFileError ObfuscatedFileUtil::CopyInForeignFile(
700 FileSystemOperationContext* context,
[email protected]a3ef4832013-02-02 05:12:33701 const base::FilePath& src_file_path,
[email protected]949f25a2012-06-27 01:53:09702 const FileSystemURL& dest_url) {
[email protected]e6bbd9c2013-05-16 10:46:45703 SandboxDirectoryDatabase* db = GetDirectoryDatabase(
[email protected]949f25a2012-06-27 01:53:09704 dest_url.origin(), dest_url.type(), true);
[email protected]7878ece2011-09-05 11:41:49705 if (!db)
706 return base::PLATFORM_FILE_ERROR_FAILED;
[email protected]294dd0312012-05-11 07:35:13707
708 base::PlatformFileInfo src_platform_file_info;
709 if (!file_util::GetFileInfo(src_file_path, &src_platform_file_info))
710 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
711
[email protected]7878ece2011-09-05 11:41:49712 FileId dest_file_id;
[email protected]949f25a2012-06-27 01:53:09713 bool overwrite = db->GetFileWithPath(dest_url.path(),
[email protected]08f8feb2012-02-26 11:53:50714 &dest_file_id);
[email protected]294dd0312012-05-11 07:35:13715
[email protected]7878ece2011-09-05 11:41:49716 FileInfo dest_file_info;
[email protected]294dd0312012-05-11 07:35:13717 base::PlatformFileInfo dest_platform_file_info; // overwrite case only
[email protected]7878ece2011-09-05 11:41:49718 if (overwrite) {
[email protected]a3ef4832013-02-02 05:12:33719 base::FilePath dest_local_path;
[email protected]294dd0312012-05-11 07:35:13720 base::PlatformFileError error = GetFileInfoInternal(
[email protected]949f25a2012-06-27 01:53:09721 db, context, dest_url.origin(), dest_url.type(), dest_file_id,
[email protected]95af7372012-05-28 07:51:20722 &dest_file_info, &dest_platform_file_info, &dest_local_path);
[email protected]294dd0312012-05-11 07:35:13723 if (error == base::PLATFORM_FILE_ERROR_NOT_FOUND)
724 overwrite = false; // fallback to non-overwrite case
725 else if (error != base::PLATFORM_FILE_OK)
726 return error;
727 else if (dest_file_info.is_directory())
[email protected]bab213be2013-01-23 15:13:08728 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION;
[email protected]294dd0312012-05-11 07:35:13729 }
730 if (!overwrite) {
[email protected]7878ece2011-09-05 11:41:49731 FileId dest_parent_id;
[email protected]8a020f62013-02-18 08:05:44732 if (!db->GetFileWithPath(VirtualPath::DirName(dest_url.path()),
[email protected]bab213be2013-01-23 15:13:08733 &dest_parent_id)) {
[email protected]7878ece2011-09-05 11:41:49734 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
735 }
[email protected]bab213be2013-01-23 15:13:08736 if (!dest_file_info.is_directory())
737 return base::PLATFORM_FILE_ERROR_FAILED;
[email protected]7878ece2011-09-05 11:41:49738 InitFileInfo(&dest_file_info, dest_parent_id,
[email protected]949f25a2012-06-27 01:53:09739 VirtualPath::BaseName(dest_url.path()).value());
[email protected]7878ece2011-09-05 11:41:49740 }
[email protected]294dd0312012-05-11 07:35:13741
742 int64 growth = src_platform_file_info.size;
743 if (overwrite)
744 growth -= dest_platform_file_info.size;
745 else
746 growth += UsageForPath(dest_file_info.name.size());
747 if (!AllocateQuota(context, growth))
748 return base::PLATFORM_FILE_ERROR_NO_SPACE;
749
750 base::PlatformFileError error;
751 if (overwrite) {
[email protected]a3ef4832013-02-02 05:12:33752 base::FilePath dest_local_path = DataPathToLocalPath(
[email protected]949f25a2012-06-27 01:53:09753 dest_url.origin(), dest_url.type(), dest_file_info.data_path);
[email protected]95af7372012-05-28 07:51:20754 error = NativeFileUtil::CopyOrMoveFile(
755 src_file_path, dest_local_path, true);
[email protected]294dd0312012-05-11 07:35:13756 } else {
757 error = CreateFile(context, src_file_path,
[email protected]949f25a2012-06-27 01:53:09758 dest_url.origin(), dest_url.type(),
[email protected]294dd0312012-05-11 07:35:13759 &dest_file_info, 0, NULL);
760 }
761
762 if (error != base::PLATFORM_FILE_OK)
763 return error;
764
[email protected]c4e6f9c2012-09-09 17:42:10765 if (overwrite) {
766 context->change_observers()->Notify(
767 &FileChangeObserver::OnModifyFile, MakeTuple(dest_url));
768 } else {
769 context->change_observers()->Notify(
770 &FileChangeObserver::OnCreateFile, MakeTuple(dest_url));
771 }
772
[email protected]caf66702012-09-07 07:02:20773 UpdateUsage(context, dest_url, growth);
[email protected]294dd0312012-05-11 07:35:13774 TouchDirectory(db, dest_file_info.parent_id);
775 return base::PLATFORM_FILE_OK;
[email protected]7878ece2011-09-05 11:41:49776}
777
778PlatformFileError ObfuscatedFileUtil::DeleteFile(
779 FileSystemOperationContext* context,
[email protected]949f25a2012-06-27 01:53:09780 const FileSystemURL& url) {
[email protected]e6bbd9c2013-05-16 10:46:45781 SandboxDirectoryDatabase* db = GetDirectoryDatabase(
[email protected]949f25a2012-06-27 01:53:09782 url.origin(), url.type(), true);
[email protected]7878ece2011-09-05 11:41:49783 if (!db)
784 return base::PLATFORM_FILE_ERROR_FAILED;
785 FileId file_id;
[email protected]949f25a2012-06-27 01:53:09786 if (!db->GetFileWithPath(url.path(), &file_id))
[email protected]7878ece2011-09-05 11:41:49787 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
[email protected]294dd0312012-05-11 07:35:13788
[email protected]d4905e2e2011-05-13 21:56:32789 FileInfo file_info;
[email protected]294dd0312012-05-11 07:35:13790 base::PlatformFileInfo platform_file_info;
[email protected]a3ef4832013-02-02 05:12:33791 base::FilePath local_path;
[email protected]294dd0312012-05-11 07:35:13792 base::PlatformFileError error = GetFileInfoInternal(
[email protected]949f25a2012-06-27 01:53:09793 db, context, url.origin(), url.type(), file_id,
[email protected]95af7372012-05-28 07:51:20794 &file_info, &platform_file_info, &local_path);
[email protected]294dd0312012-05-11 07:35:13795 if (error != base::PLATFORM_FILE_ERROR_NOT_FOUND &&
796 error != base::PLATFORM_FILE_OK)
797 return error;
798
[email protected]92b808802013-01-28 05:10:51799 if (file_info.is_directory())
800 return base::PLATFORM_FILE_ERROR_NOT_A_FILE;
[email protected]294dd0312012-05-11 07:35:13801
802 int64 growth = -UsageForPath(file_info.name.size()) - platform_file_info.size;
803 AllocateQuota(context, growth);
[email protected]7878ece2011-09-05 11:41:49804 if (!db->RemoveFileInfo(file_id)) {
805 NOTREACHED();
806 return base::PLATFORM_FILE_ERROR_FAILED;
807 }
[email protected]caf66702012-09-07 07:02:20808 UpdateUsage(context, url, growth);
[email protected]fad625e2f2011-12-08 05:38:03809 TouchDirectory(db, file_info.parent_id);
[email protected]294dd0312012-05-11 07:35:13810
[email protected]c4e6f9c2012-09-09 17:42:10811 context->change_observers()->Notify(
812 &FileChangeObserver::OnRemoveFile, MakeTuple(url));
813
[email protected]294dd0312012-05-11 07:35:13814 if (error == base::PLATFORM_FILE_ERROR_NOT_FOUND)
815 return base::PLATFORM_FILE_OK;
816
[email protected]95af7372012-05-28 07:51:20817 error = NativeFileUtil::DeleteFile(local_path);
[email protected]294dd0312012-05-11 07:35:13818 if (base::PLATFORM_FILE_OK != error)
819 LOG(WARNING) << "Leaked a backing file.";
[email protected]7878ece2011-09-05 11:41:49820 return base::PLATFORM_FILE_OK;
[email protected]d4905e2e2011-05-13 21:56:32821}
822
[email protected]bab213be2013-01-23 15:13:08823PlatformFileError ObfuscatedFileUtil::DeleteDirectory(
[email protected]7878ece2011-09-05 11:41:49824 FileSystemOperationContext* context,
[email protected]949f25a2012-06-27 01:53:09825 const FileSystemURL& url) {
[email protected]e6bbd9c2013-05-16 10:46:45826 SandboxDirectoryDatabase* db = GetDirectoryDatabase(
[email protected]949f25a2012-06-27 01:53:09827 url.origin(), url.type(), true);
[email protected]7878ece2011-09-05 11:41:49828 if (!db)
829 return base::PLATFORM_FILE_ERROR_FAILED;
[email protected]294dd0312012-05-11 07:35:13830
[email protected]7878ece2011-09-05 11:41:49831 FileId file_id;
[email protected]949f25a2012-06-27 01:53:09832 if (!db->GetFileWithPath(url.path(), &file_id))
[email protected]7878ece2011-09-05 11:41:49833 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
834 FileInfo file_info;
[email protected]bab213be2013-01-23 15:13:08835 if (!db->GetFileInfo(file_id, &file_info)) {
[email protected]7878ece2011-09-05 11:41:49836 NOTREACHED();
837 return base::PLATFORM_FILE_ERROR_FAILED;
838 }
[email protected]bab213be2013-01-23 15:13:08839 if (!file_info.is_directory())
840 return base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY;
[email protected]7878ece2011-09-05 11:41:49841 if (!db->RemoveFileInfo(file_id))
842 return base::PLATFORM_FILE_ERROR_NOT_EMPTY;
[email protected]f49dfc882012-04-05 15:02:06843 int64 growth = -UsageForPath(file_info.name.size());
844 AllocateQuota(context, growth);
[email protected]caf66702012-09-07 07:02:20845 UpdateUsage(context, url, growth);
[email protected]fad625e2f2011-12-08 05:38:03846 TouchDirectory(db, file_info.parent_id);
[email protected]c4e6f9c2012-09-09 17:42:10847 context->change_observers()->Notify(
848 &FileChangeObserver::OnRemoveDirectory, MakeTuple(url));
[email protected]7878ece2011-09-05 11:41:49849 return base::PLATFORM_FILE_OK;
850}
851
[email protected]7ab45cfa82013-04-26 07:13:20852webkit_blob::ScopedFile ObfuscatedFileUtil::CreateSnapshotFile(
[email protected]d0a1f0372012-07-19 11:17:37853 FileSystemOperationContext* context,
854 const FileSystemURL& url,
[email protected]7ab45cfa82013-04-26 07:13:20855 base::PlatformFileError* error,
[email protected]d0a1f0372012-07-19 11:17:37856 base::PlatformFileInfo* file_info,
[email protected]7ab45cfa82013-04-26 07:13:20857 base::FilePath* platform_path) {
[email protected]826df822012-08-04 01:23:56858 // We're just returning the local file information.
[email protected]7ab45cfa82013-04-26 07:13:20859 *error = GetFileInfo(context, url, file_info, platform_path);
860 if (*error == base::PLATFORM_FILE_OK && file_info->is_directory) {
[email protected]aeba9c12013-01-28 10:44:42861 *file_info = base::PlatformFileInfo();
[email protected]7ab45cfa82013-04-26 07:13:20862 *error = base::PLATFORM_FILE_ERROR_NOT_A_FILE;
[email protected]aeba9c12013-01-28 10:44:42863 }
[email protected]7ab45cfa82013-04-26 07:13:20864 return webkit_blob::ScopedFile();
[email protected]bab213be2013-01-23 15:13:08865}
866
[email protected]5453ca052013-04-11 21:15:39867scoped_ptr<FileSystemFileUtil::AbstractFileEnumerator>
868 ObfuscatedFileUtil::CreateFileEnumerator(
869 FileSystemOperationContext* context,
870 const FileSystemURL& root_url,
871 bool recursive) {
[email protected]e6bbd9c2013-05-16 10:46:45872 SandboxDirectoryDatabase* db = GetDirectoryDatabase(
[email protected]5453ca052013-04-11 21:15:39873 root_url.origin(), root_url.type(), false);
874 if (!db) {
875 return scoped_ptr<AbstractFileEnumerator>(new EmptyFileEnumerator());
876 }
877 return scoped_ptr<AbstractFileEnumerator>(
878 new ObfuscatedFileEnumerator(db, context, this, root_url, recursive));
879}
880
[email protected]bab213be2013-01-23 15:13:08881bool ObfuscatedFileUtil::IsDirectoryEmpty(
882 FileSystemOperationContext* context,
883 const FileSystemURL& url) {
[email protected]e6bbd9c2013-05-16 10:46:45884 SandboxDirectoryDatabase* db = GetDirectoryDatabase(
[email protected]bab213be2013-01-23 15:13:08885 url.origin(), url.type(), false);
886 if (!db)
887 return true; // Not a great answer, but it's what others do.
888 FileId file_id;
889 if (!db->GetFileWithPath(url.path(), &file_id))
890 return true; // Ditto.
891 FileInfo file_info;
892 if (!db->GetFileInfo(file_id, &file_info)) {
893 DCHECK(!file_id);
894 // It's the root directory and the database hasn't been initialized yet.
895 return true;
896 }
897 if (!file_info.is_directory())
898 return true;
899 std::vector<FileId> children;
900 // TODO(ericu): This could easily be made faster with help from the database.
901 if (!db->ListChildren(file_id, &children))
902 return true;
903 return children.empty();
[email protected]d0a1f0372012-07-19 11:17:37904}
905
[email protected]a3ef4832013-02-02 05:12:33906base::FilePath ObfuscatedFileUtil::GetDirectoryForOriginAndType(
[email protected]d247b842012-05-08 06:43:36907 const GURL& origin,
908 FileSystemType type,
909 bool create,
910 base::PlatformFileError* error_code) {
[email protected]a3ef4832013-02-02 05:12:33911 base::FilePath origin_dir = GetDirectoryForOrigin(origin, create, error_code);
[email protected]c7a4a10f2011-05-19 04:56:06912 if (origin_dir.empty())
[email protected]a3ef4832013-02-02 05:12:33913 return base::FilePath();
914 base::FilePath::StringType type_string = GetDirectoryNameForType(type);
[email protected]c7a4a10f2011-05-19 04:56:06915 if (type_string.empty()) {
916 LOG(WARNING) << "Unknown filesystem type requested:" << type;
[email protected]d247b842012-05-08 06:43:36917
918 if (error_code)
919 *error_code = base::PLATFORM_FILE_ERROR_INVALID_URL;
[email protected]a3ef4832013-02-02 05:12:33920 return base::FilePath();
[email protected]c7a4a10f2011-05-19 04:56:06921 }
[email protected]a3ef4832013-02-02 05:12:33922 base::FilePath path = origin_dir.Append(type_string);
[email protected]bf48a1f2012-07-11 09:35:03923 base::PlatformFileError error = base::PLATFORM_FILE_OK;
[email protected]fcc2d5f2011-05-23 22:06:26924 if (!file_util::DirectoryExists(path) &&
[email protected]d247b842012-05-08 06:43:36925 (!create || !file_util::CreateDirectory(path))) {
[email protected]bf48a1f2012-07-11 09:35:03926 error = create ?
[email protected]d247b842012-05-08 06:43:36927 base::PLATFORM_FILE_ERROR_FAILED :
928 base::PLATFORM_FILE_ERROR_NOT_FOUND;
[email protected]d247b842012-05-08 06:43:36929 }
930
931 if (error_code)
[email protected]bf48a1f2012-07-11 09:35:03932 *error_code = error;
[email protected]fcc2d5f2011-05-23 22:06:26933 return path;
[email protected]c7a4a10f2011-05-19 04:56:06934}
935
[email protected]7878ece2011-09-05 11:41:49936bool ObfuscatedFileUtil::DeleteDirectoryForOriginAndType(
[email protected]6ff17052011-07-12 06:06:07937 const GURL& origin, FileSystemType type) {
[email protected]bf48a1f2012-07-11 09:35:03938 base::PlatformFileError error = base::PLATFORM_FILE_OK;
[email protected]0b7fcc12013-05-30 13:04:14939 base::FilePath origin_type_path = GetDirectoryForOriginAndType(
940 origin, type, false, &error);
[email protected]bf48a1f2012-07-11 09:35:03941 if (origin_type_path.empty())
[email protected]6ff17052011-07-12 06:06:07942 return true;
943
[email protected]bf48a1f2012-07-11 09:35:03944 if (error != base::PLATFORM_FILE_ERROR_NOT_FOUND) {
945 // TODO(dmikurube): Consider the return value of DestroyDirectoryDatabase.
946 // We ignore its error now since 1) it doesn't matter the final result, and
947 // 2) it always returns false in Windows because of LevelDB's
948 // implementation.
949 // Information about failure would be useful for debugging.
950 DestroyDirectoryDatabase(origin, type);
951 if (!file_util::Delete(origin_type_path, true /* recursive */))
952 return false;
953 }
[email protected]c0229d02011-07-14 06:54:18954
[email protected]8a020f62013-02-18 08:05:44955 base::FilePath origin_path = VirtualPath::DirName(origin_type_path);
[email protected]d247b842012-05-08 06:43:36956 DCHECK_EQ(origin_path.value(),
957 GetDirectoryForOrigin(origin, false, NULL).value());
[email protected]c0229d02011-07-14 06:54:18958
[email protected]69fe5a72012-09-13 05:05:16959 // At this point we are sure we had successfully deleted the origin/type
960 // directory (i.e. we're ready to just return true).
[email protected]69fe5a72012-09-13 05:05:16961 // See if we have other directories in this origin directory.
962 std::vector<FileSystemType> other_types;
963 if (type != kFileSystemTypeTemporary)
964 other_types.push_back(kFileSystemTypeTemporary);
965 if (type != kFileSystemTypePersistent)
966 other_types.push_back(kFileSystemTypePersistent);
967 if (type != kFileSystemTypeSyncable)
968 other_types.push_back(kFileSystemTypeSyncable);
[email protected]a11968d2013-06-04 23:54:44969 DCHECK(type != kFileSystemTypeSyncableForInternalSync);
[email protected]69fe5a72012-09-13 05:05:16970
971 for (size_t i = 0; i < other_types.size(); ++i) {
972 if (file_util::DirectoryExists(
973 origin_path.Append(GetDirectoryNameForType(other_types[i])))) {
974 // Other type's directory exists; just return true here.
975 return true;
976 }
[email protected]c0229d02011-07-14 06:54:18977 }
978
[email protected]69fe5a72012-09-13 05:05:16979 // No other directories seem exist. Try deleting the entire origin directory.
980 InitOriginDatabase(false);
[email protected]391550b2013-05-10 04:34:12981 if (origin_database_) {
982 origin_database_->RemovePathForOrigin(
983 UTF16ToUTF8(webkit_base::GetOriginIdentifierFromURL(origin)));
984 }
[email protected]69fe5a72012-09-13 05:05:16985 if (!file_util::Delete(origin_path, true /* recursive */))
986 return false;
987
[email protected]c0229d02011-07-14 06:54:18988 return true;
[email protected]6ff17052011-07-12 06:06:07989}
990
[email protected]fcc2d5f2011-05-23 22:06:26991// static
[email protected]a3ef4832013-02-02 05:12:33992base::FilePath::StringType ObfuscatedFileUtil::GetDirectoryNameForType(
[email protected]fcc2d5f2011-05-23 22:06:26993 FileSystemType type) {
[email protected]6b931152011-05-20 21:02:35994 switch (type) {
995 case kFileSystemTypeTemporary:
996 return kTemporaryDirectoryName;
997 case kFileSystemTypePersistent:
998 return kPersistentDirectoryName;
[email protected]69fe5a72012-09-13 05:05:16999 case kFileSystemTypeSyncable:
[email protected]a11968d2013-06-04 23:54:441000 case kFileSystemTypeSyncableForInternalSync:
[email protected]69fe5a72012-09-13 05:05:161001 return kSyncableDirectoryName;
[email protected]6b931152011-05-20 21:02:351002 case kFileSystemTypeUnknown:
1003 default:
[email protected]a3ef4832013-02-02 05:12:331004 return base::FilePath::StringType();
[email protected]6b931152011-05-20 21:02:351005 }
1006}
1007
[email protected]7878ece2011-09-05 11:41:491008ObfuscatedFileUtil::AbstractOriginEnumerator*
1009ObfuscatedFileUtil::CreateOriginEnumerator() {
[email protected]e6bbd9c2013-05-16 10:46:451010 std::vector<SandboxOriginDatabase::OriginRecord> origins;
[email protected]7878ece2011-09-05 11:41:491011
1012 InitOriginDatabase(false);
1013 return new ObfuscatedOriginEnumerator(
1014 origin_database_.get(), file_system_directory_);
1015}
1016
1017bool ObfuscatedFileUtil::DestroyDirectoryDatabase(
1018 const GURL& origin, FileSystemType type) {
[email protected]e7e46732012-01-05 11:45:551019 std::string type_string = GetFileSystemTypeString(type);
[email protected]7878ece2011-09-05 11:41:491020 if (type_string.empty()) {
1021 LOG(WARNING) << "Unknown filesystem type requested:" << type;
1022 return true;
1023 }
[email protected]391550b2013-05-10 04:34:121024 std::string key =
1025 UTF16ToUTF8(webkit_base::GetOriginIdentifierFromURL(origin)) +
1026 type_string;
[email protected]7878ece2011-09-05 11:41:491027 DirectoryMap::iterator iter = directories_.find(key);
1028 if (iter != directories_.end()) {
[email protected]e6bbd9c2013-05-16 10:46:451029 SandboxDirectoryDatabase* database = iter->second;
[email protected]7878ece2011-09-05 11:41:491030 directories_.erase(iter);
1031 delete database;
1032 }
1033
[email protected]bf48a1f2012-07-11 09:35:031034 PlatformFileError error = base::PLATFORM_FILE_OK;
[email protected]0b7fcc12013-05-30 13:04:141035 base::FilePath path = GetDirectoryForOriginAndType(
1036 origin, type, false, &error);
[email protected]bf48a1f2012-07-11 09:35:031037 if (path.empty() || error == base::PLATFORM_FILE_ERROR_NOT_FOUND)
[email protected]7878ece2011-09-05 11:41:491038 return true;
[email protected]e6bbd9c2013-05-16 10:46:451039 return SandboxDirectoryDatabase::DestroyDatabase(path);
[email protected]7878ece2011-09-05 11:41:491040}
1041
[email protected]17258682013-06-05 13:38:401042void ObfuscatedFileUtil::ResetObjectLifetimeTracker() {
1043 object_lifetime_tracker_ = NULL;
1044}
1045
1046void ObfuscatedFileUtil::DropDatabases() {
1047 origin_database_.reset();
1048 STLDeleteContainerPairSecondPointers(
1049 directories_.begin(), directories_.end());
1050 directories_.clear();
1051}
1052
[email protected]7878ece2011-09-05 11:41:491053// static
[email protected]a3ef4832013-02-02 05:12:331054int64 ObfuscatedFileUtil::ComputeFilePathCost(const base::FilePath& path) {
[email protected]f49dfc882012-04-05 15:02:061055 return UsageForPath(VirtualPath::BaseName(path).value().size());
[email protected]7878ece2011-09-05 11:41:491056}
1057
[email protected]a623aae2013-06-04 06:48:461058void ObfuscatedFileUtil::MaybePrepopulateDatabase() {
1059 base::FilePath isolated_origin_dir = file_system_directory_.Append(
1060 SandboxIsolatedOriginDatabase::kOriginDirectory);
1061 if (!file_util::DirectoryExists(isolated_origin_dir))
1062 return;
1063
1064 const FileSystemType kPrepopulateTypes[] = {
1065 kFileSystemTypePersistent, kFileSystemTypeTemporary
1066 };
1067
1068 // Prepulate the directory database(s) if and only if this instance is
1069 // initialized for isolated storage dedicated for a single origin.
1070 for (size_t i = 0; i < arraysize(kPrepopulateTypes); ++i) {
1071 const FileSystemType type = kPrepopulateTypes[i];
1072 base::FilePath::StringType type_string = GetDirectoryNameForType(type);
1073 DCHECK(!type_string.empty());
1074 base::FilePath path = isolated_origin_dir.Append(type_string);
1075 if (!file_util::DirectoryExists(path))
1076 continue;
1077 scoped_ptr<SandboxDirectoryDatabase> db(new SandboxDirectoryDatabase(path));
1078 if (db->Init(SandboxDirectoryDatabase::FAIL_ON_CORRUPTION)) {
1079 directories_[GetFileSystemTypeString(type)] = db.release();
1080 MarkUsed();
1081 // Don't populate more than one database, as it may rather hurt
1082 // performance.
1083 break;
1084 }
1085 }
1086}
1087
[email protected]7878ece2011-09-05 11:41:491088PlatformFileError ObfuscatedFileUtil::GetFileInfoInternal(
[email protected]e6bbd9c2013-05-16 10:46:451089 SandboxDirectoryDatabase* db,
[email protected]7878ece2011-09-05 11:41:491090 FileSystemOperationContext* context,
[email protected]08f8feb2012-02-26 11:53:501091 const GURL& origin,
1092 FileSystemType type,
[email protected]7878ece2011-09-05 11:41:491093 FileId file_id,
1094 FileInfo* local_info,
1095 base::PlatformFileInfo* file_info,
[email protected]a3ef4832013-02-02 05:12:331096 base::FilePath* platform_file_path) {
[email protected]7878ece2011-09-05 11:41:491097 DCHECK(db);
1098 DCHECK(context);
1099 DCHECK(file_info);
1100 DCHECK(platform_file_path);
1101
1102 if (!db->GetFileInfo(file_id, local_info)) {
1103 NOTREACHED();
1104 return base::PLATFORM_FILE_ERROR_FAILED;
1105 }
1106
1107 if (local_info->is_directory()) {
[email protected]294dd0312012-05-11 07:35:131108 file_info->size = 0;
[email protected]7878ece2011-09-05 11:41:491109 file_info->is_directory = true;
1110 file_info->is_symbolic_link = false;
1111 file_info->last_modified = local_info->modification_time;
[email protected]a3ef4832013-02-02 05:12:331112 *platform_file_path = base::FilePath();
[email protected]7878ece2011-09-05 11:41:491113 // We don't fill in ctime or atime.
1114 return base::PLATFORM_FILE_OK;
1115 }
1116 if (local_info->data_path.empty())
1117 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION;
[email protected]a3ef4832013-02-02 05:12:331118 base::FilePath local_path = DataPathToLocalPath(
[email protected]08f8feb2012-02-26 11:53:501119 origin, type, local_info->data_path);
[email protected]95af7372012-05-28 07:51:201120 base::PlatformFileError error = NativeFileUtil::GetFileInfo(
1121 local_path, file_info);
[email protected]272a9d12012-06-19 02:17:551122 // We should not follow symbolic links in sandboxed file system.
1123 if (file_util::IsLink(local_path)) {
1124 LOG(WARNING) << "Found a symbolic file.";
1125 error = base::PLATFORM_FILE_ERROR_NOT_FOUND;
1126 }
[email protected]95af7372012-05-28 07:51:201127 if (error == base::PLATFORM_FILE_OK) {
1128 *platform_file_path = local_path;
1129 } else if (error == base::PLATFORM_FILE_ERROR_NOT_FOUND) {
[email protected]294dd0312012-05-11 07:35:131130 LOG(WARNING) << "Lost a backing file.";
1131 InvalidateUsageCache(context, origin, type);
1132 if (!db->RemoveFileInfo(file_id))
1133 return base::PLATFORM_FILE_ERROR_FAILED;
1134 }
1135 return error;
[email protected]7878ece2011-09-05 11:41:491136}
1137
1138PlatformFileError ObfuscatedFileUtil::CreateFile(
1139 FileSystemOperationContext* context,
[email protected]a3ef4832013-02-02 05:12:331140 const base::FilePath& src_file_path,
[email protected]08f8feb2012-02-26 11:53:501141 const GURL& dest_origin,
1142 FileSystemType dest_type,
1143 FileInfo* dest_file_info, int file_flags, PlatformFile* handle) {
[email protected]7878ece2011-09-05 11:41:491144 if (handle)
1145 *handle = base::kInvalidPlatformFileValue;
[email protected]e6bbd9c2013-05-16 10:46:451146 SandboxDirectoryDatabase* db = GetDirectoryDatabase(
[email protected]08f8feb2012-02-26 11:53:501147 dest_origin, dest_type, true);
[email protected]7878ece2011-09-05 11:41:491148
[email protected]bf48a1f2012-07-11 09:35:031149 PlatformFileError error = base::PLATFORM_FILE_OK;
[email protected]0b7fcc12013-05-30 13:04:141150 base::FilePath root = GetDirectoryForOriginAndType(
1151 dest_origin, dest_type, false, &error);
[email protected]bf48a1f2012-07-11 09:35:031152 if (error != base::PLATFORM_FILE_OK)
1153 return error;
[email protected]95af7372012-05-28 07:51:201154
[email protected]a3ef4832013-02-02 05:12:331155 base::FilePath dest_local_path;
[email protected]bf48a1f2012-07-11 09:35:031156 error = GenerateNewLocalPath(db, context, dest_origin, dest_type,
1157 &dest_local_path);
[email protected]294dd0312012-05-11 07:35:131158 if (error != base::PLATFORM_FILE_OK)
[email protected]7878ece2011-09-05 11:41:491159 return error;
[email protected]08f8feb2012-02-26 11:53:501160
[email protected]7878ece2011-09-05 11:41:491161 bool created = false;
[email protected]294dd0312012-05-11 07:35:131162 if (!src_file_path.empty()) {
[email protected]7878ece2011-09-05 11:41:491163 DCHECK(!file_flags);
1164 DCHECK(!handle);
[email protected]95af7372012-05-28 07:51:201165 error = NativeFileUtil::CopyOrMoveFile(
1166 src_file_path, dest_local_path, true /* copy */);
[email protected]7878ece2011-09-05 11:41:491167 created = true;
1168 } else {
[email protected]95af7372012-05-28 07:51:201169 if (file_util::PathExists(dest_local_path)) {
1170 if (!file_util::Delete(dest_local_path, true /* recursive */)) {
[email protected]7878ece2011-09-05 11:41:491171 NOTREACHED();
1172 return base::PLATFORM_FILE_ERROR_FAILED;
1173 }
1174 LOG(WARNING) << "A stray file detected";
[email protected]294dd0312012-05-11 07:35:131175 InvalidateUsageCache(context, dest_origin, dest_type);
[email protected]7878ece2011-09-05 11:41:491176 }
1177
1178 if (handle) {
[email protected]95af7372012-05-28 07:51:201179 error = NativeFileUtil::CreateOrOpen(
1180 dest_local_path, file_flags, handle, &created);
[email protected]7878ece2011-09-05 11:41:491181 // If this succeeds, we must close handle on any subsequent error.
1182 } else {
1183 DCHECK(!file_flags); // file_flags is only used by CreateOrOpen.
[email protected]95af7372012-05-28 07:51:201184 error = NativeFileUtil::EnsureFileExists(dest_local_path, &created);
[email protected]7878ece2011-09-05 11:41:491185 }
1186 }
1187 if (error != base::PLATFORM_FILE_OK)
1188 return error;
1189
1190 if (!created) {
1191 NOTREACHED();
1192 if (handle) {
1193 DCHECK_NE(base::kInvalidPlatformFileValue, *handle);
1194 base::ClosePlatformFile(*handle);
[email protected]95af7372012-05-28 07:51:201195 file_util::Delete(dest_local_path, false /* recursive */);
[email protected]7878ece2011-09-05 11:41:491196 }
1197 return base::PLATFORM_FILE_ERROR_FAILED;
1198 }
[email protected]95af7372012-05-28 07:51:201199
1200 // This removes the root, including the trailing slash, leaving a relative
1201 // path.
[email protected]a3ef4832013-02-02 05:12:331202 dest_file_info->data_path = base::FilePath(
[email protected]95af7372012-05-28 07:51:201203 dest_local_path.value().substr(root.value().length() + 1));
1204
[email protected]7878ece2011-09-05 11:41:491205 FileId file_id;
[email protected]08f8feb2012-02-26 11:53:501206 if (!db->AddFileInfo(*dest_file_info, &file_id)) {
[email protected]7878ece2011-09-05 11:41:491207 if (handle) {
1208 DCHECK_NE(base::kInvalidPlatformFileValue, *handle);
1209 base::ClosePlatformFile(*handle);
1210 }
[email protected]95af7372012-05-28 07:51:201211 file_util::Delete(dest_local_path, false /* recursive */);
[email protected]7878ece2011-09-05 11:41:491212 return base::PLATFORM_FILE_ERROR_FAILED;
1213 }
[email protected]08f8feb2012-02-26 11:53:501214 TouchDirectory(db, dest_file_info->parent_id);
[email protected]7878ece2011-09-05 11:41:491215
1216 return base::PLATFORM_FILE_OK;
1217}
1218
[email protected]a3ef4832013-02-02 05:12:331219base::FilePath ObfuscatedFileUtil::DataPathToLocalPath(
1220 const GURL& origin, FileSystemType type, const base::FilePath& data_path) {
[email protected]bf48a1f2012-07-11 09:35:031221 PlatformFileError error = base::PLATFORM_FILE_OK;
[email protected]0b7fcc12013-05-30 13:04:141222 base::FilePath root = GetDirectoryForOriginAndType(
1223 origin, type, false, &error);
[email protected]bf48a1f2012-07-11 09:35:031224 if (error != base::PLATFORM_FILE_OK)
[email protected]a3ef4832013-02-02 05:12:331225 return base::FilePath();
[email protected]95af7372012-05-28 07:51:201226 return root.Append(data_path);
[email protected]6b931152011-05-20 21:02:351227}
1228
[email protected]a623aae2013-06-04 06:48:461229std::string ObfuscatedFileUtil::GetDirectoryDatabaseKey(
1230 const GURL& origin, FileSystemType type) {
1231 std::string type_string = GetFileSystemTypeString(type);
1232 if (type_string.empty()) {
1233 LOG(WARNING) << "Unknown filesystem type requested:" << type;
1234 return std::string();
1235 }
1236 // For isolated origin we just use a type string as a key.
1237 if (special_storage_policy_ &&
1238 special_storage_policy_->HasIsolatedStorage(origin)) {
1239 return type_string;
1240 }
1241 return UTF16ToUTF8(webkit_base::GetOriginIdentifierFromURL(origin)) +
1242 type_string;
1243}
1244
[email protected]b9566e7c2012-10-29 10:57:461245// TODO(ericu): How to do the whole validation-without-creation thing?
1246// We may not have quota even to create the database.
1247// Ah, in that case don't even get here?
[email protected]c7a4a10f2011-05-19 04:56:061248// Still doesn't answer the quota issue, though.
[email protected]e6bbd9c2013-05-16 10:46:451249SandboxDirectoryDatabase* ObfuscatedFileUtil::GetDirectoryDatabase(
[email protected]4b4d53bd2011-07-08 07:26:051250 const GURL& origin, FileSystemType type, bool create) {
[email protected]a623aae2013-06-04 06:48:461251 std::string key = GetDirectoryDatabaseKey(origin, type);
1252 if (key.empty())
[email protected]d4905e2e2011-05-13 21:56:321253 return NULL;
[email protected]a623aae2013-06-04 06:48:461254
[email protected]d4905e2e2011-05-13 21:56:321255 DirectoryMap::iterator iter = directories_.find(key);
[email protected]4b4d53bd2011-07-08 07:26:051256 if (iter != directories_.end()) {
1257 MarkUsed();
[email protected]d4905e2e2011-05-13 21:56:321258 return iter->second;
[email protected]4b4d53bd2011-07-08 07:26:051259 }
[email protected]d4905e2e2011-05-13 21:56:321260
[email protected]bf48a1f2012-07-11 09:35:031261 PlatformFileError error = base::PLATFORM_FILE_OK;
[email protected]0b7fcc12013-05-30 13:04:141262 base::FilePath path = GetDirectoryForOriginAndType(
1263 origin, type, create, &error);
[email protected]bf48a1f2012-07-11 09:35:031264 if (error != base::PLATFORM_FILE_OK) {
1265 LOG(WARNING) << "Failed to get origin+type directory: " << path.value();
[email protected]c7a4a10f2011-05-19 04:56:061266 return NULL;
[email protected]d4905e2e2011-05-13 21:56:321267 }
[email protected]4b4d53bd2011-07-08 07:26:051268 MarkUsed();
[email protected]e6bbd9c2013-05-16 10:46:451269 SandboxDirectoryDatabase* database = new SandboxDirectoryDatabase(path);
[email protected]d4905e2e2011-05-13 21:56:321270 directories_[key] = database;
1271 return database;
1272}
1273
[email protected]a3ef4832013-02-02 05:12:331274base::FilePath ObfuscatedFileUtil::GetDirectoryForOrigin(
[email protected]d247b842012-05-08 06:43:361275 const GURL& origin, bool create, base::PlatformFileError* error_code) {
[email protected]ff875be52013-06-02 23:47:381276 if (special_storage_policy_.get() &&
[email protected]0b7fcc12013-05-30 13:04:141277 special_storage_policy_->HasIsolatedStorage(origin)) {
[email protected]a623aae2013-06-04 06:48:461278 if (isolated_origin_.is_empty())
1279 isolated_origin_ = origin;
1280 CHECK_EQ(isolated_origin_.spec(), origin.spec())
1281 << "multiple origins for an isolated site";
[email protected]0b7fcc12013-05-30 13:04:141282 }
1283
[email protected]d247b842012-05-08 06:43:361284 if (!InitOriginDatabase(create)) {
1285 if (error_code) {
1286 *error_code = create ?
1287 base::PLATFORM_FILE_ERROR_FAILED :
1288 base::PLATFORM_FILE_ERROR_NOT_FOUND;
1289 }
[email protected]a3ef4832013-02-02 05:12:331290 return base::FilePath();
[email protected]d247b842012-05-08 06:43:361291 }
[email protected]a3ef4832013-02-02 05:12:331292 base::FilePath directory_name;
[email protected]391550b2013-05-10 04:34:121293 std::string id = UTF16ToUTF8(webkit_base::GetOriginIdentifierFromURL(origin));
[email protected]34583332011-08-31 08:59:471294
1295 bool exists_in_db = origin_database_->HasOriginPath(id);
[email protected]d247b842012-05-08 06:43:361296 if (!exists_in_db && !create) {
1297 if (error_code)
1298 *error_code = base::PLATFORM_FILE_ERROR_NOT_FOUND;
[email protected]a3ef4832013-02-02 05:12:331299 return base::FilePath();
[email protected]d247b842012-05-08 06:43:361300 }
1301 if (!origin_database_->GetPathForOrigin(id, &directory_name)) {
1302 if (error_code)
1303 *error_code = base::PLATFORM_FILE_ERROR_FAILED;
[email protected]a3ef4832013-02-02 05:12:331304 return base::FilePath();
[email protected]d247b842012-05-08 06:43:361305 }
[email protected]34583332011-08-31 08:59:471306
[email protected]a3ef4832013-02-02 05:12:331307 base::FilePath path = file_system_directory_.Append(directory_name);
[email protected]34583332011-08-31 08:59:471308 bool exists_in_fs = file_util::DirectoryExists(path);
1309 if (!exists_in_db && exists_in_fs) {
[email protected]d247b842012-05-08 06:43:361310 if (!file_util::Delete(path, true)) {
1311 if (error_code)
1312 *error_code = base::PLATFORM_FILE_ERROR_FAILED;
[email protected]a3ef4832013-02-02 05:12:331313 return base::FilePath();
[email protected]d247b842012-05-08 06:43:361314 }
[email protected]34583332011-08-31 08:59:471315 exists_in_fs = false;
1316 }
1317
1318 if (!exists_in_fs) {
[email protected]d247b842012-05-08 06:43:361319 if (!create || !file_util::CreateDirectory(path)) {
1320 if (error_code)
1321 *error_code = create ?
1322 base::PLATFORM_FILE_ERROR_FAILED :
1323 base::PLATFORM_FILE_ERROR_NOT_FOUND;
[email protected]a3ef4832013-02-02 05:12:331324 return base::FilePath();
[email protected]d247b842012-05-08 06:43:361325 }
[email protected]34583332011-08-31 08:59:471326 }
1327
[email protected]d247b842012-05-08 06:43:361328 if (error_code)
1329 *error_code = base::PLATFORM_FILE_OK;
1330
[email protected]83c0d3c2011-07-15 03:36:301331 return path;
1332}
1333
[email protected]294dd0312012-05-11 07:35:131334void ObfuscatedFileUtil::InvalidateUsageCache(
1335 FileSystemOperationContext* context,
1336 const GURL& origin,
1337 FileSystemType type) {
1338 context->file_system_context()->GetQuotaUtil(type)->
1339 InvalidateUsageCache(origin, type);
1340}
1341
[email protected]7878ece2011-09-05 11:41:491342void ObfuscatedFileUtil::MarkUsed() {
[email protected]17258682013-06-05 13:38:401343 db_last_use_time_ = base::TimeTicks::Now();
[email protected]0a7328532011-05-13 23:54:431344
[email protected]17258682013-06-05 13:38:401345 // If object_lifetime_tracker_ is valid, then callback timer already running.
1346 if (object_lifetime_tracker_)
1347 return;
1348
1349 // Initialize object lifetime tracker for the first time.
1350 object_lifetime_tracker_ = new bool(true);
1351
1352 scoped_ptr<bool, Deleter> scoper(object_lifetime_tracker_, Deleter(this));
1353 file_task_runner_->PostDelayedTask(
1354 FROM_HERE,
1355 base::Bind(&MaybeDropDatabases,
1356 base::Unretained(this),
1357 file_task_runner_,
1358 base::Passed(&scoper),
1359 db_flush_delay_seconds_),
1360 base::TimeDelta::FromSeconds(db_flush_delay_seconds_));
[email protected]d4905e2e2011-05-13 21:56:321361}
1362
[email protected]7878ece2011-09-05 11:41:491363bool ObfuscatedFileUtil::InitOriginDatabase(bool create) {
[email protected]0b7fcc12013-05-30 13:04:141364 if (origin_database_)
1365 return true;
1366
1367 if (!create && !file_util::DirectoryExists(file_system_directory_))
1368 return false;
1369 if (!file_util::CreateDirectory(file_system_directory_)) {
1370 LOG(WARNING) << "Failed to create FileSystem directory: " <<
1371 file_system_directory_.value();
1372 return false;
[email protected]fcc2d5f2011-05-23 22:06:261373 }
[email protected]0b7fcc12013-05-30 13:04:141374
1375 if (!isolated_origin_.is_empty()) {
1376 DCHECK(special_storage_policy_->HasIsolatedStorage(isolated_origin_));
1377 origin_database_.reset(
1378 new SandboxIsolatedOriginDatabase(
1379 UTF16ToUTF8(webkit_base::GetOriginIdentifierFromURL(
1380 isolated_origin_)),
1381 file_system_directory_));
1382 return true;
1383 }
1384
1385 origin_database_.reset(
1386 new SandboxOriginDatabase(file_system_directory_));
[email protected]fcc2d5f2011-05-23 22:06:261387 return true;
1388}
1389
[email protected]95af7372012-05-28 07:51:201390PlatformFileError ObfuscatedFileUtil::GenerateNewLocalPath(
[email protected]e6bbd9c2013-05-16 10:46:451391 SandboxDirectoryDatabase* db,
[email protected]294dd0312012-05-11 07:35:131392 FileSystemOperationContext* context,
1393 const GURL& origin,
1394 FileSystemType type,
[email protected]a3ef4832013-02-02 05:12:331395 base::FilePath* local_path) {
[email protected]95af7372012-05-28 07:51:201396 DCHECK(local_path);
[email protected]294dd0312012-05-11 07:35:131397 int64 number;
1398 if (!db || !db->GetNextInteger(&number))
1399 return base::PLATFORM_FILE_ERROR_FAILED;
1400
[email protected]bf48a1f2012-07-11 09:35:031401 PlatformFileError error = base::PLATFORM_FILE_OK;
[email protected]0b7fcc12013-05-30 13:04:141402 base::FilePath new_local_path = GetDirectoryForOriginAndType(
1403 origin, type, false, &error);
[email protected]bf48a1f2012-07-11 09:35:031404 if (error != base::PLATFORM_FILE_OK)
[email protected]294dd0312012-05-11 07:35:131405 return base::PLATFORM_FILE_ERROR_FAILED;
1406
[email protected]bf48a1f2012-07-11 09:35:031407 // We use the third- and fourth-to-last digits as the directory.
1408 int64 directory_number = number % 10000 / 100;
[email protected]95af7372012-05-28 07:51:201409 new_local_path = new_local_path.AppendASCII(
[email protected]7d3cbc92013-03-18 22:33:041410 base::StringPrintf("%02" PRId64, directory_number));
[email protected]294dd0312012-05-11 07:35:131411
[email protected]bf48a1f2012-07-11 09:35:031412 error = NativeFileUtil::CreateDirectory(
[email protected]95af7372012-05-28 07:51:201413 new_local_path, false /* exclusive */, false /* recursive */);
[email protected]294dd0312012-05-11 07:35:131414 if (error != base::PLATFORM_FILE_OK)
1415 return error;
1416
[email protected]7d3cbc92013-03-18 22:33:041417 *local_path =
1418 new_local_path.AppendASCII(base::StringPrintf("%08" PRId64, number));
[email protected]294dd0312012-05-11 07:35:131419 return base::PLATFORM_FILE_OK;
1420}
1421
[email protected]f7ac94e2013-04-30 08:34:501422PlatformFileError ObfuscatedFileUtil::CreateOrOpenInternal(
1423 FileSystemOperationContext* context,
1424 const FileSystemURL& url, int file_flags,
1425 PlatformFile* file_handle, bool* created) {
1426 DCHECK(!(file_flags & (base::PLATFORM_FILE_DELETE_ON_CLOSE |
1427 base::PLATFORM_FILE_HIDDEN | base::PLATFORM_FILE_EXCLUSIVE_READ |
1428 base::PLATFORM_FILE_EXCLUSIVE_WRITE)));
[email protected]e6bbd9c2013-05-16 10:46:451429 SandboxDirectoryDatabase* db = GetDirectoryDatabase(
[email protected]f7ac94e2013-04-30 08:34:501430 url.origin(), url.type(), true);
1431 if (!db)
1432 return base::PLATFORM_FILE_ERROR_FAILED;
1433 FileId file_id;
1434 if (!db->GetFileWithPath(url.path(), &file_id)) {
1435 // The file doesn't exist.
1436 if (!(file_flags & (base::PLATFORM_FILE_CREATE |
1437 base::PLATFORM_FILE_CREATE_ALWAYS | base::PLATFORM_FILE_OPEN_ALWAYS)))
1438 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
1439 FileId parent_id;
1440 if (!db->GetFileWithPath(VirtualPath::DirName(url.path()),
1441 &parent_id))
1442 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
1443 FileInfo file_info;
1444 InitFileInfo(&file_info, parent_id,
1445 VirtualPath::BaseName(url.path()).value());
1446
1447 int64 growth = UsageForPath(file_info.name.size());
1448 if (!AllocateQuota(context, growth))
1449 return base::PLATFORM_FILE_ERROR_NO_SPACE;
1450 PlatformFileError error = CreateFile(
1451 context, base::FilePath(),
1452 url.origin(), url.type(), &file_info,
1453 file_flags, file_handle);
1454 if (created && base::PLATFORM_FILE_OK == error) {
1455 *created = true;
1456 UpdateUsage(context, url, growth);
1457 context->change_observers()->Notify(
1458 &FileChangeObserver::OnCreateFile, MakeTuple(url));
1459 }
1460 return error;
1461 }
1462
1463 if (file_flags & base::PLATFORM_FILE_CREATE)
1464 return base::PLATFORM_FILE_ERROR_EXISTS;
1465
1466 base::PlatformFileInfo platform_file_info;
1467 base::FilePath local_path;
1468 FileInfo file_info;
1469 base::PlatformFileError error = GetFileInfoInternal(
1470 db, context, url.origin(), url.type(), file_id,
1471 &file_info, &platform_file_info, &local_path);
1472 if (error != base::PLATFORM_FILE_OK)
1473 return error;
1474 if (file_info.is_directory())
1475 return base::PLATFORM_FILE_ERROR_NOT_A_FILE;
1476
1477 int64 delta = 0;
1478 if (file_flags & (base::PLATFORM_FILE_CREATE_ALWAYS |
1479 base::PLATFORM_FILE_OPEN_TRUNCATED)) {
1480 // The file exists and we're truncating.
1481 delta = -platform_file_info.size;
1482 AllocateQuota(context, delta);
1483 }
1484
1485 error = NativeFileUtil::CreateOrOpen(
1486 local_path, file_flags, file_handle, created);
1487 if (error == base::PLATFORM_FILE_ERROR_NOT_FOUND) {
1488 // TODO(tzik): Also invalidate on-memory usage cache in UsageTracker.
1489 // TODO(tzik): Delete database entry after ensuring the file lost.
1490 InvalidateUsageCache(context, url.origin(), url.type());
1491 LOG(WARNING) << "Lost a backing file.";
1492 error = base::PLATFORM_FILE_ERROR_FAILED;
1493 }
1494
1495 // If truncating we need to update the usage.
1496 if (error == base::PLATFORM_FILE_OK && delta) {
1497 UpdateUsage(context, url, delta);
1498 context->change_observers()->Notify(
1499 &FileChangeObserver::OnModifyFile, MakeTuple(url));
1500 }
1501 return error;
1502}
1503
[email protected]d4905e2e2011-05-13 21:56:321504} // namespace fileapi