Upload upstream chromium 108.0.5359.1
[platform/framework/web/chromium-efl.git] / sql / sandboxed_vfs_file.cc
1 // Copyright 2019 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "sql/sandboxed_vfs_file.h"
6
7 #include <atomic>
8 #include <cstring>
9 #include <type_traits>
10 #include <utility>
11
12 #include "base/check_op.h"
13 #include "base/files/file.h"
14 #include "base/files/file_path.h"
15 #include "base/logging.h"
16 #include "base/notreached.h"
17 #include "base/threading/platform_thread.h"
18 #include "build/build_config.h"
19 #include "sql/initialization.h"
20 #include "sql/sandboxed_vfs.h"
21 #include "third_party/sqlite/sqlite3.h"
22
23 namespace sql {
24
25 namespace {
26
27 int SandboxedClose(sqlite3_file* file) {
28   return SandboxedVfsFile::FromSqliteFile(*file).Close();
29 }
30 int SandboxedRead(sqlite3_file* file,
31                   void* buffer,
32                   int size,
33                   sqlite3_int64 offset) {
34   return SandboxedVfsFile::FromSqliteFile(*file).Read(buffer, size, offset);
35 }
36 int SandboxedWrite(sqlite3_file* file,
37                    const void* buffer,
38                    int size,
39                    sqlite3_int64 offset) {
40   return SandboxedVfsFile::FromSqliteFile(*file).Write(buffer, size, offset);
41 }
42 int SandboxedTruncate(sqlite3_file* file, sqlite3_int64 size) {
43   return SandboxedVfsFile::FromSqliteFile(*file).Truncate(size);
44 }
45 int SandboxedSync(sqlite3_file* file, int flags) {
46   return SandboxedVfsFile::FromSqliteFile(*file).Sync(flags);
47 }
48 int SandboxedFileSize(sqlite3_file* file, sqlite3_int64* result_size) {
49   return SandboxedVfsFile::FromSqliteFile(*file).FileSize(result_size);
50 }
51 int SandboxedLock(sqlite3_file* file, int mode) {
52   return SandboxedVfsFile::FromSqliteFile(*file).Lock(mode);
53 }
54 int SandboxedUnlock(sqlite3_file* file, int mode) {
55   return SandboxedVfsFile::FromSqliteFile(*file).Unlock(mode);
56 }
57 int SandboxedCheckReservedLock(sqlite3_file* file, int* has_reserved_lock) {
58   return SandboxedVfsFile::FromSqliteFile(*file).CheckReservedLock(
59       has_reserved_lock);
60 }
61 int SandboxedFileControl(sqlite3_file* file, int opcode, void* data) {
62   return SandboxedVfsFile::FromSqliteFile(*file).FileControl(opcode, data);
63 }
64 int SandboxedSectorSize(sqlite3_file* file) {
65   return SandboxedVfsFile::FromSqliteFile(*file).SectorSize();
66 }
67 int SandboxedDeviceCharacteristics(sqlite3_file* file) {
68   return SandboxedVfsFile::FromSqliteFile(*file).DeviceCharacteristics();
69 }
70 int SandboxedShmMap(sqlite3_file* file,
71                     int page_index,
72                     int page_size,
73                     int extend_file_if_needed,
74                     void volatile** result) {
75   return SandboxedVfsFile::FromSqliteFile(*file).ShmMap(
76       page_index, page_size, extend_file_if_needed, result);
77 }
78 int SandboxedShmLock(sqlite3_file* file, int offset, int size, int flags) {
79   return SandboxedVfsFile::FromSqliteFile(*file).ShmLock(offset, size, flags);
80 }
81 void SandboxedShmBarrier(sqlite3_file* file) {
82   SandboxedVfsFile::FromSqliteFile(*file).ShmBarrier();
83 }
84 int SandboxedShmUnmap(sqlite3_file* file, int also_delete_file) {
85   return SandboxedVfsFile::FromSqliteFile(*file).ShmUnmap(also_delete_file);
86 }
87 int SandboxedFetch(sqlite3_file* file,
88                    sqlite3_int64 offset,
89                    int size,
90                    void** result) {
91   return SandboxedVfsFile::FromSqliteFile(*file).Fetch(offset, size, result);
92 }
93 int SandboxedUnfetch(sqlite3_file* file,
94                      sqlite3_int64 offset,
95                      void* fetch_result) {
96   return SandboxedVfsFile::FromSqliteFile(*file).Unfetch(offset, fetch_result);
97 }
98
99 const sqlite3_io_methods* GetSqliteIoMethods() {
100   // VFS IO API entry points are listed at
101   // https://www.sqlite.org/c3ref/io_methods.html
102   static constexpr int kSqliteVfsIoApiVersion = 3;
103
104   static const sqlite3_io_methods kIoMethods = {
105       kSqliteVfsIoApiVersion,
106       SandboxedClose,
107       SandboxedRead,
108       SandboxedWrite,
109       SandboxedTruncate,
110       SandboxedSync,
111       SandboxedFileSize,
112       SandboxedLock,
113       SandboxedUnlock,
114       SandboxedCheckReservedLock,
115       SandboxedFileControl,
116       SandboxedSectorSize,
117       SandboxedDeviceCharacteristics,
118       SandboxedShmMap,
119       SandboxedShmLock,
120       SandboxedShmBarrier,
121       SandboxedShmUnmap,
122       SandboxedFetch,
123       SandboxedUnfetch,
124   };
125
126   return &kIoMethods;
127 }
128
129 }  // namespace
130
131 // static
132 void SandboxedVfsFile::Create(base::File file,
133                               base::FilePath file_path,
134 #if DCHECK_IS_ON()
135                               SandboxedVfsFileType file_type,
136 #endif  // DCHECK_IS_ON()
137                               SandboxedVfs* vfs,
138                               sqlite3_file& buffer) {
139   SandboxedVfsFileSqliteBridge& bridge =
140       SandboxedVfsFileSqliteBridge::FromSqliteFile(buffer);
141   bridge.sandboxed_vfs_file =
142       new SandboxedVfsFile(std::move(file), std::move(file_path),
143 #if DCHECK_IS_ON()
144                            file_type,
145 #endif  // DCHECK_IS_ON()
146                            vfs);
147   bridge.sqlite_file.pMethods = GetSqliteIoMethods();
148 }
149
150 // static
151 SandboxedVfsFile& SandboxedVfsFile::FromSqliteFile(sqlite3_file& sqlite_file) {
152   return *SandboxedVfsFileSqliteBridge::FromSqliteFile(sqlite_file)
153               .sandboxed_vfs_file;
154 }
155
156 int SandboxedVfsFile::Close() {
157   file_.Close();
158   delete this;
159   return SQLITE_OK;
160 }
161
162 int SandboxedVfsFile::Read(void* buffer, int size, sqlite3_int64 offset) {
163   DCHECK(buffer);
164   DCHECK_GE(size, 0);
165   DCHECK_GE(offset, 0);
166
167 #if DCHECK_IS_ON()
168   // See http://www.sqlite.org/fileformat2.html#database_header
169   constexpr int kSqliteDatabaseHeaderOffset = 0;
170   constexpr int kSqliteDatabaseHeaderSize = 100;
171   // SQLite's locking protocol only acquires locks on the database file. The
172   // journal and the WAL file are always unlocked. Also, as an optimization,
173   // SQLite first reads the database header without locking the file.
174   DCHECK(sqlite_lock_mode_ > SQLITE_LOCK_NONE ||
175          file_type_ != SandboxedVfsFileType::kDatabase ||
176          (offset == kSqliteDatabaseHeaderOffset &&
177           size == kSqliteDatabaseHeaderSize))
178       << "Read from database file with lock mode " << sqlite_lock_mode_
179       << "of size" << size << " at offset " << offset;
180 #endif  // DCHECK_IS_ON()
181
182   char* data = reinterpret_cast<char*>(buffer);
183
184   // If we supported mmap()ed files, we'd check for a memory mapping here,
185   // and try to fill as much of the request as possible from the mmap()ed
186   // region.
187
188   int bytes_read = file_.Read(offset, data, size);
189   DCHECK_LE(bytes_read, size);
190   if (bytes_read == size)
191     return SQLITE_OK;
192
193   if (bytes_read < 0) {
194     // SQLite first reads the database header without locking the file. On
195     // Windows, this read will fail if there is an exclusive lock on the file,
196     // even if the current process owns that lock.
197     if (sqlite_lock_mode_ == SQLITE_LOCK_NONE) {
198       // The unlocked read is considered an optimization. SQLite can continue
199       // even if the read fails, as long as failure is communicated by zeroing
200       // out the output buffer.
201       std::memset(data, 0, size);
202       return SQLITE_OK;
203     }
204
205     vfs_->SetLastError(base::File::GetLastFileError());
206     return SQLITE_IOERR_READ;
207   }
208
209   // SQLite requires that we fill the unread bytes in the buffer with zeros.
210   std::memset(data + bytes_read, 0, size - bytes_read);
211   return SQLITE_IOERR_SHORT_READ;
212 }
213
214 int SandboxedVfsFile::Write(const void* buffer,
215                             int size,
216                             sqlite3_int64 offset) {
217   DCHECK(buffer);
218   DCHECK_GE(size, 0);
219   DCHECK_GE(offset, 0);
220
221 #if DCHECK_IS_ON()
222   // SQLite's locking protocol only acquires locks on the database file. The
223   // journal and the WAL file are always unlocked.
224   DCHECK(sqlite_lock_mode_ == SQLITE_LOCK_EXCLUSIVE ||
225          file_type_ != SandboxedVfsFileType::kDatabase)
226       << "Write to database file with lock mode " << sqlite_lock_mode_;
227 #endif  // DCHECK_IS_ON()
228
229   const char* data = reinterpret_cast<const char*>(buffer);
230
231   // If we supported mmap()ed files, we'd check for a memory mapping here,
232   // and try to fill as much of the request as possible by copying to the
233   // mmap()ed region.
234
235   int bytes_written = file_.Write(offset, data, size);
236   DCHECK_LE(bytes_written, size);
237   if (bytes_written >= size)
238     return SQLITE_OK;
239
240   base::File::Error last_error = base::File::GetLastFileError();
241   vfs_->SetLastError(last_error);
242   if (last_error == base::File::Error::FILE_ERROR_NO_SPACE)
243     return SQLITE_FULL;
244
245   return SQLITE_IOERR_WRITE;
246 }
247
248 int SandboxedVfsFile::Truncate(sqlite3_int64 size) {
249   if (file_.SetLength(size))
250     return SQLITE_OK;
251
252   // On macOS < 10.15, the default sandbox blocks ftruncate(), so we have to use
253   // a sync mojo IPC to ask the browser process to call ftruncate() for us.
254   //
255   // TODO(crbug.com/1084565): Figure out if we can allow ftruncate() in renderer
256   // and utility processes. It would be useful for low-level storage APIs, like
257   // the upcoming filesystem API.
258   if (vfs_->delegate()->SetFileLength(file_path_, file_,
259                                       static_cast<size_t>(size))) {
260     return SQLITE_OK;
261   }
262
263   return SQLITE_IOERR_TRUNCATE;
264 }
265
266 int SandboxedVfsFile::Sync(int flags) {
267   // NOTE: SQLite passes in (SQLITE_SYNC_NORMAL or SQLITE_SYNC_FULL),
268   //       potentially OR-ed with SQLITE_SYNC_DATAONLY. Implementing these could
269   //       lead to better performance.
270   if (!file_.Flush()) {
271     vfs_->SetLastError(base::File::GetLastFileError());
272     return SQLITE_IOERR_FSYNC;
273   }
274
275   // The unix VFS also syncs the file's directory on the first xSync() call.
276   // Chrome's LevelDB Env implementation does the same for specific files
277   // (database manifests).
278   //
279   // For WebSQL, we would want to sync the directory at file open time, when the
280   // file is opened for writing.
281
282   return SQLITE_OK;
283 }
284
285 int SandboxedVfsFile::FileSize(sqlite3_int64* result_size) {
286   int64_t length = file_.GetLength();
287   if (length < 0) {
288     vfs_->SetLastError(base::File::GetLastFileError());
289     return SQLITE_IOERR_FSTAT;
290   }
291
292   // SQLite's unix VFS reports 1-byte files as empty. This is documented as a
293   // workaround for a fairly obscure bug. See unixFileSize() in os_unix.c.
294   if (length == 1)
295     length = 0;
296
297   *result_size = length;
298   return SQLITE_OK;
299 }
300
301 namespace {
302
303 // True if our simplified implementation uses an exclusive lock for a mode.
304 bool IsExclusiveLockMode(int sqlite_lock_mode) {
305   switch (sqlite_lock_mode) {
306     case SQLITE_LOCK_NONE:
307     case SQLITE_LOCK_SHARED:
308       return false;
309
310     case SQLITE_LOCK_RESERVED:
311     case SQLITE_LOCK_PENDING:
312     case SQLITE_LOCK_EXCLUSIVE:
313       return true;
314   }
315
316   NOTREACHED() << "Unsupported mode: " << sqlite_lock_mode;
317   return false;
318 }
319
320 }  // namespace
321
322 int SandboxedVfsFile::Lock(int mode) {
323   DCHECK_GT(mode, sqlite_lock_mode_)
324       << "SQLite asked the VFS to lock the file up to mode " << mode
325       << " but the file is already locked at mode " << sqlite_lock_mode_;
326
327 #if BUILDFLAG(IS_FUCHSIA)
328   return SQLITE_IOERR_LOCK;
329 #else
330   base::File::LockMode file_lock_mode = base::File::LockMode::kExclusive;
331
332   switch (mode) {
333     case SQLITE_LOCK_NONE:
334       return SQLITE_OK;
335
336     case SQLITE_LOCK_SHARED:
337       if (sqlite_lock_mode_ != SQLITE_LOCK_NONE)
338         return SQLITE_OK;
339
340       file_lock_mode = base::File::LockMode::kShared;
341       break;
342
343     case SQLITE_LOCK_RESERVED:
344       // A SHARED lock is required before a RESERVED lock is acquired.
345       DCHECK_EQ(sqlite_lock_mode_, SQLITE_LOCK_SHARED);
346       file_lock_mode = base::File::LockMode::kExclusive;
347       break;
348
349     case SQLITE_LOCK_PENDING:
350       NOTREACHED() << "SQLite never directly asks for PENDING locks";
351
352       // Should we ever receive PENDING lock requests, the handler for
353       // EXCLUSIVE lock requests below happens to work perfectly.
354       [[fallthrough]];
355
356     case SQLITE_LOCK_EXCLUSIVE:
357       // A SHARED lock is required before an EXCLUSIVE lock is acquired.
358       //
359       // No higher level is required. In fact, SQLite upgrades the lock directly
360       // from SHARED to EXCLUSIVE when rolling back a transaction, to avoid
361       // having other readers queue up in the RESERVED state.
362       DCHECK_GE(sqlite_lock_mode_, SQLITE_LOCK_SHARED);
363
364       if (IsExclusiveLockMode(sqlite_lock_mode_)) {
365         sqlite_lock_mode_ = mode;
366         return SQLITE_OK;
367       }
368       file_lock_mode = base::File::LockMode::kExclusive;
369       break;
370
371     default:
372       NOTREACHED() << "Unimplemented xLock() mode: " << mode;
373   }
374
375   DCHECK_EQ(IsExclusiveLockMode(mode),
376             file_lock_mode == base::File::LockMode::kExclusive)
377       << "Incorrect file_lock_mode logic for SQLite mode: " << mode;
378
379   // On POSIX, it would be possible to upgrade atomically from a shared lock to
380   // an exclusive lock. This implementation prioritizes the simplicity of no
381   // platform-specific code over being faster in high contention cases.
382   if (sqlite_lock_mode_ != SQLITE_LOCK_NONE) {
383     base::File::Error error = file_.Unlock();
384     if (error != base::File::FILE_OK) {
385       vfs_->SetLastError(base::File::GetLastFileError());
386       return SQLITE_IOERR_LOCK;
387     }
388     sqlite_lock_mode_ = SQLITE_LOCK_NONE;
389   }
390
391   base::File::Error error = file_.Lock(file_lock_mode);
392   if (error != base::File::FILE_OK) {
393     vfs_->SetLastError(base::File::GetLastFileError());
394     return SQLITE_IOERR_LOCK;
395   }
396
397   sqlite_lock_mode_ = mode;
398   return SQLITE_OK;
399 #endif  // BUILDFLAG(IS_FUCHSIA)
400 }
401
402 int SandboxedVfsFile::Unlock(int mode) {
403   // The 2nd term in the DCHECK predicate is there because SQLite occasionally
404   // attempts to unlock (to SQLITE_LOCK_NONE) a file that was already unlocked.
405   // We're not aware of any other case of no-op VFS unlock calls.
406   DCHECK(mode < sqlite_lock_mode_ ||
407          (mode == sqlite_lock_mode_ && mode == SQLITE_LOCK_NONE))
408       << "SQLite asked the VFS to unlock the file down to mode " << mode
409       << " but the file is already at mode " << sqlite_lock_mode_;
410
411   // No-op if we're already unlocked or at the requested mode.
412   if (sqlite_lock_mode_ == mode || sqlite_lock_mode_ == SQLITE_LOCK_NONE)
413     return SQLITE_OK;
414
415 #if BUILDFLAG(IS_FUCHSIA)
416   return SQLITE_IOERR_UNLOCK;
417 #else
418   // On POSIX, it is possible to downgrade atomically from an exclusive lock to
419   // a shared lock. SQLite's unix VFS takes advantage of this. This
420   // implementation prioritizes the simplicity of no platform-specific code over
421   // being faster in high contention cases.
422   base::File::Error error = file_.Unlock();
423   if (error != base::File::FILE_OK) {
424     vfs_->SetLastError(base::File::GetLastFileError());
425     return SQLITE_IOERR_UNLOCK;
426   }
427
428   if (mode == SQLITE_LOCK_NONE) {
429     sqlite_lock_mode_ = mode;
430     return SQLITE_OK;
431   }
432
433   DCHECK_EQ(mode, SQLITE_LOCK_SHARED);
434   error = file_.Lock(base::File::LockMode::kShared);
435   if (error == base::File::FILE_OK) {
436     sqlite_lock_mode_ = mode;
437     return SQLITE_OK;
438   }
439
440   // Gave up the exclusive lock, but failed to get a shared lock.
441   vfs_->SetLastError(base::File::GetLastFileError());
442   sqlite_lock_mode_ = SQLITE_LOCK_NONE;
443   return SQLITE_IOERR_UNLOCK;
444 #endif  // BUILDFLAG(IS_FUCHSIA)
445 }
446
447 int SandboxedVfsFile::CheckReservedLock(int* has_reserved_lock) {
448   if (IsExclusiveLockMode(sqlite_lock_mode_)) {
449     *has_reserved_lock = 1;
450     return SQLITE_OK;
451   }
452
453   if (sqlite_lock_mode_ == SQLITE_LOCK_SHARED) {
454     // Lock modes at or above RESERVED map to exclusive locks in our simplified
455     // implementation. If this process has a shared lock, no other process can
456     // have an exclusive lock.
457     *has_reserved_lock = 0;
458     return SQLITE_OK;
459   }
460
461 #if BUILDFLAG(IS_FUCHSIA)
462   return SQLITE_IOERR_CHECKRESERVEDLOCK;
463 #else
464   // On POSIX, it's possible to query the existing lock state of a file. The
465   // SQLite unix VFS takes advantage of this. On Windows, this isn't the case.
466   // Follow the strategy of the Windows VFS, which checks by trying to get an
467   // exclusive lock on the file.
468   base::File::Error error = file_.Lock(base::File::LockMode::kShared);
469   if (error != base::File::FILE_OK) {
470     *has_reserved_lock = 1;
471     return SQLITE_OK;
472   }
473
474   *has_reserved_lock = 0;
475   if (file_.Unlock() == base::File::FILE_OK)
476     return SQLITE_OK;
477
478   // We acquired a shared lock that we can't get rid of.
479   sqlite_lock_mode_ = SQLITE_LOCK_SHARED;
480   return SQLITE_IOERR_CHECKRESERVEDLOCK;
481 #endif  // BUILDFLAG(IS_FUCHSIA)
482 }
483
484 int SandboxedVfsFile::FileControl(int opcode, void* data) {
485   switch (opcode) {
486     case SQLITE_FCNTL_MMAP_SIZE:
487       // Implementing memory-mapping will require handling this correctly.
488       return SQLITE_NOTFOUND;
489     default:
490       return SQLITE_NOTFOUND;
491   }
492 }
493
494 int SandboxedVfsFile::SectorSize() {
495   return 0;
496 }
497
498 int SandboxedVfsFile::DeviceCharacteristics() {
499   // TODO(pwnall): Figure out if we can get away with returning 0 on Windows.
500 #if BUILDFLAG(IS_WIN)
501   return SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN;
502 #else
503   // NOTE: SQLite's unix VFS attempts to detect the underlying filesystem and
504   // sets some flags based on the result.
505   return 0;
506 #endif  // BUILDFLAG(IS_WIN)
507 }
508
509 int SandboxedVfsFile::ShmMap(int page_index,
510                              int page_size,
511                              int extend_file_if_needed,
512                              void volatile** result) {
513   DCHECK_GE(page_index, 0);
514   DCHECK_GE(page_size, 0);
515   DCHECK(result);
516
517   // https://www.sqlite.org/wal.html#use_of_wal_without_shared_memory states
518   // that SQLite only attempts to use shared memory "-shm" files for databases
519   // in WAL mode that may be accessed by multiple processes (are not EXCLUSIVE).
520   //
521   // Chrome will not only use WAL mode on EXCLUSIVE databases.
522   NOTREACHED() << "SQLite should not attempt to use shared memory";
523
524   *result = nullptr;
525   return SQLITE_IOERR;
526 }
527
528 int SandboxedVfsFile::ShmLock(int offset, int size, int flags) {
529   DCHECK_GE(offset, 0);
530   DCHECK_GE(size, 0);
531
532   // https://www.sqlite.org/wal.html#use_of_wal_without_shared_memory states
533   // that SQLite only attempts to use shared memory "-shm" files for databases
534   // in WAL mode that may be accessed by multiple processes (are not EXCLUSIVE).
535   //
536   // Chrome will not only use WAL mode on EXCLUSIVE databases.
537   NOTREACHED() << "SQLite should not attempt to use shared memory";
538
539   return SQLITE_IOERR;
540 }
541
542 void SandboxedVfsFile::ShmBarrier() {
543   // https://www.sqlite.org/wal.html#use_of_wal_without_shared_memory states
544   // that SQLite only attempts to use shared memory "-shm" files for databases
545   // in WAL mode that may be accessed by multiple processes (are not EXCLUSIVE).
546   //
547   // Chrome will not only use WAL mode on EXCLUSIVE databases.
548   NOTREACHED() << "SQLite should not attempt to use shared memory";
549
550   // All writes to shared memory that have already been issued before this
551   // function is called must complete before the function returns.
552   std::atomic_thread_fence(std::memory_order_acq_rel);
553 }
554
555 int SandboxedVfsFile::ShmUnmap(int also_delete_file) {
556   // https://www.sqlite.org/wal.html#use_of_wal_without_shared_memory states
557   // that SQLite only attempts to use shared memory "-shm" files for databases
558   // in WAL mode that may be accessed by multiple processes (are not EXCLUSIVE).
559   //
560   // Chrome will not only use WAL mode on EXCLUSIVE databases.
561   NOTREACHED() << "SQLite should not attempt to use shared memory";
562
563   return SQLITE_IOERR;
564 }
565
566 int SandboxedVfsFile::Fetch(sqlite3_int64 offset, int size, void** result) {
567   DCHECK_GE(offset, 0);
568   DCHECK_GE(size, 0);
569   DCHECK(result);
570
571   // NOTE: This would be needed for mmap()ed file support.
572   *result = nullptr;
573   return SQLITE_IOERR;
574 }
575
576 int SandboxedVfsFile::Unfetch(sqlite3_int64 offset, void* fetch_result) {
577   DCHECK_GE(offset, 0);
578   DCHECK(fetch_result);
579
580   // NOTE: This would be needed for mmap()ed file support.
581   return SQLITE_IOERR;
582 }
583
584 SandboxedVfsFile::SandboxedVfsFile(base::File file,
585                                    base::FilePath file_path,
586 #if DCHECK_IS_ON()
587                                    SandboxedVfsFileType file_type,
588 #endif  // DCHECK_IS_ON()
589                                    SandboxedVfs* vfs)
590     : file_(std::move(file)),
591       sqlite_lock_mode_(SQLITE_LOCK_NONE),
592       vfs_(vfs),
593 #if DCHECK_IS_ON()
594       file_type_(file_type),
595 #endif  // DCHECK_IS_ON()
596       file_path_(std::move(file_path)) {
597 }
598
599 SandboxedVfsFile::~SandboxedVfsFile() = default;
600
601 // static
602 SandboxedVfsFileSqliteBridge& SandboxedVfsFileSqliteBridge::FromSqliteFile(
603     sqlite3_file& sqlite_file) {
604   static_assert(std::is_standard_layout<SandboxedVfsFileSqliteBridge>::value,
605                 "needed for the reinterpret_cast below");
606   static_assert(offsetof(SandboxedVfsFileSqliteBridge, sqlite_file) == 0,
607                 "sqlite_file must be the first member of the struct.");
608
609   SandboxedVfsFileSqliteBridge& bridge =
610       reinterpret_cast<SandboxedVfsFileSqliteBridge&>(sqlite_file);
611   DCHECK_EQ(&sqlite_file, &bridge.sqlite_file)
612       << "assumed by the reinterpret_casts in the implementation";
613   return bridge;
614 }
615
616 }  // namespace sql