storage/src/FileSystemModule.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial