diff --git a/docs/fileio.md b/docs/fileio.md index a0dafce6..8d4c260e 100644 --- a/docs/fileio.md +++ b/docs/fileio.md @@ -12,9 +12,11 @@ Main features: - Create a symlink. - List files in a directory. -### fileio_read(path) +### fileio_read(path [,offset [,limit]]) Reads the file specified by `path` and returns its contents as `blob`. +If offset is supplied and is non-zero and less than the file size, then seek to that offset before reading. +If limit is supplied and is non-zero then limit the number of bytes read to limit. ```sql select fileio_write('hello.txt', 'hello world'); diff --git a/src/fileio/legacy.c b/src/fileio/legacy.c index 1e34986a..4d2a367e 100644 --- a/src/fileio/legacy.c +++ b/src/fileio/legacy.c @@ -83,7 +83,7 @@ SQLITE_EXTENSION_INIT3 ** Throw an SQLITE_IOERR if there are difficulties pulling the file ** off of disk. */ -static void readFileContents(sqlite3_context* ctx, const char* zName) { +static void readFileContents(sqlite3_context* ctx, const char* zName, const int nOffset, const int nLimit) { FILE* in; sqlite3_int64 nIn; void* pBuf; @@ -98,6 +98,23 @@ static void readFileContents(sqlite3_context* ctx, const char* zName) { fseek(in, 0, SEEK_END); nIn = ftell(in); rewind(in); + if (nOffset > nIn) { /* offset is greater than the size of the file */ + sqlite3_result_error_code(ctx, SQLITE_TOOBIG); + fclose(in); + return; + } + if (nLimit <0){ + sqlite3_result_error_code(ctx, SQLITE_TOOBIG); + fclose(in); + return; + } + if (nOffset > 0) { + fseek(in, nOffset, SEEK_SET); + nIn -= nOffset; + } + if (nLimit>0 && nLimit < nIn){ + nIn=nLimit; + } db = sqlite3_context_db_handle(ctx); mxBlob = sqlite3_limit(db, SQLITE_LIMIT_LENGTH, -1); if (nIn > mxBlob) { @@ -127,11 +144,32 @@ static void readFileContents(sqlite3_context* ctx, const char* zName) { */ static void sqlite3_readfile(sqlite3_context* context, int argc, sqlite3_value** argv) { const char* zName; - (void)(argc); /* Unused parameter */ + int nOffset; + int nLimit; zName = (const char*)sqlite3_value_text(argv[0]); if (zName == 0) return; - readFileContents(context, zName); + nOffset=0; + nLimit=0; + + if (argc>=2 && sqlite3_value_type(argv[1])!=SQLITE_NULL) { + nOffset=sqlite3_value_int(argv[1]); + if (nOffset<0) { + sqlite3_result_error(context, "offset must be >= 0", -1); + return; + } + } + + if (argc==3 && sqlite3_value_type(argv[2])!=SQLITE_NULL) { + nLimit=sqlite3_value_int(argv[2]); + if (nLimit<0) { + sqlite3_result_error(context, "limit must be >= 0", -1); + return; + } + } + + + readFileContents(context, zName, nOffset, nLimit); } /* @@ -967,8 +1005,8 @@ int fileio_scalar_init(sqlite3* db) { sqlite3_create_function(db, "fileio_mkdir", -1, flags, 0, sqlite3_mkdir, 0, 0); sqlite3_create_function(db, "mkdir", -1, flags, 0, sqlite3_mkdir, 0, 0); - sqlite3_create_function(db, "fileio_read", 1, flags, 0, sqlite3_readfile, 0, 0); - sqlite3_create_function(db, "readfile", 1, flags, 0, sqlite3_readfile, 0, 0); + sqlite3_create_function(db, "fileio_read", -1, flags, 0, sqlite3_readfile, 0, 0); + sqlite3_create_function(db, "readfile", -1, flags, 0, sqlite3_readfile, 0, 0); sqlite3_create_function(db, "fileio_symlink", 2, flags, 0, sqlite3_symlink, 0, 0); sqlite3_create_function(db, "symlink", 2, flags, 0, sqlite3_symlink, 0, 0); @@ -1153,4 +1191,4 @@ INT closedir(LPDIR dirp) { sqlite3_free(dirp); return result; } -#endif \ No newline at end of file +#endif