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

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: Merge with ToT and fix the test import. 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 "base/rand_util.h"
9 #include "components/filesystem/public/interfaces/file.mojom.h"
10 #include "components/filesystem/public/interfaces/file_system.mojom.h"
11 #include "components/filesystem/public/interfaces/types.mojom.h"
12 #include "mojo/public/cpp/bindings/lib/template_util.h"
13 #include "mojo/util/capture_util.h"
14 #include "third_party/sqlite/sqlite3.h"
15
16 using mojo::Capture;
17
18 namespace sql {
19 namespace {
20
21 // Implementation of the sqlite3 Mojo proxying vfs.
22 //
23 // This is a bunch of C callback objects which transparently proxy sqlite3's
24 // filesystem reads/writes over the mojo:filesystem service. The main
25 // entrypoint is sqlite3_mojovfs(), which proxies all the file open/delete/etc
26 // operations. mojo:filesystem has support for passing a raw file descriptor
27 // over the IPC barrier, and most of the implementation of sqlite3_io_methods
28 // is derived from the default sqlite3 unix VFS and operates on the raw file
29 // descriptors.
30
31 const int kMaxPathName = 512;
32
33 // Additional data that we store in the sqlite3_vfs's |pAppData| member.
Scott Hess - ex-Googler 2015/06/17 19:32:58 A weird thought just occurred to me. Could pAppDa
Elliot Glaysher 2015/06/17 21:59:34 Done.
34 struct MojoVFSData {
35 // The default vfs at the time MojoVFS was installed. We use the to pass
36 // through things like randomness requests and per-platform sleep calls.
37 sqlite3_vfs* parent;
38
39 // When we initialize the subsystem, we are given a filesystem::Directory
40 // object, which is the root directory of a mojo:filesystem. All access to
41 // various files are specified from this root directory.
42 filesystem::DirectoryPtr root_directory;
43 };
44
45 sqlite3_vfs* GetParentVFS(sqlite3_vfs* mojo_vfs) {
46 return reinterpret_cast<MojoVFSData*>(mojo_vfs->pAppData)->parent;
47 }
48
49 filesystem::DirectoryPtr& GetRootDirectory(sqlite3_vfs* mojo_vfs) {
50 return reinterpret_cast<MojoVFSData*>(mojo_vfs->pAppData)->root_directory;
51 }
Scott Hess - ex-Googler 2015/06/17 19:32:58 Why is this reinterpret_cast<> and GetDirectory()
Elliot Glaysher 2015/06/17 21:59:35 You can static_cast a void pointer to anything. Yo
52
53 // A struct which extends the base sqlite3_file to also hold on to a file
54 // pipe. We reinterpret_cast our sqlite3_file structs to this struct
55 // instead. This is "safe" because this struct is really just a slab of
56 // malloced memory, of which we tell sqlite how large we want with szOsFile.
57 struct MojoVFSFile {
58 // The "vtable" of our sqlite3_file "subclass".
59 sqlite3_file base;
60
61 // We keep an open pipe to the File object to keep it from cleaning itself
62 // up.
63 filesystem::FilePtr file_ptr;
64 };
65
66 filesystem::FilePtr& GetFSFile(sqlite3_file* vfs_file) {
67 return reinterpret_cast<MojoVFSFile*>(vfs_file)->file_ptr;
68 }
69
70 int MojoVFSClose(sqlite3_file* file) {
71 DVLOG(1) << "MojoVFSClose(*)";
72 using mojo::InterfacePtr;
73 GetFSFile(file).~InterfacePtr<filesystem::File>();
74 return SQLITE_OK;
75 }
76
77 int MojoVFSRead(sqlite3_file* sql_file,
78 void* buffer,
79 int size,
80 sqlite3_int64 offset) {
81 DVLOG(1) << "MojoVFSRead (" << size << " @ " << offset << ")";
82 filesystem::FileError error = filesystem::FILE_ERROR_FAILED;
83 mojo::Array<uint8_t> mojo_data;
84 GetFSFile(sql_file)->Read(size, offset, filesystem::WHENCE_FROM_BEGIN,
85 Capture(&error, &mojo_data));
86 GetFSFile(sql_file).WaitForIncomingResponse();
87
88 if (error != filesystem::FILE_ERROR_OK) {
89 // TODO(erg): Better implementation here.
90 NOTIMPLEMENTED();
91 return SQLITE_IOERR_READ;
92 }
93
94 if (mojo_data.size() == static_cast<size_t>(size)) {
95 memcpy(buffer, &mojo_data.front(), mojo_data.size());
96 return SQLITE_OK;
97 }
98
99 // We didn't read the entire buffer. We need to copy the data AND zero fill
100 // the rest of the buffer.
101 if (mojo_data.size())
102 memcpy(buffer, &mojo_data.front(), mojo_data.size());
Scott Hess - ex-Googler 2015/06/17 19:32:58 Pull this out for sharing before the full-read tes
Elliot Glaysher 2015/06/17 21:59:34 Done, but we still have to check mojo_data.size()
Scott Hess - ex-Googler 2015/06/19 20:48:01 Acknowledged.
103 memset(reinterpret_cast<char*>(buffer) + mojo_data.size(), 0,
104 size - mojo_data.size());
105
106 return SQLITE_IOERR_SHORT_READ;
107 }
108
109 int MojoVFSWrite(sqlite3_file* sql_file,
110 const void* buffer,
111 int size,
112 sqlite_int64 offset) {
113 DVLOG(1) << "MojoVFSWrite(*, " << size << ", " << offset << ")";
114 mojo::Array<uint8_t> mojo_data(size);
115 memcpy(&mojo_data.front(), buffer, size);
116
117 filesystem::FileError error = filesystem::FILE_ERROR_FAILED;
118 uint32_t num_bytes_written = 0;
119 GetFSFile(sql_file)->Write(mojo_data.Pass(), offset,
120 filesystem::WHENCE_FROM_BEGIN,
121 Capture(&error, &num_bytes_written));
122 GetFSFile(sql_file).WaitForIncomingResponse();
123 if (error != filesystem::FILE_ERROR_OK) {
124 // TODO(erg): Better implementation here.
125 NOTIMPLEMENTED();
126 return SQLITE_IOERR_WRITE;
127 }
128 if (num_bytes_written != static_cast<uint32_t>(size)) {
129 NOTIMPLEMENTED();
130 return SQLITE_IOERR_WRITE;
131 }
132
133 return SQLITE_OK;
134 }
135
136 int MojoVFSTruncate(sqlite3_file* sql_file, sqlite_int64 size) {
137 DVLOG(1) << "MojoVFSTruncate(*, " << size << ")";
138 filesystem::FileError error = filesystem::FILE_ERROR_FAILED;
139 GetFSFile(sql_file)->Truncate(size, Capture(&error));
140 GetFSFile(sql_file).WaitForIncomingResponse();
141 if (error != filesystem::FILE_ERROR_OK) {
142 // TODO(erg): Better implementation here.
143 NOTIMPLEMENTED();
144 return SQLITE_IOERR_TRUNCATE;
145 }
146
147 return SQLITE_OK;
148 }
149
150 int MojoVFSSync(sqlite3_file* sql_file, int flags) {
151 DVLOG(1) << "MojoVFSSync(*, " << flags << ")";
152 filesystem::FileError error = filesystem::FILE_ERROR_FAILED;
153 GetFSFile(sql_file)->Flush(Capture(&error));
154 GetFSFile(sql_file).WaitForIncomingResponse();
155 if (error != filesystem::FILE_ERROR_OK) {
156 // TODO(erg): Better implementation here.
157 NOTIMPLEMENTED();
158 return SQLITE_IOERR_FSYNC;
159 }
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
208 return SQLITE_OK;
209 }
210
211 int MojoVFSSectorSize(sqlite3_file* pFile) {
212 DVLOG(1) << "MojoVFSSectorSize(*)";
213 // Use the default sector size.
214 return 0;
215 }
216
217 int MojoVFSDeviceCharacteristics(sqlite3_file* pFile) {
218 DVLOG(1) << "MojoVFSDeviceCharacteristics(*)";
219 NOTIMPLEMENTED();
220 return 0;
221 }
222
223 static sqlite3_io_methods mojo_vfs_io_methods = {
224 1, /* iVersion */
225 MojoVFSClose, /* xClose */
226 MojoVFSRead, /* xRead */
227 MojoVFSWrite, /* xWrite */
228 MojoVFSTruncate, /* xTruncate */
229 MojoVFSSync, /* xSync */
230 MojoVFSFileSize, /* xFileSize */
231 MojoVFSLock, /* xLock */
232 MojoVFSUnlock, /* xUnlock */
233 MojoVFSCheckReservedLock, /* xCheckReservedLock */
234 MojoVFSFileControl, /* xFileControl */
235 MojoVFSSectorSize, /* xSectorSize */
236 MojoVFSDeviceCharacteristics, /* xDeviceCharacteristics */
237 };
238
239 int MojoVFSOpen(sqlite3_vfs* mojo_vfs,
240 const char* name,
241 sqlite3_file* file,
242 int flags,
243 int* pOutFlags) {
244 DVLOG(1) << "MojoVFSOpen(*, " << name << ", *, " << flags << ")";
245 int open_flags = 0;
246 if (flags & SQLITE_OPEN_EXCLUSIVE) {
247 DCHECK(flags & SQLITE_OPEN_CREATE);
248 open_flags = filesystem::kFlagCreate;
249 } else if (flags & SQLITE_OPEN_CREATE) {
250 DCHECK(flags & SQLITE_OPEN_READWRITE);
251 open_flags = filesystem::kFlagOpenAlways;
252 } else {
253 open_flags = filesystem::kFlagOpen;
254 }
255 open_flags |= filesystem::kFlagRead;
256 if (flags & SQLITE_OPEN_READWRITE)
257 open_flags |= filesystem::kFlagWrite;
258 if (flags & SQLITE_OPEN_DELETEONCLOSE)
259 open_flags |= filesystem::kDeleteOnClose;
260
261 // Grab the incoming file
262 filesystem::FilePtr file_ptr;
263 filesystem::FileError error = filesystem::FILE_ERROR_FAILED;
264 GetRootDirectory(mojo_vfs)->OpenFile(mojo::String(name), GetProxy(&file_ptr),
265 open_flags, Capture(&error));
266 GetRootDirectory(mojo_vfs).WaitForIncomingResponse();
267 if (error != filesystem::FILE_ERROR_OK) {
268 // TODO(erg): Translate more of the mojo error codes into sqlite error
269 // codes.
270 return SQLITE_CANTOPEN;
271 }
272
273 // Set the method table so we can be closed (and run the manual dtor call to
274 // match the following placement news).
275 file->pMethods = &mojo_vfs_io_methods;
276
277 // |file| is actually a malloced buffer of size szOsFile. This means that we
278 // need to manually use placement new to construct the C++ object which owns
279 // the pipe to our file.
280 new (&GetFSFile(file)) filesystem::FilePtr(file_ptr.Pass());
281
282 return SQLITE_OK;
283 }
284
285 int MojoVFSDelete(sqlite3_vfs* mojo_vfs, const char* filename, int sync_dir) {
286 DVLOG(1) << "MojoVFSDelete(*, " << filename << ", " << sync_dir << ")";
287 // TODO(erg): The default windows sqlite VFS has retry code to work around
288 // antivirus software keeping files open. We'll probably have to do something
289 // like that in the far future if we ever support Windows.
Scott Hess - ex-Googler 2015/06/17 19:32:58 Yeah, this sucks. It would probably make more sen
290 filesystem::FileError error = filesystem::FILE_ERROR_FAILED;
291 GetRootDirectory(mojo_vfs)->Delete(filename, 0, Capture(&error));
292 GetRootDirectory(mojo_vfs).WaitForIncomingResponse();
293
294 if (error == filesystem::FILE_ERROR_OK && sync_dir) {
295 GetRootDirectory(mojo_vfs)->Flush(Capture(&error));
296 GetRootDirectory(mojo_vfs).WaitForIncomingResponse();
297 }
298
299 return error == filesystem::FILE_ERROR_OK ? SQLITE_OK : SQLITE_IOERR_DELETE;
300 }
301
302 int MojoVFSAccess(sqlite3_vfs* mojo_vfs,
303 const char* filename,
304 int flags,
305 int* result) {
306 DVLOG(1) << "MojoVFSAccess(*, " << filename << ", " << flags << ", *)";
307 filesystem::FileError error = filesystem::FILE_ERROR_FAILED;
308
309 if (flags == SQLITE_ACCESS_READWRITE || flags == SQLITE_ACCESS_READ) {
310 bool is_writable = false;
311 GetRootDirectory(mojo_vfs)
312 ->IsWritable(filename, Capture(&error, &is_writable));
313 GetRootDirectory(mojo_vfs).WaitForIncomingResponse();
314 *result = is_writable;
315 return SQLITE_OK;
316 }
317
318 if (flags == SQLITE_ACCESS_EXISTS) {
319 bool exists = false;
320 GetRootDirectory(mojo_vfs)->Exists(filename, Capture(&error, &exists));
321 GetRootDirectory(mojo_vfs).WaitForIncomingResponse();
322 *result = exists;
323 return SQLITE_OK;
324 }
325
326 return SQLITE_IOERR;
327 }
328
329 int MojoVFSFullPathname(sqlite3_vfs* mojo_vfs,
330 const char* relative_path,
331 int absolute_path_size,
332 char* absolute_path) {
333 // The sandboxed process doesn't need to know the absolute path of the file.
334 sqlite3_snprintf(absolute_path_size, absolute_path, "%s", relative_path);
335 return SQLITE_OK;
336 }
337
338 // Don't let SQLite dynamically load things. (If we are using the
339 // mojo:filesystem proxying VFS, then it's highly likely that we are sandboxed
340 // and that any attempt to dlopen() a shared object is folly.)
341 void* MojoVFSDlOpen(sqlite3_vfs*, const char*) {
342 return 0;
343 }
344
345 void MojoVFSDlError(sqlite3_vfs*, int buf_size, char* error_msg) {
346 sqlite3_snprintf(buf_size, error_msg, "Dynamic loading not supported");
347 }
348
349 void (*MojoVFSDlSym(sqlite3_vfs*, void*, const char*))(void) {
350 return 0;
351 }
352
353 void MojoVFSDlClose(sqlite3_vfs*, void*) {
354 return;
355 }
356
357 int MojoVFSRandomness(sqlite3_vfs* mojo_vfs, int size, char* out) {
358 base::RandBytes(out, size);
359 return size;
360 }
361
362 // Proxy the rest of the calls down to the OS specific handler.
363 int MojoVFSSleep(sqlite3_vfs* mojo_vfs, int micro) {
364 return GetParentVFS(mojo_vfs)->xSleep(GetParentVFS(mojo_vfs), micro);
365 }
366
367 int MojoVFSCurrentTime(sqlite3_vfs* mojo_vfs, double* time) {
368 return GetParentVFS(mojo_vfs)->xCurrentTime(GetParentVFS(mojo_vfs), time);
369 }
370
371 int MojoVFSGetLastError(sqlite3_vfs* mojo_vfs, int a, char* b) {
372 return 0;
373 }
374
375 int MojoVFSCurrentTimeInt64(sqlite3_vfs* mojo_vfs, sqlite3_int64* out) {
376 return GetParentVFS(mojo_vfs)->xCurrentTimeInt64(GetParentVFS(mojo_vfs), out);
377 }
378
379 static sqlite3_vfs mojo_vfs = {
380 1, /* iVersion */
381 sizeof(MojoVFSFile), /* szOsFile */
382 kMaxPathName, /* mxPathname */
383 0, /* pNext */
384 "mojo", /* zName */
385 0, /* pAppData */
386 MojoVFSOpen, /* xOpen */
387 MojoVFSDelete, /* xDelete */
388 MojoVFSAccess, /* xAccess */
389 MojoVFSFullPathname, /* xFullPathname */
390 MojoVFSDlOpen, /* xDlOpen */
391 MojoVFSDlError, /* xDlError */
392 MojoVFSDlSym, /* xDlSym */
393 MojoVFSDlClose, /* xDlClose */
394 MojoVFSRandomness, /* xRandomness */
395 MojoVFSSleep, /* xSleep */
396 MojoVFSCurrentTime, /* xCurrentTime */
397 MojoVFSGetLastError, /* xGetLastError */
398 MojoVFSCurrentTimeInt64 /* xCurrentTimeInt64 */
399 };
400
401 } // namespace
402
403 ScopedMojoFilesystemVFS::ScopedMojoFilesystemVFS(
404 filesystem::DirectoryPtr root_directory) {
405 CHECK(!mojo_vfs.pAppData);
406
407 MojoVFSData* data = new MojoVFSData;
408 data->parent = sqlite3_vfs_find(NULL);
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() {
418 CHECK(mojo_vfs.pAppData);
419
420 MojoVFSData* data = static_cast<MojoVFSData*>(mojo_vfs.pAppData);
421 sqlite3_vfs* previous_fs = data->parent;
422 delete data;
423 mojo_vfs.pAppData = nullptr;
424
425 CHECK(sqlite3_vfs_unregister(&mojo_vfs) == SQLITE_OK);
426 CHECK(sqlite3_vfs_register(previous_fs, 1) == SQLITE_OK);
Scott Hess - ex-Googler 2015/06/17 19:32:58 Suggest you restore the registration setup before
Elliot Glaysher 2015/06/17 21:59:35 Done.
427 }
428
429 filesystem::DirectoryPtr& ScopedMojoFilesystemVFS::GetDirectory() {
430 return static_cast<MojoVFSData*>(mojo_vfs.pAppData)->root_directory;
Scott Hess - ex-Googler 2015/06/17 19:32:58 Maybe this should be: return GetRootDirectory(&m
431 }
432
433 } // namespace sql
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698