• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "storage/browser/database/vfs_backend.h"
6 
7 #include "base/files/file_path.h"
8 #include "base/files/file_util.h"
9 #include "base/logging.h"
10 #include "third_party/sqlite/sqlite3.h"
11 
12 namespace storage {
13 
14 static const int kFileTypeMask = 0x00007F00;
15 
16 // static
OpenTypeIsReadWrite(int desired_flags)17 bool VfsBackend::OpenTypeIsReadWrite(int desired_flags) {
18   return (desired_flags & SQLITE_OPEN_READWRITE) != 0;
19 }
20 
21 // static
OpenFileFlagsAreConsistent(int desired_flags)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
OpenFile(const base::FilePath & file_path,int desired_flags)58 base::File VfsBackend::OpenFile(const base::FilePath& file_path,
59                                 int desired_flags) {
60   DCHECK(!file_path.empty());
61 
62   // Verify the flags for consistency and create the database
63   // directory if it doesn't exist.
64   if (!OpenFileFlagsAreConsistent(desired_flags) ||
65       !base::CreateDirectory(file_path.DirName())) {
66     return base::File();
67   }
68 
69   int flags = 0;
70   flags |= base::File::FLAG_READ;
71   if (desired_flags & SQLITE_OPEN_READWRITE)
72     flags |= base::File::FLAG_WRITE;
73 
74   if (!(desired_flags & SQLITE_OPEN_MAIN_DB))
75     flags |= base::File::FLAG_EXCLUSIVE_READ | base::File::FLAG_EXCLUSIVE_WRITE;
76 
77   flags |= ((desired_flags & SQLITE_OPEN_CREATE) ?
78            base::File::FLAG_OPEN_ALWAYS : base::File::FLAG_OPEN);
79 
80   if (desired_flags & SQLITE_OPEN_EXCLUSIVE)
81     flags |= base::File::FLAG_EXCLUSIVE_READ | base::File::FLAG_EXCLUSIVE_WRITE;
82 
83   if (desired_flags & SQLITE_OPEN_DELETEONCLOSE) {
84     flags |= base::File::FLAG_TEMPORARY | base::File::FLAG_HIDDEN |
85              base::File::FLAG_DELETE_ON_CLOSE;
86   }
87 
88   // This flag will allow us to delete the file later on from the browser
89   // process.
90   flags |= base::File::FLAG_SHARE_DELETE;
91 
92   // Try to open/create the DB file.
93   return base::File(file_path, flags);
94 }
95 
96 // static
OpenTempFileInDirectory(const base::FilePath & dir_path,int desired_flags)97 base::File VfsBackend::OpenTempFileInDirectory(const base::FilePath& dir_path,
98                                                int desired_flags) {
99   // We should be able to delete temp files when they're closed
100   // and create them as needed
101   if (!(desired_flags & SQLITE_OPEN_DELETEONCLOSE) ||
102       !(desired_flags & SQLITE_OPEN_CREATE)) {
103     return base::File();
104   }
105 
106   // Get a unique temp file name in the database directory.
107   base::FilePath temp_file_path;
108   if (!base::CreateTemporaryFileInDir(dir_path, &temp_file_path))
109     return base::File();
110 
111   return OpenFile(temp_file_path, desired_flags);
112 }
113 
114 // static
DeleteFile(const base::FilePath & file_path,bool sync_dir)115 int VfsBackend::DeleteFile(const base::FilePath& file_path, bool sync_dir) {
116   if (!base::PathExists(file_path))
117     return SQLITE_OK;
118   if (!base::DeleteFile(file_path, false))
119     return SQLITE_IOERR_DELETE;
120 
121   int error_code = SQLITE_OK;
122 #if defined(OS_POSIX)
123   if (sync_dir) {
124     base::File dir(file_path.DirName(), base::File::FLAG_READ);
125     if (dir.IsValid()) {
126       if (!dir.Flush())
127         error_code = SQLITE_IOERR_DIR_FSYNC;
128     } else {
129       error_code = SQLITE_CANTOPEN;
130     }
131   }
132 #endif
133   return error_code;
134 }
135 
136 // static
GetFileAttributes(const base::FilePath & file_path)137 uint32 VfsBackend::GetFileAttributes(const base::FilePath& file_path) {
138 #if defined(OS_WIN)
139   uint32 attributes = ::GetFileAttributes(file_path.value().c_str());
140 #elif defined(OS_POSIX)
141   uint32 attributes = 0;
142   if (!access(file_path.value().c_str(), R_OK))
143     attributes |= static_cast<uint32>(R_OK);
144   if (!access(file_path.value().c_str(), W_OK))
145     attributes |= static_cast<uint32>(W_OK);
146   if (!attributes)
147     attributes = -1;
148 #endif
149   return attributes;
150 }
151 
152 // static
GetFileSize(const base::FilePath & file_path)153 int64 VfsBackend::GetFileSize(const base::FilePath& file_path) {
154   int64 size = 0;
155   return (base::GetFileSize(file_path, &size) ? size : 0);
156 }
157 
158 }  // namespace storage
159