sqlite3_bctbx_vfs.c 13.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*
sqlite3_bctbx_vfs.c
Copyright (C) 2016 Belledonne Communications SARL

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
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 24 25
#include "sqlite3_bctbx_vfs.h"
#include <sqlite3.h>

Sandrine Avakian's avatar
Sandrine Avakian committed
26 27 28 29 30
#ifndef _WIN32_WCE
#include <errno.h>
#endif /*_WIN32_WCE*/


31
#ifndef _WIN32
Simon Morlat's avatar
Simon Morlat committed
32
#if !defined(__QNXNTO__) && !defined(__ANDROID__)
33 34 35 36 37 38 39 40
#	include <langinfo.h>
#	include <locale.h>
#	include <iconv.h>
#	include <string.h>
#endif

#endif

41

42
/**
43 44 45
 * Closes the file whose file descriptor is stored in the file handle p.
 * @param  p 	sqlite3_file file handle pointer.
 * @return      SQLITE_OK if successful,  SQLITE_IOERR_CLOSE otherwise.
46 47 48 49
 */
static int sqlite3bctbx_Close(sqlite3_file *p){

	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 57 58 59 60 61 62 63
	}
	else{
		free(pFile);
		return SQLITE_IOERR_CLOSE ;
	}
}


/**
64
 * Read count bytes from the open file given by p, starting at offset and puts them in
65 66
 * the buffer pointed by buf.
 * Calls bctbx_file_read.
67
 *
68
 * @param  p  		sqlite3_file file handle pointer.
69 70 71
 * @param  buf    	buffer to write the read bytes to.
 * @param  count  	number of bytes to read
 * @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 76 77
 */
static int sqlite3bctbx_Read(sqlite3_file *p, void *buf, int count, sqlite_int64 offset){
	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 82 83 84
		if( ret==count ){
			return SQLITE_OK;
		}
		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 91 92 93 94 95 96
			return SQLITE_IOERR_READ;
		}
	}
	return SQLITE_IOERR_READ;
}

/**
97
 * Writes directly to the open file given through the p argument.
98 99
 * Calls bctbx_file_write .
 * @param  p       sqlite3_file file handle pointer.
100 101 102
 * @param  buf     Buffer containing data to write
 * @param  count   Size of data to write in bytes
 * @param  offset  File offset where to write to
103
 * @return         SQLITE_OK on success, SQLITE_IOERR_WRITE if an error occurred.
104 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 108
	int ret;
	if (pFile ){
109
		ret = bctbx_file_write(pFile->pbctbx_file, buf, count, (off_t)offset);
110 111 112 113 114 115 116
		if(ret > 0 ) return SQLITE_OK;
		else {
			return SQLITE_IOERR_WRITE;
		}
	}
	return SQLITE_IOERR_WRITE;
}
117

118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
/**
 * TRuncates or extends a file depending on the size provided.
 * @param  p    sqlite3_file file handle pointer.
 * @param  size New file size.
 * @return  SQLITE_OK on success, SQLITE_IOERR_TRUNCATE if an error occurred during truncate,	
 *          SQLITE_ERROR if ther was a problem on the file descriptor.    
 */
static int sqlite3bctbx_Truncate(sqlite3_file *p, sqlite_int64 size){
	int rc;                        
	sqlite3_bctbx_file_t *pFile = (sqlite3_bctbx_file_t*) p;
	if (pFile->pbctbx_file){
		rc = bctbx_file_truncate(pFile->pbctbx_file, size);
		if( rc < 0 ) {
			return SQLITE_IOERR_TRUNCATE;
		}
		if (rc == 0){
			return SQLITE_OK;
		}
	}
	return SQLITE_ERROR;

}
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 145 146
 * @return 		SQLITE_OK if read bytes equals count,
 *              SQLITE_IOERR_FSTAT if the file size returned is negative
 *              SQLITE_ERROR if an error occurred.
147 148 149
 */
static int sqlite3bctbx_FileSize(sqlite3_file *p, sqlite_int64 *pSize){

150
	int64_t rc;                         /* Return code from fstat() call */
151
	sqlite3_bctbx_file_t *pFile = (sqlite3_bctbx_file_t*) p;
152 153
	if (pFile->pbctbx_file){
		rc = bctbx_file_size(pFile->pbctbx_file);
154 155 156 157 158 159
		if( rc < 0 ) {
			return SQLITE_IOERR_FSTAT;
		}
		if (pSize){
			*pSize = rc;
			return SQLITE_OK;
160
		}
161 162 163 164 165 166
	}
	return SQLITE_ERROR;


}

