1 /*
2 sqlite3_bctbx_vfs.c
3 Copyright (C) 2016 Belledonne Communications SARL
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19
20 #ifdef SQLITE_STORAGE_ENABLED
21 #include "private.h"
22
23 #include "sqlite3_bctbx_vfs.h"
24 #include <sqlite3.h>
25
26 #ifndef _WIN32_WCE
27 #include <errno.h>
28 #endif /*_WIN32_WCE*/
29
30
31 #ifndef _WIN32
32 #if !defined(__QNXNTO__) && !defined(__ANDROID__)
33 # include <langinfo.h>
34 # include <locale.h>
35 # include <iconv.h>
36 # include <string.h>
37 #endif
38
39 #endif
40
41
42 /**
43 * Closes the file whose file descriptor is stored in the file handle p.
44 * @param p sqlite3_file file handle pointer.
45 * @return SQLITE_OK if successful, SQLITE_IOERR_CLOSE otherwise.
46 */
sqlite3bctbx_Close(sqlite3_file * p)47 static int sqlite3bctbx_Close(sqlite3_file *p){
48
49 int ret;
50 sqlite3_bctbx_file_t *pFile = (sqlite3_bctbx_file_t*) p;
51
52 ret = bctbx_file_close(pFile->pbctbx_file);
53 if (!ret){
54 return SQLITE_OK;
55 }
56 else{
57 free(pFile);
58 return SQLITE_IOERR_CLOSE ;
59 }
60 }
61
62
63 /**
64 * Read count bytes from the open file given by p, starting at offset and puts them in
65 * the buffer pointed by buf.
66 * Calls bctbx_file_read.
67 *
68 * @param p sqlite3_file file handle pointer.
69 * @param buf buffer to write the read bytes to.
70 * @param count number of bytes to read
71 * @param offset file offset where to start reading
72 * @return SQLITE_OK if read bytes equals count,
73 * SQLITE_IOERR_SHORT_READ if the number of bytes read is inferior to count
74 * SQLITE_IOERR_READ if an error occurred.
75 */
sqlite3bctbx_Read(sqlite3_file * p,void * buf,int count,sqlite_int64 offset)76 static int sqlite3bctbx_Read(sqlite3_file *p, void *buf, int count, sqlite_int64 offset){
77 int ret;
78 sqlite3_bctbx_file_t *pFile = (sqlite3_bctbx_file_t*) p;
79 if (pFile){
80 ret = bctbx_file_read(pFile->pbctbx_file, buf, count, (off_t)offset);
81 if( ret==count ){
82 return SQLITE_OK;
83 }
84 else if( ret >= 0 ){
85 /*fill in unread portion of buffer, as requested by sqlite3 documentation*/
86 memset(((uint8_t*)buf) + ret, 0, count-ret);
87 return SQLITE_IOERR_SHORT_READ;
88 }else {
89
90 return SQLITE_IOERR_READ;
91 }
92 }
93 return SQLITE_IOERR_READ;
94 }
95
96 /**
97 * Writes directly to the open file given through the p argument.
98 * Calls bctbx_file_write .
99 * @param p sqlite3_file file handle pointer.
100 * @param buf Buffer containing data to write
101 * @param count Size of data to write in bytes
102 * @param offset File offset where to write to
103 * @return SQLITE_OK on success, SQLITE_IOERR_WRITE if an error occurred.
104 */
sqlite3bctbx_Write(sqlite3_file * p,const void * buf,int count,sqlite_int64 offset)105 static int sqlite3bctbx_Write(sqlite3_file *p, const void *buf, int count, sqlite_int64 offset){
106 sqlite3_bctbx_file_t *pFile = (sqlite3_bctbx_file_t*) p;
107 int ret;
108 if (pFile ){
109 ret = bctbx_file_write(pFile->pbctbx_file, buf, count, (off_t)offset);
110 if(ret > 0 ) return SQLITE_OK;
111 else {
112 return SQLITE_IOERR_WRITE;
113 }
114 }
115 return SQLITE_IOERR_WRITE;
116 }
117
118 /**
119 * TRuncates or extends a file depending on the size provided.
120 * @param p sqlite3_file file handle pointer.
121 * @param size New file size.
122 * @return SQLITE_OK on success, SQLITE_IOERR_TRUNCATE if an error occurred during truncate,
123 * SQLITE_ERROR if ther was a problem on the file descriptor.
124 */
sqlite3bctbx_Truncate(sqlite3_file * p,sqlite_int64 size)125 static int sqlite3bctbx_Truncate(sqlite3_file *p, sqlite_int64 size){
126 int rc;
127 sqlite3_bctbx_file_t *pFile = (sqlite3_bctbx_file_t*) p;
128 if (pFile->pbctbx_file){
129 rc = bctbx_file_truncate(pFile->pbctbx_file, size);
130 if( rc < 0 ) {
131 return SQLITE_IOERR_TRUNCATE;
132 }
133 if (rc == 0){
134 return SQLITE_OK;
135 }
136 }
137 return SQLITE_ERROR;
138
139 }
140
141 /**
142 * Saves the file size associated with the file handle p into the argument pSize.
143 * @param p sqlite3_file file handle pointer.
144 * @return SQLITE_OK if read bytes equals count,
145 * SQLITE_IOERR_FSTAT if the file size returned is negative
146 * SQLITE_ERROR if an error occurred.
147 */
sqlite3bctbx_FileSize(sqlite3_file * p,sqlite_int64 * pSize)148 static int sqlite3bctbx_FileSize(sqlite3_file *p, sqlite_int64 *pSize){
149
150 int64_t rc; /* Return code from fstat() call */
151 sqlite3_bctbx_file_t *pFile = (sqlite3_bctbx_file_t*) p;
152 if (pFile->pbctbx_file){
153 rc = bctbx_file_size(pFile->pbctbx_file);
154 if( rc < 0 ) {
155 return SQLITE_IOERR_FSTAT;
156 }
157 if (pSize){
158 *pSize = rc;
159 return SQLITE_OK;
160 }
161 }
162 return SQLITE_ERROR;
163
164
165 }
166
167
168 /************************ PLACE HOLDER FUNCTIONS ***********************/
169 /** These functions were implemented to please the SQLite VFS
170 implementation. Some of them are just stubs, some do a very limited job. */
171
172
173 /**
174 * Returns the device characteristics for the file. Stub function
175 * to fill the SQLite VFS function pointer structure .
176 * @param p sqlite3_file file handle pointer.
177 * @return value 4096.
178 */
sqlite3bctbx_DeviceCharacteristics(sqlite3_file * p)179 static int sqlite3bctbx_DeviceCharacteristics(sqlite3_file *p){
180 int rc = 0x00001000;
181 return rc;
182 }
183
184 /**
185 * Stub function for information and control over the open file.
186 * @param p sqlite3_file file handle pointer.
187 * @param op operation
188 * @param pArg unused
189 * @return SQLITE_OK on success, SALITE_NOTFOUND otherwise.
190 */
sqlite3bctbx_FileControl(sqlite3_file * p,int op,void * pArg)191 static int sqlite3bctbx_FileControl(sqlite3_file *p, int op, void *pArg){
192 #ifdef SQLITE_FCNTL_MMAP_SIZE
193 if (op == SQLITE_FCNTL_MMAP_SIZE) return SQLITE_OK;
194 #endif
195 return SQLITE_NOTFOUND;
196
197 }
198
199 /**
200 * The lock file mechanism is not used with this VFS : checking
201 * the reserved lock is always OK.
202 * @param pUnused sqlite3_file file handle pointer.
203 * @param pResOut set to 0 since there is no lock mechanism.
204 * @return SQLITE_OK
205 */
sqlite3bctbx_nolockCheckReservedLock(sqlite3_file * pUnused,int * pResOut)206 static int sqlite3bctbx_nolockCheckReservedLock(sqlite3_file *pUnused, int *pResOut){
207 *pResOut = 0;
208 return SQLITE_OK;
209 }
210
211 /**
212 * The lock file mechanism is not used with this VFS : locking the file
213 * is always OK.
214 * @param pUnused sqlite3_file file handle pointer.
215 * @param unused unused
216 * @return SQLITE_OK
217 */
sqlite3bctbx_nolockLock(sqlite3_file * pUnused,int unused)218 static int sqlite3bctbx_nolockLock(sqlite3_file *pUnused, int unused){
219 return SQLITE_OK;
220 }
221
222 /**
223 * The lock file mechanism is not used with this VFS : unlocking the file
224 * is always OK.
225 * @param pUnused sqlite3_file file handle pointer.
226 * @param unused unused
227 * @return SQLITE_OK
228 */
sqlite3bctbx_nolockUnlock(sqlite3_file * pUnused,int unused)229 static int sqlite3bctbx_nolockUnlock(sqlite3_file *pUnused, int unused){
230 return SQLITE_OK;
231 }
232
233
234 /**
235 * Simply sync the file contents given through the file handle p
236 * to the persistent media.
237 * @param p sqlite3_file file handle pointer.
238 * @param flags unused
239 * @return SQLITE_OK on success, SLITE_IOERR_FSYNC if an error occurred.
240 */
sqlite3bctbx_Sync(sqlite3_file * p,int flags)241 static int sqlite3bctbx_Sync(sqlite3_file *p, int flags){
242 sqlite3_bctbx_file_t *pFile = (sqlite3_bctbx_file_t*)p;
243 #if _WIN32
244 int ret;
245 ret = FlushFileBuffers((HANDLE)_get_osfhandle(pFile->pbctbx_file->fd));
246 return (ret!=0 ? SQLITE_OK : SQLITE_IOERR_FSYNC);
247 #else
248 int rc = fsync(pFile->pbctbx_file->fd);
249 return (rc==0 ? SQLITE_OK : SQLITE_IOERR_FSYNC);
250 #endif
251 }
252
253 /************************ END OF PLACE HOLDER FUNCTIONS ***********************/
254
255
256
ConvertFromUtf8Filename(const char * fName)257 static char* ConvertFromUtf8Filename(const char* fName){
258 #if _WIN32
259 char* convertedFilename;
260 int nChar, nb_byte;
261 LPWSTR wideFilename;
262
263 nChar = MultiByteToWideChar(CP_UTF8, 0, fName, -1, NULL, 0);
264 if (nChar == 0) return NULL;
265 wideFilename = bctbx_malloc(nChar*sizeof(wideFilename[0]));
266 if (wideFilename == NULL) return NULL;
267 nChar = MultiByteToWideChar(CP_UTF8, 0, fName, -1, wideFilename, nChar);
268 if (nChar == 0) {
269 bctbx_free(wideFilename);
270 wideFilename = 0;
271 }
272
273 nb_byte = WideCharToMultiByte(CP_ACP, 0, wideFilename, -1, 0, 0, 0, 0);
274 if (nb_byte == 0) return NULL;
275 convertedFilename = bctbx_malloc(nb_byte);
276 if (convertedFilename == NULL) return NULL;
277 nb_byte = WideCharToMultiByte(CP_ACP, 0, wideFilename, -1, convertedFilename, nb_byte, 0, 0);
278 if (nb_byte == 0) {
279 bctbx_free(convertedFilename);
280 convertedFilename = 0;
281 }
282 bctbx_free(wideFilename);
283 return convertedFilename;
284 #elif defined(__QNXNTO__) || defined(__ANDROID__)
285 return bctbx_strdup(fName);
286 #else
287 #define MAX_PATH_SIZE 1024
288 char db_file_utf8[MAX_PATH_SIZE] = {'\0'};
289 char db_file_locale[MAX_PATH_SIZE] = "";
290 char *outbuf=db_file_locale, *inbuf=db_file_utf8;
291 size_t inbyteleft = MAX_PATH_SIZE, outbyteleft = MAX_PATH_SIZE;
292 iconv_t cb;
293
294 if (strcasecmp("UTF-8", nl_langinfo(CODESET)) == 0) {
295 strncpy(db_file_locale, fName, MAX_PATH_SIZE - 1);
296 } else {
297 strncpy(db_file_utf8, fName, MAX_PATH_SIZE-1);
298 cb = iconv_open(nl_langinfo(CODESET), "UTF-8");
299 if (cb != (iconv_t)-1) {
300 int ret;
301 ret = iconv(cb, &inbuf, &inbyteleft, &outbuf, &outbyteleft);
302 if(ret == -1) db_file_locale[0] = '\0';
303 iconv_close(cb);
304 }
305 }
306 return bctbx_strdup(db_file_locale);
307 #endif
308 }
309
310 /**
311 * Opens the file fName and populates the structure pointed by p
312 * with the necessary io_methods
313 * Methods not implemented for version 1 : xTruncate, xSectorSize.
314 * Initializes some fields in the p structure, some of which where already
315 * initialized by SQLite.
316 * @param pVfs sqlite3_vfs VFS pointer.
317 * @param fName filename
318 * @param p file handle pointer
319 * @param flags db file access flags
320 * @param pOutFlags flags used by SQLite
321 * @return SQLITE_CANTOPEN on error, SQLITE_OK on success.
322 */
sqlite3bctbx_Open(sqlite3_vfs * pVfs,const char * fName,sqlite3_file * p,int flags,int * pOutFlags)323 static int sqlite3bctbx_Open(sqlite3_vfs *pVfs, const char *fName, sqlite3_file *p, int flags, int *pOutFlags ){
324 static const sqlite3_io_methods sqlite3_bctbx_io = {
325 1, /* iVersion Structure version number */
326 sqlite3bctbx_Close, /* xClose */
327 sqlite3bctbx_Read, /* xRead */
328 sqlite3bctbx_Write, /* xWrite */
329 sqlite3bctbx_Truncate, /* xTruncate */
330 sqlite3bctbx_Sync,
331 sqlite3bctbx_FileSize,
332 sqlite3bctbx_nolockLock,
333 sqlite3bctbx_nolockUnlock,
334 sqlite3bctbx_nolockCheckReservedLock,
335 sqlite3bctbx_FileControl,
336 NULL, /* xSectorSize */
337 sqlite3bctbx_DeviceCharacteristics
338 /*other function points follows, all NULL but not present in all sqlite3 versions.*/
339 };
340
341 sqlite3_bctbx_file_t * pFile = (sqlite3_bctbx_file_t*)p; /*File handle sqlite3_bctbx_file_t*/
342 int openFlags = 0;
343 char* wFname;
344
345 /*returns error if filename is empty or file handle not initialized*/
346 if (pFile == NULL || fName == NULL){
347 return SQLITE_IOERR;
348 }
349
350 /* Set flags to open the file with */
351 if( flags&SQLITE_OPEN_EXCLUSIVE ) openFlags |= O_EXCL;
352 if( flags&SQLITE_OPEN_CREATE ) openFlags |= O_CREAT;
353 if( flags&SQLITE_OPEN_READONLY ) openFlags |= O_RDONLY;
354 if( flags&SQLITE_OPEN_READWRITE ) openFlags |= O_RDWR;
355
356 #if defined(_WIN32)
357 openFlags |= O_BINARY;
358 #endif
359 wFname = ConvertFromUtf8Filename(fName);
360 if (wFname != NULL) {
361 pFile->pbctbx_file = bctbx_file_open2(bctbx_vfs_get_default(), wFname, openFlags);
362 bctbx_free(wFname);
363 } else {
364 pFile->pbctbx_file = NULL;
365 }
366
367 if( pFile->pbctbx_file == NULL){
368 return SQLITE_CANTOPEN;
369 }
370
371 if( pOutFlags ){
372 *pOutFlags = flags;
373 }
374 pFile->base.pMethods = &sqlite3_bctbx_io;
375
376 return SQLITE_OK;
377 }
378
379
380
sqlite3_bctbx_vfs_create(void)381 sqlite3_vfs *sqlite3_bctbx_vfs_create(void){
382 static sqlite3_vfs bctbx_vfs = {
383 1, /* iVersion */
384 sizeof(sqlite3_bctbx_file_t), /* szOsFile */
385 MAXPATHNAME, /* mxPathname */
386 NULL, /* pNext */
387 LINPHONE_SQLITE3_VFS, /* zName */
388 NULL, /* pAppData */
389 sqlite3bctbx_Open, /* xOpen */
390 NULL, /* xDelete */
391 NULL, /* xAccess */
392 NULL /* xFullPathname */
393 };
394 return &bctbx_vfs;
395 }
396
397 /*static int sqlite3bctbx_winFullPathname(
398 sqlite3_vfs *pVfs, // Pointer to vfs object
399 const char *zRelative, // Possibly relative input path
400 int nFull, // Size of output buffer in bytes
401 char *zFull){
402 //LPWSTR zTemp;
403 //DWORD nByte;
404 // If this path name begins with "/X:", where "X" is any alphabetic
405 // character, discard the initial "/" from the pathname.
406 //
407 //if (zRelative[0] == '/' && sqlite3Isalpha(zRelative[1]) && zRelative[2] == ':'){
408 // zRelative++;
409 //}
410
411 nByte = GetFullPathNameW((LPCWSTR)zRelative, 0, 0, 0);
412 if (nByte == 0){
413 return SQLITE_CANTOPEN_FULLPATH;
414 }
415 nByte += 3;
416 zTemp = bctbx_malloc(nByte*sizeof(zTemp[0]));
417 memset(zTemp, 0, nByte*sizeof(zTemp[0]));
418 if (zTemp == 0){
419 return SQLITE_IOERR_NOMEM;
420 }
421 nByte = GetFullPathNameW((LPCWSTR)zRelative, nByte, zTemp, 0);
422 if (nByte == 0){
423 bctbx_free(zTemp);
424 return SQLITE_CANTOPEN_FULLPATH;
425 }
426 if (zTemp){
427 sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zTemp);
428 bctbx_free(zTemp);
429 return SQLITE_OK;
430 }
431 else{
432 return SQLITE_IOERR_NOMEM;
433 }
434 sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zRelative);
435 return SQLITE_OK;
436 }*/
437
438
439
sqlite3_bctbx_vfs_register(int makeDefault)440 void sqlite3_bctbx_vfs_register( int makeDefault){
441 sqlite3_vfs* pVfsToUse = sqlite3_bctbx_vfs_create();
442 #if _WIN32
443 sqlite3_vfs* pDefault = sqlite3_vfs_find("win32");
444 #else
445 sqlite3_vfs* pDefault = sqlite3_vfs_find("unix-none");
446 #endif
447 pVfsToUse->xCurrentTime = pDefault->xCurrentTime;
448
449 pVfsToUse->xAccess = pDefault->xAccess;
450 pVfsToUse->xFullPathname = pDefault->xFullPathname;
451
452 pVfsToUse->xDelete = pDefault->xDelete;
453 pVfsToUse->xSleep = pDefault->xSleep;
454 pVfsToUse->xRandomness = pDefault->xRandomness;
455 pVfsToUse->xGetLastError = pDefault->xGetLastError; /* Not implemented by sqlite3 :place holder */
456 /*Functions below should not be a problem sincve we are declaring ourselves
457 in version 1 */
458
459 /* used in version 2
460 xCurrentTimeInt64;*/
461 /* used in version 3
462 xGetSystemCall
463 xSetSystemCall
464 xNextSystemCall*/
465
466 sqlite3_vfs_register(pVfsToUse, makeDefault);
467
468 }
469
470
sqlite3_bctbx_vfs_unregister(void)471 void sqlite3_bctbx_vfs_unregister(void)
472 {
473 sqlite3_vfs* pVfs = sqlite3_vfs_find(LINPHONE_SQLITE3_VFS);
474 sqlite3_vfs_unregister(pVfs);
475 }
476
477 #endif /*SQLITE_STORAGE_ENABLED*/
478