Home | History | Annotate | Download | only in database
      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       !file_util::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 (!file_util::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 (file_util::GetFileSize(file_path, &size) ? size : 0);
    165 }
    166 
    167 } // namespace webkit_database
    168