Bug 1462329 [wpt PR 10991] - Server-Timing: test TAO:* for cross-origin resource...
[gecko.git] / storage / FileSystemModule.cpp
blobed2f8cdef2a7c868955bb8416e1d834e2186ee75
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
18 VirtualTableCursorBase()
20 memset(&mBase, 0, sizeof(mBase));
23 sqlite3_vtab_cursor mBase;
26 struct VirtualTableCursor : public VirtualTableCursorBase
28 public:
29 VirtualTableCursor()
30 : mRowId(-1)
32 mCurrentFileName.SetIsVoid(true);
35 const nsString& DirectoryPath() const
37 return mDirectoryPath;
40 const nsString& CurrentFileName() const
42 return mCurrentFileName;
45 int64_t RowId() const
47 return mRowId;
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;
62 nsresult
63 VirtualTableCursor::Init(const nsAString& aPath)
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;
84 nsresult
85 VirtualTableCursor::NextFile()
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;
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;
111 int Connect(sqlite3* aDB, void* aAux, int aArgc, const char* const* aArgv,
112 sqlite3_vtab** aVtab, char** aErr)
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;
125 sqlite3_vtab* vt = new sqlite3_vtab();
126 memset(vt, 0, sizeof(*vt));
128 *aVtab = vt;
130 return SQLITE_OK;
133 int Disconnect(sqlite3_vtab* aVtab )
135 delete aVtab;
137 return SQLITE_OK;
140 int BestIndex(sqlite3_vtab* aVtab, sqlite3_index_info* aInfo)
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.
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:
151 // 1. aInfo->aConstraint[i].iColumn == 1
152 // 2. aInfo->aConstraint[i].op == SQLITE_INDEX_CONSTRAINT_EQ
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.
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.
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;
170 break;
173 // TODO: handle single files (constrained also by the name column)
176 return SQLITE_OK;
179 int Open(sqlite3_vtab* aVtab, sqlite3_vtab_cursor** aCursor)
181 VirtualTableCursor* cursor = new VirtualTableCursor();
183 *aCursor = reinterpret_cast<sqlite3_vtab_cursor*>(cursor);
185 return SQLITE_OK;
188 int Close(sqlite3_vtab_cursor* aCursor)
190 VirtualTableCursor* cursor = reinterpret_cast<VirtualTableCursor*>(aCursor);
192 delete cursor;
194 return SQLITE_OK;
197 int Filter(sqlite3_vtab_cursor* aCursor, int aIdxNum, const char* aIdxStr,
198 int aArgc, sqlite3_value** aArgv)
200 VirtualTableCursor* cursor = reinterpret_cast<VirtualTableCursor*>(aCursor);
202 if(aArgc <= 0) {
203 return SQLITE_OK;
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;
215 int Next(sqlite3_vtab_cursor* aCursor)
217 VirtualTableCursor* cursor = reinterpret_cast<VirtualTableCursor*>(aCursor);
219 nsresult rv = cursor->NextFile();
220 NS_ENSURE_SUCCESS(rv, SQLITE_ERROR);
222 return SQLITE_OK;
225 int Eof(sqlite3_vtab_cursor* aCursor)
227 VirtualTableCursor* cursor = reinterpret_cast<VirtualTableCursor*>(aCursor);
228 return cursor->CurrentFileName().IsVoid() ? 1 : 0;
231 int Column(sqlite3_vtab_cursor* aCursor, sqlite3_context* aContext,
232 int aColumnIndex)
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;
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;
254 default:
255 NS_NOTREACHED("Unsupported column!");
258 return SQLITE_OK;
261 int RowId(sqlite3_vtab_cursor* aCursor, sqlite3_int64* aRowid)
263 VirtualTableCursor* cursor = reinterpret_cast<VirtualTableCursor*>(aCursor);
265 *aRowid = cursor->RowId();
267 return SQLITE_OK;
270 } // namespace
272 namespace mozilla {
273 namespace storage {
275 int RegisterFileSystemModule(sqlite3* aDB, const char* aName)
277 static sqlite3_module module = {
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
300 return sqlite3_create_module(aDB, aName, &module, nullptr);
303 } // namespace storage
304 } // namespace mozilla