#include "storage/browser/database/vfs_backend.h"
#include <stdint.h>
#include "base/check.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "build/build_config.h"
#include "third_party/sqlite/sqlite3.h"
#if BUILDFLAG(IS_WIN)
#include <windows.h>
#endif
namespace storage {
static const int kFileTypeMask = 0x00007F00;
bool VfsBackend::OpenTypeIsReadWrite(int desired_flags) {
return (desired_flags & SQLITE_OPEN_READWRITE) != 0;
}
bool VfsBackend::OpenFileFlagsAreConsistent(int desired_flags) {
const int file_type = desired_flags & kFileTypeMask;
const bool is_exclusive = (desired_flags & SQLITE_OPEN_EXCLUSIVE) != 0;
const bool is_delete = (desired_flags & SQLITE_OPEN_DELETEONCLOSE) != 0;
const bool is_create = (desired_flags & SQLITE_OPEN_CREATE) != 0;
const bool is_read_only = (desired_flags & SQLITE_OPEN_READONLY) != 0;
const bool is_read_write = (desired_flags & SQLITE_OPEN_READWRITE) != 0;
if (is_read_only == is_read_write)
return false;
if (is_create && !is_read_write)
return false;
if ((is_exclusive || is_delete) && !is_create)
return false;
return (file_type == SQLITE_OPEN_MAIN_DB) ||
(file_type == SQLITE_OPEN_TEMP_DB) ||
(file_type == SQLITE_OPEN_MAIN_JOURNAL) ||
(file_type == SQLITE_OPEN_TEMP_JOURNAL) ||
(file_type == SQLITE_OPEN_SUBJOURNAL) ||
(file_type == SQLITE_OPEN_MASTER_JOURNAL) ||
(file_type == SQLITE_OPEN_TRANSIENT_DB);
}
base::File VfsBackend::OpenFile(const base::FilePath& file_path,
int desired_flags) {
DCHECK(!file_path.empty());
if (!OpenFileFlagsAreConsistent(desired_flags) ||
!base::CreateDirectory(file_path.DirName())) {
return base::File();
}
int flags = 0;
flags |= base::File::FLAG_READ;
if (desired_flags & SQLITE_OPEN_READWRITE)
flags |= base::File::FLAG_WRITE;
if (!(desired_flags & SQLITE_OPEN_MAIN_DB))
flags |= base::File::FLAG_WIN_EXCLUSIVE_READ |
base::File::FLAG_WIN_EXCLUSIVE_WRITE;
if (desired_flags & SQLITE_OPEN_CREATE) {
flags |= (desired_flags & SQLITE_OPEN_EXCLUSIVE)
? base::File::FLAG_CREATE
: base::File::FLAG_OPEN_ALWAYS;
} else {
flags |= base::File::FLAG_OPEN;
}
if (desired_flags & SQLITE_OPEN_DELETEONCLOSE) {
flags |= base::File::FLAG_WIN_TEMPORARY | base::File::FLAG_WIN_HIDDEN |
base::File::FLAG_DELETE_ON_CLOSE;
}
flags |= base::File::FLAG_WIN_SHARE_DELETE;
flags = base::File::AddFlagsForPassingToUntrustedProcess(flags);
return base::File(file_path, flags);
}
base::File VfsBackend::OpenTempFileInDirectory(const base::FilePath& dir_path,
int desired_flags) {
if (!(desired_flags & SQLITE_OPEN_DELETEONCLOSE) ||
!(desired_flags & SQLITE_OPEN_CREATE)) {
return base::File();
}
base::FilePath temp_file_path;
if (!base::CreateTemporaryFileInDir(dir_path, &temp_file_path))
return base::File();
return OpenFile(temp_file_path, desired_flags);
}
int VfsBackend::DeleteFile(const base::FilePath& file_path, bool sync_dir) {
if (!base::PathExists(file_path))
return SQLITE_OK;
if (!base::DeleteFile(file_path))
return SQLITE_IOERR_DELETE;
int error_code = SQLITE_OK;
#if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
if (sync_dir) {
base::File dir(file_path.DirName(), base::File::FLAG_READ);
if (dir.IsValid()) {
if (!dir.Flush())
error_code = SQLITE_IOERR_DIR_FSYNC;
} else {
error_code = SQLITE_CANTOPEN;
}
}
#endif
return error_code;
}
uint32_t VfsBackend::GetFileAttributes(const base::FilePath& file_path) {
#if BUILDFLAG(IS_WIN)
uint32_t attributes = ::GetFileAttributes(file_path.value().c_str());
#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
uint32_t attributes = 0;
if (!access(file_path.value().c_str(), R_OK))
attributes |= static_cast<uint32_t>(R_OK);
if (!access(file_path.value().c_str(), W_OK))
attributes |= static_cast<uint32_t>(W_OK);
if (!attributes)
attributes = -1;
#endif
return attributes;
}
bool VfsBackend::SetFileSize(const base::FilePath& file_path, int64_t size) {
int flags = 0;
flags |= base::File::FLAG_READ;
flags |= base::File::FLAG_WRITE;
flags |= base::File::FLAG_OPEN;
base::File file = base::File(file_path, flags);
if (!file.IsValid())
return false;
return file.SetLength(size);
}
}