[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 1 | // Copyright (c) 2011 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 "webkit/fileapi/obfuscated_file_system_file_util.h" |
| 6 | |
| 7 | #include <queue> |
| 8 | |
| 9 | #include "base/file_util.h" |
[email protected] | 6b93115 | 2011-05-20 21:02:35 | [diff] [blame^] | 10 | #include "base/format_macros.h" |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 11 | #include "base/logging.h" |
[email protected] | 0a732853 | 2011-05-13 23:54:43 | [diff] [blame] | 12 | #include "base/message_loop.h" |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 13 | #include "base/string_number_conversions.h" |
[email protected] | 6b93115 | 2011-05-20 21:02:35 | [diff] [blame^] | 14 | #include "base/stringprintf.h" |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 15 | #include "base/sys_string_conversions.h" |
| 16 | #include "base/stl_util-inl.h" |
| 17 | #include "googleurl/src/gurl.h" |
| 18 | #include "webkit/fileapi/file_system_context.h" |
| 19 | #include "webkit/fileapi/file_system_operation_context.h" |
| 20 | #include "webkit/fileapi/file_system_path_manager.h" |
| 21 | #include "webkit/fileapi/quota_file_util.h" |
| 22 | #include "webkit/fileapi/sandbox_mount_point_provider.h" |
| 23 | |
| 24 | // TODO(ericu): Every instance of FileSystemFileUtil in this file should switch |
| 25 | // to QuotaFileUtil as soon as I sort out FileSystemPathManager's and |
| 26 | // SandboxMountPointProvider's lookups of the root path for a filesystem. |
| 27 | namespace { |
| 28 | |
[email protected] | 0a732853 | 2011-05-13 23:54:43 | [diff] [blame] | 29 | const int64 kFlushDelaySeconds = 10 * 60; // 10 minutes |
| 30 | |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 31 | const char kOriginDatabaseName[] = "Origins"; |
| 32 | const char kDirectoryDatabaseName[] = "Paths"; |
| 33 | |
| 34 | void InitFileInfo( |
| 35 | fileapi::FileSystemDirectoryDatabase::FileInfo* file_info, |
| 36 | fileapi::FileSystemDirectoryDatabase::FileId parent_id, |
[email protected] | 6b93115 | 2011-05-20 21:02:35 | [diff] [blame^] | 37 | const FilePath::StringType& file_name) { |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 38 | DCHECK(file_info); |
| 39 | file_info->parent_id = parent_id; |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 40 | file_info->name = file_name; |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 41 | } |
| 42 | |
[email protected] | 6b93115 | 2011-05-20 21:02:35 | [diff] [blame^] | 43 | const FilePath::CharType kLegacyDataDirectory[] = FILE_PATH_LITERAL("Legacy"); |
| 44 | |
| 45 | const FilePath::CharType kTemporaryDirectoryName[] = FILE_PATH_LITERAL("t"); |
| 46 | const FilePath::CharType kPersistentDirectoryName[] = FILE_PATH_LITERAL("p"); |
| 47 | |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 48 | } // namespace |
| 49 | |
| 50 | namespace fileapi { |
| 51 | |
| 52 | using base::PlatformFile; |
| 53 | using base::PlatformFileError; |
| 54 | |
| 55 | ObfuscatedFileSystemFileUtil::ObfuscatedFileSystemFileUtil( |
| 56 | const FilePath& file_system_directory) |
| 57 | : file_system_directory_(file_system_directory) { |
| 58 | } |
| 59 | |
| 60 | ObfuscatedFileSystemFileUtil::~ObfuscatedFileSystemFileUtil() { |
| 61 | DropDatabases(); |
| 62 | } |
| 63 | |
| 64 | PlatformFileError ObfuscatedFileSystemFileUtil::CreateOrOpen( |
| 65 | FileSystemOperationContext* context, |
| 66 | const FilePath& virtual_path, int file_flags, |
| 67 | PlatformFile* file_handle, bool* created) { |
| 68 | DCHECK(!(file_flags & (base::PLATFORM_FILE_DELETE_ON_CLOSE | |
| 69 | base::PLATFORM_FILE_HIDDEN | base::PLATFORM_FILE_EXCLUSIVE_READ | |
| 70 | base::PLATFORM_FILE_EXCLUSIVE_WRITE))); |
| 71 | FileSystemDirectoryDatabase* db = |
| 72 | GetDirectoryDatabase(context->src_origin_url(), context->src_type()); |
| 73 | if (!db) |
| 74 | return base::PLATFORM_FILE_ERROR_FAILED; |
| 75 | FileId file_id; |
| 76 | if (!db->GetFileWithPath(virtual_path, &file_id)) { |
| 77 | // The file doesn't exist. |
| 78 | if (!(file_flags & (base::PLATFORM_FILE_CREATE | |
| 79 | base::PLATFORM_FILE_CREATE_ALWAYS))) |
| 80 | return base::PLATFORM_FILE_ERROR_NOT_FOUND; |
| 81 | FileId parent_id; |
| 82 | if (!db->GetFileWithPath(virtual_path.DirName(), &parent_id)) |
| 83 | return base::PLATFORM_FILE_ERROR_NOT_FOUND; |
| 84 | FileInfo file_info; |
[email protected] | 6b93115 | 2011-05-20 21:02:35 | [diff] [blame^] | 85 | InitFileInfo(&file_info, parent_id, virtual_path.BaseName().value()); |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 86 | PlatformFileError error = CreateFile( |
[email protected] | 6b93115 | 2011-05-20 21:02:35 | [diff] [blame^] | 87 | context, context->src_origin_url(), context->src_type(), FilePath(), |
| 88 | &file_info, file_flags, file_handle); |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 89 | if (created && base::PLATFORM_FILE_OK == error) |
| 90 | *created = true; |
| 91 | return error; |
| 92 | } |
| 93 | if (file_flags & base::PLATFORM_FILE_CREATE) |
| 94 | return base::PLATFORM_FILE_ERROR_EXISTS; |
| 95 | |
| 96 | FileInfo file_info; |
| 97 | if (!db->GetFileInfo(file_id, &file_info)) { |
| 98 | NOTREACHED(); |
| 99 | return base::PLATFORM_FILE_ERROR_FAILED; |
| 100 | } |
| 101 | if (file_info.is_directory()) |
| 102 | return base::PLATFORM_FILE_ERROR_NOT_A_FILE; |
[email protected] | 6b93115 | 2011-05-20 21:02:35 | [diff] [blame^] | 103 | FilePath data_path = DataPathToLocalPath(context->src_origin_url(), |
| 104 | context->src_type(), file_info.data_path); |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 105 | return FileSystemFileUtil::GetInstance()->CreateOrOpen( |
[email protected] | 6b93115 | 2011-05-20 21:02:35 | [diff] [blame^] | 106 | context, data_path, file_flags, file_handle, created); |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 107 | } |
| 108 | |
| 109 | PlatformFileError ObfuscatedFileSystemFileUtil::EnsureFileExists( |
| 110 | FileSystemOperationContext* context, |
| 111 | const FilePath& virtual_path, |
| 112 | bool* created) { |
| 113 | FileSystemDirectoryDatabase* db = |
| 114 | GetDirectoryDatabase(context->src_origin_url(), context->src_type()); |
| 115 | if (!db) |
| 116 | return base::PLATFORM_FILE_ERROR_FAILED; |
| 117 | FileId file_id; |
| 118 | if (db->GetFileWithPath(virtual_path, &file_id)) { |
| 119 | FileInfo file_info; |
| 120 | if (!db->GetFileInfo(file_id, &file_info)) { |
| 121 | NOTREACHED(); |
| 122 | return base::PLATFORM_FILE_ERROR_FAILED; |
| 123 | } |
| 124 | if (file_info.is_directory()) |
| 125 | return base::PLATFORM_FILE_ERROR_NOT_A_FILE; |
| 126 | if (created) |
| 127 | *created = false; |
| 128 | return base::PLATFORM_FILE_OK; |
| 129 | } |
| 130 | FileId parent_id; |
| 131 | if (!db->GetFileWithPath(virtual_path.DirName(), &parent_id)) |
| 132 | return base::PLATFORM_FILE_ERROR_NOT_FOUND; |
| 133 | |
| 134 | FileInfo file_info; |
[email protected] | 6b93115 | 2011-05-20 21:02:35 | [diff] [blame^] | 135 | InitFileInfo(&file_info, parent_id, virtual_path.BaseName().value()); |
| 136 | PlatformFileError error = CreateFile(context, context->src_origin_url(), |
| 137 | context->src_type(), FilePath(), &file_info, 0, NULL); |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 138 | if (created && base::PLATFORM_FILE_OK == error) |
| 139 | *created = true; |
| 140 | return error; |
| 141 | } |
| 142 | |
| 143 | PlatformFileError ObfuscatedFileSystemFileUtil::GetLocalFilePath( |
| 144 | FileSystemOperationContext* context, |
| 145 | const FilePath& virtual_path, |
| 146 | FilePath* local_path) { |
| 147 | FilePath path = |
| 148 | GetLocalPath(context->src_origin_url(), context->src_type(), |
| 149 | virtual_path); |
| 150 | if (path.empty()) |
| 151 | return base::PLATFORM_FILE_ERROR_NOT_FOUND; |
| 152 | |
| 153 | *local_path = path; |
| 154 | return base::PLATFORM_FILE_OK; |
| 155 | } |
| 156 | |
| 157 | PlatformFileError ObfuscatedFileSystemFileUtil::GetFileInfo( |
| 158 | FileSystemOperationContext* context, |
| 159 | const FilePath& virtual_path, |
| 160 | base::PlatformFileInfo* file_info, |
| 161 | FilePath* platform_file_path) { |
| 162 | FileSystemDirectoryDatabase* db = |
| 163 | GetDirectoryDatabase(context->src_origin_url(), context->src_type()); |
| 164 | if (!db) |
| 165 | return base::PLATFORM_FILE_ERROR_FAILED; |
| 166 | FileId file_id; |
| 167 | if (!db->GetFileWithPath(virtual_path, &file_id)) |
| 168 | return base::PLATFORM_FILE_ERROR_NOT_FOUND; |
| 169 | FileInfo local_info; |
| 170 | if (!db->GetFileInfo(file_id, &local_info)) { |
| 171 | NOTREACHED(); |
| 172 | return base::PLATFORM_FILE_ERROR_FAILED; |
| 173 | } |
| 174 | if (local_info.is_directory()) { |
| 175 | file_info->is_directory = true; |
| 176 | file_info->is_symbolic_link = false; |
| 177 | file_info->last_modified = local_info.modification_time; |
| 178 | *platform_file_path = FilePath(); |
| 179 | // We don't fill in ctime or atime. |
| 180 | return base::PLATFORM_FILE_OK; |
| 181 | } |
| 182 | if (local_info.data_path.empty()) |
| 183 | return base::PLATFORM_FILE_ERROR_INVALID_OPERATION; |
[email protected] | 6b93115 | 2011-05-20 21:02:35 | [diff] [blame^] | 184 | FilePath data_path = DataPathToLocalPath(context->src_origin_url(), |
| 185 | context->src_type(), local_info.data_path); |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 186 | return FileSystemFileUtil::GetInstance()->GetFileInfo( |
[email protected] | 6b93115 | 2011-05-20 21:02:35 | [diff] [blame^] | 187 | context, data_path, file_info, platform_file_path); |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 188 | } |
| 189 | |
| 190 | PlatformFileError ObfuscatedFileSystemFileUtil::ReadDirectory( |
| 191 | FileSystemOperationContext* context, |
| 192 | const FilePath& virtual_path, |
| 193 | std::vector<base::FileUtilProxy::Entry>* entries) { |
| 194 | // TODO(kkanetkar): Implement directory read in multiple chunks. |
| 195 | FileSystemDirectoryDatabase* db = |
| 196 | GetDirectoryDatabase(context->src_origin_url(), context->src_type()); |
| 197 | if (!db) |
| 198 | return base::PLATFORM_FILE_ERROR_FAILED; |
| 199 | FileId file_id; |
| 200 | if (!db->GetFileWithPath(virtual_path, &file_id)) |
| 201 | return base::PLATFORM_FILE_ERROR_NOT_FOUND; |
| 202 | FileInfo file_info; |
| 203 | if (!db->GetFileInfo(file_id, &file_info)) { |
| 204 | DCHECK(!file_id); |
| 205 | // It's the root directory and the database hasn't been initialized yet. |
| 206 | entries->clear(); |
| 207 | return base::PLATFORM_FILE_OK; |
| 208 | } |
| 209 | if (!file_info.is_directory()) |
| 210 | return base::PLATFORM_FILE_ERROR_NOT_FOUND; |
| 211 | std::vector<FileId> children; |
| 212 | if (!db->ListChildren(file_id, &children)) { |
| 213 | NOTREACHED(); |
| 214 | return base::PLATFORM_FILE_ERROR_FAILED; |
| 215 | } |
| 216 | std::vector<FileId>::iterator iter; |
| 217 | for (iter = children.begin(); iter != children.end(); ++iter) { |
| 218 | if (!db->GetFileInfo(*iter, &file_info)) { |
| 219 | NOTREACHED(); |
| 220 | return base::PLATFORM_FILE_ERROR_FAILED; |
| 221 | } |
| 222 | base::FileUtilProxy::Entry entry; |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 223 | entry.name = file_info.name; |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 224 | entry.is_directory = file_info.is_directory(); |
| 225 | entries->push_back(entry); |
| 226 | } |
| 227 | return base::PLATFORM_FILE_OK; |
| 228 | } |
| 229 | |
| 230 | PlatformFileError ObfuscatedFileSystemFileUtil::CreateDirectory( |
| 231 | FileSystemOperationContext* context, |
| 232 | const FilePath& virtual_path, |
| 233 | bool exclusive, |
| 234 | bool recursive) { |
| 235 | FileSystemDirectoryDatabase* db = |
| 236 | GetDirectoryDatabase(context->src_origin_url(), context->src_type()); |
| 237 | if (!db) |
| 238 | return base::PLATFORM_FILE_ERROR_FAILED; |
| 239 | FileId file_id; |
| 240 | if (db->GetFileWithPath(virtual_path, &file_id)) { |
| 241 | FileInfo file_info; |
| 242 | if (exclusive) |
| 243 | return base::PLATFORM_FILE_ERROR_EXISTS; |
| 244 | if (!db->GetFileInfo(file_id, &file_info)) { |
| 245 | NOTREACHED(); |
| 246 | return base::PLATFORM_FILE_ERROR_FAILED; |
| 247 | } |
| 248 | if (!file_info.is_directory()) |
| 249 | return base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY; |
| 250 | return base::PLATFORM_FILE_OK; |
| 251 | } |
| 252 | |
| 253 | std::vector<FilePath::StringType> components; |
| 254 | virtual_path.GetComponents(&components); |
| 255 | FileId parent_id = 0; |
| 256 | size_t index; |
| 257 | for (index = 0; index < components.size(); ++index) { |
[email protected] | 89ee427 | 2011-05-16 18:45:17 | [diff] [blame] | 258 | FilePath::StringType name = components[index]; |
| 259 | if (name == FILE_PATH_LITERAL("/")) |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 260 | continue; |
| 261 | if (!db->GetChildWithName(parent_id, name, &parent_id)) |
| 262 | break; |
| 263 | } |
| 264 | if (!recursive && components.size() - index > 1) |
| 265 | return base::PLATFORM_FILE_ERROR_NOT_FOUND; |
| 266 | for (; index < components.size(); ++index) { |
| 267 | FileInfo file_info; |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 268 | file_info.name = components[index]; |
[email protected] | 89ee427 | 2011-05-16 18:45:17 | [diff] [blame] | 269 | if (file_info.name == FILE_PATH_LITERAL("/")) |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 270 | continue; |
| 271 | file_info.modification_time = base::Time::Now(); |
| 272 | file_info.parent_id = parent_id; |
| 273 | if (!db->AddFileInfo(file_info, &parent_id)) { |
| 274 | NOTREACHED(); |
| 275 | return base::PLATFORM_FILE_ERROR_FAILED; |
| 276 | } |
| 277 | } |
| 278 | return base::PLATFORM_FILE_OK; |
| 279 | } |
| 280 | |
| 281 | PlatformFileError ObfuscatedFileSystemFileUtil::CopyOrMoveFile( |
| 282 | FileSystemOperationContext* context, |
| 283 | const FilePath& src_file_path, |
| 284 | const FilePath& dest_file_path, |
| 285 | bool copy) { |
| 286 | // TODO(ericu): Handle multi-db move+copy, where src and dest aren't in the |
| 287 | // same database. Currently we'll just fail badly. This may get handled from |
| 288 | // higher-level code, though, and as we don't have cross-filesystem |
| 289 | // transactions that's not any less efficient than doing it here. |
| 290 | FileSystemDirectoryDatabase* db = |
| 291 | GetDirectoryDatabase(context->src_origin_url(), context->src_type()); |
| 292 | if (!db) |
| 293 | return base::PLATFORM_FILE_ERROR_FAILED; |
| 294 | FileId src_file_id; |
| 295 | if (!db->GetFileWithPath(src_file_path, &src_file_id)) |
| 296 | return base::PLATFORM_FILE_ERROR_NOT_FOUND; |
| 297 | FileId dest_file_id; |
| 298 | bool overwrite = db->GetFileWithPath(dest_file_path, &dest_file_id); |
| 299 | FileInfo src_file_info; |
| 300 | FileInfo dest_file_info; |
| 301 | if (!db->GetFileInfo(src_file_id, &src_file_info) || |
| 302 | src_file_info.is_directory()) { |
| 303 | NOTREACHED(); |
| 304 | return base::PLATFORM_FILE_ERROR_FAILED; |
| 305 | } |
| 306 | if (overwrite) { |
| 307 | if (!db->GetFileInfo(dest_file_id, &dest_file_info) || |
| 308 | dest_file_info.is_directory()) { |
| 309 | NOTREACHED(); |
| 310 | return base::PLATFORM_FILE_ERROR_FAILED; |
| 311 | } |
| 312 | } |
| 313 | /* |
| 314 | * Copy-with-overwrite |
| 315 | * Just overwrite data file |
| 316 | * Copy-without-overwrite |
| 317 | * Copy backing file |
| 318 | * Create new metadata pointing to new backing file. |
| 319 | * Move-with-overwrite |
| 320 | * transaction: |
| 321 | * Remove source entry. |
| 322 | * Point target entry to source entry's backing file. |
| 323 | * Delete target entry's old backing file |
| 324 | * Move-without-overwrite |
| 325 | * Just update metadata |
| 326 | */ |
| 327 | if (copy) { |
[email protected] | 6b93115 | 2011-05-20 21:02:35 | [diff] [blame^] | 328 | FilePath src_data_path = DataPathToLocalPath(context->src_origin_url(), |
| 329 | context->src_type(), src_file_info.data_path); |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 330 | if (overwrite) { |
[email protected] | 6b93115 | 2011-05-20 21:02:35 | [diff] [blame^] | 331 | FilePath dest_data_path = DataPathToLocalPath(context->src_origin_url(), |
| 332 | context->src_type(), dest_file_info.data_path); |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 333 | return FileSystemFileUtil::GetInstance()->CopyOrMoveFile(context, |
[email protected] | 6b93115 | 2011-05-20 21:02:35 | [diff] [blame^] | 334 | src_data_path, dest_data_path, copy); |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 335 | } else { |
| 336 | FileId dest_parent_id; |
| 337 | if (!db->GetFileWithPath(dest_file_path.DirName(), &dest_parent_id)) { |
| 338 | NOTREACHED(); // We shouldn't be called in this case. |
| 339 | return base::PLATFORM_FILE_ERROR_NOT_FOUND; |
| 340 | } |
| 341 | InitFileInfo(&dest_file_info, dest_parent_id, |
[email protected] | 6b93115 | 2011-05-20 21:02:35 | [diff] [blame^] | 342 | dest_file_path.BaseName().value()); |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 343 | return CreateFile(context, context->dest_origin_url(), |
[email protected] | 6b93115 | 2011-05-20 21:02:35 | [diff] [blame^] | 344 | context->dest_type(), src_data_path, &dest_file_info, 0, |
| 345 | NULL); |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 346 | } |
| 347 | } else { // It's a move. |
| 348 | if (overwrite) { |
| 349 | if (!db->OverwritingMoveFile(src_file_id, dest_file_id)) |
| 350 | return base::PLATFORM_FILE_ERROR_FAILED; |
[email protected] | 6b93115 | 2011-05-20 21:02:35 | [diff] [blame^] | 351 | FilePath dest_data_path = DataPathToLocalPath(context->src_origin_url(), |
| 352 | context->src_type(), dest_file_info.data_path); |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 353 | if (base::PLATFORM_FILE_OK != |
| 354 | FileSystemFileUtil::GetInstance()->DeleteFile( |
[email protected] | 6b93115 | 2011-05-20 21:02:35 | [diff] [blame^] | 355 | context, dest_data_path)) |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 356 | LOG(WARNING) << "Leaked a backing file."; |
| 357 | return base::PLATFORM_FILE_OK; |
| 358 | } else { |
| 359 | FileId dest_parent_id; |
| 360 | if (!db->GetFileWithPath(dest_file_path.DirName(), &dest_parent_id)) { |
| 361 | NOTREACHED(); |
| 362 | return base::PLATFORM_FILE_ERROR_FAILED; |
| 363 | } |
| 364 | src_file_info.parent_id = dest_parent_id; |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 365 | src_file_info.name = dest_file_path.BaseName().value(); |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 366 | if (!db->UpdateFileInfo(src_file_id, src_file_info)) |
| 367 | return base::PLATFORM_FILE_ERROR_FAILED; |
| 368 | return base::PLATFORM_FILE_OK; |
| 369 | } |
| 370 | } |
| 371 | NOTREACHED(); |
| 372 | return base::PLATFORM_FILE_ERROR_FAILED; |
| 373 | } |
| 374 | |
| 375 | PlatformFileError ObfuscatedFileSystemFileUtil::DeleteFile( |
| 376 | FileSystemOperationContext* context, |
| 377 | const FilePath& virtual_path) { |
| 378 | FileSystemDirectoryDatabase* db = |
| 379 | GetDirectoryDatabase(context->src_origin_url(), context->src_type()); |
| 380 | if (!db) |
| 381 | return base::PLATFORM_FILE_ERROR_FAILED; |
| 382 | FileId file_id; |
| 383 | if (!db->GetFileWithPath(virtual_path, &file_id)) |
| 384 | return base::PLATFORM_FILE_ERROR_NOT_FOUND; |
| 385 | FileInfo file_info; |
| 386 | if (!db->GetFileInfo(file_id, &file_info) || file_info.is_directory()) { |
| 387 | NOTREACHED(); |
| 388 | return base::PLATFORM_FILE_ERROR_FAILED; |
| 389 | } |
| 390 | if (!db->RemoveFileInfo(file_id)) { |
| 391 | NOTREACHED(); |
| 392 | return base::PLATFORM_FILE_ERROR_FAILED; |
| 393 | } |
[email protected] | 6b93115 | 2011-05-20 21:02:35 | [diff] [blame^] | 394 | FilePath data_path = DataPathToLocalPath(context->src_origin_url(), |
| 395 | context->src_type(), file_info.data_path); |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 396 | if (base::PLATFORM_FILE_OK != |
[email protected] | 6b93115 | 2011-05-20 21:02:35 | [diff] [blame^] | 397 | FileSystemFileUtil::GetInstance()->DeleteFile(context, data_path)) |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 398 | LOG(WARNING) << "Leaked a backing file."; |
| 399 | return base::PLATFORM_FILE_OK; |
| 400 | } |
| 401 | |
| 402 | PlatformFileError ObfuscatedFileSystemFileUtil::DeleteSingleDirectory( |
| 403 | FileSystemOperationContext* context, |
| 404 | const FilePath& virtual_path) { |
| 405 | FileSystemDirectoryDatabase* db = |
| 406 | GetDirectoryDatabase(context->src_origin_url(), context->src_type()); |
| 407 | if (!db) |
| 408 | return base::PLATFORM_FILE_ERROR_FAILED; |
| 409 | FileId file_id; |
| 410 | if (!db->GetFileWithPath(virtual_path, &file_id)) |
| 411 | return base::PLATFORM_FILE_ERROR_NOT_FOUND; |
| 412 | FileInfo file_info; |
| 413 | if (!db->GetFileInfo(file_id, &file_info) || !file_info.is_directory()) { |
| 414 | NOTREACHED(); |
| 415 | return base::PLATFORM_FILE_ERROR_FAILED; |
| 416 | } |
| 417 | if (!db->RemoveFileInfo(file_id)) |
[email protected] | c7a4a10f | 2011-05-19 04:56:06 | [diff] [blame] | 418 | return base::PLATFORM_FILE_ERROR_NOT_EMPTY; |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 419 | return base::PLATFORM_FILE_OK; |
| 420 | } |
| 421 | |
| 422 | PlatformFileError ObfuscatedFileSystemFileUtil::Touch( |
| 423 | FileSystemOperationContext* context, |
| 424 | const FilePath& virtual_path, |
| 425 | const base::Time& last_access_time, |
| 426 | const base::Time& last_modified_time) { |
| 427 | FileSystemDirectoryDatabase* db = |
| 428 | GetDirectoryDatabase(context->src_origin_url(), context->src_type()); |
| 429 | if (!db) |
| 430 | return base::PLATFORM_FILE_ERROR_FAILED; |
| 431 | FileId file_id; |
| 432 | if (db->GetFileWithPath(virtual_path, &file_id)) { |
| 433 | FileInfo file_info; |
| 434 | if (!db->GetFileInfo(file_id, &file_info)) { |
| 435 | NOTREACHED(); |
| 436 | return base::PLATFORM_FILE_ERROR_FAILED; |
| 437 | } |
| 438 | if (file_info.is_directory()) { |
| 439 | file_info.modification_time = last_modified_time; |
| 440 | if (!db->UpdateFileInfo(file_id, file_info)) |
| 441 | return base::PLATFORM_FILE_ERROR_FAILED; |
| 442 | return base::PLATFORM_FILE_OK; |
| 443 | } |
[email protected] | 6b93115 | 2011-05-20 21:02:35 | [diff] [blame^] | 444 | FilePath data_path = DataPathToLocalPath(context->src_origin_url(), |
| 445 | context->src_type(), file_info.data_path); |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 446 | return FileSystemFileUtil::GetInstance()->Touch( |
[email protected] | 6b93115 | 2011-05-20 21:02:35 | [diff] [blame^] | 447 | context, data_path, last_access_time, last_modified_time); |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 448 | } |
| 449 | FileId parent_id; |
| 450 | if (!db->GetFileWithPath(virtual_path.DirName(), &parent_id)) |
| 451 | return base::PLATFORM_FILE_ERROR_NOT_FOUND; |
| 452 | |
| 453 | FileInfo file_info; |
[email protected] | 6b93115 | 2011-05-20 21:02:35 | [diff] [blame^] | 454 | InitFileInfo(&file_info, parent_id, virtual_path.BaseName().value()); |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 455 | // In the event of a sporadic underlying failure, we might create a new file, |
| 456 | // but fail to update its mtime + atime. |
[email protected] | 6b93115 | 2011-05-20 21:02:35 | [diff] [blame^] | 457 | PlatformFileError error = CreateFile(context, context->src_origin_url(), |
| 458 | context->src_type(), FilePath(), &file_info, 0, NULL); |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 459 | if (base::PLATFORM_FILE_OK != error) |
| 460 | return error; |
| 461 | |
[email protected] | 6b93115 | 2011-05-20 21:02:35 | [diff] [blame^] | 462 | FilePath data_path = DataPathToLocalPath(context->src_origin_url(), |
| 463 | context->src_type(), file_info.data_path); |
| 464 | return FileSystemFileUtil::GetInstance()->Touch(context, data_path, |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 465 | last_access_time, last_modified_time); |
| 466 | } |
| 467 | |
| 468 | PlatformFileError ObfuscatedFileSystemFileUtil::Truncate( |
| 469 | FileSystemOperationContext* context, |
| 470 | const FilePath& virtual_path, |
| 471 | int64 length) { |
| 472 | FilePath local_path = |
| 473 | GetLocalPath(context->src_origin_url(), context->src_type(), |
| 474 | virtual_path); |
| 475 | if (local_path.empty()) |
| 476 | return base::PLATFORM_FILE_ERROR_NOT_FOUND; |
| 477 | return FileSystemFileUtil::GetInstance()->Truncate( |
| 478 | context, local_path, length); |
| 479 | } |
| 480 | |
| 481 | bool ObfuscatedFileSystemFileUtil::PathExists( |
| 482 | FileSystemOperationContext* context, |
| 483 | const FilePath& virtual_path) { |
| 484 | FileSystemDirectoryDatabase* db = |
| 485 | GetDirectoryDatabase(context->src_origin_url(), context->src_type()); |
| 486 | if (!db) |
| 487 | return false; |
| 488 | FileId file_id; |
| 489 | return db->GetFileWithPath(virtual_path, &file_id); |
| 490 | } |
| 491 | |
| 492 | bool ObfuscatedFileSystemFileUtil::DirectoryExists( |
| 493 | FileSystemOperationContext* context, |
| 494 | const FilePath& virtual_path) { |
| 495 | FileSystemDirectoryDatabase* db = |
| 496 | GetDirectoryDatabase(context->src_origin_url(), context->src_type()); |
| 497 | if (!db) |
| 498 | return false; |
| 499 | FileId file_id; |
| 500 | if (!db->GetFileWithPath(virtual_path, &file_id)) |
| 501 | return false; |
| 502 | FileInfo file_info; |
| 503 | if (!db->GetFileInfo(file_id, &file_info)) { |
| 504 | NOTREACHED(); |
| 505 | return false; |
| 506 | } |
| 507 | return file_info.is_directory(); |
| 508 | } |
| 509 | |
| 510 | bool ObfuscatedFileSystemFileUtil::IsDirectoryEmpty( |
| 511 | FileSystemOperationContext* context, |
| 512 | const FilePath& virtual_path) { |
| 513 | FileSystemDirectoryDatabase* db = |
| 514 | GetDirectoryDatabase(context->src_origin_url(), context->src_type()); |
| 515 | if (!db) |
| 516 | return false; |
| 517 | FileId file_id; |
| 518 | if (!db->GetFileWithPath(virtual_path, &file_id)) |
| 519 | return true; // Not a great answer, but it's what others do. |
| 520 | FileInfo file_info; |
| 521 | if (!db->GetFileInfo(file_id, &file_info)) { |
| 522 | DCHECK(!file_id); |
| 523 | // It's the root directory and the database hasn't been initialized yet. |
| 524 | return true; |
| 525 | } |
| 526 | if (!file_info.is_directory()) |
| 527 | return true; |
| 528 | std::vector<FileId> children; |
| 529 | // TODO(ericu): This could easily be made faster with help from the database. |
| 530 | if (!db->ListChildren(file_id, &children)) |
| 531 | return true; |
| 532 | return children.empty(); |
| 533 | } |
| 534 | |
| 535 | class ObfuscatedFileSystemFileEnumerator |
| 536 | : public FileSystemFileUtil::AbstractFileEnumerator { |
| 537 | public: |
| 538 | ObfuscatedFileSystemFileEnumerator( |
| 539 | FileSystemDirectoryDatabase* db, const FilePath& virtual_root_path) |
| 540 | : db_(db) { |
| 541 | FileId file_id; |
| 542 | FileInfo file_info; |
| 543 | if (!db_->GetFileWithPath(virtual_root_path, &file_id)) |
| 544 | return; |
| 545 | if (!db_->GetFileInfo(file_id, &file_info)) |
| 546 | return; |
| 547 | if (!file_info.is_directory()) |
| 548 | return; |
| 549 | FileRecord record = { file_id, file_info, virtual_root_path }; |
| 550 | display_queue_.push(record); |
| 551 | Next(); // Enumerators don't include the directory itself. |
| 552 | } |
| 553 | |
| 554 | ~ObfuscatedFileSystemFileEnumerator() {} |
| 555 | |
| 556 | virtual FilePath Next() { |
| 557 | ProcessRecurseQueue(); |
| 558 | if (display_queue_.empty()) |
| 559 | return FilePath(); |
| 560 | current_ = display_queue_.front(); |
| 561 | display_queue_.pop(); |
| 562 | if (current_.file_info.is_directory()) |
| 563 | recurse_queue_.push(current_); |
| 564 | return current_.file_path; |
| 565 | } |
| 566 | |
| 567 | virtual bool IsDirectory() { |
| 568 | return current_.file_info.is_directory(); |
| 569 | } |
| 570 | |
| 571 | private: |
| 572 | typedef FileSystemDirectoryDatabase::FileId FileId; |
| 573 | typedef FileSystemDirectoryDatabase::FileInfo FileInfo; |
| 574 | |
| 575 | struct FileRecord { |
| 576 | FileId file_id; |
| 577 | FileInfo file_info; |
| 578 | FilePath file_path; |
| 579 | }; |
| 580 | |
| 581 | void ProcessRecurseQueue() { |
| 582 | while (display_queue_.empty() && !recurse_queue_.empty()) { |
| 583 | FileRecord directory = recurse_queue_.front(); |
| 584 | std::vector<FileId> children; |
| 585 | recurse_queue_.pop(); |
| 586 | if (!db_->ListChildren(directory.file_id, &children)) |
| 587 | return; |
| 588 | std::vector<FileId>::iterator iter; |
| 589 | for (iter = children.begin(); iter != children.end(); ++iter) { |
| 590 | FileRecord child; |
| 591 | child.file_id = *iter; |
| 592 | if (!db_->GetFileInfo(child.file_id, &child.file_info)) |
| 593 | return; |
[email protected] | 89ee427 | 2011-05-16 18:45:17 | [diff] [blame] | 594 | child.file_path = directory.file_path.Append(child.file_info.name); |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 595 | display_queue_.push(child); |
| 596 | } |
| 597 | } |
| 598 | } |
| 599 | |
| 600 | std::queue<FileRecord> display_queue_; |
| 601 | std::queue<FileRecord> recurse_queue_; |
| 602 | FileRecord current_; |
| 603 | FileSystemDirectoryDatabase* db_; |
| 604 | }; |
| 605 | |
| 606 | FileSystemFileUtil::AbstractFileEnumerator* |
| 607 | ObfuscatedFileSystemFileUtil::CreateFileEnumerator( |
| 608 | FileSystemOperationContext* context, |
| 609 | const FilePath& root_path) { |
| 610 | FileSystemDirectoryDatabase* db = |
| 611 | GetDirectoryDatabase(context->src_origin_url(), context->src_type()); |
| 612 | if (!db) |
| 613 | return new FileSystemFileUtil::EmptyFileEnumerator(); |
| 614 | return new ObfuscatedFileSystemFileEnumerator(db, root_path); |
| 615 | } |
| 616 | |
| 617 | PlatformFileError ObfuscatedFileSystemFileUtil::CreateFile( |
| 618 | FileSystemOperationContext* context, |
[email protected] | 6b93115 | 2011-05-20 21:02:35 | [diff] [blame^] | 619 | const GURL& origin_url, FileSystemType type, const FilePath& source_path, |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 620 | FileInfo* file_info, int file_flags, PlatformFile* handle) { |
| 621 | if (handle) |
| 622 | *handle = base::kInvalidPlatformFileValue; |
| 623 | FileSystemDirectoryDatabase* db = GetDirectoryDatabase(origin_url, type); |
| 624 | int64 number; |
| 625 | if (!db || !db->GetNextInteger(&number)) |
| 626 | return base::PLATFORM_FILE_ERROR_FAILED; |
| 627 | // We use the third- and fourth-to-last digits as the directory. |
| 628 | int64 directory_number = number % 10000 / 100; |
| 629 | FilePath path = |
[email protected] | c7a4a10f | 2011-05-19 04:56:06 | [diff] [blame] | 630 | GetDirectoryForOriginAndType(origin_url, type, false); |
| 631 | if (path.empty()) |
| 632 | return base::PLATFORM_FILE_ERROR_FAILED; |
[email protected] | 6b93115 | 2011-05-20 21:02:35 | [diff] [blame^] | 633 | |
| 634 | path = path.AppendASCII(StringPrintf("%02" PRIu64, directory_number)); |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 635 | PlatformFileError error; |
| 636 | error = FileSystemFileUtil::GetInstance()->CreateDirectory( |
| 637 | context, path, false /* exclusive */, false /* recursive */); |
| 638 | if (base::PLATFORM_FILE_OK != error) |
| 639 | return error; |
[email protected] | 6b93115 | 2011-05-20 21:02:35 | [diff] [blame^] | 640 | path = path.AppendASCII(StringPrintf("%08" PRIu64, number)); |
| 641 | FilePath data_path = LocalPathToDataPath(origin_url, type, path); |
| 642 | if (data_path.empty()) |
| 643 | return base::PLATFORM_FILE_ERROR_FAILED; |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 644 | bool created = false; |
[email protected] | 6b93115 | 2011-05-20 21:02:35 | [diff] [blame^] | 645 | if (!source_path.empty()) { |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 646 | DCHECK(!file_flags); |
| 647 | DCHECK(!handle); |
| 648 | error = FileSystemFileUtil::GetInstance()->CopyOrMoveFile( |
[email protected] | 6b93115 | 2011-05-20 21:02:35 | [diff] [blame^] | 649 | context, source_path, path, true /* copy */); |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 650 | created = true; |
| 651 | } else { |
| 652 | if (handle) { |
| 653 | error = FileSystemFileUtil::GetInstance()->CreateOrOpen( |
| 654 | context, path, file_flags, handle, &created); |
| 655 | // If this succeeds, we must close handle on any subsequent error. |
| 656 | } else { |
| 657 | DCHECK(!file_flags); // file_flags is only used by CreateOrOpen. |
| 658 | error = FileSystemFileUtil::GetInstance()->EnsureFileExists( |
| 659 | context, path, &created); |
| 660 | } |
| 661 | } |
| 662 | if (error != base::PLATFORM_FILE_OK) |
| 663 | return error; |
| 664 | |
| 665 | if (!created) { |
| 666 | NOTREACHED(); |
| 667 | if (handle) { |
| 668 | base::ClosePlatformFile(*handle); |
| 669 | FileSystemFileUtil::GetInstance()->DeleteFile(context, path); |
| 670 | } |
| 671 | return base::PLATFORM_FILE_ERROR_FAILED; |
| 672 | } |
[email protected] | 6b93115 | 2011-05-20 21:02:35 | [diff] [blame^] | 673 | file_info->data_path = data_path; |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 674 | FileId file_id; |
| 675 | if (!db->AddFileInfo(*file_info, &file_id)) { |
| 676 | if (handle) |
| 677 | base::ClosePlatformFile(*handle); |
| 678 | FileSystemFileUtil::GetInstance()->DeleteFile(context, path); |
| 679 | return base::PLATFORM_FILE_ERROR_FAILED; |
| 680 | } |
| 681 | |
| 682 | return base::PLATFORM_FILE_OK; |
| 683 | } |
| 684 | |
| 685 | FilePath ObfuscatedFileSystemFileUtil::GetLocalPath( |
| 686 | const GURL& origin_url, |
| 687 | FileSystemType type, |
| 688 | const FilePath& virtual_path) { |
| 689 | FileSystemDirectoryDatabase* db = GetDirectoryDatabase(origin_url, type); |
| 690 | if (!db) |
| 691 | return FilePath(); |
| 692 | FileId file_id; |
| 693 | if (!db->GetFileWithPath(virtual_path, &file_id)) |
| 694 | return FilePath(); |
| 695 | FileInfo file_info; |
| 696 | if (!db->GetFileInfo(file_id, &file_info) || file_info.is_directory()) { |
| 697 | NOTREACHED(); |
| 698 | return FilePath(); // Directories have no local path. |
| 699 | } |
[email protected] | 6b93115 | 2011-05-20 21:02:35 | [diff] [blame^] | 700 | return DataPathToLocalPath(origin_url, type, file_info.data_path); |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 701 | } |
| 702 | |
[email protected] | c7a4a10f | 2011-05-19 04:56:06 | [diff] [blame] | 703 | FilePath ObfuscatedFileSystemFileUtil::GetDirectoryForOriginAndType( |
| 704 | const GURL& origin, FileSystemType type, bool create) { |
| 705 | FilePath origin_dir = GetDirectoryForOrigin(origin, create); |
| 706 | if (origin_dir.empty()) |
| 707 | return FilePath(); |
[email protected] | 6b93115 | 2011-05-20 21:02:35 | [diff] [blame^] | 708 | FilePath::StringType type_string = GetDirectoryNameForType(type); |
[email protected] | c7a4a10f | 2011-05-19 04:56:06 | [diff] [blame] | 709 | if (type_string.empty()) { |
| 710 | LOG(WARNING) << "Unknown filesystem type requested:" << type; |
| 711 | return FilePath(); |
| 712 | } |
[email protected] | 6b93115 | 2011-05-20 21:02:35 | [diff] [blame^] | 713 | return origin_dir.Append(type_string); |
[email protected] | c7a4a10f | 2011-05-19 04:56:06 | [diff] [blame] | 714 | } |
| 715 | |
| 716 | FilePath ObfuscatedFileSystemFileUtil::GetDirectoryForOrigin( |
| 717 | const GURL& origin, bool create) { |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 718 | if (!origin_database_.get()) { |
[email protected] | c7a4a10f | 2011-05-19 04:56:06 | [diff] [blame] | 719 | if (!create && !file_util::DirectoryExists(file_system_directory_)) { |
| 720 | return FilePath(); |
| 721 | } |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 722 | if (!file_util::CreateDirectory(file_system_directory_)) { |
[email protected] | c7a4a10f | 2011-05-19 04:56:06 | [diff] [blame] | 723 | LOG(WARNING) << "Failed to create FileSystem directory: " << |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 724 | file_system_directory_.value(); |
| 725 | return FilePath(); |
| 726 | } |
| 727 | origin_database_.reset( |
| 728 | new FileSystemOriginDatabase( |
| 729 | file_system_directory_.AppendASCII(kOriginDatabaseName))); |
| 730 | } |
| 731 | FilePath directory_name; |
[email protected] | c7a4a10f | 2011-05-19 04:56:06 | [diff] [blame] | 732 | // TODO(ericu): This should probably be using GetOriginIdentifierFromURL from |
| 733 | // sandbox_mount_point_provider.cc, instead of just using origin.spec(). |
| 734 | if (!create && !origin_database_->HasOriginPath(origin.spec())) |
| 735 | return FilePath(); |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 736 | if (!origin_database_->GetPathForOrigin(origin.spec(), &directory_name)) |
| 737 | return FilePath(); |
[email protected] | c7a4a10f | 2011-05-19 04:56:06 | [diff] [blame] | 738 | return file_system_directory_.Append(directory_name); |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 739 | } |
| 740 | |
[email protected] | 6b93115 | 2011-05-20 21:02:35 | [diff] [blame^] | 741 | bool ObfuscatedFileSystemFileUtil::MigrateFromOldSandbox( |
| 742 | const GURL& origin_url, FileSystemType type, const FilePath& src_root) { |
| 743 | if (!DestroyDirectoryDatabase(origin_url, type)) |
| 744 | return false; |
| 745 | FilePath dest_root = GetDirectoryForOriginAndType(origin_url, type, true); |
| 746 | if (dest_root.empty()) |
| 747 | return false; |
| 748 | FileSystemDirectoryDatabase* db = GetDirectoryDatabase(origin_url, type); |
| 749 | if (!db) |
| 750 | return false; |
| 751 | |
| 752 | file_util::FileEnumerator file_enum(src_root, true, |
| 753 | static_cast<file_util::FileEnumerator::FILE_TYPE>( |
| 754 | file_util::FileEnumerator::FILES | |
| 755 | file_util::FileEnumerator::DIRECTORIES)); |
| 756 | FilePath src_full_path; |
| 757 | size_t root_path_length = src_root.value().length() + 1; // +1 for the slash |
| 758 | while (!(src_full_path = file_enum.Next()).empty()) { |
| 759 | file_util::FileEnumerator::FindInfo info; |
| 760 | file_enum.GetFindInfo(&info); |
| 761 | FilePath relative_virtual_path = |
| 762 | FilePath(src_full_path.value().substr(root_path_length)); |
| 763 | if (relative_virtual_path.empty()) { |
| 764 | LOG(WARNING) << "Failed to convert path to relative: " << |
| 765 | src_full_path.value(); |
| 766 | return false; |
| 767 | } |
| 768 | FileId file_id; |
| 769 | if (db->GetFileWithPath(relative_virtual_path, &file_id)) { |
| 770 | NOTREACHED(); // File already exists. |
| 771 | return false; |
| 772 | } |
| 773 | if (!db->GetFileWithPath(relative_virtual_path.DirName(), &file_id)) { |
| 774 | NOTREACHED(); // Parent doesn't exist. |
| 775 | return false; |
| 776 | } |
| 777 | |
| 778 | FileInfo file_info; |
| 779 | file_info.name = src_full_path.BaseName().value(); |
| 780 | if (file_util::FileEnumerator::IsDirectory(info)) { |
| 781 | #if defined(OS_WIN) |
| 782 | file_info.modification_time = |
| 783 | base::Time::FromFileTime(info.ftLastWriteTime); |
| 784 | #elif defined(OS_POSIX) |
| 785 | file_info.modification_time = base::Time::FromTimeT(info.stat.st_mtime); |
| 786 | #endif |
| 787 | } else { |
| 788 | file_info.data_path = |
| 789 | FilePath(kLegacyDataDirectory).Append(relative_virtual_path); |
| 790 | } |
| 791 | file_info.parent_id = file_id; |
| 792 | if (!db->AddFileInfo(file_info, &file_id)) { |
| 793 | NOTREACHED(); |
| 794 | return false; |
| 795 | } |
| 796 | } |
| 797 | // TODO(ericu): Should we adjust the mtime of the root directory to match as |
| 798 | // well? |
| 799 | FilePath legacy_dest_dir = dest_root.Append(kLegacyDataDirectory); |
| 800 | return file_util::Move(src_root, legacy_dest_dir); |
| 801 | } |
| 802 | |
| 803 | FilePath::StringType ObfuscatedFileSystemFileUtil::GetDirectoryNameForType( |
| 804 | FileSystemType type) const { |
| 805 | switch (type) { |
| 806 | case kFileSystemTypeTemporary: |
| 807 | return kTemporaryDirectoryName; |
| 808 | case kFileSystemTypePersistent: |
| 809 | return kPersistentDirectoryName; |
| 810 | case kFileSystemTypeUnknown: |
| 811 | default: |
| 812 | return FilePath::StringType(); |
| 813 | } |
| 814 | } |
| 815 | |
| 816 | FilePath ObfuscatedFileSystemFileUtil::DataPathToLocalPath( |
| 817 | const GURL& origin, FileSystemType type, const FilePath& data_path) { |
| 818 | FilePath root = GetDirectoryForOriginAndType(origin, type, false); |
| 819 | if (root.empty()) |
| 820 | return root; |
| 821 | return root.Append(data_path); |
| 822 | } |
| 823 | |
| 824 | FilePath ObfuscatedFileSystemFileUtil::LocalPathToDataPath( |
| 825 | const GURL& origin, FileSystemType type, const FilePath& local_path) { |
| 826 | FilePath root = GetDirectoryForOriginAndType(origin, type, false); |
| 827 | if (root.empty()) |
| 828 | return root; |
| 829 | // This removes the root, including the trailing slash, leaving a relative |
| 830 | // path. |
| 831 | return FilePath(local_path.value().substr(root.value().length() + 1)); |
| 832 | } |
| 833 | |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 834 | // TODO: How to do the whole validation-without-creation thing? We may not have |
[email protected] | c7a4a10f | 2011-05-19 04:56:06 | [diff] [blame] | 835 | // quota even to create the database. Ah, in that case don't even get here? |
| 836 | // Still doesn't answer the quota issue, though. |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 837 | FileSystemDirectoryDatabase* ObfuscatedFileSystemFileUtil::GetDirectoryDatabase( |
| 838 | const GURL& origin, FileSystemType type) { |
| 839 | |
[email protected] | 0a732853 | 2011-05-13 23:54:43 | [diff] [blame] | 840 | MarkUsed(); |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 841 | std::string type_string = |
| 842 | FileSystemPathManager::GetFileSystemTypeString(type); |
| 843 | if (type_string.empty()) { |
| 844 | LOG(WARNING) << "Unknown filesystem type requested:" << type; |
| 845 | return NULL; |
| 846 | } |
[email protected] | c7a4a10f | 2011-05-19 04:56:06 | [diff] [blame] | 847 | // TODO(ericu): This should probably be using GetOriginIdentifierFromURL from |
| 848 | // sandbox_mount_point_provider.cc, instead of just using origin.spec(). |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 849 | std::string key = origin.spec() + type_string; |
| 850 | DirectoryMap::iterator iter = directories_.find(key); |
| 851 | if (iter != directories_.end()) |
| 852 | return iter->second; |
| 853 | |
[email protected] | c7a4a10f | 2011-05-19 04:56:06 | [diff] [blame] | 854 | FilePath path = GetDirectoryForOriginAndType(origin, type, true); |
| 855 | if (path.empty()) |
| 856 | return NULL; |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 857 | if (!file_util::DirectoryExists(path)) { |
| 858 | if (!file_util::CreateDirectory(path)) { |
[email protected] | c7a4a10f | 2011-05-19 04:56:06 | [diff] [blame] | 859 | LOG(WARNING) << "Failed to origin+type directory: " << path.value(); |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 860 | return NULL; |
| 861 | } |
| 862 | } |
| 863 | path = path.AppendASCII(kDirectoryDatabaseName); |
| 864 | FileSystemDirectoryDatabase* database = new FileSystemDirectoryDatabase(path); |
| 865 | directories_[key] = database; |
| 866 | return database; |
| 867 | } |
| 868 | |
[email protected] | 0a732853 | 2011-05-13 23:54:43 | [diff] [blame] | 869 | void ObfuscatedFileSystemFileUtil::MarkUsed() { |
| 870 | if (timer_.IsRunning()) |
| 871 | timer_.Reset(); |
| 872 | else |
| 873 | timer_.Start(base::TimeDelta::FromSeconds(kFlushDelaySeconds), this, |
| 874 | &ObfuscatedFileSystemFileUtil::DropDatabases); |
| 875 | } |
| 876 | |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 877 | void ObfuscatedFileSystemFileUtil::DropDatabases() { |
| 878 | origin_database_.reset(); |
| 879 | STLDeleteContainerPairSecondPointers( |
| 880 | directories_.begin(), directories_.end()); |
| 881 | directories_.clear(); |
| 882 | } |
| 883 | |
[email protected] | 6b93115 | 2011-05-20 21:02:35 | [diff] [blame^] | 884 | bool ObfuscatedFileSystemFileUtil::DestroyDirectoryDatabase( |
| 885 | const GURL& origin, FileSystemType type) { |
| 886 | std::string type_string = |
| 887 | FileSystemPathManager::GetFileSystemTypeString(type); |
| 888 | if (type_string.empty()) { |
| 889 | LOG(WARNING) << "Unknown filesystem type requested:" << type; |
| 890 | return true; |
| 891 | } |
| 892 | // TODO(ericu): This should probably be using GetOriginIdentifierFromURL from |
| 893 | // sandbox_mount_point_provider.cc, instead of just using origin.spec(). |
| 894 | std::string key = origin.spec() + type_string; |
| 895 | DirectoryMap::iterator iter = directories_.find(key); |
| 896 | if (iter != directories_.end()) |
| 897 | directories_.erase(iter); |
| 898 | |
| 899 | FilePath path = GetDirectoryForOriginAndType(origin, type, false); |
| 900 | if (path.empty()) |
| 901 | return true; |
| 902 | if (!file_util::DirectoryExists(path)) |
| 903 | return true; |
| 904 | path = path.AppendASCII(kDirectoryDatabaseName); |
| 905 | return FileSystemDirectoryDatabase::DestroyDatabase(path); |
| 906 | } |
| 907 | |
[email protected] | d4905e2e | 2011-05-13 21:56:32 | [diff] [blame] | 908 | } // namespace fileapi |