1 // Copyright (c) 2013 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 // A tool to dump HTML5 filesystem from CUI. 6 // 7 // Usage: 8 // 9 // ./out/Release/dump_file_system [options] <filesystem dir> [origin]... 10 // 11 // If no origin is specified, this dumps all origins in the profile dir. 12 // 13 // Available options: 14 // 15 // -t : dumps temporary files instead of persistent. 16 // -s : dumps syncable files instead of persistent. 17 // -l : more information will be displayed. 18 // 19 // The format of -l option is: 20 // 21 // === ORIGIN origin_name origin_dir === 22 // file_name file_id file_size file_content_path 23 // ... 24 // 25 // where file_name has a trailing slash, file_size is the number of 26 // children, and file_content_path is empty if the file is a directory. 27 // 28 29 #include <stdio.h> 30 #include <stdlib.h> 31 32 #include <stack> 33 #include <string> 34 #include <utility> 35 #include <vector> 36 37 #include "base/file_util.h" 38 #include "base/files/file_path.h" 39 #include "base/format_macros.h" 40 #include "base/strings/stringprintf.h" 41 #include "webkit/browser/fileapi/obfuscated_file_util.h" 42 #include "webkit/browser/fileapi/sandbox_directory_database.h" 43 #include "webkit/browser/fileapi/sandbox_file_system_backend.h" 44 #include "webkit/browser/fileapi/sandbox_origin_database.h" 45 #include "webkit/common/fileapi/file_system_types.h" 46 #include "webkit/common/fileapi/file_system_util.h" 47 48 namespace { 49 50 bool g_opt_long; 51 const char* g_opt_fs_type = "p"; 52 53 void ShowMessageAndExit(const std::string& msg) { 54 fprintf(stderr, "%s\n", msg.c_str()); 55 exit(EXIT_FAILURE); 56 } 57 58 void ShowUsageAndExit(const std::string& arg0) { 59 ShowMessageAndExit( 60 "Usage: " + arg0 + 61 " [-l] [-t] [-s] <filesystem dir> [origin]..."); 62 } 63 64 } // namespace 65 66 namespace fileapi { 67 68 static void DumpDirectoryTree(const std::string& origin_name, 69 base::FilePath origin_dir) { 70 origin_dir = origin_dir.Append(g_opt_fs_type); 71 72 printf("=== ORIGIN %s %s ===\n", 73 origin_name.c_str(), FilePathToString(origin_dir).c_str()); 74 75 if (!base::DirectoryExists(origin_dir)) 76 return; 77 78 SandboxDirectoryDatabase directory_db(origin_dir); 79 SandboxDirectoryDatabase::FileId root_id; 80 if (!directory_db.GetFileWithPath(StringToFilePath("/"), &root_id)) 81 return; 82 83 std::stack<std::pair<SandboxDirectoryDatabase::FileId, 84 std::string> > paths; 85 paths.push(std::make_pair(root_id, "")); 86 while (!paths.empty()) { 87 SandboxDirectoryDatabase::FileId id = paths.top().first; 88 const std::string dirname = paths.top().second; 89 paths.pop(); 90 91 SandboxDirectoryDatabase::FileInfo info; 92 if (!directory_db.GetFileInfo(id, &info)) { 93 ShowMessageAndExit(base::StringPrintf("GetFileInfo failed for %"PRId64, 94 id)); 95 } 96 97 const std::string name = 98 dirname + "/" + FilePathToString(base::FilePath(info.name)); 99 std::vector<SandboxDirectoryDatabase::FileId> children; 100 if (info.is_directory()) { 101 if (!directory_db.ListChildren(id, &children)) { 102 ShowMessageAndExit(base::StringPrintf( 103 "ListChildren failed for %s (%"PRId64")", 104 info.name.c_str(), id)); 105 } 106 107 for (size_t j = children.size(); j; j--) 108 paths.push(make_pair(children[j-1], name)); 109 } 110 111 // +1 for the leading extra slash. 112 const char* display_name = name.c_str() + 1; 113 const char* directory_suffix = info.is_directory() ? "/" : ""; 114 if (g_opt_long) { 115 int64 size; 116 if (info.is_directory()) { 117 size = static_cast<int64>(children.size()); 118 } else { 119 base::GetFileSize(origin_dir.Append(info.data_path), &size); 120 } 121 // TODO(hamaji): Modification time? 122 printf("%s%s %"PRId64" %"PRId64" %s\n", 123 display_name, 124 directory_suffix, 125 id, 126 size, 127 FilePathToString(info.data_path).c_str()); 128 } else { 129 printf("%s%s\n", display_name, directory_suffix); 130 } 131 } 132 } 133 134 static void DumpOrigin(const base::FilePath& file_system_dir, 135 const std::string& origin_name) { 136 SandboxOriginDatabase origin_db(file_system_dir); 137 base::FilePath origin_dir; 138 if (!origin_db.HasOriginPath(origin_name)) { 139 ShowMessageAndExit("Origin " + origin_name + " is not in " + 140 FilePathToString(file_system_dir)); 141 } 142 143 if (!origin_db.GetPathForOrigin(origin_name, &origin_dir)) { 144 ShowMessageAndExit("Failed to get path of origin " + origin_name + 145 " in " + FilePathToString(file_system_dir)); 146 } 147 DumpDirectoryTree(origin_name, file_system_dir.Append(origin_dir)); 148 } 149 150 static void DumpFileSystem(const base::FilePath& file_system_dir) { 151 SandboxOriginDatabase origin_db(file_system_dir); 152 std::vector<SandboxOriginDatabase::OriginRecord> origins; 153 origin_db.ListAllOrigins(&origins); 154 for (size_t i = 0; i < origins.size(); i++) { 155 const SandboxOriginDatabase::OriginRecord& origin = origins[i]; 156 DumpDirectoryTree(origin.origin, file_system_dir.Append(origin.path)); 157 puts(""); 158 } 159 } 160 161 } // namespace fileapi 162 163 int main(int argc, char* argv[]) { 164 const char* arg0 = argv[0]; 165 std::string username = "Default"; 166 while (true) { 167 if (argc < 2) 168 ShowUsageAndExit(arg0); 169 170 if (std::string(argv[1]) == "-l") { 171 g_opt_long = true; 172 argc--; 173 argv++; 174 } else if (std::string(argv[1]) == "-t") { 175 g_opt_fs_type = "t"; 176 argc--; 177 argv++; 178 } else if (std::string(argv[1]) == "-s") { 179 g_opt_fs_type = "s"; 180 argc--; 181 argv++; 182 } else { 183 break; 184 } 185 } 186 187 if (argc < 2) 188 ShowUsageAndExit(arg0); 189 190 const base::FilePath file_system_dir = fileapi::StringToFilePath(argv[1]); 191 if (!base::DirectoryExists(file_system_dir)) { 192 ShowMessageAndExit(fileapi::FilePathToString(file_system_dir) + 193 " is not a filesystem directory"); 194 } 195 196 if (argc == 2) { 197 fileapi::DumpFileSystem(file_system_dir); 198 } else { 199 for (int i = 2; i < argc; i++) { 200 fileapi::DumpOrigin(file_system_dir, argv[i]); 201 } 202 } 203 return 0; 204 } 205