167 168

/************************ PLACE HOLDER FUNCTIONS ***********************/
169
/** These functions were implemented to please the SQLite VFS
170 171 172
implementation. Some of them are just stubs, some do a very limited job. */


173
/**
174 175 176 177
 * Returns the device characteristics for the file. Stub function
 * to fill the SQLite VFS function pointer structure .
 * @param  p 	sqlite3_file file handle pointer.
 * @return		value 4096.
178 179 180 181 182 183 184
 */
static int sqlite3bctbx_DeviceCharacteristics(sqlite3_file *p){
	int rc = 0x00001000;
	return rc;
}

/**
185 186 187 188 189
 * Stub function for information and control over the open file.
 * @param  p    sqlite3_file file handle pointer.
 * @param  op   operation
 * @param  pArg unused
 * @return      SQLITE_OK on success, SALITE_NOTFOUND otherwise.
190 191
 */
static int sqlite3bctbx_FileControl(sqlite3_file *p, int op, void *pArg){
Simon Morlat's avatar
Simon Morlat committed
192
#ifdef SQLITE_FCNTL_MMAP_SIZE
193
	if (op == SQLITE_FCNTL_MMAP_SIZE) return SQLITE_OK;
Simon Morlat's avatar
Simon Morlat committed
194
#endif
195 196 197 198 199
	return SQLITE_NOTFOUND;

}

/**
200 201 202 203 204
 * The lock file mechanism is not used with this VFS : checking
 * the reserved lock is always OK.
 * @param  pUnused sqlite3_file file handle pointer.
 * @param  pResOut set to 0 since there is no lock mechanism.
 * @return         SQLITE_OK
205 206 207 208 209 210 211
 */
static int sqlite3bctbx_nolockCheckReservedLock(sqlite3_file *pUnused, int *pResOut){
	*pResOut = 0;
	return SQLITE_OK;
}

/**
212
 * The lock file mechanism is not used with this VFS : locking the file
213 214 215 216
 * is always OK.
 * @param  pUnused sqlite3_file file handle pointer.
 * @param  unused  unused
 * @return         SQLITE_OK
217 218 219 220 221 222
 */
static int sqlite3bctbx_nolockLock(sqlite3_file *pUnused, int unused){
	return SQLITE_OK;
}

/**
223 224 225 226 227
 * The lock file mechanism is not used with this VFS : unlocking the file
  * is always OK.
 * @param  pUnused sqlite3_file file handle pointer.
 * @param  unused  unused
 * @return         SQLITE_OK
228 229 230 231 232 233
 */
static int sqlite3bctbx_nolockUnlock(sqlite3_file *pUnused, int unused){
	return SQLITE_OK;
}


234
/**
235 236 237 238 239
 * Simply sync the file contents given through the file handle p
 * to the persistent media.
 * @param  p 	 sqlite3_file file handle pointer.
 * @param  flags unused
 * @return       SQLITE_OK on success, SLITE_IOERR_FSYNC if an error occurred.
240 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 248 249 250
#else
	int rc = fsync(pFile->pbctbx_file->fd);
	return (rc==0 ? SQLITE_OK : SQLITE_IOERR_FSYNC);
#endif
251 252
}

Sandrine Avakian's avatar
Sandrine Avakian committed
253
/************************ END OF PLACE HOLDER FUNCTIONS ***********************/
254

Sandrine Avakian's avatar
Sandrine Avakian committed
255 256


