An error occurred while loading the file. Please try again.
-
Mickaël Turnel authored
Improve C# wrapper management of strings to ensure proper UTF-8 conversion while passing from and to C library. Fix memory leaks. Add .NET wrapper tester. Add setlocale() to force utf-8 when loading Factory.Instance. Fix invalid wide string to string conversion when fetching the application data directory, causing non-UTF8 string to be returned. Add missing directory separators.
507637db
/*
* Copyright (c) 2010-2022 Belledonne Communications SARL.
*
* This file is part of Liblinphone
* (see https://gitlab.linphone.org/BC/public/liblinphone).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "bctoolbox/charconv.h"
#include <bctoolbox/defs.h>
#include "sqlite3_bctbx_vfs.h"
#include <sqlite3.h>
#ifndef _WIN32_WCE
#include <errno.h>
#endif /*_WIN32_WCE*/
#include "private.h"
/**
* 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.
*/
static int sqlite3bctbx_Close(sqlite3_file *p) {
int ret;
sqlite3_bctbx_file_t *pFile = (sqlite3_bctbx_file_t *)p;
ret = bctbx_file_close(pFile->pbctbx_file);
if (!ret) {
return SQLITE_OK;
} else {
free(pFile);
return SQLITE_IOERR_CLOSE;
}
}
/**
* Read count bytes from the open file given by p, starting at offset and puts them in
* the buffer pointed by buf.
* Calls bctbx_file_read.
*
* @param p sqlite3_file file handle pointer.
* @param buf buffer to write the read bytes to.
* @param count number of bytes to read
* @param offset file offset where to start reading
* @return SQLITE_OK if read bytes equals count,
* SQLITE_IOERR_SHORT_READ if the number of bytes read is inferior to count
* SQLITE_IOERR_READ if an error occurred.
*/
static int sqlite3bctbx_Read(sqlite3_file *p, void *buf, int count, sqlite_int64 offset) {
int ret;
sqlite3_bctbx_file_t *pFile = (sqlite3_bctbx_file_t *)p;
if (pFile) {
ret = (int)bctbx_file_read(pFile->pbctbx_file, buf, (size_t)count, (off_t)offset);
if (ret == count) {
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
return SQLITE_OK;
} else if (ret >= 0) {
/*fill in unread portion of buffer, as requested by sqlite3 documentation*/
memset(((uint8_t *)buf) + ret, 0, (size_t)(count - ret));
return SQLITE_IOERR_SHORT_READ;
} else {
return SQLITE_IOERR_READ;
}
}
return SQLITE_IOERR_READ;
}
/**
* Writes directly to the open file given through the p argument.
* Calls bctbx_file_write .
* @param p sqlite3_file file handle pointer.
* @param buf Buffer containing data to write
* @param count Size of data to write in bytes
* @param offset File offset where to write to
* @return SQLITE_OK on success, SQLITE_IOERR_WRITE if an error occurred.
*/
static int sqlite3bctbx_Write(sqlite3_file *p, const void *buf, int count, sqlite_int64 offset) {
sqlite3_bctbx_file_t *pFile = (sqlite3_bctbx_file_t *)p;
int ret;
if (pFile) {
ret = (int)bctbx_file_write(pFile->pbctbx_file, buf, (size_t)count, (off_t)offset);
if (ret > 0) return SQLITE_OK;
else {
return SQLITE_IOERR_WRITE;
}
}
return SQLITE_IOERR_WRITE;
}
/**
* 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;
}
/**
* Saves the file size associated with the file handle p into the argument pSize.
* @param p sqlite3_file file handle pointer.
* @return SQLITE_OK if read bytes equals count,
* SQLITE_IOERR_FSTAT if the file size returned is negative
* SQLITE_ERROR if an error occurred.
*/
static int sqlite3bctbx_FileSize(sqlite3_file *p, sqlite_int64 *pSize) {
int64_t rc; /* Return code from fstat() call */
sqlite3_bctbx_file_t *pFile = (sqlite3_bctbx_file_t *)p;
if (pFile->pbctbx_file) {
rc = bctbx_file_size(pFile->pbctbx_file);
141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
if (rc < 0) {
return SQLITE_IOERR_FSTAT;
}
if (pSize) {
*pSize = rc;
return SQLITE_OK;
}
}
return SQLITE_ERROR;
}
/************************ PLACE HOLDER FUNCTIONS ***********************/
/** These functions were implemented to please the SQLite VFS
implementation. Some of them are just stubs, some do a very limited job. */
/**
* 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.
*/
static int sqlite3bctbx_DeviceCharacteristics(BCTBX_UNUSED(sqlite3_file *p)) {
int rc = 0x00001000;
return rc;
}
/**
* 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.
*/
static int sqlite3bctbx_FileControl(BCTBX_UNUSED(sqlite3_file *p), BCTBX_UNUSED(int op), BCTBX_UNUSED(void *pArg)) {
#ifdef SQLITE_FCNTL_MMAP_SIZE
if (op == SQLITE_FCNTL_MMAP_SIZE) return SQLITE_OK;
#endif
return SQLITE_NOTFOUND;
}
/**
* 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
*/
static int sqlite3bctbx_nolockCheckReservedLock(BCTBX_UNUSED(sqlite3_file *pUnused), int *pResOut) {
*pResOut = 0;
return SQLITE_OK;
}
/**
* The lock file mechanism is not used with this VFS : locking the file
* is always OK.
* @param pUnused sqlite3_file file handle pointer.
* @param unused unused
* @return SQLITE_OK
*/
static int sqlite3bctbx_nolockLock(BCTBX_UNUSED(sqlite3_file *pUnused), BCTBX_UNUSED(int unused)) {
return SQLITE_OK;
}
/**
* 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
*/
211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
static int sqlite3bctbx_nolockUnlock(BCTBX_UNUSED(sqlite3_file *pUnused), BCTBX_UNUSED(int unused)) {
return SQLITE_OK;
}
/**
* 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.
*/
static int sqlite3bctbx_Sync(sqlite3_file *p, BCTBX_UNUSED(int flags)) {
sqlite3_bctbx_file_t *pFile = (sqlite3_bctbx_file_t *)p;
int ret = bctbx_file_sync(pFile->pbctbx_file);
return (ret == BCTBX_VFS_OK ? SQLITE_OK : SQLITE_IOERR_FSYNC);
}
/************************ END OF PLACE HOLDER FUNCTIONS ***********************/
/**
* Opens the file fName and populates the structure pointed by p
* with the necessary io_methods
* Methods not implemented for version 1 : xTruncate, xSectorSize.
* 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
* @param flags db file access flags
* @param pOutFlags flags used by SQLite
* @return SQLITE_CANTOPEN on error, SQLITE_OK on success.
*/
static int
sqlite3bctbx_Open(BCTBX_UNUSED(sqlite3_vfs *pVfs), const char *fName, sqlite3_file *p, int flags, int *pOutFlags) {
static const sqlite3_io_methods sqlite3_bctbx_io = {
1, /* iVersion Structure version number */
sqlite3bctbx_Close, /* xClose */
sqlite3bctbx_Read, /* xRead */
sqlite3bctbx_Write, /* xWrite */
sqlite3bctbx_Truncate, /* xTruncate */
sqlite3bctbx_Sync,
sqlite3bctbx_FileSize,
sqlite3bctbx_nolockLock,
sqlite3bctbx_nolockUnlock,
sqlite3bctbx_nolockCheckReservedLock,
sqlite3bctbx_FileControl,
NULL, /* xSectorSize */
sqlite3bctbx_DeviceCharacteristics
/*other function points follows, all NULL but not present in all sqlite3 versions.*/
};
sqlite3_bctbx_file_t *pFile = (sqlite3_bctbx_file_t *)p; /*File handle sqlite3_bctbx_file_t*/
int openFlags = 0;
char *wFname;
/*returns error if filename is empty or file handle not initialized*/
if (pFile == NULL || fName == NULL) {
return SQLITE_IOERR;
}
/* Set flags to open the file with */
if (flags & SQLITE_OPEN_EXCLUSIVE) openFlags |= O_EXCL;
if (flags & SQLITE_OPEN_CREATE) openFlags |= O_CREAT;
if (flags & SQLITE_OPEN_READONLY) openFlags |= O_RDONLY;
if (flags & SQLITE_OPEN_READWRITE) openFlags |= O_RDWR;
#if defined(_WIN32)
openFlags |= O_BINARY;
#endif
/* sqlite3 requires an UTF-8 encoded path, but UTF-8 may not be the
281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
* process current locale. */
wFname = bctbx_utf8_to_locale(fName);
if (wFname != NULL) {
pFile->pbctbx_file = bctbx_file_open2(bctbx_vfs_get_default(), wFname, openFlags);
bctbx_free(wFname);
} else {
pFile->pbctbx_file = NULL;
}
if (pFile->pbctbx_file == NULL) {
return SQLITE_CANTOPEN;
}
if (pOutFlags) {
*pOutFlags = flags;
}
pFile->base.pMethods = &sqlite3_bctbx_io;
return SQLITE_OK;
}
sqlite3_vfs *sqlite3_bctbx_vfs_create(void) {
static sqlite3_vfs bctbx_vfs = {
1, /* iVersion */
sizeof(sqlite3_bctbx_file_t), /* szOsFile */
MAXPATHNAME, /* mxPathname */
NULL, /* pNext */
BCTBX_SQLITE3_VFS, /* zName */
NULL, /* pAppData */
sqlite3bctbx_Open, /* xOpen */
NULL, /* xDelete */
NULL, /* xAccess */
NULL /* xFullPathname */
};
return &bctbx_vfs;
}
/*static int sqlite3bctbx_winFullPathname(
sqlite3_vfs *pVfs, // Pointer to vfs object
const char *zRelative, // Possibly relative input path
int nFull, // Size of output buffer in bytes
char *zFull){
//LPWSTR zTemp;
//DWORD nByte;
// If this path name begins with "/X:", where "X" is any alphabetic
// character, discard the initial "/" from the pathname.
//
//if (zRelative[0] == '/' && sqlite3Isalpha(zRelative[1]) && zRelative[2] == ':'){
// zRelative++;
//}
nByte = GetFullPathNameW((LPCWSTR)zRelative, 0, 0, 0);
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;
351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
}
else{
return SQLITE_IOERR_NOMEM;
}
sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zRelative);
return SQLITE_OK;
}*/
void sqlite3_bctbx_vfs_register(int makeDefault) {
sqlite3_vfs *pVfsToUse = sqlite3_bctbx_vfs_create();
#if _WIN32
sqlite3_vfs *pDefault = sqlite3_vfs_find("win32");
#else
sqlite3_vfs *pDefault = sqlite3_vfs_find("unix-none");
#endif
pVfsToUse->xCurrentTime = pDefault->xCurrentTime;
pVfsToUse->xAccess = pDefault->xAccess;
pVfsToUse->xFullPathname = pDefault->xFullPathname;
pVfsToUse->xDelete = pDefault->xDelete;
pVfsToUse->xSleep = pDefault->xSleep;
pVfsToUse->xRandomness = pDefault->xRandomness;
pVfsToUse->xGetLastError = pDefault->xGetLastError; /* Not implemented by sqlite3 :place holder */
/*Functions below should not be a problem sincve we are declaring ourselves
in version 1 */
/* used in version 2
xCurrentTimeInt64;*/
/* used in version 3
xGetSystemCall
xSetSystemCall
xNextSystemCall*/
sqlite3_vfs_register(pVfsToUse, makeDefault);
}
void sqlite3_bctbx_vfs_unregister(void) {
sqlite3_vfs *pVfs = sqlite3_vfs_find(BCTBX_SQLITE3_VFS);
sqlite3_vfs_unregister(pVfs);
}