storage/src/FileSystemModule.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
michael@0 2 * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
michael@0 3 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #include "FileSystemModule.h"
michael@0 8
michael@0 9 #include "sqlite3.h"
michael@0 10 #include "nsString.h"
michael@0 11 #include "nsISimpleEnumerator.h"
michael@0 12 #include "nsIFile.h"
michael@0 13
michael@0 14 namespace {
michael@0 15
michael@0 16 struct VirtualTableCursorBase
michael@0 17 {
michael@0 18 VirtualTableCursorBase()
michael@0 19 {
michael@0 20 memset(&mBase, 0, sizeof(mBase));
michael@0 21 }
michael@0 22
michael@0 23 sqlite3_vtab_cursor mBase;
michael@0 24 };
michael@0 25
michael@0 26 struct VirtualTableCursor : public VirtualTableCursorBase
michael@0 27 {
michael@0 28 public:
michael@0 29 VirtualTableCursor()
michael@0 30 : mRowId(-1)
michael@0 31 {
michael@0 32 mCurrentFileName.SetIsVoid(true);
michael@0 33 }
michael@0 34
michael@0 35 const nsString& DirectoryPath() const
michael@0 36 {
michael@0 37 return mDirectoryPath;
michael@0 38 }
michael@0 39
michael@0 40 const nsString& CurrentFileName() const
michael@0 41 {
michael@0 42 return mCurrentFileName;
michael@0 43 }
michael@0 44
michael@0 45 int64_t RowId() const
michael@0 46 {
michael@0 47 return mRowId;
michael@0 48 }
michael@0 49
michael@0 50 nsresult Init(const nsAString& aPath);
michael@0 51 nsresult NextFile();
michael@0 52
michael@0 53 private:
michael@0 54 nsCOMPtr<nsISimpleEnumerator> mEntries;
michael@0 55
michael@0 56 nsString mDirectoryPath;
michael@0 57 nsString mCurrentFileName;
michael@0 58
michael@0 59 int64_t mRowId;
michael@0 60 };
michael@0 61
michael@0 62 nsresult
michael@0 63 VirtualTableCursor::Init(const nsAString& aPath)
michael@0 64 {
michael@0 65 nsCOMPtr<nsIFile> directory =
michael@0 66 do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
michael@0 67 NS_ENSURE_TRUE(directory, NS_ERROR_FAILURE);
michael@0 68
michael@0 69 nsresult rv = directory->InitWithPath(aPath);
michael@0 70 NS_ENSURE_SUCCESS(rv, rv);
michael@0 71
michael@0 72 rv = directory->GetPath(mDirectoryPath);
michael@0 73 NS_ENSURE_SUCCESS(rv, rv);
michael@0 74
michael@0 75 rv = directory->GetDirectoryEntries(getter_AddRefs(mEntries));
michael@0 76 NS_ENSURE_SUCCESS(rv, rv);
michael@0 77
michael@0 78 rv = NextFile();
michael@0 79 NS_ENSURE_SUCCESS(rv, rv);
michael@0 80
michael@0 81 return NS_OK;
michael@0 82 }
michael@0 83
michael@0 84 nsresult
michael@0 85 VirtualTableCursor::NextFile()
michael@0 86 {
michael@0 87 bool hasMore;
michael@0 88 nsresult rv = mEntries->HasMoreElements(&hasMore);
michael@0 89 NS_ENSURE_SUCCESS(rv, rv);
michael@0 90
michael@0 91 if (!hasMore) {
michael@0 92 mCurrentFileName.SetIsVoid(true);
michael@0 93 return NS_OK;
michael@0 94 }
michael@0 95
michael@0 96 nsCOMPtr<nsISupports> entry;
michael@0 97 rv = mEntries->GetNext(getter_AddRefs(entry));
michael@0 98 NS_ENSURE_SUCCESS(rv, rv);
michael@0 99
michael@0 100 nsCOMPtr<nsIFile> file = do_QueryInterface(entry);
michael@0 101 NS_ENSURE_TRUE(file, NS_ERROR_FAILURE);
michael@0 102
michael@0 103 rv = file->GetLeafName(mCurrentFileName);
michael@0 104 NS_ENSURE_SUCCESS(rv, rv);
michael@0 105
michael@0 106 mRowId++;
michael@0 107
michael@0 108 return NS_OK;
michael@0 109 }
michael@0 110
michael@0 111 int Connect(sqlite3* aDB, void* aAux, int aArgc, const char* const* aArgv,
michael@0 112 sqlite3_vtab** aVtab, char** aErr)
michael@0 113 {
michael@0 114 static const char virtualTableSchema[] =
michael@0 115 "CREATE TABLE fs ("
michael@0 116 "name TEXT, "
michael@0 117 "path TEXT"
michael@0 118 ")";
michael@0 119
michael@0 120 int rc = sqlite3_declare_vtab(aDB, virtualTableSchema);
michael@0 121 if (rc != SQLITE_OK) {
michael@0 122 return rc;
michael@0 123 }
michael@0 124
michael@0 125 sqlite3_vtab* vt = new sqlite3_vtab();
michael@0 126 memset(vt, 0, sizeof(*vt));
michael@0 127
michael@0 128 *aVtab = vt;
michael@0 129
michael@0 130 return SQLITE_OK;
michael@0 131 }
michael@0 132
michael@0 133 int Disconnect(sqlite3_vtab* aVtab )
michael@0 134 {
michael@0 135 delete aVtab;
michael@0 136
michael@0 137 return SQLITE_OK;
michael@0 138 }
michael@0 139
michael@0 140 int BestIndex(sqlite3_vtab* aVtab, sqlite3_index_info* aInfo)
michael@0 141 {
michael@0 142 // Here we specify what index constraints we want to handle. That is, there
michael@0 143 // might be some columns with particular constraints in which we can help
michael@0 144 // SQLite narrow down the result set.
michael@0 145 //
michael@0 146 // For example, take the "path = x" where x is a directory. In this case,
michael@0 147 // we can narrow our search to just this directory instead of the entire file
michael@0 148 // system. This can be a significant optimization. So, we want to handle that
michael@0 149 // constraint. To do so, we would look for two specific input conditions:
michael@0 150 //
michael@0 151 // 1. aInfo->aConstraint[i].iColumn == 1
michael@0 152 // 2. aInfo->aConstraint[i].op == SQLITE_INDEX_CONSTRAINT_EQ
michael@0 153 //
michael@0 154 // The first states that the path column is being used in one of the input
michael@0 155 // constraints and the second states that the constraint involves the equal
michael@0 156 // operator.
michael@0 157 //
michael@0 158 // An even more specific search would be for name='xxx', in which case we
michael@0 159 // can limit the search to a single file, if it exists.
michael@0 160 //
michael@0 161 // What we have to do here is look for all of our index searches and select
michael@0 162 // the narrowest. We can only pick one, so obviously we want the one that
michael@0 163 // is the most specific, which leads to the smallest result set.
michael@0 164
michael@0 165 for(int i = 0; i < aInfo->nConstraint; i++) {
michael@0 166 if (aInfo->aConstraint[i].iColumn == 1 && aInfo->aConstraint[i].usable) {
michael@0 167 if (aInfo->aConstraint[i].op & SQLITE_INDEX_CONSTRAINT_EQ) {
michael@0 168 aInfo->aConstraintUsage[i].argvIndex = 1;
michael@0 169 }
michael@0 170 break;
michael@0 171 }
michael@0 172
michael@0 173 // TODO: handle single files (constrained also by the name column)
michael@0 174 }
michael@0 175
michael@0 176 return SQLITE_OK;
michael@0 177 }
michael@0 178
michael@0 179 int Open(sqlite3_vtab* aVtab, sqlite3_vtab_cursor** aCursor)
michael@0 180 {
michael@0 181 VirtualTableCursor* cursor = new VirtualTableCursor();
michael@0 182
michael@0 183 *aCursor = reinterpret_cast<sqlite3_vtab_cursor*>(cursor);
michael@0 184
michael@0 185 return SQLITE_OK;
michael@0 186 }
michael@0 187
michael@0 188 int Close(sqlite3_vtab_cursor* aCursor)
michael@0 189 {
michael@0 190 VirtualTableCursor* cursor = reinterpret_cast<VirtualTableCursor*>(aCursor);
michael@0 191
michael@0 192 delete cursor;
michael@0 193
michael@0 194 return SQLITE_OK;
michael@0 195 }
michael@0 196
michael@0 197 int Filter(sqlite3_vtab_cursor* aCursor, int aIdxNum, const char* aIdxStr,
michael@0 198 int aArgc, sqlite3_value** aArgv)
michael@0 199 {
michael@0 200 VirtualTableCursor* cursor = reinterpret_cast<VirtualTableCursor*>(aCursor);
michael@0 201
michael@0 202 if(aArgc <= 0) {
michael@0 203 return SQLITE_OK;
michael@0 204 }
michael@0 205
michael@0 206 nsDependentString path(
michael@0 207 reinterpret_cast<const char16_t*>(::sqlite3_value_text16(aArgv[0])));
michael@0 208
michael@0 209 nsresult rv = cursor->Init(path);
michael@0 210 NS_ENSURE_SUCCESS(rv, SQLITE_ERROR);
michael@0 211
michael@0 212 return SQLITE_OK;
michael@0 213 }
michael@0 214
michael@0 215 int Next(sqlite3_vtab_cursor* aCursor)
michael@0 216 {
michael@0 217 VirtualTableCursor* cursor = reinterpret_cast<VirtualTableCursor*>(aCursor);
michael@0 218
michael@0 219 nsresult rv = cursor->NextFile();
michael@0 220 NS_ENSURE_SUCCESS(rv, SQLITE_ERROR);
michael@0 221
michael@0 222 return SQLITE_OK;
michael@0 223 }
michael@0 224
michael@0 225 int Eof(sqlite3_vtab_cursor* aCursor)
michael@0 226 {
michael@0 227 VirtualTableCursor* cursor = reinterpret_cast<VirtualTableCursor*>(aCursor);
michael@0 228 return cursor->CurrentFileName().IsVoid() ? 1 : 0;
michael@0 229 }
michael@0 230
michael@0 231 int Column(sqlite3_vtab_cursor* aCursor, sqlite3_context* aContext,
michael@0 232 int aColumnIndex)
michael@0 233 {
michael@0 234 VirtualTableCursor* cursor = reinterpret_cast<VirtualTableCursor*>(aCursor);
michael@0 235
michael@0 236 switch (aColumnIndex) {
michael@0 237 // name
michael@0 238 case 0: {
michael@0 239 const nsString& name = cursor->CurrentFileName();
michael@0 240 sqlite3_result_text16(aContext, name.get(),
michael@0 241 name.Length() * sizeof(char16_t),
michael@0 242 SQLITE_TRANSIENT);
michael@0 243 break;
michael@0 244 }
michael@0 245
michael@0 246 // path
michael@0 247 case 1: {
michael@0 248 const nsString& path = cursor->DirectoryPath();
michael@0 249 sqlite3_result_text16(aContext, path.get(),
michael@0 250 path.Length() * sizeof(char16_t),
michael@0 251 SQLITE_TRANSIENT);
michael@0 252 break;
michael@0 253 }
michael@0 254 default:
michael@0 255 NS_NOTREACHED("Unsupported column!");
michael@0 256 }
michael@0 257
michael@0 258 return SQLITE_OK;
michael@0 259 }
michael@0 260
michael@0 261 int RowId(sqlite3_vtab_cursor* aCursor, sqlite3_int64* aRowid)
michael@0 262 {
michael@0 263 VirtualTableCursor* cursor = reinterpret_cast<VirtualTableCursor*>(aCursor);
michael@0 264
michael@0 265 *aRowid = cursor->RowId();
michael@0 266
michael@0 267 return SQLITE_OK;
michael@0 268 }
michael@0 269
michael@0 270 } // anonymous namespace
michael@0 271
michael@0 272 namespace mozilla {
michael@0 273 namespace storage {
michael@0 274
michael@0 275 int RegisterFileSystemModule(sqlite3* aDB, const char* aName)
michael@0 276 {
michael@0 277 static sqlite3_module module = {
michael@0 278 1,
michael@0 279 Connect,
michael@0 280 Connect,
michael@0 281 BestIndex,
michael@0 282 Disconnect,
michael@0 283 Disconnect,
michael@0 284 Open,
michael@0 285 Close,
michael@0 286 Filter,
michael@0 287 Next,
michael@0 288 Eof,
michael@0 289 Column,
michael@0 290 RowId,
michael@0 291 nullptr,
michael@0 292 nullptr,
michael@0 293 nullptr,
michael@0 294 nullptr,
michael@0 295 nullptr,
michael@0 296 nullptr,
michael@0 297 nullptr
michael@0 298 };
michael@0 299
michael@0 300 return sqlite3_create_module(aDB, aName, &module, nullptr);
michael@0 301 }
michael@0 302
michael@0 303 } // namespace storage
michael@0 304 } // namespace mozilla

mercurial