|
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 <string.h> |
|
8 #include "mozilla/Telemetry.h" |
|
9 #include "mozilla/Preferences.h" |
|
10 #include "sqlite3.h" |
|
11 #include "nsThreadUtils.h" |
|
12 #include "mozilla/dom/quota/PersistenceType.h" |
|
13 #include "mozilla/dom/quota/QuotaManager.h" |
|
14 #include "mozilla/dom/quota/QuotaObject.h" |
|
15 #include "mozilla/IOInterposer.h" |
|
16 |
|
17 // The last VFS version for which this file has been updated. |
|
18 #define LAST_KNOWN_VFS_VERSION 3 |
|
19 |
|
20 // The last io_methods version for which this file has been updated. |
|
21 #define LAST_KNOWN_IOMETHODS_VERSION 3 |
|
22 |
|
23 /** |
|
24 * This preference is a workaround to allow users/sysadmins to identify |
|
25 * that the profile exists on an NFS share whose implementation |
|
26 * is incompatible with SQLite's default locking implementation. |
|
27 * Bug 433129 attempted to automatically identify such file-systems, |
|
28 * but a reliable way was not found and it was determined that the fallback |
|
29 * locking is slower than POSIX locking, so we do not want to do it by default. |
|
30 */ |
|
31 #define PREF_NFS_FILESYSTEM "storage.nfs_filesystem" |
|
32 |
|
33 namespace { |
|
34 |
|
35 using namespace mozilla; |
|
36 using namespace mozilla::dom::quota; |
|
37 |
|
38 struct Histograms { |
|
39 const char *name; |
|
40 const Telemetry::ID readB; |
|
41 const Telemetry::ID writeB; |
|
42 const Telemetry::ID readMS; |
|
43 const Telemetry::ID writeMS; |
|
44 const Telemetry::ID syncMS; |
|
45 }; |
|
46 |
|
47 #define SQLITE_TELEMETRY(FILENAME, HGRAM) \ |
|
48 { FILENAME, \ |
|
49 Telemetry::MOZ_SQLITE_ ## HGRAM ## _READ_B, \ |
|
50 Telemetry::MOZ_SQLITE_ ## HGRAM ## _WRITE_B, \ |
|
51 Telemetry::MOZ_SQLITE_ ## HGRAM ## _READ_MS, \ |
|
52 Telemetry::MOZ_SQLITE_ ## HGRAM ## _WRITE_MS, \ |
|
53 Telemetry::MOZ_SQLITE_ ## HGRAM ## _SYNC_MS \ |
|
54 } |
|
55 |
|
56 Histograms gHistograms[] = { |
|
57 SQLITE_TELEMETRY("places.sqlite", PLACES), |
|
58 SQLITE_TELEMETRY("cookies.sqlite", COOKIES), |
|
59 SQLITE_TELEMETRY("webappsstore.sqlite", WEBAPPS), |
|
60 SQLITE_TELEMETRY(nullptr, OTHER) |
|
61 }; |
|
62 #undef SQLITE_TELEMETRY |
|
63 |
|
64 /** RAII class for measuring how long io takes on/off main thread |
|
65 */ |
|
66 class IOThreadAutoTimer { |
|
67 public: |
|
68 /** |
|
69 * IOThreadAutoTimer measures time spent in IO. Additionally it |
|
70 * automatically determines whether IO is happening on the main |
|
71 * thread and picks an appropriate histogram. |
|
72 * |
|
73 * @param id takes a telemetry histogram id. The id+1 must be an |
|
74 * equivalent histogram for the main thread. Eg, MOZ_SQLITE_OPEN_MS |
|
75 * is followed by MOZ_SQLITE_OPEN_MAIN_THREAD_MS. |
|
76 * |
|
77 * @param aOp optionally takes an IO operation to report through the |
|
78 * IOInterposer. Filename will be reported as NULL, and reference will be |
|
79 * either "sqlite-mainthread" or "sqlite-otherthread". |
|
80 */ |
|
81 IOThreadAutoTimer(Telemetry::ID id, |
|
82 IOInterposeObserver::Operation aOp = IOInterposeObserver::OpNone) |
|
83 : start(TimeStamp::Now()), |
|
84 id(id), |
|
85 op(aOp) |
|
86 { |
|
87 } |
|
88 |
|
89 /** |
|
90 * This constructor is for when we want to report an operation to |
|
91 * IOInterposer but do not require a telemetry probe. |
|
92 * |
|
93 * @param aOp IO Operation to report through the IOInterposer. |
|
94 */ |
|
95 IOThreadAutoTimer(IOInterposeObserver::Operation aOp) |
|
96 : start(TimeStamp::Now()), |
|
97 id(Telemetry::HistogramCount), |
|
98 op(aOp) |
|
99 { |
|
100 } |
|
101 |
|
102 ~IOThreadAutoTimer() |
|
103 { |
|
104 TimeStamp end(TimeStamp::Now()); |
|
105 uint32_t mainThread = NS_IsMainThread() ? 1 : 0; |
|
106 if (id != Telemetry::HistogramCount) { |
|
107 Telemetry::AccumulateTimeDelta(static_cast<Telemetry::ID>(id + mainThread), |
|
108 start, end); |
|
109 } |
|
110 // We don't report SQLite I/O on Windows because we have a comprehensive |
|
111 // mechanism for intercepting I/O on that platform that captures a superset |
|
112 // of the data captured here. |
|
113 #if defined(MOZ_ENABLE_PROFILER_SPS) && !defined(XP_WIN) |
|
114 if (IOInterposer::IsObservedOperation(op)) { |
|
115 const char* main_ref = "sqlite-mainthread"; |
|
116 const char* other_ref = "sqlite-otherthread"; |
|
117 |
|
118 // Create observation |
|
119 IOInterposeObserver::Observation ob(op, start, end, |
|
120 (mainThread ? main_ref : other_ref)); |
|
121 // Report observation |
|
122 IOInterposer::Report(ob); |
|
123 } |
|
124 #endif /* defined(MOZ_ENABLE_PROFILER_SPS) && !defined(XP_WIN) */ |
|
125 } |
|
126 |
|
127 private: |
|
128 const TimeStamp start; |
|
129 const Telemetry::ID id; |
|
130 IOInterposeObserver::Operation op; |
|
131 }; |
|
132 |
|
133 struct telemetry_file { |
|
134 // Base class. Must be first |
|
135 sqlite3_file base; |
|
136 |
|
137 // histograms pertaining to this file |
|
138 Histograms *histograms; |
|
139 |
|
140 // quota object for this file |
|
141 nsRefPtr<QuotaObject> quotaObject; |
|
142 |
|
143 // This contains the vfs that actually does work |
|
144 sqlite3_file pReal[1]; |
|
145 }; |
|
146 |
|
147 /* |
|
148 ** Close a telemetry_file. |
|
149 */ |
|
150 int |
|
151 xClose(sqlite3_file *pFile) |
|
152 { |
|
153 telemetry_file *p = (telemetry_file *)pFile; |
|
154 int rc; |
|
155 { // Scope for IOThreadAutoTimer |
|
156 IOThreadAutoTimer ioTimer(IOInterposeObserver::OpClose); |
|
157 rc = p->pReal->pMethods->xClose(p->pReal); |
|
158 } |
|
159 if( rc==SQLITE_OK ){ |
|
160 delete p->base.pMethods; |
|
161 p->base.pMethods = nullptr; |
|
162 p->quotaObject = nullptr; |
|
163 } |
|
164 return rc; |
|
165 } |
|
166 |
|
167 /* |
|
168 ** Read data from a telemetry_file. |
|
169 */ |
|
170 int |
|
171 xRead(sqlite3_file *pFile, void *zBuf, int iAmt, sqlite_int64 iOfst) |
|
172 { |
|
173 telemetry_file *p = (telemetry_file *)pFile; |
|
174 IOThreadAutoTimer ioTimer(p->histograms->readMS, IOInterposeObserver::OpRead); |
|
175 int rc; |
|
176 rc = p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst); |
|
177 // sqlite likes to read from empty files, this is normal, ignore it. |
|
178 if (rc != SQLITE_IOERR_SHORT_READ) |
|
179 Telemetry::Accumulate(p->histograms->readB, rc == SQLITE_OK ? iAmt : 0); |
|
180 return rc; |
|
181 } |
|
182 |
|
183 /* |
|
184 ** Write data to a telemetry_file. |
|
185 */ |
|
186 int |
|
187 xWrite(sqlite3_file *pFile, const void *zBuf, int iAmt, sqlite_int64 iOfst) |
|
188 { |
|
189 telemetry_file *p = (telemetry_file *)pFile; |
|
190 if (p->quotaObject && !p->quotaObject->MaybeAllocateMoreSpace(iOfst, iAmt)) { |
|
191 return SQLITE_FULL; |
|
192 } |
|
193 IOThreadAutoTimer ioTimer(p->histograms->writeMS, IOInterposeObserver::OpWrite); |
|
194 int rc; |
|
195 rc = p->pReal->pMethods->xWrite(p->pReal, zBuf, iAmt, iOfst); |
|
196 Telemetry::Accumulate(p->histograms->writeB, rc == SQLITE_OK ? iAmt : 0); |
|
197 return rc; |
|
198 } |
|
199 |
|
200 /* |
|
201 ** Truncate a telemetry_file. |
|
202 */ |
|
203 int |
|
204 xTruncate(sqlite3_file *pFile, sqlite_int64 size) |
|
205 { |
|
206 IOThreadAutoTimer ioTimer(Telemetry::MOZ_SQLITE_TRUNCATE_MS); |
|
207 telemetry_file *p = (telemetry_file *)pFile; |
|
208 int rc; |
|
209 Telemetry::AutoTimer<Telemetry::MOZ_SQLITE_TRUNCATE_MS> timer; |
|
210 rc = p->pReal->pMethods->xTruncate(p->pReal, size); |
|
211 if (rc == SQLITE_OK && p->quotaObject) { |
|
212 p->quotaObject->UpdateSize(size); |
|
213 } |
|
214 return rc; |
|
215 } |
|
216 |
|
217 /* |
|
218 ** Sync a telemetry_file. |
|
219 */ |
|
220 int |
|
221 xSync(sqlite3_file *pFile, int flags) |
|
222 { |
|
223 telemetry_file *p = (telemetry_file *)pFile; |
|
224 IOThreadAutoTimer ioTimer(p->histograms->syncMS, IOInterposeObserver::OpFSync); |
|
225 return p->pReal->pMethods->xSync(p->pReal, flags); |
|
226 } |
|
227 |
|
228 /* |
|
229 ** Return the current file-size of a telemetry_file. |
|
230 */ |
|
231 int |
|
232 xFileSize(sqlite3_file *pFile, sqlite_int64 *pSize) |
|
233 { |
|
234 IOThreadAutoTimer ioTimer(IOInterposeObserver::OpStat); |
|
235 telemetry_file *p = (telemetry_file *)pFile; |
|
236 int rc; |
|
237 rc = p->pReal->pMethods->xFileSize(p->pReal, pSize); |
|
238 return rc; |
|
239 } |
|
240 |
|
241 /* |
|
242 ** Lock a telemetry_file. |
|
243 */ |
|
244 int |
|
245 xLock(sqlite3_file *pFile, int eLock) |
|
246 { |
|
247 telemetry_file *p = (telemetry_file *)pFile; |
|
248 int rc; |
|
249 rc = p->pReal->pMethods->xLock(p->pReal, eLock); |
|
250 return rc; |
|
251 } |
|
252 |
|
253 /* |
|
254 ** Unlock a telemetry_file. |
|
255 */ |
|
256 int |
|
257 xUnlock(sqlite3_file *pFile, int eLock) |
|
258 { |
|
259 telemetry_file *p = (telemetry_file *)pFile; |
|
260 int rc; |
|
261 rc = p->pReal->pMethods->xUnlock(p->pReal, eLock); |
|
262 return rc; |
|
263 } |
|
264 |
|
265 /* |
|
266 ** Check if another file-handle holds a RESERVED lock on a telemetry_file. |
|
267 */ |
|
268 int |
|
269 xCheckReservedLock(sqlite3_file *pFile, int *pResOut) |
|
270 { |
|
271 telemetry_file *p = (telemetry_file *)pFile; |
|
272 int rc = p->pReal->pMethods->xCheckReservedLock(p->pReal, pResOut); |
|
273 return rc; |
|
274 } |
|
275 |
|
276 /* |
|
277 ** File control method. For custom operations on a telemetry_file. |
|
278 */ |
|
279 int |
|
280 xFileControl(sqlite3_file *pFile, int op, void *pArg) |
|
281 { |
|
282 telemetry_file *p = (telemetry_file *)pFile; |
|
283 int rc = p->pReal->pMethods->xFileControl(p->pReal, op, pArg); |
|
284 return rc; |
|
285 } |
|
286 |
|
287 /* |
|
288 ** Return the sector-size in bytes for a telemetry_file. |
|
289 */ |
|
290 int |
|
291 xSectorSize(sqlite3_file *pFile) |
|
292 { |
|
293 telemetry_file *p = (telemetry_file *)pFile; |
|
294 int rc; |
|
295 rc = p->pReal->pMethods->xSectorSize(p->pReal); |
|
296 return rc; |
|
297 } |
|
298 |
|
299 /* |
|
300 ** Return the device characteristic flags supported by a telemetry_file. |
|
301 */ |
|
302 int |
|
303 xDeviceCharacteristics(sqlite3_file *pFile) |
|
304 { |
|
305 telemetry_file *p = (telemetry_file *)pFile; |
|
306 int rc; |
|
307 rc = p->pReal->pMethods->xDeviceCharacteristics(p->pReal); |
|
308 return rc; |
|
309 } |
|
310 |
|
311 /* |
|
312 ** Shared-memory operations. |
|
313 */ |
|
314 int |
|
315 xShmLock(sqlite3_file *pFile, int ofst, int n, int flags) |
|
316 { |
|
317 telemetry_file *p = (telemetry_file *)pFile; |
|
318 return p->pReal->pMethods->xShmLock(p->pReal, ofst, n, flags); |
|
319 } |
|
320 |
|
321 int |
|
322 xShmMap(sqlite3_file *pFile, int iRegion, int szRegion, int isWrite, void volatile **pp) |
|
323 { |
|
324 telemetry_file *p = (telemetry_file *)pFile; |
|
325 int rc; |
|
326 rc = p->pReal->pMethods->xShmMap(p->pReal, iRegion, szRegion, isWrite, pp); |
|
327 return rc; |
|
328 } |
|
329 |
|
330 void |
|
331 xShmBarrier(sqlite3_file *pFile){ |
|
332 telemetry_file *p = (telemetry_file *)pFile; |
|
333 p->pReal->pMethods->xShmBarrier(p->pReal); |
|
334 } |
|
335 |
|
336 int |
|
337 xShmUnmap(sqlite3_file *pFile, int delFlag){ |
|
338 telemetry_file *p = (telemetry_file *)pFile; |
|
339 int rc; |
|
340 rc = p->pReal->pMethods->xShmUnmap(p->pReal, delFlag); |
|
341 return rc; |
|
342 } |
|
343 |
|
344 int |
|
345 xFetch(sqlite3_file *pFile, sqlite3_int64 iOff, int iAmt, void **pp) |
|
346 { |
|
347 telemetry_file *p = (telemetry_file *)pFile; |
|
348 MOZ_ASSERT(p->pReal->pMethods->iVersion >= 3); |
|
349 return p->pReal->pMethods->xFetch(p->pReal, iOff, iAmt, pp); |
|
350 } |
|
351 |
|
352 int |
|
353 xUnfetch(sqlite3_file *pFile, sqlite3_int64 iOff, void *pResOut) |
|
354 { |
|
355 telemetry_file *p = (telemetry_file *)pFile; |
|
356 MOZ_ASSERT(p->pReal->pMethods->iVersion >= 3); |
|
357 return p->pReal->pMethods->xUnfetch(p->pReal, iOff, pResOut); |
|
358 } |
|
359 |
|
360 int |
|
361 xOpen(sqlite3_vfs* vfs, const char *zName, sqlite3_file* pFile, |
|
362 int flags, int *pOutFlags) |
|
363 { |
|
364 IOThreadAutoTimer ioTimer(Telemetry::MOZ_SQLITE_OPEN_MS, |
|
365 IOInterposeObserver::OpCreateOrOpen); |
|
366 Telemetry::AutoTimer<Telemetry::MOZ_SQLITE_OPEN_MS> timer; |
|
367 sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData); |
|
368 int rc; |
|
369 telemetry_file *p = (telemetry_file *)pFile; |
|
370 Histograms *h = nullptr; |
|
371 // check if the filename is one we are probing for |
|
372 for(size_t i = 0;i < sizeof(gHistograms)/sizeof(gHistograms[0]);i++) { |
|
373 h = &gHistograms[i]; |
|
374 // last probe is the fallback probe |
|
375 if (!h->name) |
|
376 break; |
|
377 if (!zName) |
|
378 continue; |
|
379 const char *match = strstr(zName, h->name); |
|
380 if (!match) |
|
381 continue; |
|
382 char c = match[strlen(h->name)]; |
|
383 // include -wal/-journal too |
|
384 if (!c || c == '-') |
|
385 break; |
|
386 } |
|
387 p->histograms = h; |
|
388 |
|
389 const char* persistenceType; |
|
390 const char* group; |
|
391 const char* origin; |
|
392 if ((flags & SQLITE_OPEN_URI) && |
|
393 (persistenceType = sqlite3_uri_parameter(zName, "persistenceType")) && |
|
394 (group = sqlite3_uri_parameter(zName, "group")) && |
|
395 (origin = sqlite3_uri_parameter(zName, "origin"))) { |
|
396 QuotaManager* quotaManager = QuotaManager::Get(); |
|
397 MOZ_ASSERT(quotaManager); |
|
398 |
|
399 p->quotaObject = quotaManager->GetQuotaObject(PersistenceTypeFromText( |
|
400 nsDependentCString(persistenceType)), nsDependentCString(group), |
|
401 nsDependentCString(origin), NS_ConvertUTF8toUTF16(zName)); |
|
402 } |
|
403 |
|
404 rc = orig_vfs->xOpen(orig_vfs, zName, p->pReal, flags, pOutFlags); |
|
405 if( rc != SQLITE_OK ) |
|
406 return rc; |
|
407 if( p->pReal->pMethods ){ |
|
408 sqlite3_io_methods *pNew = new sqlite3_io_methods; |
|
409 const sqlite3_io_methods *pSub = p->pReal->pMethods; |
|
410 memset(pNew, 0, sizeof(*pNew)); |
|
411 // If the io_methods version is higher than the last known one, you should |
|
412 // update this VFS adding appropriate IO methods for any methods added in |
|
413 // the version change. |
|
414 pNew->iVersion = pSub->iVersion; |
|
415 MOZ_ASSERT(pNew->iVersion <= LAST_KNOWN_IOMETHODS_VERSION); |
|
416 pNew->xClose = xClose; |
|
417 pNew->xRead = xRead; |
|
418 pNew->xWrite = xWrite; |
|
419 pNew->xTruncate = xTruncate; |
|
420 pNew->xSync = xSync; |
|
421 pNew->xFileSize = xFileSize; |
|
422 pNew->xLock = xLock; |
|
423 pNew->xUnlock = xUnlock; |
|
424 pNew->xCheckReservedLock = xCheckReservedLock; |
|
425 pNew->xFileControl = xFileControl; |
|
426 pNew->xSectorSize = xSectorSize; |
|
427 pNew->xDeviceCharacteristics = xDeviceCharacteristics; |
|
428 if (pNew->iVersion >= 2) { |
|
429 // Methods added in version 2. |
|
430 pNew->xShmMap = pSub->xShmMap ? xShmMap : 0; |
|
431 pNew->xShmLock = pSub->xShmLock ? xShmLock : 0; |
|
432 pNew->xShmBarrier = pSub->xShmBarrier ? xShmBarrier : 0; |
|
433 pNew->xShmUnmap = pSub->xShmUnmap ? xShmUnmap : 0; |
|
434 } |
|
435 if (pNew->iVersion >= 3) { |
|
436 // Methods added in version 3. |
|
437 // SQLite 3.7.17 calls these methods without checking for nullptr first, |
|
438 // so we always define them. Verify that we're not going to call |
|
439 // nullptrs, though. |
|
440 MOZ_ASSERT(pSub->xFetch); |
|
441 pNew->xFetch = xFetch; |
|
442 MOZ_ASSERT(pSub->xUnfetch); |
|
443 pNew->xUnfetch = xUnfetch; |
|
444 } |
|
445 pFile->pMethods = pNew; |
|
446 } |
|
447 return rc; |
|
448 } |
|
449 |
|
450 int |
|
451 xDelete(sqlite3_vfs* vfs, const char *zName, int syncDir) |
|
452 { |
|
453 sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData); |
|
454 return orig_vfs->xDelete(orig_vfs, zName, syncDir); |
|
455 } |
|
456 |
|
457 int |
|
458 xAccess(sqlite3_vfs *vfs, const char *zName, int flags, int *pResOut) |
|
459 { |
|
460 sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData); |
|
461 return orig_vfs->xAccess(orig_vfs, zName, flags, pResOut); |
|
462 } |
|
463 |
|
464 int |
|
465 xFullPathname(sqlite3_vfs *vfs, const char *zName, int nOut, char *zOut) |
|
466 { |
|
467 sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData); |
|
468 return orig_vfs->xFullPathname(orig_vfs, zName, nOut, zOut); |
|
469 } |
|
470 |
|
471 void* |
|
472 xDlOpen(sqlite3_vfs *vfs, const char *zFilename) |
|
473 { |
|
474 sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData); |
|
475 return orig_vfs->xDlOpen(orig_vfs, zFilename); |
|
476 } |
|
477 |
|
478 void |
|
479 xDlError(sqlite3_vfs *vfs, int nByte, char *zErrMsg) |
|
480 { |
|
481 sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData); |
|
482 orig_vfs->xDlError(orig_vfs, nByte, zErrMsg); |
|
483 } |
|
484 |
|
485 void |
|
486 (*xDlSym(sqlite3_vfs *vfs, void *pHdle, const char *zSym))(void){ |
|
487 sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData); |
|
488 return orig_vfs->xDlSym(orig_vfs, pHdle, zSym); |
|
489 } |
|
490 |
|
491 void |
|
492 xDlClose(sqlite3_vfs *vfs, void *pHandle) |
|
493 { |
|
494 sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData); |
|
495 orig_vfs->xDlClose(orig_vfs, pHandle); |
|
496 } |
|
497 |
|
498 int |
|
499 xRandomness(sqlite3_vfs *vfs, int nByte, char *zOut) |
|
500 { |
|
501 sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData); |
|
502 return orig_vfs->xRandomness(orig_vfs, nByte, zOut); |
|
503 } |
|
504 |
|
505 int |
|
506 xSleep(sqlite3_vfs *vfs, int microseconds) |
|
507 { |
|
508 sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData); |
|
509 return orig_vfs->xSleep(orig_vfs, microseconds); |
|
510 } |
|
511 |
|
512 int |
|
513 xCurrentTime(sqlite3_vfs *vfs, double *prNow) |
|
514 { |
|
515 sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData); |
|
516 return orig_vfs->xCurrentTime(orig_vfs, prNow); |
|
517 } |
|
518 |
|
519 int |
|
520 xGetLastError(sqlite3_vfs *vfs, int nBuf, char *zBuf) |
|
521 { |
|
522 sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData); |
|
523 return orig_vfs->xGetLastError(orig_vfs, nBuf, zBuf); |
|
524 } |
|
525 |
|
526 int |
|
527 xCurrentTimeInt64(sqlite3_vfs *vfs, sqlite3_int64 *piNow) |
|
528 { |
|
529 sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData); |
|
530 return orig_vfs->xCurrentTimeInt64(orig_vfs, piNow); |
|
531 } |
|
532 |
|
533 static |
|
534 int |
|
535 xSetSystemCall(sqlite3_vfs *vfs, const char *zName, sqlite3_syscall_ptr pFunc) |
|
536 { |
|
537 sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData); |
|
538 return orig_vfs->xSetSystemCall(orig_vfs, zName, pFunc); |
|
539 } |
|
540 |
|
541 static |
|
542 sqlite3_syscall_ptr |
|
543 xGetSystemCall(sqlite3_vfs *vfs, const char *zName) |
|
544 { |
|
545 sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData); |
|
546 return orig_vfs->xGetSystemCall(orig_vfs, zName); |
|
547 } |
|
548 |
|
549 static |
|
550 const char * |
|
551 xNextSystemCall(sqlite3_vfs *vfs, const char *zName) |
|
552 { |
|
553 sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData); |
|
554 return orig_vfs->xNextSystemCall(orig_vfs, zName); |
|
555 } |
|
556 |
|
557 } |
|
558 |
|
559 namespace mozilla { |
|
560 namespace storage { |
|
561 |
|
562 sqlite3_vfs* ConstructTelemetryVFS() |
|
563 { |
|
564 #if defined(XP_WIN) |
|
565 #define EXPECTED_VFS "win32" |
|
566 #define EXPECTED_VFS_NFS "win32" |
|
567 #else |
|
568 #define EXPECTED_VFS "unix" |
|
569 #define EXPECTED_VFS_NFS "unix-excl" |
|
570 #endif |
|
571 |
|
572 bool expected_vfs; |
|
573 sqlite3_vfs *vfs; |
|
574 if (Preferences::GetBool(PREF_NFS_FILESYSTEM)) { |
|
575 vfs = sqlite3_vfs_find(EXPECTED_VFS_NFS); |
|
576 expected_vfs = (vfs != nullptr); |
|
577 } |
|
578 else { |
|
579 vfs = sqlite3_vfs_find(nullptr); |
|
580 expected_vfs = vfs->zName && !strcmp(vfs->zName, EXPECTED_VFS); |
|
581 } |
|
582 if (!expected_vfs) { |
|
583 return nullptr; |
|
584 } |
|
585 |
|
586 sqlite3_vfs *tvfs = new ::sqlite3_vfs; |
|
587 memset(tvfs, 0, sizeof(::sqlite3_vfs)); |
|
588 // If the VFS version is higher than the last known one, you should update |
|
589 // this VFS adding appropriate methods for any methods added in the version |
|
590 // change. |
|
591 tvfs->iVersion = vfs->iVersion; |
|
592 MOZ_ASSERT(vfs->iVersion <= LAST_KNOWN_VFS_VERSION); |
|
593 tvfs->szOsFile = sizeof(telemetry_file) - sizeof(sqlite3_file) + vfs->szOsFile; |
|
594 tvfs->mxPathname = vfs->mxPathname; |
|
595 tvfs->zName = "telemetry-vfs"; |
|
596 tvfs->pAppData = vfs; |
|
597 tvfs->xOpen = xOpen; |
|
598 tvfs->xDelete = xDelete; |
|
599 tvfs->xAccess = xAccess; |
|
600 tvfs->xFullPathname = xFullPathname; |
|
601 tvfs->xDlOpen = xDlOpen; |
|
602 tvfs->xDlError = xDlError; |
|
603 tvfs->xDlSym = xDlSym; |
|
604 tvfs->xDlClose = xDlClose; |
|
605 tvfs->xRandomness = xRandomness; |
|
606 tvfs->xSleep = xSleep; |
|
607 tvfs->xCurrentTime = xCurrentTime; |
|
608 tvfs->xGetLastError = xGetLastError; |
|
609 if (tvfs->iVersion >= 2) { |
|
610 // Methods added in version 2. |
|
611 tvfs->xCurrentTimeInt64 = xCurrentTimeInt64; |
|
612 } |
|
613 if (tvfs->iVersion >= 3) { |
|
614 // Methods added in version 3. |
|
615 tvfs->xSetSystemCall = xSetSystemCall; |
|
616 tvfs->xGetSystemCall = xGetSystemCall; |
|
617 tvfs->xNextSystemCall = xNextSystemCall; |
|
618 } |
|
619 return tvfs; |
|
620 } |
|
621 |
|
622 } |
|
623 } |