Coverage Report

Created: 2018-09-25 14:53

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