1 // Copyright (c) 2011 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 "webkit/browser/database/vfs_backend.h" 6 7 #include "base/file_util.h" 8 #include "base/files/file_path.h" 9 #include "base/logging.h" 10 #include "third_party/sqlite/sqlite3.h" 11 12 namespace webkit_database { 13 14 static const int kFileTypeMask = 0x00007F00; 15 16 // static 17 bool VfsBackend::OpenTypeIsReadWrite(int desired_flags) { 18 return (desired_flags & SQLITE_OPEN_READWRITE) != 0; 19 } 20 21 // static 22 bool VfsBackend::OpenFileFlagsAreConsistent(int desired_flags) { 23 const int file_type = desired_flags & kFileTypeMask; 24 const bool is_exclusive = (desired_flags & SQLITE_OPEN_EXCLUSIVE) != 0; 25 const bool is_delete = (desired_flags & SQLITE_OPEN_DELETEONCLOSE) != 0; 26 const bool is_create = (desired_flags & SQLITE_OPEN_CREATE) != 0; 27 const bool is_read_only = (desired_flags & SQLITE_OPEN_READONLY) != 0; 28 const bool is_read_write = (desired_flags & SQLITE_OPEN_READWRITE) != 0; 29 30 // All files should be opened either read-write or read-only, but not both. 31 if (is_read_only == is_read_write) 32 return false; 33 34 // If a new file is created, it must also be writable. 35 if (is_create && !is_read_write) 36 return false; 37 38 // If we're accessing an existing file, we cannot give exclusive access, and 39 // we can't delete it. 40 // Normally, we'd also check that 'is_delete' is false for a main DB, main 41 // journal or master journal file; however, when in incognito mode, we use 42 // the SQLITE_OPEN_DELETEONCLOSE flag when opening those files too and keep 43 // an open handle to them for as long as the incognito profile is around. 44 if ((is_exclusive || is_delete) && !is_create) 45 return false; 46 47 // Make sure we're opening the DB directory or that a file type is set. 48 return (file_type == SQLITE_OPEN_MAIN_DB) || 49 (file_type == SQLITE_OPEN_TEMP_DB) || 50 (file_type == SQLITE_OPEN_MAIN_JOURNAL) || 51 (file_type == SQLITE_OPEN_TEMP_JOURNAL) || 52 (file_type == SQLITE_OPEN_SUBJOURNAL) || 53 (file_type == SQLITE_OPEN_MASTER_JOURNAL) || 54 (file_type == SQLITE_OPEN_TRANSIENT_DB); 55 } 56 57 // static 58 void VfsBackend::OpenFile(const base::FilePath& file_path, 59 int desired_flags, 60 base::PlatformFile* file_handle) { 61 DCHECK(!file_path.empty()); 62 63 // Verify the flags for consistency and create the database 64 // directory if it doesn't exist. 65 if (!OpenFileFlagsAreConsistent(desired_flags) || 66 !base::CreateDirectory(file_path.DirName())) 67 return; 68 69 int flags = 0; 70 flags |= base::PLATFORM_FILE_READ; 71 if (desired_flags & SQLITE_OPEN_READWRITE) 72 flags |= base::PLATFORM_FILE_WRITE; 73 74 if (!(desired_flags & SQLITE_OPEN_MAIN_DB)) { 75 flags |= base::PLATFORM_FILE_EXCLUSIVE_READ | 76 base::PLATFORM_FILE_EXCLUSIVE_WRITE; 77 } 78 79 flags |= ((desired_flags & SQLITE_OPEN_CREATE) ? 80 base::PLATFORM_FILE_OPEN_ALWAYS : base::PLATFORM_FILE_OPEN); 81 82 if (desired_flags & SQLITE_OPEN_EXCLUSIVE) { 83 flags |= base::PLATFORM_FILE_EXCLUSIVE_READ | 84 base::PLATFORM_FILE_EXCLUSIVE_WRITE; 85 } 86 87 if (desired_flags & SQLITE_OPEN_DELETEONCLOSE) { 88 flags |= base::PLATFORM_FILE_TEMPORARY | base::PLATFORM_FILE_HIDDEN | 89 base::PLATFORM_FILE_DELETE_ON_CLOSE; 90 } 91 92 // This flag will allow us to delete the file later on from the browser 93 // process. 94 flags |= base::PLATFORM_FILE_SHARE_DELETE; 95 96 // Try to open/create the DB file. 97 *file_handle = 98 base::CreatePlatformFile(file_path, flags, NULL, NULL); 99 } 100 101 // static 102 void VfsBackend::OpenTempFileInDirectory( 103 const base::FilePath& dir_path, 104 int desired_flags, 105 base::PlatformFile* file_handle) { 106 // We should be able to delete temp files when they're closed 107 // and create them as needed 108 if (!(desired_flags & SQLITE_OPEN_DELETEONCLOSE) || 109 !(desired_flags & SQLITE_OPEN_CREATE)) { 110 return; 111 } 112 113 // Get a unique temp file name in the database directory. 114 base::FilePath temp_file_path; 115 if (!base::CreateTemporaryFileInDir(dir_path, &temp_file_path)) 116 return; 117 118 OpenFile(temp_file_path, desired_flags, file_handle); 119 } 120 121 // static 122 int VfsBackend::DeleteFile(const base::FilePath& file_path, bool sync_dir) { 123 if (!base::PathExists(file_path)) 124 return SQLITE_OK; 125 if (!base::DeleteFile(file_path, false)) 126 return SQLITE_IOERR_DELETE; 127 128 int error_code = SQLITE_OK; 129 #if defined(OS_POSIX) 130 if (sync_dir) { 131 base::PlatformFile dir_fd = base::CreatePlatformFile( 132 file_path.DirName(), base::PLATFORM_FILE_READ, NULL, NULL); 133 if (dir_fd == base::kInvalidPlatformFileValue) { 134 error_code = SQLITE_CANTOPEN; 135 } else { 136 if (fsync(dir_fd)) 137 error_code = SQLITE_IOERR_DIR_FSYNC; 138 base::ClosePlatformFile(dir_fd); 139 } 140 } 141 #endif 142 return error_code; 143 } 144 145 // static 146 uint32 VfsBackend::GetFileAttributes(const base::FilePath& file_path) { 147 #if defined(OS_WIN) 148 uint32 attributes = ::GetFileAttributes(file_path.value().c_str()); 149 #elif defined(OS_POSIX) 150 uint32 attributes = 0; 151 if (!access(file_path.value().c_str(), R_OK)) 152 attributes |= static_cast<uint32>(R_OK); 153 if (!access(file_path.value().c_str(), W_OK)) 154 attributes |= static_cast<uint32>(W_OK); 155 if (!attributes) 156 attributes = -1; 157 #endif 158 return attributes; 159 } 160 161 // static 162 int64 VfsBackend::GetFileSize(const base::FilePath& file_path) { 163 int64 size = 0; 164 return (base::GetFileSize(file_path, &size) ? size : 0); 165 } 166 167 } // namespace webkit_database 168