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

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: Another round. 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"
Scott Hess - ex-Googler 2015/06/19 20:48:02 Since this is in a mojo/ subdir, willing to defer
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
20 sqlite3_vfs* GetParentVFS(sqlite3_vfs* mojo_vfs) {
21 return static_cast<ScopedMojoFilesystemVFS*>(mojo_vfs->pAppData)->parent_;
22 }
23
24 filesystem::DirectoryPtr& GetRootDirectory(sqlite3_vfs* mojo_vfs) {
25 return static_cast<ScopedMojoFilesystemVFS*>(mojo_vfs->pAppData)->
26 root_directory_;
27 }
28
29 namespace {
30
31 // Implementation of the sqlite3 Mojo proxying vfs.
32 //
33 // This is a bunch of C callback objects which transparently proxy sqlite3's
34 // filesystem reads/writes over the mojo:filesystem service. The main
35 // entrypoint is sqlite3_mojovfs(), which proxies all the file open/delete/etc
36 // operations. mojo:filesystem has support for passing a raw file descriptor
37 // over the IPC barrier, and most of the implementation of sqlite3_io_methods
38 // is derived from the default sqlite3 unix VFS and operates on the raw file
39 // descriptors.
40
41 const int kMaxPathName = 512;
42
43 // A struct which extends the base sqlite3_file to also hold on to a file
44 // pipe. We reinterpret_cast our sqlite3_file structs to this struct
45 // instead. This is "safe" because this struct is really just a slab of
46 // malloced memory, of which we tell sqlite how large we want with szOsFile.
47 struct MojoVFSFile {
48 // The "vtable" of our sqlite3_file "subclass".
49 sqlite3_file base;
50
51 // We keep an open pipe to the File object to keep it from cleaning itself
52 // up.
53 filesystem::FilePtr file_ptr;
54 };
55
56 filesystem::FilePtr& GetFSFile(sqlite3_file* vfs_file) {
57 return reinterpret_cast<MojoVFSFile*>(vfs_file)->file_ptr;
58 }
59
60 int MojoVFSClose(sqlite3_file* file) {
61 DVLOG(1) << "MojoVFSClose(*)";
62 using filesystem::FilePtr;
63 GetFSFile(file).~FilePtr();
64 return SQLITE_OK;
65 }
66
67 int MojoVFSRead(sqlite3_file* sql_file,
68 void* buffer,
69 int size,
70 sqlite3_int64 offset) {
71 DVLOG(1) << "MojoVFSRead (" << size << " @ " << offset << ")";
72 filesystem::FileError error = filesystem::FILE_ERROR_FAILED;
73 mojo::Array<uint8_t> mojo_data;
74 GetFSFile(sql_file)->Read(size, offset, filesystem::WHENCE_FROM_BEGIN,
75 Capture(&error, &mojo_data));
76 GetFSFile(sql_file).WaitForIncomingResponse();
77
78 if (error != filesystem::FILE_ERROR_OK) {
79 // TODO(erg): Better implementation here.
80 NOTIMPLEMENTED();
81 return SQLITE_IOERR_READ;
82 }
83
84 if (mojo_data.size())
85 memcpy(buffer, &mojo_data.front(), mojo_data.size());
86 if (mojo_data.size() == static_cast<size_t>(size))
87 return SQLITE_OK;
88
89 // We didn't read the entire buffer. Fill the rest of the buffer with zeros.
90 memset(reinterpret_cast<char*>(buffer) + mojo_data.size(), 0,
91 size - mojo_data.size());
92
93 return SQLITE_IOERR_SHORT_READ;
94 }
95
96 int MojoVFSWrite(sqlite3_file* sql_file,
97 const void* buffer,
98 int size,
99 sqlite_int64 offset) {
100 DVLOG(1) << "MojoVFSWrite(*, " << size << ", " << offset << ")";
101 mojo::Array<uint8_t> mojo_data(size);
102 memcpy(&mojo_data.front(), buffer, size);
103
104 filesystem::FileError error = filesystem::FILE_ERROR_FAILED;
105 uint32_t num_bytes_written = 0;
106 GetFSFile(sql_file)->Write(mojo_data.Pass(), offset,
107 filesystem::WHENCE_FROM_BEGIN,
108 Capture(&error, &num_bytes_written));
109 GetFSFile(sql_file).WaitForIncomingResponse();
110 if (error != filesystem::FILE_ERROR_OK) {
111 // TODO(erg): Better implementation here.
112 NOTIMPLEMENTED();
113 return SQLITE_IOERR_WRITE;
114 }
115 if (num_bytes_written != static_cast<uint32_t>(size)) {
116 NOTIMPLEMENTED();
117 return SQLITE_IOERR_WRITE;
118 }
119
120 return SQLITE_OK;
121 }
122
123 int MojoVFSTruncate(sqlite3_file* sql_file, sqlite_int64 size) {
124 DVLOG(1) << "MojoVFSTruncate(*, " << size << ")";
125 filesystem::FileError error = filesystem::FILE_ERROR_FAILED;
126 GetFSFile(sql_file)->Truncate(size, Capture(&error));
127 GetFSFile(sql_file).WaitForIncomingResponse();
128 if (error != filesystem::FILE_ERROR_OK) {
129 // TODO(erg): Better implementation here.
130 NOTIMPLEMENTED();
131 return SQLITE_IOERR_TRUNCATE;
132 }
133
134 return SQLITE_OK;
135 }
136
137 int MojoVFSSync(sqlite3_file* sql_file, int flags) {
138 DVLOG(1) << "MojoVFSSync(*, " << flags << ")";
139 filesystem::FileError error = filesystem::FILE_ERROR_FAILED;
140 GetFSFile(sql_file)->Flush(Capture(&error));
141 GetFSFile(sql_file).WaitForIncomingResponse();
142 if (error != filesystem::FILE_ERROR_OK) {
143 // TODO(erg): Better implementation here.
144 NOTIMPLEMENTED();
145 return SQLITE_IOERR_FSYNC;
146 }
147
148 return SQLITE_OK;
149 }
150
151 int MojoVFSFileSize(sqlite3_file* sql_file, sqlite_int64* size) {
152 DVLOG(1) << "MojoVFSFileSize(*)";
153
154 filesystem::FileError err = filesystem::FILE_ERROR_FAILED;
155 filesystem::FileInformationPtr file_info;
156 GetFSFile(sql_file)->Stat(Capture(&err, &file_info));
157 GetFSFile(sql_file).WaitForIncomingResponse();
158
159 if (err != filesystem::FILE_ERROR_OK) {
160 // TODO(erg): Better implementation here.
161 NOTIMPLEMENTED();
162 return SQLITE_IOERR_FSTAT;
163 }
164
165 *size = file_info->size;
166 return SQLITE_OK;
167 }
168
169 // TODO(erg): The current base::File interface isn't sufficient to handle
170 // sqlite's locking primitives, which are done on byte ranges in the file. (See
171 // "File Locking Notes" in sqlite3.c.)
172 int MojoVFSLock(sqlite3_file* pFile, int eLock) {
173 DVLOG(1) << "MojoVFSLock(*, " << eLock << ")";
174 return SQLITE_OK;
175 }
176 int MojoVFSUnlock(sqlite3_file* pFile, int eLock) {
177 DVLOG(1) << "MojoVFSUnlock(*, " << eLock << ")";
178 return SQLITE_OK;
179 }
180 int MojoVFSCheckReservedLock(sqlite3_file* pFile, int* pResOut) {
181 DVLOG(1) << "MojoVFSCheckReservedLock(*)";
182 *pResOut = 0;
183 return SQLITE_OK;
184 }
185
186 // TODO(erg): This is the minimal implementation to get a few tests passing;
187 // lots more needs to be done here.
188 int MojoVFSFileControl(sqlite3_file* pFile, int op, void* pArg) {
189 DVLOG(1) << "MojoVFSFileControl(*, " << op << ", *)";
190 if (op == SQLITE_FCNTL_PRAGMA) {
191 // Returning NOTFOUND tells sqlite that we aren't doing any processing.
192 return SQLITE_NOTFOUND;
193 }
194
195 return SQLITE_OK;
196 }
197
198 int MojoVFSSectorSize(sqlite3_file* pFile) {
199 DVLOG(1) << "MojoVFSSectorSize(*)";
200 // Use the default sector size.
201 return 0;
202 }
203
204 int MojoVFSDeviceCharacteristics(sqlite3_file* pFile) {
205 DVLOG(1) << "MojoVFSDeviceCharacteristics(*)";
206 NOTIMPLEMENTED();
207 return 0;
208 }
209
210 static sqlite3_io_methods mojo_vfs_io_methods = {
211 1, /* iVersion */
212 MojoVFSClose, /* xClose */
213 MojoVFSRead, /* xRead */
214 MojoVFSWrite, /* xWrite */
215 MojoVFSTruncate, /* xTruncate */
216 MojoVFSSync, /* xSync */
217 MojoVFSFileSize, /* xFileSize */
218 MojoVFSLock, /* xLock */
219 MojoVFSUnlock, /* xUnlock */
220 MojoVFSCheckReservedLock, /* xCheckReservedLock */
221 MojoVFSFileControl, /* xFileControl */
222 MojoVFSSectorSize, /* xSectorSize */
223 MojoVFSDeviceCharacteristics, /* xDeviceCharacteristics */
224 };
225
226 int MojoVFSOpen(sqlite3_vfs* mojo_vfs,
227 const char* name,
228 sqlite3_file* file,
229 int flags,
230 int* pOutFlags) {
231 DVLOG(1) << "MojoVFSOpen(*, " << name << ", *, " << flags << ")";
232 int open_flags = 0;
233 if (flags & SQLITE_OPEN_EXCLUSIVE) {
234 DCHECK(flags & SQLITE_OPEN_CREATE);
235 open_flags = filesystem::kFlagCreate;
236 } else if (flags & SQLITE_OPEN_CREATE) {
237 DCHECK(flags & SQLITE_OPEN_READWRITE);
238 open_flags = filesystem::kFlagOpenAlways;
239 } else {
240 open_flags = filesystem::kFlagOpen;
241 }
242 open_flags |= filesystem::kFlagRead;
243 if (flags & SQLITE_OPEN_READWRITE)
244 open_flags |= filesystem::kFlagWrite;
245 if (flags & SQLITE_OPEN_DELETEONCLOSE)
246 open_flags |= filesystem::kDeleteOnClose;
247
248 // Grab the incoming file
249 filesystem::FilePtr file_ptr;
250 filesystem::FileError error = filesystem::FILE_ERROR_FAILED;
251 GetRootDirectory(mojo_vfs)->OpenFile(mojo::String(name), GetProxy(&file_ptr),
252 open_flags, Capture(&error));
253 GetRootDirectory(mojo_vfs).WaitForIncomingResponse();
254 if (error != filesystem::FILE_ERROR_OK) {
255 // TODO(erg): Translate more of the mojo error codes into sqlite error
256 // codes.
257 return SQLITE_CANTOPEN;
258 }
259
260 // Set the method table so we can be closed (and run the manual dtor call to
261 // match the following placement news).
262 file->pMethods = &mojo_vfs_io_methods;
263
264 // |file| is actually a malloced buffer of size szOsFile. This means that we
265 // need to manually use placement new to construct the C++ object which owns
266 // the pipe to our file.
267 new (&GetFSFile(file)) filesystem::FilePtr(file_ptr.Pass());
268
269 return SQLITE_OK;
270 }
271
272 int MojoVFSDelete(sqlite3_vfs* mojo_vfs, const char* filename, int sync_dir) {
273 DVLOG(1) << "MojoVFSDelete(*, " << filename << ", " << sync_dir << ")";
274 // TODO(erg): The default windows sqlite VFS has retry code to work around
275 // antivirus software keeping files open. We'll probably have to do something
276 // like that in the far future if we ever support Windows.
277 filesystem::FileError error = filesystem::FILE_ERROR_FAILED;
278 GetRootDirectory(mojo_vfs)->Delete(filename, 0, Capture(&error));
279 GetRootDirectory(mojo_vfs).WaitForIncomingResponse();
280
281 if (error == filesystem::FILE_ERROR_OK && sync_dir) {
282 GetRootDirectory(mojo_vfs)->Flush(Capture(&error));
283 GetRootDirectory(mojo_vfs).WaitForIncomingResponse();
284 }
285
286 return error == filesystem::FILE_ERROR_OK ? SQLITE_OK : SQLITE_IOERR_DELETE;
287 }
288
289 int MojoVFSAccess(sqlite3_vfs* mojo_vfs,
290 const char* filename,
291 int flags,
292 int* result) {
293 DVLOG(1) << "MojoVFSAccess(*, " << filename << ", " << flags << ", *)";
294 filesystem::FileError error = filesystem::FILE_ERROR_FAILED;
295
296 if (flags == SQLITE_ACCESS_READWRITE || flags == SQLITE_ACCESS_READ) {
297 bool is_writable = false;
298 GetRootDirectory(mojo_vfs)
299 ->IsWritable(filename, Capture(&error, &is_writable));
300 GetRootDirectory(mojo_vfs).WaitForIncomingResponse();
301 *result = is_writable;
302 return SQLITE_OK;
303 }
304
305 if (flags == SQLITE_ACCESS_EXISTS) {
306 bool exists = false;
307 GetRootDirectory(mojo_vfs)->Exists(filename, Capture(&error, &exists));
308 GetRootDirectory(mojo_vfs).WaitForIncomingResponse();
309 *result = exists;
310 return SQLITE_OK;
311 }
312
313 return SQLITE_IOERR;
314 }
315
316 int MojoVFSFullPathname(sqlite3_vfs* mojo_vfs,
317 const char* relative_path,
318 int absolute_path_size,
319 char* absolute_path) {
320 // The sandboxed process doesn't need to know the absolute path of the file.
321 sqlite3_snprintf(absolute_path_size, absolute_path, "%s", relative_path);
322 return SQLITE_OK;
323 }
324
325 // Don't let SQLite dynamically load things. (If we are using the
326 // mojo:filesystem proxying VFS, then it's highly likely that we are sandboxed
327 // and that any attempt to dlopen() a shared object is folly.)
328 void* MojoVFSDlOpen(sqlite3_vfs*, const char*) {
329 return 0;
330 }
331
332 void MojoVFSDlError(sqlite3_vfs*, int buf_size, char* error_msg) {
333 sqlite3_snprintf(buf_size, error_msg, "Dynamic loading not supported");
334 }
335
336 void (*MojoVFSDlSym(sqlite3_vfs*, void*, const char*))(void) {
337 return 0;
338 }
339
340 void MojoVFSDlClose(sqlite3_vfs*, void*) {
341 return;
342 }
343
344 int MojoVFSRandomness(sqlite3_vfs* mojo_vfs, int size, char* out) {
345 base::RandBytes(out, size);
346 return size;
347 }
348
349 // Proxy the rest of the calls down to the OS specific handler.
350 int MojoVFSSleep(sqlite3_vfs* mojo_vfs, int micro) {
351 return GetParentVFS(mojo_vfs)->xSleep(GetParentVFS(mojo_vfs), micro);
352 }
353
354 int MojoVFSCurrentTime(sqlite3_vfs* mojo_vfs, double* time) {
355 return GetParentVFS(mojo_vfs)->xCurrentTime(GetParentVFS(mojo_vfs), time);
356 }
357
358 int MojoVFSGetLastError(sqlite3_vfs* mojo_vfs, int a, char* b) {
359 return 0;
360 }
361
362 int MojoVFSCurrentTimeInt64(sqlite3_vfs* mojo_vfs, sqlite3_int64* out) {
363 return GetParentVFS(mojo_vfs)->xCurrentTimeInt64(GetParentVFS(mojo_vfs), out);
364 }
365
366 static sqlite3_vfs mojo_vfs = {
367 1, /* iVersion */
368 sizeof(MojoVFSFile), /* szOsFile */
369 kMaxPathName, /* mxPathname */
370 0, /* pNext */
371 "mojo", /* zName */
372 0, /* pAppData */
373 MojoVFSOpen, /* xOpen */
374 MojoVFSDelete, /* xDelete */
375 MojoVFSAccess, /* xAccess */
376 MojoVFSFullPathname, /* xFullPathname */
377 MojoVFSDlOpen, /* xDlOpen */
378 MojoVFSDlError, /* xDlError */
379 MojoVFSDlSym, /* xDlSym */
380 MojoVFSDlClose, /* xDlClose */
381 MojoVFSRandomness, /* xRandomness */
382 MojoVFSSleep, /* xSleep */
383 MojoVFSCurrentTime, /* xCurrentTime */
384 MojoVFSGetLastError, /* xGetLastError */
385 MojoVFSCurrentTimeInt64 /* xCurrentTimeInt64 */
386 };
387
388 } // namespace
389
390 ScopedMojoFilesystemVFS::ScopedMojoFilesystemVFS(
391 filesystem::DirectoryPtr root_directory)
392 : parent_(sqlite3_vfs_find(NULL)),
393 root_directory_(root_directory.Pass()) {
394 CHECK(!mojo_vfs.pAppData);
395 mojo_vfs.pAppData = this;
396 mojo_vfs.mxPathname = parent_->mxPathname;
397
398 CHECK(sqlite3_vfs_register(&mojo_vfs, 1) == SQLITE_OK);
399 }
400
401 ScopedMojoFilesystemVFS::~ScopedMojoFilesystemVFS() {
402 CHECK(mojo_vfs.pAppData);
403 mojo_vfs.pAppData = nullptr;
404
405 CHECK(sqlite3_vfs_register(parent_, 1) == SQLITE_OK);
406 CHECK(sqlite3_vfs_unregister(&mojo_vfs) == SQLITE_OK);
407 }
408
409 filesystem::DirectoryPtr& ScopedMojoFilesystemVFS::GetDirectory() {
410 return root_directory_;
411 }
412
413 } // namespace sql
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698