tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

FileSystemModule.cpp (7029B)


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