Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(72)

Side by Side Diff: sql/mojo/enable_mojo_fs.cc

Issue 1176653002: mandoline filesystem: add a sqlite3 vfs to proxy filesystem usage. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Patch cleanup now that gn check passes. Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
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/mojo/enable_mojo_fs.h"
6
7 #include "base/logging.h"
8 #include "components/filesystem/public/interfaces/file.mojom.h"
9 #include "components/filesystem/public/interfaces/file_system.mojom.h"
10 #include "components/filesystem/public/interfaces/types.mojom.h"
11 #include "mojo/public/cpp/bindings/lib/template_util.h"
12 #include "mojo/util/capture_util.h"
13 #include "third_party/sqlite/sqlite3.h"
14
15 using mojo::Capture;
16
17 namespace sql {
18 namespace {
19
20 // Implementation of the sqlite3 Mojo proxying vfs.
sky 2015/06/10 21:26:27 I'm assuming shess is reviewing all this.
21 //
22 // This is a bunch of C callback objects which transparently proxy sqlite3's
23 // filesystem reads/writes over the mojo:filesystem service. The main
24 // entrypoint is sqlite3_mojovfs(), which proxies all the file open/delete/etc
25 // operations. mojo:filesystem has support for passing a raw file descriptor
26 // over the IPC barrier, and most of the implementation of sqlite3_io_methods
27 // is derived from the default sqlite3 unix VFS and operates on the raw file
28 // descriptors.
29
30 #if defined(OS_WIN)
31 const char kParentVFS[] = "win32";
32 #elif defined(OS_POSIX)
33 const char kParentVFS[] = "unix";
34 #endif
35
36 const int kMaxPathName = 512;
37
38 // Additional data that we store in the sqlite3_vfs's |pAppData| member.
39 struct MojoVFSData {
40 // The default vfs at the time MojoVFS was installed. We use the to pass
41 // through things like randomness requests and per-platform sleep calls.
42 sqlite3_vfs* parent;
43
44 // When we initialize the subsystem, we are given a filesystem::Directory
45 // object, which is the root directory of a mojo:filesystem. All access to
46 // various files are specified from this root directory.
47 filesystem::DirectoryPtr root_directory;
Scott Hess - ex-Googler 2015/06/10 22:35:46 To make sure I'm clear on this - all databases for
Elliot Glaysher 2015/06/12 22:36:43 ...within a service/origin combination. The curre
Scott Hess - ex-Googler 2015/06/17 19:32:58 So all connections used by all clients in a single
Elliot Glaysher 2015/06/17 21:59:34 All sql::Connections in a process will use the sam
Scott Hess - ex-Googler 2015/06/19 20:48:01 Acknowledged.
48 };
49
50 sqlite3_vfs* GetParentVFS(sqlite3_vfs* mojo_vfs) {
51 return reinterpret_cast<MojoVFSData*>(mojo_vfs->pAppData)->parent;
52 }
53
54 filesystem::DirectoryPtr& GetRootDirectory(sqlite3_vfs* mojo_vfs) {
55 return reinterpret_cast<MojoVFSData*>(mojo_vfs->pAppData)->root_directory;
56 }
57
58 // A struct which extends the base sqlite3_file to also hold on to a file
59 // pipe. We reinterpret_cast our sqlite3_file structs to this struct
60 // instead. This is "safe" because this struct is really just a slab of
61 // malloced memory, of which we tell sqlite how large we want with szOsFile.
62 struct MojoVFSFile {
63 // The "vtable" of our sqlite3_file "subclass".
64 sqlite3_file base;
65
66 // We keep an open pipe to the File object to keep it from cleaning itself
67 // up.
68 filesystem::FilePtr file_ptr;
69 };
70
71 filesystem::FilePtr& GetFSFile(sqlite3_file* vfs_file) {
72 return reinterpret_cast<MojoVFSFile*>(vfs_file)->file_ptr;
73 }
74
75 int MojoVFSClose(sqlite3_file* file) {
76 DVLOG(1) << "MojoVFSClose(*)";
77 using mojo::InterfacePtr;
78 GetFSFile(file).~InterfacePtr<filesystem::File>();
Scott Hess - ex-Googler 2015/06/10 22:35:45 Symmetry-wise, why not: delete (&GetFSFile(file
Elliot Glaysher 2015/06/12 22:36:44 Because there's no such thing as placement delete.
Scott Hess - ex-Googler 2015/06/17 19:32:58 But you need to call the destructor, and as a casu
Elliot Glaysher 2015/06/17 21:59:34 Ah. I see what you're saying. Calling ~FilePtr().
Scott Hess - ex-Googler 2015/06/19 20:48:01 Ewwww.
79 return SQLITE_OK;
80 }
81
82 int MojoVFSRead(sqlite3_file* sql_file,
83 void* buffer,
84 int size,
85 sqlite3_int64 offset) {
86 DVLOG(1) << "MojoVFSRead (" << size << " @ " << offset << ")";
87 filesystem::FileError error = filesystem::FILE_ERROR_FAILED;
88 mojo::Array<uint8_t> mojo_data;
89 GetFSFile(sql_file)->Read(size, offset, filesystem::WHENCE_FROM_BEGIN,
90 Capture(&error, &mojo_data));
91 GetFSFile(sql_file).WaitForIncomingResponse();
92
93 if (error != filesystem::FILE_ERROR_OK) {
94 // TODO(erg): Better implementation here.
95 NOTIMPLEMENTED();
96 return SQLITE_IOERR_READ;
97 }
98
99 if (mojo_data.size() == static_cast<size_t>(size)) {
100 memcpy(buffer, &mojo_data.front(), mojo_data.size());
101 return SQLITE_OK;
102 }
103
104 // We didn't read the entire buffer. We need to copy the data AND zero fill
105 // the rest of the buffer.
106 if (mojo_data.size())
107 memcpy(buffer, &mojo_data.front(), mojo_data.size());
108 memset(reinterpret_cast<char*>(buffer) + mojo_data.size(), 0,
109 size - mojo_data.size());
110
111 return SQLITE_IOERR_SHORT_READ;
Scott Hess - ex-Googler 2015/06/10 22:35:45 Good to know about!
112 }
113
114 int MojoVFSWrite(sqlite3_file* sql_file,
115 const void* buffer,
116 int size,
117 sqlite_int64 offset) {
118 DVLOG(1) << "MojoVFSWrite(*, " << size << ", " << offset << ")";
119 mojo::Array<uint8_t> mojo_data(size);
120 memcpy(&mojo_data.front(), buffer, size);
121
122 filesystem::FileError error = filesystem::FILE_ERROR_FAILED;
123 uint32_t num_bytes_written = 0;
124 GetFSFile(sql_file)->Write(mojo_data.Pass(), offset,
125 filesystem::WHENCE_FROM_BEGIN,
126 Capture(&error, &num_bytes_written));
127 GetFSFile(sql_file).WaitForIncomingResponse();
128 if (error != filesystem::FILE_ERROR_OK) {
129 // TODO(erg): Better implementation here.
130 NOTIMPLEMENTED();
131 return SQLITE_IOERR_WRITE;
132 }
133 if (num_bytes_written != static_cast<uint32_t>(size)) {
134 NOTIMPLEMENTED();
135 return SQLITE_IOERR_WRITE;
136 }
137
138 return SQLITE_OK;
139 }
140
141 int MojoVFSTruncate(sqlite3_file* sql_file, sqlite_int64 size) {
142 DVLOG(1) << "MojoVFSTruncate(*, " << size << ")";
143 filesystem::FileError error = filesystem::FILE_ERROR_FAILED;
144 GetFSFile(sql_file)->Truncate(size, Capture(&error));
145 GetFSFile(sql_file).WaitForIncomingResponse();
146 if (error != filesystem::FILE_ERROR_OK) {
147 // TODO(erg): Better implementation here.
148 NOTIMPLEMENTED();
149 return SQLITE_IOERR_TRUNCATE;
150 }
151
152 return SQLITE_OK;
153 }
154
155 int MojoVFSSync(sqlite3_file* mojo_vfs, int flags) {
156 // TODO(erg): We need to flush data. This requires cooperation in
157 // mojo:filesystem.
158 DVLOG(1) << "MojoVFSSync(*, " << flags << ")";
159 NOTIMPLEMENTED();
160
161 return SQLITE_OK;
162 }
163
164 int MojoVFSFileSize(sqlite3_file* sql_file, sqlite_int64* size) {
165 DVLOG(1) << "MojoVFSFileSize(*)";
166
167 filesystem::FileError err = filesystem::FILE_ERROR_FAILED;
168 filesystem::FileInformationPtr file_info;
169 GetFSFile(sql_file)->Stat(Capture(&err, &file_info));
170 GetFSFile(sql_file).WaitForIncomingResponse();
171
172 if (err != filesystem::FILE_ERROR_OK) {
173 // TODO(erg): Better implementation here.
174 NOTIMPLEMENTED();
175 return SQLITE_IOERR_FSTAT;
176 }
177
178 *size = file_info->size;
179 return SQLITE_OK;
180 }
181
182 // TODO(erg): The current base::File interface isn't sufficient to handle
183 // sqlite's locking primitives, which are done on byte ranges in the file. (See
184 // "File Locking Notes" in sqlite3.c.)
185 int MojoVFSLock(sqlite3_file* pFile, int eLock) {
186 DVLOG(1) << "MojoVFSLock(*, " << eLock << ")";
187 return SQLITE_OK;
188 }
189 int MojoVFSUnlock(sqlite3_file* pFile, int eLock) {
190 DVLOG(1) << "MojoVFSUnlock(*, " << eLock << ")";
191 return SQLITE_OK;
192 }
193 int MojoVFSCheckReservedLock(sqlite3_file* pFile, int* pResOut) {
194 DVLOG(1) << "MojoVFSCheckReservedLock(*)";
195 *pResOut = 0;
196 return SQLITE_OK;
197 }
198
199 // TODO(erg): This is the minimal implementation to get a few tests passing;
200 // lots more needs to be done here.
201 int MojoVFSFileControl(sqlite3_file* pFile, int op, void* pArg) {
202 DVLOG(1) << "MojoVFSFileControl(*, " << op << ", *)";
203 if (op == SQLITE_FCNTL_PRAGMA) {
204 // Returning NOTFOUND tells sqlite that we aren't doing any processing.
205 return SQLITE_NOTFOUND;
206 }
207 // TODO(erg): Unsure if we need to manually handle SQLITE_FCNTL_FILE_POINTER.
Scott Hess - ex-Googler 2015/06/10 22:35:45 SQLITE_FCNTL_FILE_POINTER is magic, and is handled
Elliot Glaysher 2015/06/12 22:36:44 Done.
208
209 return SQLITE_OK;
210 }
211
212 int MojoVFSSectorSize(sqlite3_file* pFile) {
213 DVLOG(1) << "MojoVFSSectorSize(*)";
214 NOTIMPLEMENTED();
215 return SQLITE_OK;
Scott Hess - ex-Googler 2015/06/10 22:35:45 Returns a value, SQLITE_OK being 0 will just happe
Elliot Glaysher 2015/06/12 22:36:43 Done.
216 }
217
218 int MojoVFSDeviceCharacteristics(sqlite3_file* pFile) {
219 DVLOG(1) << "MojoVFSDeviceCharacteristics(*)";
220 NOTIMPLEMENTED();
221 return SQLITE_OK;
Scott Hess - ex-Googler 2015/06/10 22:35:45 This returns a bitmask. Again, SQLITE_OK happens
Elliot Glaysher 2015/06/12 22:36:44 Done.
222 }
223
224 static sqlite3_io_methods mojo_vfs_io_methods = {
225 1, /* iVersion */
226 MojoVFSClose, /* xClose */
227 MojoVFSRead, /* xRead */
228 MojoVFSWrite, /* xWrite */
229 MojoVFSTruncate, /* xTruncate */
230 MojoVFSSync, /* xSync */
231 MojoVFSFileSize, /* xFileSize */
232 MojoVFSLock, /* xLock */
233 MojoVFSUnlock, /* xUnlock */
234 MojoVFSCheckReservedLock, /* xCheckReservedLock */
235 MojoVFSFileControl, /* xFileControl */
236 MojoVFSSectorSize, /* xSectorSize */
237 MojoVFSDeviceCharacteristics, /* xDeviceCharacteristics */
238 0, /* xShmMap */
Scott Hess - ex-Googler 2015/06/10 22:35:45 You don't need to provide these for version 1. If
Elliot Glaysher 2015/06/12 22:36:44 Deleted. (I had put it for future reference, but w
239 0, /* xShmLock */
240 0, /* xShmBarrier */
241 0 /* xShmUnmap */
242 };
243
244 // who allocates sqlite3_file?
Scott Hess - ex-Googler 2015/06/10 22:35:45 The caller provides szOsFile bytes as part of a gr
Elliot Glaysher 2015/06/12 22:36:43 (Comment was left over from a previous time when I
245 int MojoVFSOpen(sqlite3_vfs* mojo_vfs,
246 const char* name,
247 sqlite3_file* file,
248 int flags,
249 int* pOutFlags) {
250 DVLOG(1) << "MojoVFSOpen(*, " << name << ", *, " << flags << ")";
251 int open_flags = 0;
252 if (flags & SQLITE_OPEN_EXCLUSIVE) {
253 DCHECK(flags & SQLITE_OPEN_CREATE);
254 open_flags = filesystem::kFlagCreate;
255 } else if (flags & SQLITE_OPEN_CREATE) {
256 DCHECK(flags & SQLITE_OPEN_READWRITE);
257 open_flags = filesystem::kFlagOpenAlways;
258 } else {
259 open_flags = filesystem::kFlagOpen;
260 }
261 open_flags |= filesystem::kFlagRead;
262 if (flags & SQLITE_OPEN_READWRITE)
263 open_flags |= filesystem::kFlagWrite;
264
265 // Grab the incoming file
266 filesystem::FilePtr file_ptr;
267 filesystem::FileError error = filesystem::FILE_ERROR_FAILED;
268 GetRootDirectory(mojo_vfs)->OpenFile(mojo::String(name), GetProxy(&file_ptr),
269 open_flags, Capture(&error));
270 GetRootDirectory(mojo_vfs).WaitForIncomingResponse();
271 if (error != filesystem::FILE_ERROR_OK) {
272 // TODO(erg): Translate more of the mojo error codes into sqlite error
273 // codes.
274 return SQLITE_CANTOPEN;
275 }
276
277 // Set the method table so we can be closed (and run the manual dtor call to
278 // match the following placement news).
279 file->pMethods = &mojo_vfs_io_methods;
280
281 // |file| is actually a malloced buffer of size szOsFile. This means that we
282 // need to manually use placement new to construct the C++ object which owns
283 // the pipe to our file.
284 new (&GetFSFile(file)) filesystem::FilePtr(file_ptr.Pass());
285
286 return SQLITE_OK;
287 }
288
289 int MojoVFSDelete(sqlite3_vfs* mojo_vfs, const char* filename, int sync_dir) {
290 DVLOG(1) << "MojoVFSDelete(*, " << filename << ", " << sync_dir << ")";
291 filesystem::FileError error = filesystem::FILE_ERROR_FAILED;
292 GetRootDirectory(mojo_vfs)->Delete(filename, 0, Capture(&error));
293 GetRootDirectory(mojo_vfs).WaitForIncomingResponse();
294
295 // TODO(erg): sync_dir?
Scott Hess - ex-Googler 2015/06/10 22:35:45 This may have per-platform warts, unfortunately.
Elliot Glaysher 2015/06/12 22:36:43 I have added a Flush() on sync_dir, which is what
296
297 return error == filesystem::FILE_ERROR_OK ? SQLITE_OK : SQLITE_IOERR_DELETE;
298 }
299
300 int MojoVFSAccess(sqlite3_vfs* mojo_vfs,
301 const char* filename,
302 int flags,
303 int* result) {
304 DVLOG(1) << "MojoVFSAccess(*, " << filename << ", " << flags << ", *)";
305 filesystem::FileError error = filesystem::FILE_ERROR_FAILED;
306
307 if (flags == SQLITE_ACCESS_READWRITE || flags == SQLITE_ACCESS_READ) {
308 bool is_wriable = false;
Scott Hess - ex-Googler 2015/06/10 22:35:45 is_writable.
Elliot Glaysher 2015/06/12 22:36:44 Done.
309 GetRootDirectory(mojo_vfs)
310 ->IsWritable(filename, Capture(&error, &is_wriable));
311 GetRootDirectory(mojo_vfs).WaitForIncomingResponse();
312 *result = is_wriable;
313 return SQLITE_OK;
314 }
315
316 if (flags == SQLITE_ACCESS_EXISTS) {
317 bool exists = false;
318 GetRootDirectory(mojo_vfs)->Exists(filename, Capture(&error, &exists));
319 GetRootDirectory(mojo_vfs).WaitForIncomingResponse();
320 *result = exists;
321 return SQLITE_OK;
322 }
323
324 return SQLITE_IOERR;
Scott Hess - ex-Googler 2015/06/10 22:35:45 So ... does someone guarantee that any file which
325 }
326
327 int MojoVFSFullPathname(sqlite3_vfs* mojo_vfs,
328 const char* relative_path,
329 int absolute_path_size,
330 char* absolute_path) {
331 // The sandboxed process doesn't need to know the absolute path of the file.
332 sqlite3_snprintf(absolute_path_size, absolute_path, "%s", relative_path);
333 return SQLITE_OK;
334 }
335
336 // If we are using the mojo:filesystem proxying VFS, then it's highly likely
337 // that we are sandboxed and that any attempt to dlopen() a shared object is
338 // folly.
Scott Hess - ex-Googler 2015/06/10 22:35:45 IMHO you should upgrade this to "Don't let SQLite
Elliot Glaysher 2015/06/12 22:36:44 Done.
339 void* MojoVFSDlOpen(sqlite3_vfs*, const char*) {
340 return 0;
341 }
342
343 void MojoVFSDlError(sqlite3_vfs*, int buf_size, char* error_msg) {
344 sqlite3_snprintf(buf_size, error_msg, "Dynamic loading not supported");
345 }
346
347 void (*MojoVFSDlSym(sqlite3_vfs*, void*, const char*))(void) {
348 return 0;
349 }
350
351 void MojoVFSDlClose(sqlite3_vfs*, void*) {
352 return;
353 }
354
355 // Proxy the rest of the calls down to the OS specific handler.
356 int MojoVFSRandomness(sqlite3_vfs* mojo_vfs, int byte, char* out) {
357 return GetParentVFS(mojo_vfs)->xRandomness(GetParentVFS(mojo_vfs), byte, out);
358 }
Scott Hess - ex-Googler 2015/06/10 22:35:45 This one in particular might make more sense to im
Elliot Glaysher 2015/06/12 22:36:44 The timing stuff looks complicated enough that I'm
359
360 int MojoVFSSleep(sqlite3_vfs* mojo_vfs, int micro) {
361 return GetParentVFS(mojo_vfs)->xSleep(GetParentVFS(mojo_vfs), micro);
362 }
363
364 int MojoVFSCurrentTime(sqlite3_vfs* mojo_vfs, double* time) {
365 return GetParentVFS(mojo_vfs)->xCurrentTime(GetParentVFS(mojo_vfs), time);
366 }
367
368 int MojoVFSGetLastError(sqlite3_vfs* mojo_vfs, int a, char* b) {
369 return GetParentVFS(mojo_vfs)->xGetLastError(GetParentVFS(mojo_vfs), a, b);
370 }
371
372 int MojoVFSCurrentTimeInt64(sqlite3_vfs* mojo_vfs, sqlite3_int64* out) {
373 return GetParentVFS(mojo_vfs)->xCurrentTimeInt64(GetParentVFS(mojo_vfs), out);
374 }
375
376 static sqlite3_vfs mojo_vfs = {
377 1, /* iVersion */
378 sizeof(MojoVFSFile), /* szOsFile */
379 kMaxPathName, /* mxPathname */
380 0, /* pNext */
381 "mojo", /* zName */
382 0, /* pAppData */
383 MojoVFSOpen, /* xOpen */
384 MojoVFSDelete, /* xDelete */
385 MojoVFSAccess, /* xAccess */
386 MojoVFSFullPathname, /* xFullPathname */
387 MojoVFSDlOpen, /* xDlOpen */
388 MojoVFSDlError, /* xDlError */
389 MojoVFSDlSym, /* xDlSym */
390 MojoVFSDlClose, /* xDlClose */
391 MojoVFSRandomness, /* xRandomness */
392 MojoVFSSleep, /* xSleep */
393 MojoVFSCurrentTime, /* xCurrentTime */
394 MojoVFSGetLastError, /* xGetLastError */
395 MojoVFSCurrentTimeInt64 /* xCurrentTimeInt64 */
396 };
397
398 } // namespace
399
400 bool ScopedMojoFilesystemVFS::vfs_set_ = false;
401
402 ScopedMojoFilesystemVFS::ScopedMojoFilesystemVFS(
403 filesystem::DirectoryPtr root_directory) {
404 CHECK(!vfs_set_);
405 vfs_set_ = true;
Scott Hess - ex-Googler 2015/06/10 22:35:45 This could be implemented in terms of a check on t
406
407 MojoVFSData* data = new MojoVFSData;
408 data->parent = sqlite3_vfs_find(kParentVFS);
Scott Hess - ex-Googler 2015/06/10 22:35:46 Use NULL to say "The default VFS for this system",
409 data->root_directory = root_directory.Pass();
410 mojo_vfs.pAppData = data;
411
412 mojo_vfs.mxPathname = data->parent->mxPathname;
413
414 CHECK(sqlite3_vfs_register(&mojo_vfs, 1) == SQLITE_OK);
415 }
416
417 ScopedMojoFilesystemVFS::~ScopedMojoFilesystemVFS() {
Scott Hess - ex-Googler 2015/06/10 22:35:45 Before clearing the pAppData, this needs to reset
Elliot Glaysher 2015/06/12 22:36:43 These three comments about how we deal with the de
418 delete static_cast<MojoVFSData*>(mojo_vfs.pAppData);
419
420 CHECK(vfs_set_);
421 vfs_set_ = false;
422 }
423
424 filesystem::DirectoryPtr& ScopedMojoFilesystemVFS::GetDirectory() {
425 return static_cast<MojoVFSData*>(mojo_vfs.pAppData)->root_directory;
426 }
427
428 } // namespace sql
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698