Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qsql_sqlite_vfs.cpp
Go to the documentation of this file.
1// Copyright (C) 2023 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:critical reason:data-parser
4
6
7#include <QFile>
8
9#include <limits.h> // defines PATH_MAX on unix
10#include <sqlite3.h>
11#include <stdio.h> // defines FILENAME_MAX everywhere
12
13#ifndef PATH_MAX
14# define PATH_MAX FILENAME_MAX
15#endif
16#if SQLITE_VERSION_NUMBER < 3040000
17typedef const char *sqlite3_filename;
18#endif
19
20QT_BEGIN_NAMESPACE
21
22namespace {
23struct Vfs : sqlite3_vfs {
24 sqlite3_vfs *pVfs;
25 sqlite3_io_methods ioMethods;
26};
27
28struct File : sqlite3_file {
29 class QtFile : public QFile {
30 public:
31 QtFile(const QString &name, bool removeOnClose)
32 : QFile(name)
33 , removeOnClose(removeOnClose)
34 {}
35
37 {
38 if (removeOnClose)
39 remove();
40 }
41 private:
42 bool removeOnClose;
43 };
45};
46
47
48int xClose(sqlite3_file *sfile)
49{
50 auto file = static_cast<File *>(sfile);
51 delete file->pFile;
52 file->pFile = nullptr;
53 return SQLITE_OK;
54}
55
56int xRead(sqlite3_file *sfile, void *ptr, int iAmt, sqlite3_int64 iOfst)
57{
58 auto file = static_cast<File *>(sfile);
59 if (!file->pFile->seek(iOfst))
60 return SQLITE_IOERR_READ;
61
62 auto sz = file->pFile->read(static_cast<char *>(ptr), iAmt);
63 if (sz < iAmt) {
64 memset(static_cast<char *>(ptr) + sz, 0, size_t(iAmt - sz));
65 return SQLITE_IOERR_SHORT_READ;
66 }
67 return SQLITE_OK;
68}
69
70int xWrite(sqlite3_file *sfile, const void *data, int iAmt, sqlite3_int64 iOfst)
71{
72 auto file = static_cast<File *>(sfile);
73 if (!file->pFile->seek(iOfst))
74 return SQLITE_IOERR_SEEK;
75 return file->pFile->write(reinterpret_cast<const char*>(data), iAmt) == iAmt ? SQLITE_OK : SQLITE_IOERR_WRITE;
76}
77
78int xTruncate(sqlite3_file *sfile, sqlite3_int64 size)
79{
80 auto file = static_cast<File *>(sfile);
81 return file->pFile->resize(size) ? SQLITE_OK : SQLITE_IOERR_TRUNCATE;
82}
83
84int xSync(sqlite3_file *sfile, int /*flags*/)
85{
86 static_cast<File *>(sfile)->pFile->flush();
87 return SQLITE_OK;
88}
89
90int xFileSize(sqlite3_file *sfile, sqlite3_int64 *pSize)
91{
92 auto file = static_cast<File *>(sfile);
93 *pSize = file->pFile->size();
94 return SQLITE_OK;
95}
96
97// No lock/unlock for QFile, QLockFile doesn't work for me
98
99int xLock(sqlite3_file *, int) { return SQLITE_OK; }
100
101int xUnlock(sqlite3_file *, int) { return SQLITE_OK; }
102
103int xCheckReservedLock(sqlite3_file *, int *pResOut)
104{
105 *pResOut = 0;
106 return SQLITE_OK;
107}
108
109int xFileControl(sqlite3_file *, int, void *) { return SQLITE_NOTFOUND; }
110
111int xSectorSize(sqlite3_file *)
112{
113 return 4096;
114}
115
116int xDeviceCharacteristics(sqlite3_file *)
117{
118 return 0; // no SQLITE_IOCAP_XXX
119}
120
121int xOpen(sqlite3_vfs *svfs, sqlite3_filename zName, sqlite3_file *sfile,
122 int flags, int *pOutFlags)
123{
124 auto vfs = static_cast<Vfs *>(svfs);
125 auto file = static_cast<File *>(sfile);
126 memset(file, 0, sizeof(File));
127 QIODeviceBase::OpenMode mode = QIODeviceBase::NotOpen;
128 if (!zName || (flags & SQLITE_OPEN_MEMORY))
129 return SQLITE_PERM;
130 if ((flags & SQLITE_OPEN_READONLY) &&
131 !(flags & SQLITE_OPEN_READWRITE) &&
132 !(flags & SQLITE_OPEN_CREATE) &&
133 !(flags & SQLITE_OPEN_DELETEONCLOSE)) {
134 mode |= QIODeviceBase::OpenModeFlag::ReadOnly;
135 } else {
136 /*
137 ** ^The [SQLITE_OPEN_EXCLUSIVE] flag is always used in conjunction
138 ** with the [SQLITE_OPEN_CREATE] flag, which are both directly
139 ** analogous to the O_EXCL and O_CREAT flags of the POSIX open()
140 ** API. The SQLITE_OPEN_EXCLUSIVE flag, when paired with the
141 ** SQLITE_OPEN_CREATE, is used to indicate that file should always
142 ** be created, and that it is an error if it already exists.
143 ** It is <i>not</i> used to indicate the file should be opened
144 ** for exclusive access.
145 */
146 if ((flags & SQLITE_OPEN_CREATE) && (flags & SQLITE_OPEN_EXCLUSIVE))
147 mode |= QIODeviceBase::OpenModeFlag::NewOnly;
148
149 if (flags & SQLITE_OPEN_READWRITE)
150 mode |= QIODeviceBase::OpenModeFlag::ReadWrite;
151 }
152
153 file->pMethods = &vfs->ioMethods;
154 file->pFile = new File::QtFile(QString::fromUtf8(zName), bool(flags & SQLITE_OPEN_DELETEONCLOSE));
155 if (!file->pFile->open(mode))
156 return SQLITE_CANTOPEN;
157 if (pOutFlags)
158 *pOutFlags = flags;
159
160 return SQLITE_OK;
161}
162
163int xDelete(sqlite3_vfs *, const char *zName, int)
164{
165 return QFile::remove(QString::fromUtf8(zName)) ? SQLITE_OK : SQLITE_ERROR;
166}
167
168int xAccess(sqlite3_vfs */*svfs*/, const char *zName, int flags, int *pResOut)
169{
170 *pResOut = 0;
171 switch (flags) {
172 case SQLITE_ACCESS_EXISTS:
173 case SQLITE_ACCESS_READ:
174 *pResOut = QFile::exists(QString::fromUtf8(zName));
175 break;
176 default:
177 break;
178 }
179 return SQLITE_OK;
180}
181
182int xFullPathname(sqlite3_vfs *, const char *zName, int nOut, char *zOut)
183{
184 if (!zName)
185 return SQLITE_ERROR;
186
187 int i = 0;
188 for (;zName[i] && i < nOut; ++i)
189 zOut[i] = zName[i];
190
191 if (i >= nOut)
192 return SQLITE_ERROR;
193
194 zOut[i] = '\0';
195 return SQLITE_OK;
196}
197
198int xRandomness(sqlite3_vfs *svfs, int nByte, char *zOut)
199{
200 auto vfs = static_cast<Vfs *>(svfs)->pVfs;
201 return vfs->xRandomness(vfs, nByte, zOut);
202}
203
204int xSleep(sqlite3_vfs *svfs, int microseconds)
205{
206 auto vfs = static_cast<Vfs *>(svfs)->pVfs;
207 return vfs->xSleep(vfs, microseconds);
208}
209
210int xCurrentTime(sqlite3_vfs *svfs, double *zOut)
211{
212 auto vfs = static_cast<Vfs *>(svfs)->pVfs;
213 return vfs->xCurrentTime(vfs, zOut);
214}
215
216int xGetLastError(sqlite3_vfs *, int, char *)
217{
218 return 0;
219}
220
221int xCurrentTimeInt64(sqlite3_vfs *svfs, sqlite3_int64 *zOut)
222{
223 auto vfs = static_cast<Vfs *>(svfs)->pVfs;
224 return vfs->xCurrentTimeInt64(vfs, zOut);
225}
226} // namespace {
227
229{
230 static Vfs vfs;
231 memset(&vfs, 0, sizeof(Vfs));
232 vfs.iVersion = 1;
233 vfs.szOsFile = sizeof(File);
234 vfs.mxPathname = PATH_MAX;
235 vfs.zName = "QtVFS";
236 vfs.xOpen = &xOpen;
237 vfs.xDelete = &xDelete;
238 vfs.xAccess = &xAccess;
239 vfs.xFullPathname = &xFullPathname;
240 vfs.xRandomness = &xRandomness;
241 vfs.xSleep = &xSleep;
242 vfs.xCurrentTime = &xCurrentTime;
243 vfs.xGetLastError = &xGetLastError;
244 vfs.xCurrentTimeInt64 = &xCurrentTimeInt64;
245 vfs.pVfs = sqlite3_vfs_find(nullptr);
246 vfs.ioMethods.iVersion = 1;
247 vfs.ioMethods.xClose = &xClose;
248 vfs.ioMethods.xRead = &xRead;
249 vfs.ioMethods.xWrite = &xWrite;
250 vfs.ioMethods.xTruncate = &xTruncate;
251 vfs.ioMethods.xSync = &xSync;
252 vfs.ioMethods.xFileSize = &xFileSize;
253 vfs.ioMethods.xLock = &xLock;
254 vfs.ioMethods.xUnlock = &xUnlock;
255 vfs.ioMethods.xCheckReservedLock = &xCheckReservedLock;
256 vfs.ioMethods.xFileControl = &xFileControl;
257 vfs.ioMethods.xSectorSize = &xSectorSize;
258 vfs.ioMethods.xDeviceCharacteristics = &xDeviceCharacteristics;
259
260 sqlite3_vfs_register(&vfs, 0);
261}
262
263QT_END_NAMESPACE
QtFile(const QString &name, bool removeOnClose)
int xRandomness(sqlite3_vfs *svfs, int nByte, char *zOut)
int xWrite(sqlite3_file *sfile, const void *data, int iAmt, sqlite3_int64 iOfst)
int xLock(sqlite3_file *, int)
int xSleep(sqlite3_vfs *svfs, int microseconds)
int xOpen(sqlite3_vfs *svfs, sqlite3_filename zName, sqlite3_file *sfile, int flags, int *pOutFlags)
int xGetLastError(sqlite3_vfs *, int, char *)
int xFileSize(sqlite3_file *sfile, sqlite3_int64 *pSize)
int xRead(sqlite3_file *sfile, void *ptr, int iAmt, sqlite3_int64 iOfst)
int xFullPathname(sqlite3_vfs *, const char *zName, int nOut, char *zOut)
int xAccess(sqlite3_vfs *, const char *zName, int flags, int *pResOut)
int xCurrentTime(sqlite3_vfs *svfs, double *zOut)
int xFileControl(sqlite3_file *, int, void *)
int xDeviceCharacteristics(sqlite3_file *)
int xCheckReservedLock(sqlite3_file *, int *pResOut)
int xSectorSize(sqlite3_file *)
int xUnlock(sqlite3_file *, int)
int xSync(sqlite3_file *sfile, int)
int xDelete(sqlite3_vfs *, const char *zName, int)
int xCurrentTimeInt64(sqlite3_vfs *svfs, sqlite3_int64 *zOut)
int xTruncate(sqlite3_file *sfile, sqlite3_int64 size)
int xClose(sqlite3_file *sfile)
#define PATH_MAX
void register_qt_vfs()
sqlite3_io_methods ioMethods