[M120 Migration][VD] Fix url crash in RequestCertificateConfirm
[platform/framework/web/chromium-efl.git] / sql / vfs_wrapper_fuchsia.cc
1 // Copyright 2019 The Chromium Authors
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 "sql/vfs_wrapper_fuchsia.h"
6
7 #include "base/check_op.h"
8 #include "base/containers/fixed_flat_set.h"
9 #include "base/containers/flat_map.h"
10 #include "base/containers/flat_set.h"
11 #include "base/logging.h"
12 #include "base/no_destructor.h"
13 #include "base/notreached.h"
14 #include "base/synchronization/lock.h"
15 #include "base/thread_annotations.h"
16 #include "sql/vfs_wrapper.h"
17
18 namespace sql {
19
20 namespace {
21
22 struct FileLock {
23   int lock_level;
24   // Used to track the pointers to different VfsFile instances that hold shared
25   // locks on the same underlying file. The pointer is only used as a unique id
26   // for the VfsFile instance. The contents are never accessed.
27   base::flat_set<VfsFile*> readers = {};
28   // Used to track a VfsFile instance that holds a reserved/pending/exclusive
29   // lock for writing. The pointer is only used as a unique id for the VfsFile
30   // instance. The contents are never accessed.
31   VfsFile* writer = nullptr;
32 };
33
34 // Singleton that stores and mutates state as described in
35 // https://www.sqlite.org/lockingv3.html
36 class FuchsiaFileLockManager {
37  public:
38   FuchsiaFileLockManager() = default;
39
40   // Returns lock manager for the current process.
41   static FuchsiaFileLockManager* Instance() {
42     static base::NoDestructor<FuchsiaFileLockManager> lock_manager;
43     return lock_manager.get();
44   }
45
46   int Lock(VfsFile* vfs_file, int requested_lock) {
47     DCHECK_GT(requested_lock, SQLITE_LOCK_NONE)
48         << "SQLITE_LOCK_NONE can only be set via Unlock";
49     base::AutoLock lock(lock_);
50     const auto file_lock_state = GetFileLockStateLocked(vfs_file);
51
52     // Allow any lock level since the lock isn't held.
53     if (file_lock_state.readers.empty() && file_lock_state.writer == nullptr) {
54       if (requested_lock == SQLITE_LOCK_SHARED) {
55         locked_files_[vfs_file->file_name] = {.lock_level = requested_lock,
56                                               .readers = {vfs_file}};
57       } else {
58         locked_files_[vfs_file->file_name] = {.lock_level = requested_lock,
59                                               .writer = vfs_file};
60       }
61
62       return SQLITE_OK;
63     }
64
65     if (requested_lock == SQLITE_LOCK_SHARED) {
66       if (file_lock_state.lock_level >= SQLITE_LOCK_PENDING) {
67         DVLOG(1) << "lock for file " << vfs_file->file_name
68                  << " is held by a writer and cannot be shared.";
69         return SQLITE_BUSY;
70       }
71
72       locked_files_[vfs_file->file_name].readers.insert(vfs_file);
73       return SQLITE_OK;
74     }
75
76     if (file_lock_state.writer != nullptr &&
77         file_lock_state.writer != vfs_file) {
78       DVLOG(1) << "lock for file " << vfs_file->file_name
79                << " is already held by another writer.";
80       return SQLITE_BUSY;
81     }
82
83     if (requested_lock == SQLITE_LOCK_EXCLUSIVE &&
84         (file_lock_state.readers.size() > 1 ||
85          (file_lock_state.readers.size() == 1 &&
86           !file_lock_state.readers.contains(vfs_file)))) {
87       DVLOG(1) << "lock for file " << vfs_file->file_name
88                << " is held by readers and can't yet be upgraded to exclusive.";
89       return SQLITE_BUSY;
90     }
91
92     DCHECK(file_lock_state.writer == nullptr ||
93            file_lock_state.writer == vfs_file);
94     locked_files_[vfs_file->file_name].lock_level = requested_lock;
95     locked_files_[vfs_file->file_name].writer = vfs_file;
96     locked_files_[vfs_file->file_name].readers.erase(vfs_file);
97     DCHECK(locked_files_[vfs_file->file_name].lock_level <
98                SQLITE_LOCK_EXCLUSIVE ||
99            locked_files_[vfs_file->file_name].readers.empty());
100     return SQLITE_OK;
101   }
102
103   int Unlock(VfsFile* vfs_file, int requested_lock) {
104     base::AutoLock lock(lock_);
105     const auto file_lock_state = GetFileLockStateLocked(vfs_file);
106
107     DCHECK_LE(requested_lock, file_lock_state.lock_level)
108         << "Attempted to unlock to a higher lock level, unlock can only "
109            "decrement.";
110
111     // Shortcut if the caller doesn't currently hold a lock.
112     if (!file_lock_state.readers.contains(vfs_file) &&
113         file_lock_state.writer != vfs_file) {
114       DVLOG(1) << "caller can't unlock because it doesn't currently "
115                << "hold a lock for file " << vfs_file->file_name;
116       return SQLITE_OK;
117     }
118
119     if (requested_lock == SQLITE_LOCK_NONE) {
120       locked_files_[vfs_file->file_name].readers.erase(vfs_file);
121     } else if (requested_lock == SQLITE_LOCK_SHARED) {
122       locked_files_[vfs_file->file_name].readers.insert(vfs_file);
123     }
124
125     if (requested_lock < SQLITE_LOCK_RESERVED &&
126         file_lock_state.writer == vfs_file) {
127       locked_files_[vfs_file->file_name].writer = nullptr;
128     }
129
130     // Check that `vfs_file` is correctly tracked given the `requested_lock`.
131     DCHECK(requested_lock == SQLITE_LOCK_SHARED ||
132            !locked_files_[vfs_file->file_name].readers.contains(vfs_file));
133     DCHECK_EQ(requested_lock > SQLITE_LOCK_SHARED,
134               locked_files_[vfs_file->file_name].writer == vfs_file);
135
136     // Mark lock level as shared if there are only shared usages.
137     if (!file_lock_state.readers.empty() && file_lock_state.writer == nullptr) {
138       locked_files_[vfs_file->file_name].lock_level = SQLITE_LOCK_SHARED;
139       return SQLITE_OK;
140     }
141
142     // Remove lock if there are no usages left.
143     if (file_lock_state.readers.empty() && file_lock_state.writer == nullptr) {
144       DCHECK_EQ(requested_lock, SQLITE_LOCK_NONE);
145       locked_files_.erase(vfs_file->file_name);
146       return SQLITE_OK;
147     }
148
149     if (file_lock_state.writer != vfs_file) {
150       DCHECK_GE(file_lock_state.lock_level, SQLITE_LOCK_RESERVED);
151       DCHECK_LE(requested_lock, SQLITE_LOCK_SHARED);
152       return SQLITE_OK;
153     }
154
155     locked_files_[vfs_file->file_name].lock_level = requested_lock;
156     return SQLITE_OK;
157   }
158
159   int CheckReservedLock(VfsFile* vfs_file, int* result) {
160     base::AutoLock lock(lock_);
161     const auto file_lock_state = GetFileLockStateLocked(vfs_file);
162
163     switch (file_lock_state.lock_level) {
164       case SQLITE_LOCK_NONE:
165       case SQLITE_LOCK_SHARED:
166         *result = 0;
167         return SQLITE_OK;
168       case SQLITE_LOCK_RESERVED:
169       case SQLITE_LOCK_PENDING:
170       case SQLITE_LOCK_EXCLUSIVE:
171         *result = 1;
172         return SQLITE_OK;
173       default:
174         return SQLITE_IOERR_CHECKRESERVEDLOCK;
175     }
176   }
177
178  private:
179   ~FuchsiaFileLockManager() = delete;
180
181   const FileLock& GetFileLockStateLocked(VfsFile* vfs_file)
182       EXCLUSIVE_LOCKS_REQUIRED(lock_) {
183     static const FileLock kUnlockedFileLock = {.lock_level = SQLITE_LOCK_NONE};
184     const auto file_lock_state_iter = locked_files_.find(vfs_file->file_name);
185     if (file_lock_state_iter == locked_files_.end()) {
186       return kUnlockedFileLock;
187     }
188
189     return file_lock_state_iter->second;
190   }
191
192   base::Lock lock_;
193
194   // Set of all currently locked files.
195   base::flat_map<std::string, FileLock> locked_files_ GUARDED_BY(lock_);
196 };
197
198 }  // namespace
199
200 int Lock(sqlite3_file* sqlite_file, int file_lock) {
201   DCHECK(file_lock == SQLITE_LOCK_SHARED || file_lock == SQLITE_LOCK_RESERVED ||
202          file_lock == SQLITE_LOCK_PENDING ||
203          file_lock == SQLITE_LOCK_EXCLUSIVE);
204
205   auto* vfs_file = reinterpret_cast<VfsFile*>(sqlite_file);
206   return FuchsiaFileLockManager::Instance()->Lock(vfs_file, file_lock);
207 }
208
209 int Unlock(sqlite3_file* sqlite_file, int file_lock) {
210   auto* vfs_file = reinterpret_cast<VfsFile*>(sqlite_file);
211   return FuchsiaFileLockManager::Instance()->Unlock(vfs_file, file_lock);
212 }
213
214 int CheckReservedLock(sqlite3_file* sqlite_file, int* result) {
215   auto* vfs_file = reinterpret_cast<VfsFile*>(sqlite_file);
216   return FuchsiaFileLockManager::Instance()->CheckReservedLock(vfs_file,
217                                                                result);
218 }
219
220 }  // namespace sql