Movatterモバイル変換


[0]ホーム

URL:


Google Git
Sign in
chromium /chromium /src /refs/heads/main /. /sql /sandboxed_vfs.cc
blob: b6bf826fe0b7e47775c7005129b14d8b8243fe2e [file] [log] [blame] [edit]
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include"sql/sandboxed_vfs.h"
#include<algorithm>
#include<cstring>
#include<memory>
#include<optional>
#include<ostream>
#include<string>
#include<string_view>
#include<utility>
#include<vector>
#include"base/check.h"
#include"base/check_op.h"
#include"base/compiler_specific.h"
#include"base/files/file.h"
#include"base/files/file_path.h"
#include"base/no_destructor.h"
#include"base/notreached.h"
#include"base/threading/platform_thread.h"
#include"base/time/time.h"
#include"sql/initialization.h"
#include"sql/sandboxed_vfs_file.h"
#include"sql/vfs_wrapper.h"
#include"third_party/sqlite/sqlite3.h"
namespace sql{
namespace{
// Extracts the SandboxedVfs* stashed in a SQLite VFS structure.
SandboxedVfs&SandboxedVfsFromSqliteVfs(sqlite3_vfs& vfs){
return*reinterpret_cast<SandboxedVfs*>(vfs.pAppData);
}
intSandboxedVfsOpen(sqlite3_vfs* vfs,
constchar* full_path,
sqlite3_file* result_file,
int requested_flags,
int* granted_flags){
returnSandboxedVfsFromSqliteVfs(*vfs).Open(full_path,*result_file,
requested_flags, granted_flags);
}
intSandboxedVfsDelete(sqlite3_vfs* vfs,constchar* full_path,int sync_dir){
returnSandboxedVfsFromSqliteVfs(*vfs).Delete(full_path, sync_dir);
}
intSandboxedVfsAccess(sqlite3_vfs* vfs,
constchar* full_path,
int flags,
int* result){
returnSandboxedVfsFromSqliteVfs(*vfs).Access(full_path, flags,*result);
}
intSandboxedVfsFullPathname(sqlite3_vfs* vfs,
constchar* file_path,
int result_size,
char* result){
returnSandboxedVfsFromSqliteVfs(*vfs).FullPathname(file_path, result_size,
result);
}
intSandboxedVfsRandomness(sqlite3_vfs* vfs,int result_size,char* result){
returnSandboxedVfsFromSqliteVfs(*vfs).Randomness(result_size, result);
}
intSandboxedVfsSleep(sqlite3_vfs* vfs,int microseconds){
returnSandboxedVfsFromSqliteVfs(*vfs).Sleep(microseconds);
}
intSandboxedVfsGetLastError(sqlite3_vfs* vfs,
int message_size,
char* message){
returnSandboxedVfsFromSqliteVfs(*vfs).GetLastError(message_size, message);
}
intSandboxedVfsCurrentTimeInt64(sqlite3_vfs* vfs, sqlite3_int64* result_ms){
returnSandboxedVfsFromSqliteVfs(*vfs).CurrentTimeInt64(result_ms);
}
sqlite3_vfsSqliteVfsFor(SandboxedVfs* sandboxed_vfs,constchar* name){
DCHECK_EQ(sandboxed_vfs,reinterpret_cast<SandboxedVfs*>(
reinterpret_cast<void*>(sandboxed_vfs)))
<<"This implementation round-trips SandboxedVfs* via void*";
// VFS API entry points are listed at https://www.sqlite.org/c3ref/vfs.html
staticconstexprint kSqliteVfsApiVersion=3;
// Maximum file path size.
// TODO(pwnall): Obtain this from //base or some other good place.
staticconstexprint kSqliteMaxPathSize=512;
return{
kSqliteVfsApiVersion,
sizeof(SandboxedVfsFileSqliteBridge),
kSqliteMaxPathSize,
/*pNext=*/nullptr,
name,
/*pAppData=*/reinterpret_cast<void*>(sandboxed_vfs),
SandboxedVfsOpen,
SandboxedVfsDelete,
SandboxedVfsAccess,
SandboxedVfsFullPathname,
/*xDlOpen=*/nullptr,
/*xDlError=*/nullptr,
/*xDlSym=*/nullptr,
/*xDlClose=*/nullptr,
SandboxedVfsRandomness,
SandboxedVfsSleep,
/*xCurrentTime=*/nullptr,// Deprecated in API versions 2 and above.
SandboxedVfsGetLastError,
SandboxedVfsCurrentTimeInt64,
/*xSetSystemCall=*/nullptr,
/*xGetSystemCall=*/nullptr,
/*xNextSystemCall=*/nullptr,
};
}
// SQLite measures time according to the Julian calendar.
base::TimeSqliteEpoch(){
// The ".5" is intentional -- days in the Julian calendar start at noon.
// The offset is in the SQLite source code (os_unix.c) multiplied by 10.
constexprconstdouble kUnixEpochAsJulianDay=2440587.5;
return base::Time::FromMillisecondsSinceUnixEpoch(
-kUnixEpochAsJulianDay* base::Time::kMillisecondsPerDay);
}
// `full_path_cstr` must be a filename argument passed to the VFS from SQLite.
SandboxedVfsFileTypeVfsFileTypeFromPath(constchar* full_path_cstr){
std::string_view full_path(full_path_cstr);
if(full_path== sqlite3_filename_database(full_path_cstr)){
returnSandboxedVfsFileType::kDatabase;
}
if(full_path== sqlite3_filename_journal(full_path_cstr)){
returnSandboxedVfsFileType::kJournal;
}
if(full_path== sqlite3_filename_wal(full_path_cstr)){
returnSandboxedVfsFileType::kWal;
}
NOTREACHED()
<<"Argument is not a file name buffer passed from SQLite to a VFS: "
<< full_path;
}
}// namespace
// static
voidSandboxedVfs::Register(constchar* name,
std::unique_ptr<Delegate>delegate,
bool make_default){
static base::NoDestructor<std::vector<SandboxedVfs*>>
registered_vfs_instances;
sql::EnsureSqliteInitialized(/*create_wrapper=*/false);
registered_vfs_instances->push_back(
newSandboxedVfs(name, std::move(delegate), make_default));
}
intSandboxedVfs::Open(constchar* full_path,
sqlite3_file& result_file,
int requested_flags,
int* granted_flags){
base::FilePath file_path= base::FilePath::FromUTF8Unsafe(full_path);
base::File file= delegate_->OpenFile(file_path, requested_flags);
if(!file.IsValid()){
// TODO(pwnall): Figure out if we can remove the fallback to read-only.
if(!(requested_flags& SQLITE_OPEN_READWRITE)){
// The SQLite API requires that pMethods is set to null even if the open
// call returns a failure status.
result_file.pMethods=nullptr;
return SQLITE_CANTOPEN;
}
int new_flags=
(requested_flags&~SQLITE_OPEN_READWRITE)| SQLITE_OPEN_READONLY;
returnOpen(full_path, result_file, new_flags, granted_flags);
}
SandboxedVfsFile* vfs_file=
delegate_->RetrieveSandboxedVfsFile(std::move(file), std::move(file_path),
VfsFileTypeFromPath(full_path),this);
if(!vfs_file){
return SQLITE_CANTOPEN;
}
// Bind the sandboxed file pointer with the sqlite_file structure. This
// pointer can later be unboxed (retrieved from the vfs_file structure after
// an upcast from sqlite_file* to a SandboxedVfsFileSqliteBridge*) and use
// this pointer to redirect the calls (from the sqlite io_methods calls) to
// their corresponding sandboxed implementation.
SandboxedVfsFile::BindSandboxedFile(vfs_file, result_file);
if(granted_flags)
*granted_flags= requested_flags;
return SQLITE_OK;
}
intSandboxedVfs::Delete(constchar* full_path,int sync_dir){
DCHECK(full_path);
return delegate_->DeleteFile(base::FilePath::FromUTF8Unsafe(full_path),
sync_dir==1);
}
intSandboxedVfs::Access(constchar* full_path,int flags,int& result){
DCHECK(full_path);
std::optional<PathAccessInfo> access=
delegate_->GetPathAccess(base::FilePath::FromUTF8Unsafe(full_path));
if(!access){
result=0;
return SQLITE_OK;
}
switch(flags){
case SQLITE_ACCESS_EXISTS:
result=1;
break;
case SQLITE_ACCESS_READ:
result= access->can_read?1:0;
break;
case SQLITE_ACCESS_READWRITE:
result=(access->can_read&& access->can_write)?1:0;
break;
default:
NOTREACHED()<<"Unsupported xAccess flags: "<< flags;
}
return SQLITE_OK;
}
intSandboxedVfs::FullPathname(constchar* file_path,
int result_size,
char* result){
DCHECK(file_path);
DCHECK_GT(result_size,0);
DCHECK(result);
// Renderer processes cannot access files directly, so it doesn't make sense
// to expose full paths here.
size_t file_path_size= std::strlen(file_path)+1;
if(static_cast<size_t>(result_size)< file_path_size)
return SQLITE_CANTOPEN;
UNSAFE_TODO(std::memcpy(result, file_path, file_path_size));
return SQLITE_OK;
}
intSandboxedVfs::Randomness(int result_size,char* result){
DCHECK_GT(result_size,0);
DCHECK(result);
// TODO(pwnall): Figure out if we need a real implementation.
UNSAFE_TODO(std::memset(result,0, result_size));
return result_size;
}
intSandboxedVfs::Sleep(int microseconds){
DCHECK_GE(microseconds,0);
base::PlatformThread::Sleep(base::Microseconds(microseconds));
return SQLITE_OK;
}
intSandboxedVfs::GetLastError(int message_size,char* message)const{
DCHECK_GE(message_size,0);
DCHECK(message_size==0|| message);
std::string error_string= base::File::ErrorToString(last_error_);
size_t error_string_size= error_string.length()+1;
size_t copy_length=
std::min(static_cast<size_t>(message_size), error_string_size);
std::copy_n(error_string.c_str(), copy_length, message);
// The return value is zero if the message fits in the buffer, and non-zero if
// it does not fit.
return copy_length!= error_string_size;
}
intSandboxedVfs::CurrentTimeInt64(sqlite3_int64* result_ms){
DCHECK(result_ms);
base::TimeDelta delta= base::Time::Now()- sqlite_epoch_;
*result_ms= delta.InMilliseconds();
return SQLITE_OK;
}
SandboxedVfs::SandboxedVfs(constchar* name,
std::unique_ptr<Delegate>delegate,
bool make_default)
: sandboxed_vfs_(SqliteVfsFor(this, name)),
sqlite_epoch_(SqliteEpoch()),
delegate_(std::move(delegate)),
last_error_(base::File::FILE_OK){
if(make_default){
// This shouldn't override the VFS wrapper.
DCHECK_NE(std::string_view(sqlite3_vfs_find(nullptr)->zName),
kVfsWrapperName);
}
// The register function returns a SQLite status as an int. The status is
// ignored here. If registration fails, we'd want to report the error while
// attempting to open a database. This is exactly what will happen, because
// SQLite won't find the VFS we're asking for.
sqlite3_vfs_register(&sandboxed_vfs_, make_default?1:0);
}
}// namespace sql

[8]ページ先頭

©2009-2025 Movatter.jp