1 /*-
2  * See the file LICENSE for redistribution information.
3  *
4  * Copyright (c) 2010 Oracle.  All rights reserved.
5  *
6  */
7 
8 /*
9 ** This file implements the sqlite bfile extension for Berkeley DB.
10 */
11 #include <assert.h>
12 #include <string.h>
13 #include <stdio.h>
14 #include <sys/stat.h>
15 #include <fcntl.h>
16 #include <unistd.h>
17 #include <errno.h>
18 #ifdef BFILE_USE_CAPIS
19 #include <bfile.h>
20 #endif
21 #include <sqlite3ext.h>
22 SQLITE_EXTENSION_INIT1
23 
24 #define DIRECTORY		"'BFILE_DIRECTORY'"
25 #define BFILE_PREFIX		"B"
26 #define PATH_SEPARATOR		"/"
27 #define INTERNAL_ERR_MSG	"internal error"
28 #define UNIQUE_ERR_MSG		"Directory already exist"
29 #define NOT_EXIST_ERR_MSG	"Directory does not exist"
30 
31 static void BFileCreateDirectoryFunc(sqlite3_context *, int, sqlite3_value **);
32 static void BFileReplaceDirectoryFunc(sqlite3_context *, int, sqlite3_value **);
33 static void BFileDropDirectoryFunc(sqlite3_context *, int, sqlite3_value **);
34 static void BFileNameFunc(sqlite3_context *, int, sqlite3_value **);
35 static void BFileFullPathFunc(sqlite3_context *, int, sqlite3_value **);
36 static int search_path_by_alias(sqlite3 *, char *, char *, int, char **);
37 static int get_full_path(sqlite3 *, char *, int, char **);
38 
39 /*
40  * The BFileCreateDirectoryFunc() SQL function create a directory object.
41  */
BFileCreateDirectoryFunc(sqlite3_context * context,int argc,sqlite3_value ** argv)42 static void BFileCreateDirectoryFunc(
43 	sqlite3_context *context,
44 	int argc,
45 	sqlite3_value **argv)
46 {
47 	sqlite3 *db;
48 	sqlite3_stmt *stmt = NULL;
49 	char *alias, *path;
50 	int alias_size, path_size, rc = 0;
51 #define DIR_INS "insert into "DIRECTORY" values(?,?);"
52 
53 	assert(context != NULL && argv != NULL && argc == 2);
54 
55 	alias = (char *)sqlite3_value_text(argv[0]);
56 	alias_size = sqlite3_value_bytes(argv[0]);
57 	path = (char *)sqlite3_value_text(argv[1]);
58 	path_size = sqlite3_value_bytes(argv[1]);
59 
60 	db = (sqlite3 *)sqlite3_user_data(context);
61 
62 	if (sqlite3_prepare_v2(db, DIR_INS, sizeof(DIR_INS) - 1, &stmt, NULL))
63 		goto err;
64 
65 	if (sqlite3_bind_text(stmt, 1, alias, alias_size, SQLITE_STATIC))
66 		goto err;
67 
68 	if (sqlite3_bind_text(stmt, 2, path, path_size, SQLITE_STATIC))
69 		goto err;
70 
71 	if ((rc = sqlite3_step(stmt)) != SQLITE_DONE)
72 		goto err;
73 
74 	sqlite3_finalize(stmt);
75 
76 	return;
77 err:
78 	if (stmt)
79 		sqlite3_finalize(stmt);
80 
81 	if (rc == SQLITE_CONSTRAINT)
82 		sqlite3_result_error(context, UNIQUE_ERR_MSG, -1);
83 	else
84 		sqlite3_result_error(context, INTERNAL_ERR_MSG, -1);
85 }
86 
87 /*
88  * The BFileReplaceDirectoryFunc() SQL function replace a directory object.
89  */
BFileReplaceDirectoryFunc(sqlite3_context * context,int argc,sqlite3_value ** argv)90 static void BFileReplaceDirectoryFunc(
91 	sqlite3_context *context,
92 	int argc,
93 	sqlite3_value **argv)
94 {
95 	sqlite3 *db;
96 	sqlite3_stmt *stmt = NULL;
97 	char *alias, *path;
98 	int alias_size, path_size, changed = 1;
99 #define DIR_UPD "update "DIRECTORY" set PATH=? where ALIAS=?;"
100 
101 	assert(context != NULL && argv != NULL && argc == 2);
102 
103 	alias = (char *)sqlite3_value_text(argv[0]);
104 	alias_size = sqlite3_value_bytes(argv[0]);
105 	path = (char *)sqlite3_value_text(argv[1]);
106 	path_size = sqlite3_value_bytes(argv[1]);
107 
108 	db = (sqlite3 *)sqlite3_user_data(context);
109 
110 	if (sqlite3_prepare(db, DIR_UPD, sizeof(DIR_UPD) - 1, &stmt, NULL))
111 		goto err;
112 
113 	if (sqlite3_bind_text(stmt, 1, path, path_size, SQLITE_STATIC))
114 		goto err;
115 
116 	if (sqlite3_bind_text(stmt, 2, alias, alias_size, SQLITE_STATIC))
117 		goto err;
118 
119 	if (sqlite3_step(stmt) != SQLITE_DONE)
120 		goto err;
121 
122 	if ((changed = sqlite3_changes(db)) < 1)
123 		goto err;
124 
125 	sqlite3_finalize(stmt);
126 
127 	return;
128 err:
129 	if (stmt)
130 		sqlite3_finalize(stmt);
131 
132 	if (changed < 1)
133 		sqlite3_result_error(context, NOT_EXIST_ERR_MSG, -1);
134 	else
135 		sqlite3_result_error(context, INTERNAL_ERR_MSG, -1);
136 }
137 
138 /*
139  * The BFileDropDirectoryFunc() SQL function drop a directory object.
140  */
BFileDropDirectoryFunc(sqlite3_context * context,int argc,sqlite3_value ** argv)141 static void BFileDropDirectoryFunc(
142 	sqlite3_context *context,
143 	int argc,
144 	sqlite3_value **argv)
145 {
146 	sqlite3 *db;
147 	sqlite3_stmt *stmt = NULL;
148 	char *alias;
149 	int alias_size, changed = 1;
150 #define DIR_DEL "delete from "DIRECTORY" where ALIAS=?;"
151 
152 	assert(context != NULL && argv != NULL && argc == 1);
153 
154 	alias = (char *)sqlite3_value_text(argv[0]);
155 	alias_size = sqlite3_value_bytes(argv[0]);
156 
157 	db = (sqlite3 *)sqlite3_user_data(context);
158 
159 	if (sqlite3_prepare(db, DIR_DEL, sizeof(DIR_DEL) - 1, &stmt, NULL))
160 		goto err;
161 
162 	if (sqlite3_bind_text(stmt, 1, alias, alias_size, SQLITE_STATIC))
163 		goto err;
164 
165 	if (sqlite3_step(stmt) != SQLITE_DONE)
166 		goto err;
167 
168 	if ((changed = sqlite3_changes(db)) < 1)
169 		goto err;
170 
171 	sqlite3_finalize(stmt);
172 
173 	return;
174 err:
175 	if (stmt)
176 		sqlite3_finalize(stmt);
177 
178 	if (changed < 1)
179 		sqlite3_result_error(context, NOT_EXIST_ERR_MSG, -1);
180 	else
181 		sqlite3_result_error(context, INTERNAL_ERR_MSG, -1);
182 }
183 
184 /*
185  * The BFileNameFunc() SQL function returns locator of a BFile.
186  */
BFileNameFunc(sqlite3_context * context,int argc,sqlite3_value ** argv)187 static void BFileNameFunc(
188 	sqlite3_context *context,
189 	int argc,
190 	sqlite3_value **argv)
191 {
192 	int dir_alias_size, filename_size, n;
193 	char *locator, *pLoc;
194 
195 	assert(context != NULL && argc == 2 && argv != NULL);
196 
197 	dir_alias_size = sqlite3_value_bytes(argv[0]);
198 	filename_size = sqlite3_value_bytes(argv[1]);
199 
200 	if (filename_size == 0) {
201 		sqlite3_result_null(context);
202 		return;
203 	}
204 
205 	n = strlen(BFILE_PREFIX) + 2 * sizeof(char) + dir_alias_size +
206 	    filename_size;
207 
208 	locator = (char *)sqlite3_malloc(n);
209 	if (locator == NULL) {
210 		sqlite3_result_error_nomem(context);
211 		return;
212 	}
213 
214 	/* prefix to avoid be converted to number */
215 	pLoc = locator;
216 	memcpy(pLoc, BFILE_PREFIX, strlen(BFILE_PREFIX));
217 
218 	pLoc += strlen(BFILE_PREFIX);
219 	*pLoc = dir_alias_size & 0xff;
220 	*(pLoc + 1) = (dir_alias_size >> 8) & 0xff;
221 
222 	pLoc += 2 * sizeof(char);
223 	memcpy(pLoc, (char *)sqlite3_value_text(argv[0]), dir_alias_size);
224 
225 	pLoc += dir_alias_size;
226 	memcpy(pLoc, (char *)sqlite3_value_text(argv[1]), filename_size);
227 
228 	sqlite3_result_blob(context, locator, n, SQLITE_TRANSIENT);
229 }
230 
231 /*
232  * The BFileFullPathFunc() SQL function  returns full path of a BFile
233  */
BFileFullPathFunc(sqlite3_context * context,int argc,sqlite3_value ** argv)234 static void BFileFullPathFunc(
235 	sqlite3_context *context,
236 	int argc,
237 	sqlite3_value **argv)
238 {
239 	int rc;
240 	sqlite3 *db;
241 	int loc_size;
242 	char *pLoc, *full_path;
243 
244 	assert(context != NULL && argc == 1 && argv != NULL);
245 
246 	loc_size = sqlite3_value_bytes(argv[0]);
247 	if (loc_size == 0) {
248 		sqlite3_result_null(context);
249 		return;
250 	}
251 
252 	pLoc = (char *)sqlite3_value_text(argv[0]);
253 	db = (sqlite3 *)sqlite3_user_data(context);
254 
255 	rc = get_full_path(db, pLoc, loc_size, &full_path);
256 	if (rc) {
257 		if (rc == SQLITE_NOMEM)
258 			sqlite3_result_error_nomem(context);
259 		else
260 			sqlite3_result_error(context, "internal error", -1);
261 
262 		return;
263 	}
264 
265 	sqlite3_result_text(context, full_path, strlen(full_path), sqlite3_free);
266 }
267 
268 /*
269  * The search_path_by_alias() function  returns the path of an alias
270  */
search_path_by_alias(sqlite3 * db,char * zSql,char * alias,int alias_size,char ** old_path)271 static int search_path_by_alias(
272 	sqlite3 *db,
273 	char *zSql,
274 	char *alias,
275 	int alias_size,
276 	char **old_path)
277 {
278 	int rc;
279 	sqlite3_stmt *stmt;
280 	char *result;
281 
282 	assert(db != NULL && zSql != NULL && old_path != NULL && alias != NULL);
283 	*old_path = NULL;
284 
285 	rc = sqlite3_prepare(db, zSql, strlen(zSql), &stmt, NULL);
286 	if (rc) {
287 		rc = SQLITE_ERROR;
288 		goto err;
289 	}
290 
291 	rc = sqlite3_bind_text(stmt, 1, alias, alias_size, SQLITE_STATIC);
292 	if (rc) {
293 		rc = SQLITE_ERROR;
294 		goto err;
295 	}
296 
297 	while ((rc = sqlite3_step(stmt)) == SQLITE_BUSY){};
298 	if (rc == SQLITE_DONE) {
299 		rc = SQLITE_OK;
300 		goto err;
301 	}
302 
303 	if (rc != SQLITE_ROW) {
304 		rc = SQLITE_ERROR;
305 		goto err;
306 	}
307 
308 	result = (char *)sqlite3_column_text(stmt, 0);
309 	*old_path = sqlite3_malloc(strlen(result) + 1);
310 	if (*old_path == NULL)
311 		rc = SQLITE_NOMEM;
312 	else {
313 		strcpy(*old_path, result);
314 		rc = SQLITE_OK;
315 	}
316 
317 err:
318 	if (stmt)
319 		sqlite3_finalize(stmt);
320 	return rc;
321 }
322 
323 /*
324  * The get_full_path() function returns the full path of a locator
325  */
get_full_path(sqlite3 * db,char * pLoc,int loc_size,char ** pFull_path)326 static int get_full_path(
327 	sqlite3 *db,
328 	char *pLoc,
329 	int loc_size,
330 	char **pFull_path)
331 {
332 	int rc;
333 	char *sql = "select path from "DIRECTORY" where alias=?;";
334 	int  dir_alias_size, dir_size, filename_size;
335 	char *dir_path;
336 
337 	assert(db != NULL && pLoc != NULL && loc_size > 0 &&
338 		pFull_path != NULL);
339 
340 	if (loc_size <= strlen(BFILE_PREFIX) + 2 * sizeof(char))
341 		return SQLITE_ERROR;
342 
343 	if (strncmp(pLoc, BFILE_PREFIX, strlen(BFILE_PREFIX)))
344 		return SQLITE_ERROR;
345 
346 	pLoc += strlen(BFILE_PREFIX);
347 
348 	dir_alias_size = ((*(pLoc + 1)) << 8) | (*pLoc);
349 	filename_size = loc_size - strlen(BFILE_PREFIX) - 2 * sizeof(char) -
350 	    dir_alias_size;
351 	pLoc += 2 * sizeof(char);
352 
353 	if ((rc = search_path_by_alias(db, sql, pLoc, dir_alias_size,
354 	    &dir_path)))
355 		return rc;
356 
357 	dir_size = dir_path == NULL ? dir_alias_size : strlen(dir_path);
358 	*pFull_path = sqlite3_malloc(dir_size + filename_size +
359 	    strlen(PATH_SEPARATOR) + 1);
360 	if (*pFull_path == NULL)
361 		return SQLITE_NOMEM;
362 
363 	memcpy(*pFull_path, dir_path == NULL ? pLoc : dir_path, dir_size);
364 	if (dir_path != NULL)
365 		sqlite3_free(dir_path);
366 
367 	memcpy(*pFull_path + dir_size, PATH_SEPARATOR, strlen(PATH_SEPARATOR));
368 	memcpy(*pFull_path + dir_size + strlen(PATH_SEPARATOR), pLoc +
369 	    dir_alias_size, filename_size);
370 
371 	*(*pFull_path + dir_size + strlen(PATH_SEPARATOR) + filename_size) = 0;
372 
373 	return SQLITE_OK;
374 }
375 
376 /*
377  * SQLite invokes this routine once when it loads the extension.
378  * Create new functions, collating sequences, and virtual table
379  * modules here.  This is usually the only exported symbol in
380  * the shared library.
381  */
382 #define FIND_DIRECTORY						\
383 	"SELECT COUNT(name) FROM sqlite_master			\
384 		WHERE name = "DIRECTORY" AND TYPE = 'table';"
385 #define CREATE_DIRECTORY					\
386 	"CREATE TABLE "DIRECTORY"(				\
387 		ALIAS TEXT PRIMARY KEY,				\
388 		PATH TEXT					\
389 	);"
390 
391 #ifdef BFILE_USE_CAPIS
392 typedef struct BfileHdl BfileHdl;
393 struct BfileHdl {
394 	char *full_path;		/* full path of the BFILE */
395 	int fd;				/* file discriptor of the BFILE */
396 };
397 
398 /*
399  * Access BFILE element of the current row in the row set
400  */
sqlite3_column_bfile(sqlite3_stmt * pStmt,int iCol,sqlite3_bfile ** ppBfile)401 SQLITE_API int sqlite3_column_bfile(
402 	sqlite3_stmt *pStmt,
403 	int iCol,
404 	sqlite3_bfile **ppBfile
405 )
406 {
407 	BfileHdl *pHdl;
408 	char * pLoc;
409 	int loc_size, rc;
410 	sqlite3 *db;
411 #define IS_ERROR(rc) \
412 	((rc)!= SQLITE_OK && (rc) != SQLITE_ROW && (rc) != SQLITE_DONE)
413 
414 	if (pStmt == NULL || iCol < 0 || iCol >= sqlite3_column_count(pStmt)
415 	    || ppBfile == NULL)
416 		return SQLITE_ERROR;
417 
418 	db = sqlite3_db_handle(pStmt);
419 
420 	/*
421 	 * If a memory allocation error occurs during the evaluation of any of
422 	 * these routines, a default value is returned. The default value is
423 	 * either the integer 0, the floating point number 0.0, or a NULL
424 	 * pointer. Subsequent calls to sqlite3_errcode() will return
425 	 * SQLITE_NOMEM.
426 	 */
427 	pLoc = (char *)sqlite3_column_blob(pStmt, iCol);
428 	if (pLoc == NULL) {
429 		*ppBfile = NULL;
430 		rc = sqlite3_errcode(db);
431 		return (IS_ERROR(rc) ? SQLITE_ERROR : SQLITE_OK);
432 	}
433 
434 	pHdl = sqlite3_malloc(sizeof(BfileHdl));
435 	if (pHdl == NULL) {
436 		*ppBfile = NULL;
437 		return SQLITE_ERROR;
438 	}
439 
440 	pHdl->fd = -1;
441 
442 	loc_size = sqlite3_column_bytes(pStmt, iCol);
443 
444 	rc = get_full_path(db, pLoc, loc_size,&(pHdl->full_path));
445 
446 	if (rc) {
447 		if (pHdl != NULL)
448 			sqlite3_free(pHdl);
449 		*ppBfile = NULL;
450 		return SQLITE_ERROR;
451 	}
452 
453 	*ppBfile = (sqlite3_bfile *)pHdl;
454 
455 	return SQLITE_OK;
456 }
457 
458 /*
459  * Open a BFILE
460  */
sqlite3_bfile_open(sqlite3_bfile * pBfile)461 SQLITE_API int sqlite3_bfile_open(
462 	sqlite3_bfile *pBfile)
463 {
464 	BfileHdl *pHdl;
465 
466 	if (pBfile == NULL)
467 		return SQLITE_OK;
468 
469 
470 	pHdl = (BfileHdl *)pBfile;
471 
472 	if (pHdl->fd == -1)
473 		pHdl->fd = open(pHdl->full_path, O_RDONLY);
474 
475 	return SQLITE_OK;
476 }
477 
478 /*
479  * Check if file is open using this BFLIE
480  */
sqlite3_bfile_close(sqlite3_bfile * pBfile)481 SQLITE_API int sqlite3_bfile_close(
482 	sqlite3_bfile *pBfile)
483 {
484 	BfileHdl *pHdl;
485 
486 	if (pBfile == NULL)
487 		return SQLITE_OK;
488 
489 	pHdl = (BfileHdl *)pBfile;
490 
491 	close(pHdl->fd);
492 
493 	pHdl->fd = -1;
494 
495 	return SQLITE_OK;
496 }
497 
498 /*
499  * Check if file is open using this BFLIE
500  */
sqlite3_bfile_is_open(sqlite3_bfile * pBfile,int * open)501 SQLITE_API int sqlite3_bfile_is_open(
502 	sqlite3_bfile *pBfile,
503 	int *open)
504 {
505 	BfileHdl *pHdl;
506 	int rc, exist;
507 
508 	if (open == NULL)
509 		return SQLITE_ERROR;
510 
511 	if (pBfile == NULL) {
512 		*open = 0;
513 		return SQLITE_OK;
514 	}
515 
516 	rc = sqlite3_bfile_file_exists(pBfile, &exist);
517 	if (rc != SQLITE_OK || exist != 1) {
518 		*open = 0;
519 		return SQLITE_ERROR;
520 	}
521 
522 	pHdl = (BfileHdl *)pBfile;
523 
524 	*open = (pHdl->fd == -1) ? 0 : 1;
525 
526 	return SQLITE_OK;
527 }
528 
529 /*
530  * Read a portion of a BFILE
531  */
sqlite3_bfile_read(sqlite3_bfile * pBfile,void * z,int nSize,off_t iOffset,int * nRead)532 SQLITE_API int sqlite3_bfile_read(
533 	sqlite3_bfile *pBfile,
534 	void *z,
535 	int nSize,
536 	off_t iOffset,
537 	int *nRead)
538 {
539 	BfileHdl *pHdl;
540 	int rc;
541 	off_t size;
542 
543 	if (z == NULL || nSize <= 0 || iOffset < 0 || nRead == NULL)
544 		return SQLITE_ERROR;
545 
546 	rc = sqlite3_bfile_size(pBfile, &size);
547 	if (rc != SQLITE_OK || iOffset > size) {
548 		*nRead = 0;
549 		return SQLITE_ERROR;
550 	}
551 
552 	if (pBfile == NULL) {
553 		*(char *)z = 0;
554 		*nRead = 0;
555 		return SQLITE_OK;
556 	}
557 
558 	pHdl = (BfileHdl *)pBfile;
559 
560 	if (pHdl->fd == -1) {
561 		*nRead = 0;
562 		return SQLITE_ERROR;
563 	}
564 
565 	if ((rc = lseek(pHdl->fd, iOffset, SEEK_SET)) == -1) {
566 		*nRead = 0;
567 		return SQLITE_ERROR;
568 	}
569 
570 	if ((*nRead = read(pHdl->fd, z, nSize)) == -1) {
571 		*nRead = 0;
572 		return SQLITE_ERROR;
573 	}
574 
575 	return SQLITE_OK;
576 }
577 
578 /*
579  * Check if a file exists
580  */
sqlite3_bfile_file_exists(sqlite3_bfile * pBfile,int * exist)581 SQLITE_API int sqlite3_bfile_file_exists(
582 	sqlite3_bfile *pBfile,
583 	int *exist
584 )
585 {
586 	BfileHdl *pHdl;
587 
588 	if (exist == NULL)
589 		return SQLITE_ERROR;
590 
591 	if (pBfile == NULL) {
592 		*exist = 0;
593 		return SQLITE_OK;
594 	}
595 
596 	pHdl = (BfileHdl *)pBfile;
597 
598 	if ((pHdl->fd != -1) || (!access(pHdl->full_path, F_OK)))
599 		*exist = 1;
600 	else
601 		*exist = 0;
602 
603 	return SQLITE_OK;
604 }
605 
606 /*
607  * Get File size of a BFILE
608  */
sqlite3_bfile_size(sqlite3_bfile * pBfile,off_t * size)609 SQLITE_API int sqlite3_bfile_size(
610 	sqlite3_bfile *pBfile,
611 	off_t *size)
612 {
613 	BfileHdl *pHdl;
614 	struct stat st;
615 	int rc;
616 
617 	if (size == NULL)
618 		return SQLITE_ERROR;
619 
620 	if (pBfile == NULL) {
621 		*size = 0;
622 		return SQLITE_OK;
623 	}
624 
625 	pHdl = (BfileHdl *)pBfile;
626 
627 	memset(&st, 0, sizeof(st));
628 
629 	if ((rc = stat(pHdl->full_path, &st)) == -1) {
630 		*size = 0;
631 		return SQLITE_ERROR;
632 	}
633 
634 	*size = st.st_size;
635 
636 	return SQLITE_OK;
637 }
638 
639 /*
640  * Finalize a BFILE
641  */
sqlite3_bfile_final(sqlite3_bfile * pBfile)642 SQLITE_API int sqlite3_bfile_final(
643 	sqlite3_bfile *pBfile)
644 {
645 	BfileHdl *pHdl;
646 
647 	pHdl = (BfileHdl *)pBfile;
648 
649 	if (pHdl != NULL) {
650 		if (pHdl->full_path != NULL)
651 			sqlite3_free(pHdl->full_path);
652 
653 		sqlite3_free(pHdl);
654 	}
655 
656 	return SQLITE_OK;
657 }
658 #else
659 typedef struct BfileHdl BfileHdl;
660 struct BfileHdl {
661 	char *full_path;	/* full path of the BFILE */
662 	int fd;			/* file discriptor of the BFILE*/
663 	char *zBuf;		/* read buf */
664 	int zBufSiz;		/* read buf size */
665 };
666 
667 /*
668  * Open a BFILE
669  */
BFileOpenFunc(sqlite3_context * context,int argc,sqlite3_value ** argv)670 static void BFileOpenFunc(
671 	sqlite3_context *context,
672 	int argc,
673 	sqlite3_value **argv)
674 {
675 	int rc;
676 	sqlite3 *db;		/* db handle */
677 	int loc_size;		/* BFile locater size */
678 	int fd;			/* file descriptor */
679 	char *pLoc;		/* BFile locater */
680 	char *full_path;	/* full path */
681 	BfileHdl *pHdl;		/* BFile handle */
682 
683 	assert(context != NULL && argc == 1 && argv != NULL);
684 	full_path = NULL, pHdl = NULL;
685 	fd = -1;
686 
687 	loc_size = sqlite3_value_bytes(argv[0]);
688 	if (loc_size <= strlen(BFILE_PREFIX)) {
689 		sqlite3_result_int(context, 0);
690 		return;
691 	}
692 
693 	db = (sqlite3 *)sqlite3_user_data(context);
694 	pLoc = (char *)sqlite3_value_text(argv[0]);
695 	assert(db != NULL && pLoc != NULL);
696 
697 	rc = get_full_path(db, pLoc, loc_size, &full_path);
698 	if (rc)
699 		goto err;
700 
701 	fd = open(full_path, O_RDONLY);
702 	if (fd == -1) {
703 		if (errno == ENOENT)
704 		    sqlite3_result_int(context, 0);
705 		else
706 		    rc = -1;
707 		goto err;
708 	}
709 
710 	pHdl = sqlite3_malloc(sizeof(BfileHdl));
711 	if (pHdl == NULL) {
712 		rc = SQLITE_NOMEM;
713 		goto err;
714 	}
715 
716 	memset(pHdl, 0, sizeof(BfileHdl));
717 	pHdl->full_path = full_path;
718 	pHdl->fd = fd;
719 	sqlite3_result_int64(context, (sqlite3_int64)pHdl);
720 	return;
721 
722 err:
723 	if (rc == SQLITE_NOMEM)
724 		sqlite3_result_error_nomem(context);
725 	else if (rc)
726 		sqlite3_result_error(context, "internal error", -1);
727 
728 	if (pHdl != NULL)
729 		sqlite3_free(pHdl);
730 
731 	if (fd >= 0)
732 		close(fd);
733 
734 	if (full_path != NULL)
735 		sqlite3_free(full_path);
736 }
737 
738 /*
739  * Close a BFILE
740  */
BFileCloseFunc(sqlite3_context * context,int argc,sqlite3_value ** argv)741 static void BFileCloseFunc(
742 	sqlite3_context *context,
743 	int argc,
744 	sqlite3_value **argv)
745 {
746 	BfileHdl *pHdl;
747 
748 	assert(context != NULL && argc == 1 && argv != NULL);
749 
750 	pHdl = (BfileHdl*)sqlite3_value_int64(argv[0]);
751 	if (pHdl != NULL) {
752 		if (pHdl->fd >= 0)
753 			close(pHdl->fd);
754 		if (pHdl->full_path != NULL)
755 			sqlite3_free(pHdl->full_path);
756 		if (pHdl->zBuf != NULL)
757 			sqlite3_free(pHdl->zBuf);
758 		sqlite3_free(pHdl);
759 	}
760 }
761 
__bfile_get_size(char * full_path,off_t * size)762 static int __bfile_get_size(
763 	char *full_path,
764 	off_t *size)
765 {
766 	struct stat st;
767 	int rc;
768 
769 	assert(full_path != NULL && size != NULL);
770 	memset(&st, 0, sizeof(st));
771 
772 	if ((rc = stat(full_path, &st)) == -1) {
773 		*size = 0;
774 		return SQLITE_ERROR;
775 	}
776 
777 	*size = st.st_size;
778 
779 	return SQLITE_OK;
780 }
781 
782 /*
783  * Read a portion of a BFILE
784  */
BFileReadFunc(sqlite3_context * context,int argc,sqlite3_value ** argv)785 static void BFileReadFunc(
786 	sqlite3_context *context,
787 	int argc,
788 	sqlite3_value **argv)
789 {
790 	int rc;
791 	BfileHdl *pHdl;		/* BFile handle */
792 	int nSize;		/* up to nSize bytes would be read */
793 	int nRead;		/* the number of bytes read actually */
794 	off_t size;		/* the size of the underlying file */
795 	off_t iOffset;		/* the position from which read would start */
796 	char *z;		/* the pointer of read buffer */
797 
798 	assert(context != NULL && argc == 3 && argv != NULL);
799 
800 	pHdl = (BfileHdl*)sqlite3_value_int64(argv[0]);
801 	if (pHdl == NULL || pHdl->full_path == NULL || pHdl->fd < 0) {
802 		sqlite3_result_error(context, "invalid bfile handle", -1);
803 		return;
804 	}
805 
806 	nSize = sqlite3_value_int(argv[1]);
807 	iOffset = (off_t)sqlite3_value_int(argv[2]);
808 
809 	rc = __bfile_get_size(pHdl->full_path, &size);
810 	if (rc != SQLITE_OK) {
811 		sqlite3_result_error(context, "internal error", -1);
812 		return;
813 	} else if (nSize <= 0) {
814 		sqlite3_result_error(context, "invalid size", -1);
815 		return;
816 	} else if (iOffset < 0) {
817 		sqlite3_result_error(context, "invalid offset", -1);
818 		return;
819 	} else if (iOffset > size) {
820 		sqlite3_result_null(context);
821 		return;
822 	}
823 
824 	if ((rc = lseek(pHdl->fd, iOffset, SEEK_SET)) == -1) {
825 		sqlite3_result_error(context, "disk I/O error", -1);
826 		return;
827 	}
828 
829 	if (pHdl->zBuf == NULL || pHdl->zBufSiz < nSize) {
830 		z = pHdl->zBuf == NULL ? sqlite3_malloc(nSize) :
831 			sqlite3_realloc(pHdl->zBuf, nSize);
832 		if (z == NULL) {
833 			sqlite3_result_error_nomem(context);
834 			return;
835 		}
836 		pHdl->zBuf = z;
837 		pHdl->zBufSiz = nSize;
838 	}
839 
840 	if ((nRead = read(pHdl->fd, pHdl->zBuf, nSize)) == -1) {
841 		sqlite3_result_error(context, "disk I/O error", -1);
842 		return;
843 	}
844 
845 	sqlite3_result_blob(context, pHdl->zBuf, nRead, SQLITE_STATIC);
846 }
847 
848 /*
849  * Get File size of a BFILE
850  */
BFileSizeFunc(sqlite3_context * context,int argc,sqlite3_value ** argv)851 static void BFileSizeFunc(
852 	sqlite3_context *context,
853 	int argc,
854 	sqlite3_value **argv)
855 {
856 	int rc;
857 	sqlite3 *db;
858 	int loc_size;
859 	off_t size;
860 	char *pLoc, *full_path;
861 
862 	assert(context != NULL && argc == 1 && argv != NULL);
863 	full_path = NULL;
864 
865 	loc_size = sqlite3_value_bytes(argv[0]);
866 	if (loc_size <= strlen(BFILE_PREFIX)) {
867 		sqlite3_result_int(context, -1);
868 		return;
869 	}
870 
871 	db = (sqlite3 *)sqlite3_user_data(context);
872 	pLoc = (char *)sqlite3_value_text(argv[0]);
873 	assert(db != NULL && pLoc != NULL);
874 
875 	rc = get_full_path(db, pLoc, loc_size, &full_path);
876 	if (rc) {
877 		if (rc == SQLITE_NOMEM)
878 			sqlite3_result_error_nomem(context);
879 		else
880 			sqlite3_result_error(context, "internal error", -1);
881 		return;
882 	}
883 
884 	/* check existence, if not exits at at set size as -1 */
885 	if (access(full_path, F_OK))
886 		sqlite3_result_int(context, -1);
887 	else if (__bfile_get_size(full_path, &size) == SQLITE_OK)
888 		sqlite3_result_int(context, size);
889 	else
890 		sqlite3_result_error(context, "internal error", -1);
891 
892 	sqlite3_free(full_path);
893 }
894 #endif
895 
sqlite3_extension_init(sqlite3 * db,char ** pzErrMsg,const sqlite3_api_routines * pApi)896 int sqlite3_extension_init(
897 	sqlite3 *db,
898 	char **pzErrMsg,
899 	const sqlite3_api_routines *pApi)
900 {
901 	int rc;
902 	sqlite3_stmt *pSelect;
903 
904 	SQLITE_EXTENSION_INIT2(pApi)
905 
906 	sqlite3_create_function(db, "BFILE_NAME", 2, SQLITE_ANY, 0,
907 	    BFileNameFunc, 0, 0);
908 
909 	sqlite3_create_function(db, "BFILE_FULLPATH", 1, SQLITE_ANY, db,
910 	    BFileFullPathFunc, 0, 0);
911 
912 	sqlite3_create_function(db, "BFILE_CREATE_DIRECTORY", 2, SQLITE_ANY,
913 		db, BFileCreateDirectoryFunc, 0, 0);
914 
915 	sqlite3_create_function(db, "BFILE_REPLACE_DIRECTORY", 2, SQLITE_ANY,
916 		db, BFileReplaceDirectoryFunc, 0, 0);
917 
918 	sqlite3_create_function(db, "BFILE_DROP_DIRECTORY", 1, SQLITE_ANY,
919 		db, BFileDropDirectoryFunc, 0, 0);
920 
921 #ifndef BFILE_USE_CAPIS
922 	/* Bfile functions instead of c version */
923 	sqlite3_create_function(db, "BFILE_OPEN", 1, SQLITE_ANY, db,
924 	    BFileOpenFunc, 0, 0);
925 
926 	sqlite3_create_function(db, "BFILE_CLOSE", 1, SQLITE_ANY, 0,
927 	    BFileCloseFunc, 0, 0);
928 
929 	sqlite3_create_function(db, "BFILE_READ", 3, SQLITE_ANY, 0,
930 	    BFileReadFunc, 0, 0);
931 
932 	sqlite3_create_function(db, "BFILE_SIZE", 1, SQLITE_ANY, db,
933 	    BFileSizeFunc, 0, 0);
934 #endif
935 
936 	rc = sqlite3_prepare(db, FIND_DIRECTORY, -1, &pSelect, 0);
937 	if (rc != SQLITE_OK || !pSelect)
938 		return rc;
939 
940 	rc = sqlite3_step(pSelect);
941 	if (rc == SQLITE_ROW && sqlite3_column_int(pSelect, 0) == 0)
942 		rc = sqlite3_exec(db, CREATE_DIRECTORY, 0, 0, pzErrMsg);
943 
944 	rc = sqlite3_finalize(pSelect);
945 
946 	return rc;
947 }
948