| // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "storage/browser/database/vfs_backend.h" |
| |
| #include "base/files/file_path.h" |
| #include "base/files/file_util.h" |
| #include "base/logging.h" |
| #include "third_party/sqlite/sqlite3.h" |
| |
| namespace storage { |
| |
| static const int kFileTypeMask = 0x00007F00; |
| |
| // static |
| bool VfsBackend::OpenTypeIsReadWrite(int desired_flags) { |
| return (desired_flags & SQLITE_OPEN_READWRITE) != 0; |
| } |
| |
| // static |
| 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; |
| |
| // All files should be opened either read-write or read-only, but not both. |
| if (is_read_only == is_read_write) |
| return false; |
| |
| // If a new file is created, it must also be writable. |
| if (is_create && !is_read_write) |
| return false; |
| |
| // If we're accessing an existing file, we cannot give exclusive access, and |
| // we can't delete it. |
| // Normally, we'd also check that 'is_delete' is false for a main DB, main |
| // journal or master journal file; however, when in incognito mode, we use |
| // the SQLITE_OPEN_DELETEONCLOSE flag when opening those files too and keep |
| // an open handle to them for as long as the incognito profile is around. |
| if ((is_exclusive || is_delete) && !is_create) |
| return false; |
| |
| // Make sure we're opening the DB directory or that a file type is set. |
| 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); |
| } |
| |
| // static |
| base::File VfsBackend::OpenFile(const base::FilePath& file_path, |
| int desired_flags) { |
| DCHECK(!file_path.empty()); |
| |
| // Verify the flags for consistency and create the database |
| // directory if it doesn't exist. |
| 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_EXCLUSIVE_READ | base::File::FLAG_EXCLUSIVE_WRITE; |
| |
| flags |= ((desired_flags & SQLITE_OPEN_CREATE) ? |
| base::File::FLAG_OPEN_ALWAYS : base::File::FLAG_OPEN); |
| |
| if (desired_flags & SQLITE_OPEN_EXCLUSIVE) |
| flags |= base::File::FLAG_EXCLUSIVE_READ | base::File::FLAG_EXCLUSIVE_WRITE; |
| |
| if (desired_flags & SQLITE_OPEN_DELETEONCLOSE) { |
| flags |= base::File::FLAG_TEMPORARY | base::File::FLAG_HIDDEN | |
| base::File::FLAG_DELETE_ON_CLOSE; |
| } |
| |
| // This flag will allow us to delete the file later on from the browser |
| // process. |
| flags |= base::File::FLAG_SHARE_DELETE; |
| |
| // Try to open/create the DB file. |
| return base::File(file_path, flags); |
| } |
| |
| // static |
| base::File VfsBackend::OpenTempFileInDirectory(const base::FilePath& dir_path, |
| int desired_flags) { |
| // We should be able to delete temp files when they're closed |
| // and create them as needed |
| if (!(desired_flags & SQLITE_OPEN_DELETEONCLOSE) || |
| !(desired_flags & SQLITE_OPEN_CREATE)) { |
| return base::File(); |
| } |
| |
| // Get a unique temp file name in the database directory. |
| base::FilePath temp_file_path; |
| if (!base::CreateTemporaryFileInDir(dir_path, &temp_file_path)) |
| return base::File(); |
| |
| return OpenFile(temp_file_path, desired_flags); |
| } |
| |
| // static |
| int VfsBackend::DeleteFile(const base::FilePath& file_path, bool sync_dir) { |
| if (!base::PathExists(file_path)) |
| return SQLITE_OK; |
| if (!base::DeleteFile(file_path, false)) |
| return SQLITE_IOERR_DELETE; |
| |
| int error_code = SQLITE_OK; |
| #if defined(OS_POSIX) |
| 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; |
| } |
| |
| // static |
| uint32 VfsBackend::GetFileAttributes(const base::FilePath& file_path) { |
| #if defined(OS_WIN) |
| uint32 attributes = ::GetFileAttributes(file_path.value().c_str()); |
| #elif defined(OS_POSIX) |
| uint32 attributes = 0; |
| if (!access(file_path.value().c_str(), R_OK)) |
| attributes |= static_cast<uint32>(R_OK); |
| if (!access(file_path.value().c_str(), W_OK)) |
| attributes |= static_cast<uint32>(W_OK); |
| if (!attributes) |
| attributes = -1; |
| #endif |
| return attributes; |
| } |
| |
| // static |
| int64 VfsBackend::GetFileSize(const base::FilePath& file_path) { |
| int64 size = 0; |
| return (base::GetFileSize(file_path, &size) ? size : 0); |
| } |
| |
| // static |
| bool VfsBackend::SetFileSize(const base::FilePath& file_path, int64 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); |
| } |
| |
| } // namespace storage |