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"
11 #include "nsIDirectoryEnumerator.h"
16 struct VirtualTableCursorBase
{
17 VirtualTableCursorBase() { memset(&mBase
, 0, sizeof(mBase
)); }
19 sqlite3_vtab_cursor mBase
;
22 struct VirtualTableCursor
: public VirtualTableCursorBase
{
24 VirtualTableCursor() : mRowId(-1) { mCurrentFileName
.SetIsVoid(true); }
26 const nsString
& DirectoryPath() const { return mDirectoryPath
; }
28 const nsString
& CurrentFileName() const { return mCurrentFileName
; }
30 int64_t RowId() const { return mRowId
; }
32 nsresult
Init(const nsAString
& aPath
);
36 nsCOMPtr
<nsIDirectoryEnumerator
> mEntries
;
38 nsString mDirectoryPath
;
39 nsString mCurrentFileName
;
44 nsresult
VirtualTableCursor::Init(const nsAString
& aPath
) {
45 nsCOMPtr
<nsIFile
> directory
= do_CreateInstance(NS_LOCAL_FILE_CONTRACTID
);
46 NS_ENSURE_TRUE(directory
, NS_ERROR_FAILURE
);
48 nsresult rv
= directory
->InitWithPath(aPath
);
49 NS_ENSURE_SUCCESS(rv
, rv
);
51 rv
= directory
->GetPath(mDirectoryPath
);
52 NS_ENSURE_SUCCESS(rv
, rv
);
54 rv
= directory
->GetDirectoryEntries(getter_AddRefs(mEntries
));
55 NS_ENSURE_SUCCESS(rv
, rv
);
58 NS_ENSURE_SUCCESS(rv
, rv
);
63 nsresult
VirtualTableCursor::NextFile() {
65 nsresult rv
= mEntries
->HasMoreElements(&hasMore
);
66 NS_ENSURE_SUCCESS(rv
, rv
);
69 mCurrentFileName
.SetIsVoid(true);
73 nsCOMPtr
<nsISupports
> entry
;
74 rv
= mEntries
->GetNext(getter_AddRefs(entry
));
75 NS_ENSURE_SUCCESS(rv
, rv
);
77 nsCOMPtr
<nsIFile
> file
= do_QueryInterface(entry
);
78 NS_ENSURE_TRUE(file
, NS_ERROR_FAILURE
);
80 rv
= file
->GetLeafName(mCurrentFileName
);
81 NS_ENSURE_SUCCESS(rv
, rv
);
88 int Connect(sqlite3
* aDB
, void* aAux
, int aArgc
, const char* const* aArgv
,
89 sqlite3_vtab
** aVtab
, char** aErr
) {
90 static const char virtualTableSchema
[] =
96 int rc
= sqlite3_declare_vtab(aDB
, virtualTableSchema
);
97 if (rc
!= SQLITE_OK
) {
101 sqlite3_vtab
* vt
= new sqlite3_vtab();
102 memset(vt
, 0, sizeof(*vt
));
109 int Disconnect(sqlite3_vtab
* aVtab
) {
115 int BestIndex(sqlite3_vtab
* aVtab
, sqlite3_index_info
* aInfo
) {
116 // Here we specify what index constraints we want to handle. That is, there
117 // might be some columns with particular constraints in which we can help
118 // SQLite narrow down the result set.
120 // For example, take the "path = x" where x is a directory. In this case,
121 // we can narrow our search to just this directory instead of the entire file
122 // system. This can be a significant optimization. So, we want to handle that
123 // constraint. To do so, we would look for two specific input conditions:
125 // 1. aInfo->aConstraint[i].iColumn == 1
126 // 2. aInfo->aConstraint[i].op == SQLITE_INDEX_CONSTRAINT_EQ
128 // The first states that the path column is being used in one of the input
129 // constraints and the second states that the constraint involves the equal
132 // An even more specific search would be for name='xxx', in which case we
133 // can limit the search to a single file, if it exists.
135 // What we have to do here is look for all of our index searches and select
136 // the narrowest. We can only pick one, so obviously we want the one that
137 // is the most specific, which leads to the smallest result set.
139 for (int i
= 0; i
< aInfo
->nConstraint
; i
++) {
140 if (aInfo
->aConstraint
[i
].iColumn
== 1 && aInfo
->aConstraint
[i
].usable
) {
141 if (aInfo
->aConstraint
[i
].op
& SQLITE_INDEX_CONSTRAINT_EQ
) {
142 aInfo
->aConstraintUsage
[i
].argvIndex
= 1;
147 // TODO: handle single files (constrained also by the name column)
153 int Open(sqlite3_vtab
* aVtab
, sqlite3_vtab_cursor
** aCursor
) {
154 VirtualTableCursor
* cursor
= new VirtualTableCursor();
156 *aCursor
= reinterpret_cast<sqlite3_vtab_cursor
*>(cursor
);
161 int Close(sqlite3_vtab_cursor
* aCursor
) {
162 VirtualTableCursor
* cursor
= reinterpret_cast<VirtualTableCursor
*>(aCursor
);
169 int Filter(sqlite3_vtab_cursor
* aCursor
, int aIdxNum
, const char* aIdxStr
,
170 int aArgc
, sqlite3_value
** aArgv
) {
171 VirtualTableCursor
* cursor
= reinterpret_cast<VirtualTableCursor
*>(aCursor
);
177 const char16_t
* value
=
178 static_cast<const char16_t
*>(::sqlite3_value_text16(aArgv
[0]));
180 nsDependentString
path(value
,
181 ::sqlite3_value_bytes16(aArgv
[0]) / sizeof(char16_t
));
183 nsresult rv
= cursor
->Init(path
);
184 NS_ENSURE_SUCCESS(rv
, SQLITE_ERROR
);
189 int Next(sqlite3_vtab_cursor
* aCursor
) {
190 VirtualTableCursor
* cursor
= reinterpret_cast<VirtualTableCursor
*>(aCursor
);
192 nsresult rv
= cursor
->NextFile();
193 NS_ENSURE_SUCCESS(rv
, SQLITE_ERROR
);
198 int Eof(sqlite3_vtab_cursor
* aCursor
) {
199 VirtualTableCursor
* cursor
= reinterpret_cast<VirtualTableCursor
*>(aCursor
);
200 return cursor
->CurrentFileName().IsVoid() ? 1 : 0;
203 int Column(sqlite3_vtab_cursor
* aCursor
, sqlite3_context
* aContext
,
205 VirtualTableCursor
* cursor
= reinterpret_cast<VirtualTableCursor
*>(aCursor
);
207 switch (aColumnIndex
) {
210 const nsString
& name
= cursor
->CurrentFileName();
211 sqlite3_result_text16(aContext
, name
.get(),
212 name
.Length() * sizeof(char16_t
), SQLITE_TRANSIENT
);
218 const nsString
& path
= cursor
->DirectoryPath();
219 sqlite3_result_text16(aContext
, path
.get(),
220 path
.Length() * sizeof(char16_t
), SQLITE_TRANSIENT
);
224 MOZ_ASSERT_UNREACHABLE("Unsupported column!");
230 int RowId(sqlite3_vtab_cursor
* aCursor
, sqlite3_int64
* aRowid
) {
231 VirtualTableCursor
* cursor
= reinterpret_cast<VirtualTableCursor
*>(aCursor
);
233 *aRowid
= cursor
->RowId();
243 int RegisterFileSystemModule(sqlite3
* aDB
, const char* aName
) {
244 static sqlite3_module module
= {
245 1, Connect
, Connect
, BestIndex
, Disconnect
, Disconnect
, Open
,
246 Close
, Filter
, Next
, Eof
, Column
, RowId
, nullptr,
247 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr};
249 return sqlite3_create_module(aDB
, aName
, &module
, nullptr);
252 } // namespace storage
253 } // namespace mozilla