| // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| // |
| // A tool to dump HTML5 filesystem from CUI. |
| // |
| // Usage: |
| // |
| // ./out/Release/dump_file_system [options] <filesystem dir> [origin]... |
| // |
| // If no origin is specified, this dumps all origins in the profile dir. |
| // For Chrome App, which has a separate storage directory, specify "primary" |
| // as the origin name. |
| // |
| // Available options: |
| // |
| // -t : dumps temporary files instead of persistent. |
| // -s : dumps syncable files instead of persistent. |
| // -l : more information will be displayed. |
| // |
| // The format of -l option is: |
| // |
| // === ORIGIN origin_name origin_dir === |
| // file_name file_id file_size file_content_path |
| // ... |
| // |
| // where file_name has a trailing slash, file_size is the number of |
| // children, and file_content_path is empty if the file is a directory. |
| // |
| |
| #include <stddef.h> |
| #include <stdint.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| |
| #include <stack> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include "base/files/file_path.h" |
| #include "base/files/file_util.h" |
| #include "base/format_macros.h" |
| #include "base/strings/stringprintf.h" |
| #include "storage/browser/fileapi/obfuscated_file_util.h" |
| #include "storage/browser/fileapi/sandbox_directory_database.h" |
| #include "storage/browser/fileapi/sandbox_file_system_backend.h" |
| #include "storage/browser/fileapi/sandbox_origin_database.h" |
| #include "storage/browser/fileapi/sandbox_prioritized_origin_database.h" |
| #include "storage/common/fileapi/file_system_types.h" |
| #include "storage/common/fileapi/file_system_util.h" |
| |
| namespace { |
| |
| bool g_opt_long; |
| const base::FilePath::CharType* g_opt_fs_type = FILE_PATH_LITERAL("p"); |
| |
| void ShowMessageAndExit(const std::string& msg) { |
| fprintf(stderr, "%s\n", msg.c_str()); |
| exit(EXIT_FAILURE); |
| } |
| |
| void ShowUsageAndExit(const std::string& arg0) { |
| ShowMessageAndExit( |
| "Usage: " + arg0 + |
| " [-l] [-t] [-s] <filesystem dir> [origin]..."); |
| } |
| |
| } // namespace |
| |
| namespace storage { |
| |
| static void DumpDirectoryTree(const std::string& origin_name, |
| base::FilePath origin_dir) { |
| origin_dir = origin_dir.Append(g_opt_fs_type); |
| |
| printf("=== ORIGIN %s %s ===\n", |
| origin_name.c_str(), FilePathToString(origin_dir).c_str()); |
| |
| if (!base::DirectoryExists(origin_dir)) |
| return; |
| |
| SandboxDirectoryDatabase directory_db(origin_dir, NULL); |
| SandboxDirectoryDatabase::FileId root_id; |
| if (!directory_db.GetFileWithPath(StringToFilePath("/"), &root_id)) |
| return; |
| |
| std::stack<std::pair<SandboxDirectoryDatabase::FileId, |
| std::string> > paths; |
| paths.push(std::make_pair(root_id, "")); |
| while (!paths.empty()) { |
| SandboxDirectoryDatabase::FileId id = paths.top().first; |
| const std::string dirname = paths.top().second; |
| paths.pop(); |
| |
| SandboxDirectoryDatabase::FileInfo info; |
| if (!directory_db.GetFileInfo(id, &info)) { |
| ShowMessageAndExit(base::StringPrintf("GetFileInfo failed for %" PRId64, |
| id)); |
| } |
| |
| const std::string name = |
| dirname + "/" + FilePathToString(base::FilePath(info.name)); |
| std::vector<SandboxDirectoryDatabase::FileId> children; |
| if (info.is_directory()) { |
| if (!directory_db.ListChildren(id, &children)) { |
| ShowMessageAndExit(base::StringPrintf( |
| "ListChildren failed for %s (%" PRId64 ")", |
| info.name.c_str(), id)); |
| } |
| |
| for (size_t j = children.size(); j; j--) |
| paths.push(make_pair(children[j-1], name)); |
| } |
| |
| // +1 for the leading extra slash. |
| const char* display_name = name.c_str() + 1; |
| const char* directory_suffix = info.is_directory() ? "/" : ""; |
| if (g_opt_long) { |
| int64_t size; |
| if (info.is_directory()) { |
| size = static_cast<int64_t>(children.size()); |
| } else { |
| base::GetFileSize(origin_dir.Append(info.data_path), &size); |
| } |
| // TODO(hamaji): Modification time? |
| printf("%s%s %" PRId64 " %" PRId64 " %s\n", |
| display_name, |
| directory_suffix, |
| id, |
| size, |
| FilePathToString(info.data_path).c_str()); |
| } else { |
| printf("%s%s\n", display_name, directory_suffix); |
| } |
| } |
| } |
| |
| static base::FilePath GetOriginDir(const base::FilePath& file_system_dir, |
| const std::string& origin_name) { |
| if (base::PathExists(file_system_dir.Append( |
| SandboxPrioritizedOriginDatabase::kPrimaryOriginFile))) { |
| return base::FilePath( |
| SandboxPrioritizedOriginDatabase::kPrimaryDirectory); |
| } |
| |
| SandboxOriginDatabase origin_db(file_system_dir, NULL); |
| base::FilePath origin_dir; |
| if (!origin_db.HasOriginPath(origin_name)) { |
| ShowMessageAndExit("Origin " + origin_name + " is not in " + |
| FilePathToString(file_system_dir)); |
| } |
| |
| if (!origin_db.GetPathForOrigin(origin_name, &origin_dir)) { |
| ShowMessageAndExit("Failed to get path of origin " + origin_name + |
| " in " + FilePathToString(file_system_dir)); |
| } |
| |
| return origin_dir; |
| } |
| |
| static void DumpOrigin(const base::FilePath& file_system_dir, |
| const std::string& origin_name) { |
| base::FilePath origin_dir = GetOriginDir(file_system_dir, origin_name); |
| DumpDirectoryTree(origin_name, file_system_dir.Append(origin_dir)); |
| } |
| |
| static void DumpFileSystem(const base::FilePath& file_system_dir) { |
| SandboxOriginDatabase origin_db(file_system_dir, NULL); |
| std::vector<SandboxOriginDatabase::OriginRecord> origins; |
| origin_db.ListAllOrigins(&origins); |
| for (size_t i = 0; i < origins.size(); i++) { |
| const SandboxOriginDatabase::OriginRecord& origin = origins[i]; |
| DumpDirectoryTree(origin.origin, file_system_dir.Append(origin.path)); |
| puts(""); |
| } |
| } |
| |
| } // namespace storage |
| |
| int main(int argc, char* argv[]) { |
| const char* arg0 = argv[0]; |
| while (true) { |
| if (argc < 2) |
| ShowUsageAndExit(arg0); |
| |
| if (std::string(argv[1]) == "-l") { |
| g_opt_long = true; |
| argc--; |
| argv++; |
| } else if (std::string(argv[1]) == "-t") { |
| g_opt_fs_type = FILE_PATH_LITERAL("t"); |
| argc--; |
| argv++; |
| } else if (std::string(argv[1]) == "-s") { |
| g_opt_fs_type = FILE_PATH_LITERAL("s"); |
| argc--; |
| argv++; |
| } else { |
| break; |
| } |
| } |
| |
| if (argc < 2) |
| ShowUsageAndExit(arg0); |
| |
| const base::FilePath file_system_dir = storage::StringToFilePath(argv[1]); |
| if (!base::DirectoryExists(file_system_dir)) { |
| ShowMessageAndExit(storage::FilePathToString(file_system_dir) + |
| " is not a filesystem directory"); |
| } |
| |
| if (argc == 2) { |
| storage::DumpFileSystem(file_system_dir); |
| } else { |
| for (int i = 2; i < argc; i++) { |
| storage::DumpOrigin(file_system_dir, argv[i]); |
| } |
| } |
| return 0; |
| } |