257 258 259 260 261 262
static char* ConvertFromUtf8Filename(const char* fName){
#if _WIN32
	char* convertedFilename;
	int nChar, nb_byte;
	LPWSTR wideFilename;
	
Sandrine Avakian's avatar
Sandrine Avakian committed
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 267 268
	if (wideFilename == NULL) return NULL;
	nChar = MultiByteToWideChar(CP_UTF8, 0, fName, -1, wideFilename, nChar);
	if (nChar == 0) {
269 270
		bctbx_free(wideFilename);
		wideFilename = 0;
Sandrine Avakian's avatar
Sandrine Avakian committed
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 277 278
	if (convertedFilename == NULL) return NULL;
	nb_byte = WideCharToMultiByte(CP_ACP, 0, wideFilename, -1, convertedFilename, nb_byte, 0, 0);
	if (nb_byte == 0) {
279 280 281 282 283
		bctbx_free(convertedFilename);
		convertedFilename = 0;
	}
	bctbx_free(wideFilename);
	return convertedFilename;
Simon Morlat's avatar
Simon Morlat committed
284
#elif defined(__QNXNTO__) || defined(__ANDROID__)
285
	return bctbx_strdup(fName);
286 287 288 289 290 291 292 293
#else
	#define MAX_PATH_SIZE 1024
	char db_file_utf8[MAX_PATH_SIZE] = {'\0'};
	char db_file_locale[MAX_PATH_SIZE] = "";
	char *outbuf=db_file_locale, *inbuf=db_file_utf8;
	size_t inbyteleft = MAX_PATH_SIZE, outbyteleft = MAX_PATH_SIZE;
	iconv_t cb;
	
294 295 296 297 298 299 300 301 302 303 304
	if (strcasecmp("UTF-8", nl_langinfo(CODESET)) == 0) {
		strncpy(db_file_locale, fName, MAX_PATH_SIZE - 1);
	} else {
		strncpy(db_file_utf8, fName, MAX_PATH_SIZE-1);
		cb = iconv_open(nl_langinfo(CODESET), "UTF-8");
		if (cb != (iconv_t)-1) {
			int ret;
			ret = iconv(cb, &inbuf, &inbyteleft, &outbuf, &outbyteleft);
			if(ret == -1) db_file_locale[0] = '\0';
			iconv_close(cb);
		}
Sandrine Avakian's avatar
Sandrine Avakian committed
305
	}
306 307
	return bctbx_strdup(db_file_locale);
#endif
Sandrine Avakian's avatar
Sandrine Avakian committed
308
}
309

310
/**
311 312
 * Opens the file fName and populates the structure pointed by p
 * with the necessary io_methods
313
 * Methods not implemented for version 1 : xTruncate, xSectorSize.
314 315 316 317 318
 * Initializes some fields in the p structure, some of which where already
 * initialized by SQLite.
 * @param  pVfs      sqlite3_vfs VFS pointer.
 * @param  fName     filename
 * @param  p         file handle pointer
319
 * @param  flags     db file access flags
320 321
 * @param  pOutFlags flags used by SQLite
 * @return           SQLITE_CANTOPEN on error, SQLITE_OK on success.
322 323 324
 */
static  int sqlite3bctbx_Open(sqlite3_vfs *pVfs, const char *fName, sqlite3_file *p, int flags, int *pOutFlags ){
	static const sqlite3_io_methods sqlite3_bctbx_io = {
325
		1,										/* iVersion         Structure version number */
326 327 328
		sqlite3bctbx_Close,                 	/* xClose */
		sqlite3bctbx_Read,                  	/* xRead */
		sqlite3bctbx_Write,                 	/* xWrite */
329
		sqlite3bctbx_Truncate,					/* xTruncate */
330
		sqlite3bctbx_Sync,
331
		sqlite3bctbx_FileSize,
332 333 334 335
		sqlite3bctbx_nolockLock,
		sqlite3bctbx_nolockUnlock,
		sqlite3bctbx_nolockCheckReservedLock,
		sqlite3bctbx_FileControl,
336
		NULL,									/* xSectorSize */
337 338
		sqlite3bctbx_DeviceCharacteristics
		/*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 347 348
	if (pFile == NULL || fName == NULL){
		return SQLITE_IOERR;
	}
349
	
350
	/* Set flags  to open the file with */
Sandrine Avakian's avatar
Sandrine Avakian committed
351
	if( flags&SQLITE_OPEN_EXCLUSIVE ) openFlags  |= O_EXCL;
352 353 354
	if( flags&SQLITE_OPEN_CREATE )    openFlags |= O_CREAT;
	if( flags&SQLITE_OPEN_READONLY )  openFlags |= O_RDONLY;
	if( flags&SQLITE_OPEN_READWRITE ) openFlags |= O_RDWR;
355

Sandrine Avakian's avatar
Sandrine Avakian committed
356 357 358
#if defined(_WIN32)
	openFlags |= O_BINARY;
#endif
359
	wFname = ConvertFromUtf8Filename(fName);
360 361 362 363 364 365
	if (wFname != NULL) {
		pFile->pbctbx_file = bctbx_file_open2(bctbx_vfs_get_default(), wFname, openFlags);
		bctbx_free(wFname);
	} else {
		pFile->pbctbx_file = NULL;
	}
366
	
367
	if( pFile->pbctbx_file == NULL){
368 369
		return SQLITE_CANTOPEN;
	}
370

371
	if( pOutFlags ){
372
    	*pOutFlags = flags;
373 374
  	}
	pFile->base.pMethods = &sqlite3_bctbx_io;
375

376 377 378
	return SQLITE_OK;
}

379

380

381 382
sqlite3_vfs *sqlite3_bctbx_vfs_create(void){
  static sqlite3_vfs bctbx_vfs = {
383 384 385 386 387 388 389 390 391
    1,								/* iVersion */
    sizeof(sqlite3_bctbx_file_t),	/* szOsFile */
    MAXPATHNAME,					/* mxPathname */
    NULL,							/* pNext */
    LINPHONE_SQLITE3_VFS,			/* zName */
    NULL,							/* pAppData */
    sqlite3bctbx_Open,				/* xOpen */
    NULL,							/* xDelete */
    NULL,							/* xAccess */
392
    NULL							/* xFullPathname */
393 394 395 396
  };
  return &bctbx_vfs;
}

397
/*static int sqlite3bctbx_winFullPathname(
Sylvain Berfini's avatar
Sylvain Berfini committed
398 399 400
										sqlite3_vfs *pVfs,            // Pointer to vfs object
										const char *zRelative,        // Possibly relative input path
										int nFull,                    // Size of output buffer in bytes
401 402 403
										char *zFull){
	//LPWSTR zTemp;
	//DWORD nByte;
Sylvain Berfini's avatar
Sylvain Berfini committed
404 405 406
	// If this path name begins with "/X:", where "X" is any alphabetic
	// character, discard the initial "/" from the pathname.
	//
407 408 409 410
	//if (zRelative[0] == '/' && sqlite3Isalpha(zRelative[1]) && zRelative[2] == ':'){
	//	zRelative++;
	//}

Sylvain Berfini's avatar
Sylvain Berfini committed
411
	 nByte = GetFullPathNameW((LPCWSTR)zRelative, 0, 0, 0);
412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432
	 if (nByte == 0){
		return SQLITE_CANTOPEN_FULLPATH;
	 }
	 nByte += 3;
	 zTemp = bctbx_malloc(nByte*sizeof(zTemp[0]));
	 memset(zTemp, 0, nByte*sizeof(zTemp[0]));
	 if (zTemp == 0){
		return SQLITE_IOERR_NOMEM;
	 }
	 nByte = GetFullPathNameW((LPCWSTR)zRelative, nByte, zTemp, 0);
	 if (nByte == 0){
		bctbx_free(zTemp);
		return SQLITE_CANTOPEN_FULLPATH;
	 }
	 if (zTemp){
		sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zTemp);
		bctbx_free(zTemp);
		return SQLITE_OK;
	 }
	 else{
		return SQLITE_IOERR_NOMEM;
Sylvain Berfini's avatar
Sylvain Berfini committed
433
	 }
434 435
	sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zRelative);
	return SQLITE_OK;
436
}*/
437

Sandrine Avakian's avatar
Sandrine Avakian committed
438

439 440 441

void sqlite3_bctbx_vfs_register( int makeDefault){
	sqlite3_vfs* pVfsToUse = sqlite3_bctbx_vfs_create();
442 443 444
	#if _WIN32
	sqlite3_vfs* pDefault = sqlite3_vfs_find("win32");
	#else
445
	sqlite3_vfs* pDefault = sqlite3_vfs_find("unix-none");
446
	#endif
447
	pVfsToUse->xCurrentTime = pDefault->xCurrentTime;
Sandrine Avakian's avatar
Sandrine Avakian committed
448
	
449
	pVfsToUse->xAccess =  pDefault->xAccess;
450
	pVfsToUse->xFullPathname = pDefault->xFullPathname;
Sandrine Avakian's avatar
Sandrine Avakian committed
451

452 453 454 455
	pVfsToUse->xDelete = pDefault->xDelete;
	pVfsToUse->xSleep = pDefault->xSleep;
	pVfsToUse->xRandomness = pDefault->xRandomness;
	pVfsToUse->xGetLastError = pDefault->xGetLastError; /* Not implemented by sqlite3 :place holder */
456 457
	/*Functions below should not be a problem sincve we are declaring ourselves
	 in version 1 */
458 459

	/* used in version 2
460
	xCurrentTimeInt64;*/
461
	/* used in version 3
462 463 464
	xGetSystemCall
	xSetSystemCall
	xNextSystemCall*/
465 466 467 468 469 470 471 472

	sqlite3_vfs_register(pVfsToUse, makeDefault);

}


void sqlite3_bctbx_vfs_unregister(void)
{
473
	sqlite3_vfs* pVfs = sqlite3_vfs_find(LINPHONE_SQLITE3_VFS);
474 475 476
	sqlite3_vfs_unregister(pVfs);
}

477
#endif /*SQLITE_STORAGE_ENABLED*/