1
0
mirror of https://github.com/sqlite/sqlite.git synced 2026-10-23 21:49:02 +03:00

Enhance the readfile() function in the fileio.c extension so that it

is able to read from pipes.
[bugs:/info/2026-10-20T14:02:37Z|Enhancement request 2026-10-20T14:02:37Z]

FossilOrigin-Name: 49d185f2ac2d01c6b1bd9c20d13628eff3803529faaf969bace3981f6acc7a28
This commit is contained in:
drh
2026-10-20 17:46:19 +00:00
parent f95dc99bc6
commit d3d85df39e
4 changed files with 72 additions and 14 deletions

View File

@@ -221,8 +221,10 @@ static int fileio_mkdir(const char *zPath){
*/
static void readFileContents(sqlite3_context *ctx, const char *zName){
FILE *in;
sqlite3_int64 nIn;
void *pBuf;
sqlite3_int64 nIn; /* Size of the file according to ftell() */
sqlite3_int64 nAlloc; /* Bytes allocated for pBuf */
sqlite3_int64 nRead = 0; /* Bytes read so far */
unsigned char *pBuf;
sqlite3 *db;
int mxBlob;
@@ -231,9 +233,12 @@ static void readFileContents(sqlite3_context *ctx, const char *zName){
/* File does not exist or is unreadable. Leave the result set to NULL. */
return;
}
/* The size reported by ftell() is only a hint. It is -1 for pipes and
** FIFOs and 0 for many files under /proc. Keep reading until EOF. */
fseek(in, 0, SEEK_END);
nIn = ftell(in);
rewind(in);
if( nIn<0 ) nIn = 0;
db = sqlite3_context_db_handle(ctx);
mxBlob = sqlite3_limit(db, SQLITE_LIMIT_LENGTH, -1);
if( nIn>mxBlob ){
@@ -241,17 +246,41 @@ static void readFileContents(sqlite3_context *ctx, const char *zName){
fclose(in);
return;
}
pBuf = sqlite3_malloc64( nIn ? nIn : 1 );
/* One extra byte so that EOF on a regular file is seen without a
** reallocation. */
nAlloc = nIn+1;
pBuf = sqlite3_malloc64( nAlloc );
if( pBuf==0 ){
sqlite3_result_error_nomem(ctx);
fclose(in);
return;
}
if( nIn==(sqlite3_int64)fread(pBuf, 1, (size_t)nIn, in) ){
sqlite3_result_blob64(ctx, pBuf, nIn, sqlite3_free);
}else{
while( 1 ){
unsigned char *pNew;
nRead += fread(pBuf+nRead, 1, (size_t)(nAlloc-nRead), in);
if( nRead>mxBlob ){
sqlite3_result_error_code(ctx, SQLITE_TOOBIG);
sqlite3_free(pBuf);
fclose(in);
return;
}
if( nRead<nAlloc ) break; /* Short read means EOF or an error */
nAlloc *= 2;
if( nAlloc>(sqlite3_int64)mxBlob+1 ) nAlloc = (sqlite3_int64)mxBlob+1;
pNew = sqlite3_realloc64(pBuf, nAlloc);
if( pNew==0 ){
sqlite3_result_error_nomem(ctx);
sqlite3_free(pBuf);
fclose(in);
return;
}
pBuf = pNew;
}
if( ferror(in) ){
sqlite3_result_error_code(ctx, SQLITE_IOERR);
sqlite3_free(pBuf);
}else{
sqlite3_result_blob64(ctx, pBuf, nRead, sqlite3_free);
}
fclose(in);
}

View File

@@ -1,5 +1,5 @@
C Remove\sa\sdebugging\s".mode\s-v"\sin\sthe\sdump.sql\stest\sscript\sthat\swas\naccidentally\sleft\sin\sthe\sprevious\scheck-in.
D 2026-10-20T17:42:52.465
C Enhance\sthe\sreadfile()\sfunction\sin\sthe\sfileio.c\sextension\sso\sthat\sit\nis\sable\sto\sread\sfrom\spipes.\n[bugs:/info/2026-10-20T14:02:37Z|Enhancement\srequest\s2026-10-20T14:02:37Z]
D 2026-10-20T17:46:19.164
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
@@ -379,7 +379,7 @@ F ext/misc/decimal.c 68e987966e4772efdb8df03e2bf253d02bae3254af29fd4a99d34fc6e6f
F ext/misc/diskused.c 444139c01398df6f73e8a021c91e24d97d7914f5c1b49f55dd503abbca347c6e
F ext/misc/eval.c d4ea2d9898fbe4d30d38ff675ee51958d3bb0601a145bade56dee8b8f438cc5b
F ext/misc/explain.c 04c9270fd8cf93a9bceb12d2f5f67e3f09a4e58b3e0efe14d24531444d2fffdf
F ext/misc/fileio.c f32d7488e229cc52283b6f8d9370b004aa92e7a3054aef320cbdbdecb08c4ee5
F ext/misc/fileio.c 6bf2543ae190401f5fda74661c20387a450071eb5d17bfc05d3b45416bbedcb7
F ext/misc/fossildelta.c 0af6a5ef3db6bba299271c29b604489e4a5d9e75395c6b83460405a9ccf05c2a
F ext/misc/fuzzer.c 32cef9a29864a1bc1329ccb6dfa613f197bb83491a7612c2ca2c83ee26cd8f14
F ext/misc/ieee754.c 2901d08a586d00a1d3c0fd89e03c57ee9e2b5f013b0daab9e49c7a48a9d5946b
@@ -1189,7 +1189,7 @@ F test/exprfault.test 7475e363c7221847855722e9dd2459cf60088f6b172c0c808dba75f89e
F test/exprfault2.test c49e84273898969af5dbc4fe6a3f4335f14639799f343590336c9ddf84425965
F test/expridx1.test b464520126e1d781a7800f8540621c82e8bbc526f089ff8b0b57ffc51feea6b7
F test/expridx2.test 13348ed208a5d18d9cef7d0a70f8e17948d3c0b5b46508c0573b7e983456165f
F test/extension01.test 5de412c66276105901c370770175003381fdcb0c4da7054fa43cf4a31e0bfa3a
F test/extension01.test abdb32528871c4daa445bc5a18e75873cd1257dae05af2703838b744b9913534
F test/external_reader.test 6fdec43eeca23eb32faad1e95a4d1abc402bc8b3db70df12d6fc08a637f4a2b5
F test/extraquick.test cb254400bd42bfb777ff675356aabf3287978f79
F test/fallocate.test 37a62e396a68eeede8f8d2ecf23573a80faceb630788d314d0a073d862616717
@@ -2295,8 +2295,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee
F tool/warnings.sh a554d13f6e5cf3760f041b87939e3d616ec6961859c3245e8ef701d1eafc2ca2
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c
P ecd172bb44be40841336cf2ec42f2505c4f98a96eace3e4862e038a3c147770d
R 15e9f2d7ecdc986aac547ffba1bf6e5b
P 632943da2d3e58696ec0a7548e18a99a57a3dd51f700f24144377a6d8fdb8c06
R 975aef2d01879a69ec2ec2c8d7f2e5c6
U drh
Z 5f956cdbddb3debc5fab777fad1cc812
Z c01cc06719b3a1f0fd241b4960900888
# Remove this line to create a well-formed Fossil manifest.

View File

@@ -1 +1 @@
632943da2d3e58696ec0a7548e18a99a57a3dd51f700f24144377a6d8fdb8c06
49d185f2ac2d01c6b1bd9c20d13628eff3803529faaf969bace3981f6acc7a28

View File

@@ -80,4 +80,33 @@ do_test 1.7 {
}
} {nil}
# readfile() must read until EOF rather than trusting the size reported
# by ftell(). That size is -1 for a pipe or FIFO and 0 for many files
# under /proc.
#
forcedelete fifo1
if {$::tcl_platform(platform)=="unix" && ![catch {exec mkfifo fifo1}]} {
do_test 2.1 {
exec sh -c {printf hello >fifo1} &
db eval { SELECT CAST(readfile('fifo1') AS TEXT) }
} {hello}
do_test 2.2 {
exec sh -c {head -c 100000 /dev/zero >fifo1} &
db eval { SELECT length(readfile('fifo1')) }
} {100000}
do_test 2.3 {
set mx [sqlite3_limit db SQLITE_LIMIT_LENGTH 1000]
exec sh -c {head -c 100000 /dev/zero >fifo1 2>/dev/null} &
set res [catchsql { SELECT length(readfile('fifo1')) }]
sqlite3_limit db SQLITE_LIMIT_LENGTH $mx
set res
} {1 {string or blob too big}}
forcedelete fifo1
}
if {[file readable /proc/self/status]} {
do_execsql_test 2.4 {
SELECT length(readfile('/proc/self/status'))>0
} {1}
}
finish_test