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