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"
10 #include "nsComponentManagerUtils.h"
12 #include "nsIDirectoryEnumerator.h"
17 struct VirtualTableCursorBase
{
18 VirtualTableCursorBase() { memset(&mBase
, 0, sizeof(mBase
)); }
20 sqlite3_vtab_cursor mBase
;
23 struct VirtualTableCursor
: public VirtualTableCursorBase
{
25 VirtualTableCursor() : mRowId(-1) { mCurrentFileName
.SetIsVoid(true); }
27 const nsString
& DirectoryPath() const { return mDirectoryPath
; }
29 const nsString
& CurrentFileName() const { return mCurrentFileName
; }
31 int64_t RowId() const { return mRowId
; }
33 nsresult
Init(const nsAString
& aPath
);
37 nsCOMPtr
<nsIDirectoryEnumerator
> mEntries
;
39 nsString mDirectoryPath
;
40 nsString mCurrentFileName
;
45 nsresult
VirtualTableCursor::Init(const nsAString
& aPath
) {
46 nsCOMPtr
<nsIFile
> directory
= do_CreateInstance(NS_LOCAL_FILE_CONTRACTID
);
47 NS_ENSURE_TRUE(directory
, NS_ERROR_FAILURE
);
49 nsresult rv
= directory
->InitWithPath(aPath
);
50 NS_ENSURE_SUCCESS(rv
, rv
);
52 rv
= directory
->GetPath(mDirectoryPath
);
53 NS_ENSURE_SUCCESS(rv
, rv
);
55 rv
= directory
->GetDirectoryEntries(getter_AddRefs(mEntries
));
56 NS_ENSURE_SUCCESS(rv
, rv
);
59 NS_ENSURE_SUCCESS(rv
, rv
);
64 nsresult
VirtualTableCursor::NextFile() {
66 nsresult rv
= mEntries
->HasMoreElements(&hasMore
);
67 NS_ENSURE_SUCCESS(rv
, rv
);
70 mCurrentFileName
.SetIsVoid(true);
74 nsCOMPtr
<nsISupports
> entry
;
75 rv
= mEntries
->GetNext(getter_AddRefs(entry
));
76 NS_ENSURE_SUCCESS(rv
, rv
);
78 nsCOMPtr
<nsIFile
> file
= do_QueryInterface(entry
);
79 NS_ENSURE_TRUE(file
, NS_ERROR_FAILURE
);
81 rv
= file
->GetLeafName(mCurrentFileName
);
82 NS_ENSURE_SUCCESS(rv
, rv
);
89 int Connect(sqlite3
* aDB
, void* aAux
, int aArgc
, const char* const* aArgv
,
90 sqlite3_vtab
** aVtab
, char** aErr
) {
91 static const char virtualTableSchema
[] =
97 int rc
= sqlite3_declare_vtab(aDB
, virtualTableSchema
);
98 if (rc
!= SQLITE_OK
) {
102 sqlite3_vtab
* vt
= new sqlite3_vtab();
103 memset(vt
, 0, sizeof(*vt
));
110 int Disconnect(sqlite3_vtab
* aVtab
) {
116 int BestIndex(sqlite3_vtab
* aVtab
, sqlite3_index_info
* aInfo
) {
117 // Here we specify what index constraints we want to handle. That is, there
118 // might be some columns with particular constraints in which we can help
119 // SQLite narrow down the result set.
121 // For example, take the "path = x" where x is a directory. In this case,
122 // we can narrow our search to just this directory instead of the entire file
123 // system. This can be a significant optimization. So, we want to handle that
124 // constraint. To do so, we would look for two specific input conditions:
126 // 1. aInfo->aConstraint[i].iColumn == 1
127 // 2. aInfo->aConstraint[i].op == SQLITE_INDEX_CONSTRAINT_EQ
129 // The first states that the path column is being used in one of the input
130 // constraints and the second states that the constraint involves the equal
133 // An even more specific search would be for name='xxx', in which case we
134 // can limit the search to a single file, if it exists.
136 // What we have to do here is look for all of our index searches and select
137 // the narrowest. We can only pick one, so obviously we want the one that
138 // is the most specific, which leads to the smallest result set.
140 for (int i
= 0; i
< aInfo
->nConstraint
; i
++) {
141 if (aInfo
->aConstraint
[i
].iColumn
== 1 && aInfo
->aConstraint
[i
].usable
) {
142 if (aInfo
->aConstraint
[i
].op
& SQLITE_INDEX_CONSTRAINT_EQ
) {
143 aInfo
->aConstraintUsage
[i
].argvIndex
= 1;
148 // TODO: handle single files (constrained also by the name column)
154 int Open(sqlite3_vtab
* aVtab
, sqlite3_vtab_cursor
** aCursor
) {
155 VirtualTableCursor
* cursor
= new VirtualTableCursor();
157 *aCursor
= reinterpret_cast<sqlite3_vtab_cursor
*>(cursor
);
162 int Close(sqlite3_vtab_cursor
* aCursor
) {
163 VirtualTableCursor
* cursor
= reinterpret_cast<VirtualTableCursor
*>(aCursor
);
170 int Filter(sqlite3_vtab_cursor
* aCursor
, int aIdxNum
, const char* aIdxStr
,
171 int aArgc
, sqlite3_value
** aArgv
) {
172 VirtualTableCursor
* cursor
= reinterpret_cast<VirtualTableCursor
*>(aCursor
);
178 const char16_t
* value
=
179 static_cast<const char16_t
*>(::sqlite3_value_text16(aArgv
[0]));
181 nsDependentString
path(value
,
182 ::sqlite3_value_bytes16(aArgv
[0]) / sizeof(char16_t
));
184 nsresult rv
= cursor
->Init(path
);
185 NS_ENSURE_SUCCESS(rv
, SQLITE_ERROR
);
190 int Next(sqlite3_vtab_cursor
* aCursor
) {
191 VirtualTableCursor
* cursor
= reinterpret_cast<VirtualTableCursor
*>(aCursor
);
193 nsresult rv
= cursor
->NextFile();
194 NS_ENSURE_SUCCESS(rv
, SQLITE_ERROR
);
199 int Eof(sqlite3_vtab_cursor
* aCursor
) {
200 VirtualTableCursor
* cursor
= reinterpret_cast<VirtualTableCursor
*>(aCursor
);
201 return cursor
->CurrentFileName().IsVoid() ? 1 : 0;
204 int Column(sqlite3_vtab_cursor
* aCursor
, sqlite3_context
* aContext
,
206 VirtualTableCursor
* cursor
= reinterpret_cast<VirtualTableCursor
*>(aCursor
);
208 switch (aColumnIndex
) {
211 const nsString
& name
= cursor
->CurrentFileName();
212 sqlite3_result_text16(aContext
, name
.get(),
213 name
.Length() * sizeof(char16_t
), SQLITE_TRANSIENT
);
219 const nsString
& path
= cursor
->DirectoryPath();
220 sqlite3_result_text16(aContext
, path
.get(),
221 path
.Length() * sizeof(char16_t
), SQLITE_TRANSIENT
);
225 MOZ_ASSERT_UNREACHABLE("Unsupported column!");
231 int RowId(sqlite3_vtab_cursor
* aCursor
, sqlite3_int64
* aRowid
) {
232 VirtualTableCursor
* cursor
= reinterpret_cast<VirtualTableCursor
*>(aCursor
);
234 *aRowid
= cursor
->RowId();
244 int RegisterFileSystemModule(sqlite3
* aDB
, const char* aName
) {
245 static sqlite3_module module
= {
246 1, Connect
, Connect
, BestIndex
, Disconnect
, Disconnect
, Open
,
247 Close
, Filter
, Next
, Eof
, Column
, RowId
, nullptr,
248 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr};
250 return sqlite3_create_module(aDB
, aName
, &module
, nullptr);
253 } // namespace storage
254 } // namespace mozilla