storage/src/TelemetryVFS.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

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

mercurial