forked from mirrors/gecko-dev
		
	 a8939590de
			
		
	
	
		a8939590de
		
	
	
	
	
		
			
			The bulk of this commit was generated by running:
  run-clang-tidy.py \
    -checks='-*,llvm-namespace-comment' \
    -header-filter=^/.../mozilla-central/.* \
    -fix
		
	
			
		
			
				
	
	
		
			304 lines
		
	
	
	
		
			6.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			304 lines
		
	
	
	
		
			6.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 | |
|  * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
 | |
|  * This Source Code Form is subject to the terms of the Mozilla Public
 | |
|  * License, v. 2.0. If a copy of the MPL was not distributed with this
 | |
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | |
| 
 | |
| #include "FileSystemModule.h"
 | |
| 
 | |
| #include "sqlite3.h"
 | |
| #include "nsString.h"
 | |
| #include "nsISimpleEnumerator.h"
 | |
| #include "nsIFile.h"
 | |
| 
 | |
| namespace {
 | |
| 
 | |
| struct VirtualTableCursorBase
 | |
| {
 | |
|   VirtualTableCursorBase()
 | |
|   {
 | |
|     memset(&mBase, 0, sizeof(mBase));
 | |
|   }
 | |
| 
 | |
|   sqlite3_vtab_cursor mBase;
 | |
| };
 | |
| 
 | |
| struct VirtualTableCursor : public VirtualTableCursorBase
 | |
| {
 | |
| public:
 | |
|   VirtualTableCursor()
 | |
|   : mRowId(-1)
 | |
|   {
 | |
|     mCurrentFileName.SetIsVoid(true);
 | |
|   }
 | |
| 
 | |
|   const nsString& DirectoryPath() const
 | |
|   {
 | |
|     return mDirectoryPath;
 | |
|   }
 | |
| 
 | |
|   const nsString& CurrentFileName() const
 | |
|   {
 | |
|     return mCurrentFileName;
 | |
|   }
 | |
| 
 | |
|   int64_t RowId() const
 | |
|   {
 | |
|     return mRowId;
 | |
|   }
 | |
| 
 | |
|   nsresult Init(const nsAString& aPath);
 | |
|   nsresult NextFile();
 | |
| 
 | |
| private:
 | |
|   nsCOMPtr<nsISimpleEnumerator> mEntries;
 | |
| 
 | |
|   nsString mDirectoryPath;
 | |
|   nsString mCurrentFileName;
 | |
| 
 | |
|   int64_t mRowId;
 | |
| };
 | |
| 
 | |
| nsresult
 | |
| VirtualTableCursor::Init(const nsAString& aPath)
 | |
| {
 | |
|   nsCOMPtr<nsIFile> directory =
 | |
|     do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
 | |
|   NS_ENSURE_TRUE(directory, NS_ERROR_FAILURE);
 | |
| 
 | |
|   nsresult rv = directory->InitWithPath(aPath);
 | |
|   NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|   rv = directory->GetPath(mDirectoryPath);
 | |
|   NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|   rv = directory->GetDirectoryEntries(getter_AddRefs(mEntries));
 | |
|   NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|   rv = NextFile();
 | |
|   NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| nsresult
 | |
| VirtualTableCursor::NextFile()
 | |
| {
 | |
|   bool hasMore;
 | |
|   nsresult rv = mEntries->HasMoreElements(&hasMore);
 | |
|   NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|   if (!hasMore) {
 | |
|     mCurrentFileName.SetIsVoid(true);
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|   nsCOMPtr<nsISupports> entry;
 | |
|   rv = mEntries->GetNext(getter_AddRefs(entry));
 | |
|   NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|   nsCOMPtr<nsIFile> file = do_QueryInterface(entry);
 | |
|   NS_ENSURE_TRUE(file, NS_ERROR_FAILURE);
 | |
| 
 | |
|   rv = file->GetLeafName(mCurrentFileName);
 | |
|   NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|   mRowId++;
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| int Connect(sqlite3* aDB, void* aAux, int aArgc, const char* const* aArgv,
 | |
|             sqlite3_vtab** aVtab, char** aErr)
 | |
| {
 | |
|   static const char virtualTableSchema[] =
 | |
|     "CREATE TABLE fs ("
 | |
|       "name TEXT, "
 | |
|       "path TEXT"
 | |
|     ")";
 | |
| 
 | |
|   int rc = sqlite3_declare_vtab(aDB, virtualTableSchema);
 | |
|   if (rc != SQLITE_OK) {
 | |
|     return rc;
 | |
|   }
 | |
| 
 | |
|   sqlite3_vtab* vt = new sqlite3_vtab();
 | |
|   memset(vt, 0, sizeof(*vt));
 | |
| 
 | |
|   *aVtab = vt;
 | |
| 
 | |
|   return SQLITE_OK;
 | |
| }
 | |
| 
 | |
| int Disconnect(sqlite3_vtab* aVtab )
 | |
| {
 | |
|   delete aVtab;
 | |
| 
 | |
|   return SQLITE_OK;
 | |
| }
 | |
| 
 | |
| int BestIndex(sqlite3_vtab* aVtab, sqlite3_index_info* aInfo)
 | |
| {
 | |
|   // Here we specify what index constraints we want to handle. That is, there
 | |
|   // might be some columns with particular constraints in which we can help
 | |
|   // SQLite narrow down the result set.
 | |
|   //
 | |
|   // For example, take the "path = x" where x is a directory. In this case,
 | |
|   // we can narrow our search to just this directory instead of the entire file
 | |
|   // system. This can be a significant optimization. So, we want to handle that
 | |
|   // constraint. To do so, we would look for two specific input conditions:
 | |
|   //
 | |
|   // 1. aInfo->aConstraint[i].iColumn == 1
 | |
|   // 2. aInfo->aConstraint[i].op == SQLITE_INDEX_CONSTRAINT_EQ
 | |
|   //
 | |
|   // The first states that the path column is being used in one of the input
 | |
|   // constraints and the second states that the constraint involves the equal
 | |
|   // operator.
 | |
|   //
 | |
|   // An even more specific search would be for name='xxx', in which case we
 | |
|   // can limit the search to a single file, if it exists.
 | |
|   //
 | |
|   // What we have to do here is look for all of our index searches and select
 | |
|   // the narrowest. We can only pick one, so obviously we want the one that
 | |
|   // is the most specific, which leads to the smallest result set.
 | |
| 
 | |
|   for(int i = 0; i < aInfo->nConstraint; i++) {
 | |
|     if (aInfo->aConstraint[i].iColumn == 1 && aInfo->aConstraint[i].usable) {
 | |
|       if (aInfo->aConstraint[i].op & SQLITE_INDEX_CONSTRAINT_EQ) {
 | |
|         aInfo->aConstraintUsage[i].argvIndex = 1;
 | |
|       }
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     // TODO: handle single files (constrained also by the name column)
 | |
|   }
 | |
| 
 | |
|   return SQLITE_OK;
 | |
| }
 | |
| 
 | |
| int Open(sqlite3_vtab* aVtab, sqlite3_vtab_cursor** aCursor)
 | |
| {
 | |
|   VirtualTableCursor* cursor = new VirtualTableCursor();
 | |
| 
 | |
|   *aCursor = reinterpret_cast<sqlite3_vtab_cursor*>(cursor);
 | |
| 
 | |
|   return SQLITE_OK;
 | |
| }
 | |
| 
 | |
| int Close(sqlite3_vtab_cursor* aCursor)
 | |
| {
 | |
|   VirtualTableCursor* cursor = reinterpret_cast<VirtualTableCursor*>(aCursor);
 | |
| 
 | |
|   delete cursor;
 | |
| 
 | |
|   return SQLITE_OK;
 | |
| }
 | |
| 
 | |
| int Filter(sqlite3_vtab_cursor* aCursor, int aIdxNum, const char* aIdxStr,
 | |
|            int aArgc, sqlite3_value** aArgv)
 | |
| {
 | |
|   VirtualTableCursor* cursor = reinterpret_cast<VirtualTableCursor*>(aCursor);
 | |
| 
 | |
|   if(aArgc <= 0) {
 | |
|     return SQLITE_OK;
 | |
|   }
 | |
| 
 | |
|   nsDependentString path(
 | |
|     reinterpret_cast<const char16_t*>(::sqlite3_value_text16(aArgv[0])));
 | |
| 
 | |
|   nsresult rv = cursor->Init(path);
 | |
|   NS_ENSURE_SUCCESS(rv, SQLITE_ERROR);
 | |
| 
 | |
|   return SQLITE_OK;
 | |
| }
 | |
| 
 | |
| int Next(sqlite3_vtab_cursor* aCursor)
 | |
| {
 | |
|   VirtualTableCursor* cursor = reinterpret_cast<VirtualTableCursor*>(aCursor);
 | |
| 
 | |
|   nsresult rv = cursor->NextFile();
 | |
|   NS_ENSURE_SUCCESS(rv, SQLITE_ERROR);
 | |
| 
 | |
|   return SQLITE_OK;
 | |
| }
 | |
| 
 | |
| int Eof(sqlite3_vtab_cursor* aCursor)
 | |
| {
 | |
|   VirtualTableCursor* cursor = reinterpret_cast<VirtualTableCursor*>(aCursor);
 | |
|   return cursor->CurrentFileName().IsVoid() ? 1 : 0;
 | |
| }
 | |
| 
 | |
| int Column(sqlite3_vtab_cursor* aCursor, sqlite3_context* aContext,
 | |
|            int aColumnIndex)
 | |
| {
 | |
|   VirtualTableCursor* cursor = reinterpret_cast<VirtualTableCursor*>(aCursor);
 | |
| 
 | |
|   switch (aColumnIndex) {
 | |
|     // name
 | |
|     case 0: {
 | |
|       const nsString& name = cursor->CurrentFileName();
 | |
|       sqlite3_result_text16(aContext, name.get(),
 | |
|                             name.Length() * sizeof(char16_t),
 | |
|                             SQLITE_TRANSIENT);
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     // path
 | |
|     case 1: {
 | |
|       const nsString& path = cursor->DirectoryPath();
 | |
|       sqlite3_result_text16(aContext, path.get(),
 | |
|                             path.Length() * sizeof(char16_t),
 | |
|                             SQLITE_TRANSIENT);
 | |
|       break;
 | |
|     }
 | |
|     default:
 | |
|       NS_NOTREACHED("Unsupported column!");
 | |
|   }
 | |
| 
 | |
|   return SQLITE_OK;
 | |
| }
 | |
| 
 | |
| int RowId(sqlite3_vtab_cursor* aCursor, sqlite3_int64* aRowid)
 | |
| {
 | |
|   VirtualTableCursor* cursor = reinterpret_cast<VirtualTableCursor*>(aCursor);
 | |
| 
 | |
|   *aRowid = cursor->RowId();
 | |
| 
 | |
|   return SQLITE_OK;
 | |
| }
 | |
| 
 | |
| } // namespace
 | |
| 
 | |
| namespace mozilla {
 | |
| namespace storage {
 | |
| 
 | |
| int RegisterFileSystemModule(sqlite3* aDB, const char* aName)
 | |
| {
 | |
|   static sqlite3_module module = {
 | |
|     1,
 | |
|     Connect,
 | |
|     Connect,
 | |
|     BestIndex,
 | |
|     Disconnect,
 | |
|     Disconnect,
 | |
|     Open,
 | |
|     Close,
 | |
|     Filter,
 | |
|     Next,
 | |
|     Eof,
 | |
|     Column,
 | |
|     RowId,
 | |
|     nullptr,
 | |
|     nullptr,
 | |
|     nullptr,
 | |
|     nullptr,
 | |
|     nullptr,
 | |
|     nullptr,
 | |
|     nullptr
 | |
|   };
 | |
| 
 | |
|   return sqlite3_create_module(aDB, aName, &module, nullptr);
 | |
| }
 | |
| 
 | |
| } // namespace storage
 | |
| } // namespace mozilla
 |