diff options
author | dan <dan@noemail.net> | 2017-12-14 19:15:07 +0000 |
---|---|---|
committer | dan <dan@noemail.net> | 2017-12-14 19:15:07 +0000 |
commit | ac15e2d7ccfb706d020d4a42fc4d809f6ca1cca8 (patch) | |
tree | 36793dd83ee1158e37bcfc54af31e25421033c41 /ext/misc/fileio.c | |
parent | 0d0547fec67e1ef00b68fdfd648709f7f5477719 (diff) | |
download | sqlite-ac15e2d7ccfb706d020d4a42fc4d809f6ca1cca8.tar.gz sqlite-ac15e2d7ccfb706d020d4a42fc4d809f6ca1cca8.zip |
Have the writefile() function optionally set the modification-time of the
files it writes or creates. And many small fixes to the new code on this
branch.
FossilOrigin-Name: 7b51269caebe1492885fe9b965892f49a3f8bdb1d666b0203d594c30f9e83938
Diffstat (limited to 'ext/misc/fileio.c')
-rw-r--r-- | ext/misc/fileio.c | 136 |
1 files changed, 107 insertions, 29 deletions
diff --git a/ext/misc/fileio.c b/ext/misc/fileio.c index 232017399..7dbac4043 100644 --- a/ext/misc/fileio.c +++ b/ext/misc/fileio.c @@ -11,21 +11,67 @@ ****************************************************************************** ** ** This SQLite extension implements SQL functions readfile() and -** writefile(). +** writefile(), and eponymous virtual type "fsdir". ** -** Also, an eponymous virtual table type "fsdir". Used as follows: +** WRITEFILE(FILE, DATA [, MODE [, MTIME]]): ** -** SELECT * FROM fsdir($dirname); +** If neither of the optional arguments is present, then this UDF +** function writes blob DATA to file FILE. If successful, the number +** of bytes written is returned. If an error occurs, NULL is returned. ** -** Returns one row for each entry in the directory $dirname. No row is -** returned for "." or "..". Row columns are as follows: +** If the first option argument - MODE - is present, then it must +** be passed an integer value that corresponds to a POSIX mode +** value (file type + permissions, as returned in the stat.st_mode +** field by the stat() system call). Three types of files may +** be written/created: ** -** name: Name of directory entry. -** mode: Value of stat.st_mode for directory entry. -** mtime: Value of stat.st_mtime for directory entry. -** data: For a regular file, a blob containing the file data. For a -** symlink, a text value containing the text of the link. For a -** directory, NULL. +** regular files: (mode & 0170000)==0100000 +** symbolic links: (mode & 0170000)==0120000 +** directories: (mode & 0170000)==0040000 +** +** For a directory, the DATA is ignored. For a symbolic link, it is +** interpreted as text and used as the target of the link. For a +** regular file, it is interpreted as a blob and written into the +** named file. Regardless of the type of file, its permissions are +** set to (mode & 0777) before returning. +** +** If the optional MTIME argument is present, then it is interpreted +** as an integer - the number of seconds since the unix epoch. The +** modification-time of the target file is set to this value before +** returning. +** +** If three or more arguments are passed to this function and an +** error is encountered, an exception is raised. +** +** READFILE(FILE): +** +** Read and return the contents of file FILE (type blob) from disk. +** +** FSDIR: +** +** Used as follows: +** +** SELECT * FROM fsdir($path [, $dir]); +** +** Parameter $path is an absolute or relative pathname. If the file that it +** refers to does not exist, it is an error. If the path refers to a regular +** file or symbolic link, it returns a single row. Or, if the path refers +** to a directory, it returns one row for the directory, and one row for each +** file within the hierarchy rooted at $path. +** +** Each row has the following columns: +** +** name: Path to file or directory (text value). +** mode: Value of stat.st_mode for directory entry (an integer). +** mtime: Value of stat.st_mtime for directory entry (an integer). +** data: For a regular file, a blob containing the file data. For a +** symlink, a text value containing the text of the link. For a +** directory, NULL. +** +** If a non-NULL value is specified for the optional $dir parameter and +** $path is a relative path, then $path is interpreted relative to $dir. +** And the paths returned in the "name" column of the table are also +** relative to directory $dir. */ #include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 @@ -45,6 +91,10 @@ SQLITE_EXTENSION_INIT1 #define FSDIR_SCHEMA "(name,mode,mtime,data,path HIDDEN,dir HIDDEN)" +/* +** Set the result stored by context ctx to a blob containing the +** contents of file zName. +*/ static void readFileContents(sqlite3_context *ctx, const char *zName){ FILE *in; long nIn; @@ -81,6 +131,10 @@ static void readfileFunc( readFileContents(context, zName); } +/* +** Set the error message contained in context ctx to the results of +** vprintf(zFmt, ...). +*/ static void ctxErrorMsg(sqlite3_context *ctx, const char *zFmt, ...){ char *zMsg = 0; va_list ap; @@ -138,11 +192,16 @@ static int makeDirectory( return rc; } +/* +** This function does the work for the writefile() UDF. Refer to +** header comments at the top of this file for details. +*/ static int writeFile( - sqlite3_context *pCtx, - const char *zFile, - mode_t mode, - sqlite3_value *pData + sqlite3_context *pCtx, /* Context to return bytes written in */ + const char *zFile, /* File to write */ + sqlite3_value *pData, /* Data to write */ + mode_t mode, /* MODE parameter passed to writefile() */ + sqlite3_int64 mtime /* MTIME parameter (or -1 to not set time) */ ){ if( S_ISLNK(mode) ){ const char *zTo = (const char*)sqlite3_value_text(pData); @@ -178,22 +237,30 @@ static int writeFile( } } fclose(out); - if( rc==0 && chmod(zFile, mode & 0777) ){ + if( rc==0 && mode && chmod(zFile, mode & 0777) ){ rc = 1; } if( rc ) return 2; sqlite3_result_int64(pCtx, nWrite); } } + + if( mtime>=0 ){ + struct timespec times[2]; + times[0].tv_nsec = times[1].tv_nsec = 0; + times[0].tv_sec = time(0); + times[1].tv_sec = mtime; + if( utimensat(AT_FDCWD, zFile, times, AT_SYMLINK_NOFOLLOW) ){ + return 1; + } + } + return 0; } /* -** Implementation of the "writefile(W,X[,Y]])" SQL function. -** -** The argument X is written into file W. The number of bytes written is -** returned. Or NULL is returned if something goes wrong, such as being unable -** to open file X for writing. +** Implementation of the "writefile(W,X[,Y[,Z]]])" SQL function. +** Refer to header comments at the top of this file for details. */ static void writefileFunc( sqlite3_context *context, @@ -203,8 +270,9 @@ static void writefileFunc( const char *zFile; mode_t mode = 0; int res; + sqlite3_int64 mtime = -1; - if( argc<2 || argc>3 ){ + if( argc<2 || argc>4 ){ sqlite3_result_error(context, "wrong number of arguments to function writefile()", -1 ); @@ -214,18 +282,20 @@ static void writefileFunc( zFile = (const char*)sqlite3_value_text(argv[0]); if( zFile==0 ) return; if( argc>=3 ){ - sqlite3_result_int(context, 0); mode = sqlite3_value_int(argv[2]); } + if( argc==4 ){ + mtime = sqlite3_value_int64(argv[3]); + } - res = writeFile(context, zFile, mode, argv[1]); + res = writeFile(context, zFile, argv[1], mode, mtime); if( res==1 && errno==ENOENT ){ if( makeDirectory(zFile, mode)==SQLITE_OK ){ - res = writeFile(context, zFile, mode, argv[1]); + res = writeFile(context, zFile, argv[1], mode, mtime); } } - if( res!=0 ){ + if( argc>2 && res!=0 ){ if( S_ISLNK(mode) ){ ctxErrorMsg(context, "failed to create symlink: %s", zFile); }else if( S_ISDIR(mode) ){ @@ -313,6 +383,10 @@ static int fsdirOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ return SQLITE_OK; } +/* +** Reset a cursor back to the state it was in when first returned +** by fsdirOpen(). +*/ static void fsdirResetCursor(fsdir_cursor *pCur){ int i; for(i=0; i<=pCur->iLvl; i++){ @@ -341,6 +415,10 @@ static int fsdirClose(sqlite3_vtab_cursor *cur){ return SQLITE_OK; } +/* +** Set the error message for the virtual table associated with cursor +** pCur to the results of vprintf(zFmt, ...). +*/ static void fsdirSetErrmsg(fsdir_cursor *pCur, const char *zFmt, ...){ va_list ap; va_start(ap, zFmt); @@ -586,6 +664,9 @@ static int fsdirBestIndex( return SQLITE_OK; } +/* +** Register the "fsdir" virtual table. +*/ static int fsdirRegister(sqlite3 *db){ static sqlite3_module fsdirModule = { 0, /* iVersion */ @@ -611,9 +692,6 @@ static int fsdirRegister(sqlite3 *db){ }; int rc = sqlite3_create_module(db, "fsdir", &fsdirModule, 0); - if( rc==SQLITE_OK ){ - rc = sqlite3_create_module(db, "fsentry", &fsdirModule, (void*)1); - } return rc; } #else /* SQLITE_OMIT_VIRTUALTABLE */ |