From: drh <> Date: Mon, 23 Feb 2026 00:57:00 +0000 (+0000) Subject: Improved implementation of realpath() in the fileio.c extension that does not require X-Git-Tag: version-3.52.0~43 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=95fe5b9c38ca5700c21b8c3e6eee9dcaad4a0fa1;p=thirdparty%2Fsqlite.git Improved implementation of realpath() in the fileio.c extension that does not require the last element of the path to actually exist. FossilOrigin-Name: 4df4999484d9008d8af3c9c340810e0cf5f57161ba053ed5501276b450577039 --- diff --git a/ext/misc/fileio.c b/ext/misc/fileio.c index 876b397c70..e103d42332 100644 --- a/ext/misc/fileio.c +++ b/ext/misc/fileio.c @@ -94,6 +94,8 @@ SQLITE_EXTENSION_INIT1 # include # include # define STRUCT_STAT struct stat +# include +# include #else # include "windirent.h" # include @@ -1055,26 +1057,20 @@ static int fsdirRegister(sqlite3 *db){ #endif /* -** The realpath() C-language function, implemented as an SQL function. +** This version of realpath() works on any system. The string +** returned is held in memory allocated using sqlite3_malloc64(). +** The caller is responsible for calling sqlite3_free(). */ -static void realpathFunc( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ +static char *portable_realpath(const char *zPath){ #if !defined(_WIN32) /* BEGIN unix */ - const char *zPath; /* Input */ char *zOut = 0; /* Result */ - char *z = 0; /* Temporary buffer */ + char *z; /* Temporary buffer */ #if defined(PATH_MAX) char zBuf[PATH_MAX+1]; /* Space for the temporary buffer */ #endif - (void)argc; - zPath = (const char*)sqlite3_value_text(argv[0]); - if( zPath==0 ) return; - + if( zPath==0 ) return 0; #if defined(PATH_MAX) z = realpath(zPath, zBuf); if( z ){ @@ -1089,36 +1085,81 @@ static void realpathFunc( free(z); } } + return zOut; #else /* End UNIX, Begin WINDOWS */ - const char *zPath; /* Input */ wchar_t *zPath16; /* UTF16 translation of zPath */ char *zOut = 0; /* Result */ wchar_t *z = 0; /* Temporary buffer */ - (void)argc; - zPath = (const char*)sqlite3_value_text(argv[0]); - if( zPath==0 ) return; + if( zPath==0 ) return 0; zPath16 = sqlite3_win32_utf8_to_unicode(zPath); - if( zPath16==0 ) return; + if( zPath16==0 ) return 0; z = _wfullpath(NULL, zPath16, 0); sqlite3_free(zPath16); - if( z==0 ){ - sqlite3_result_error(context, "unable to resolve path", -1); - return; + if( z ){ + zOut = sqlite3_win32_unicode_to_utf8(z); + free(z); } - zOut = sqlite3_win32_unicode_to_utf8(z); - free(z); + return zOut; #endif /* End WINDOWS, Begin common code */ +} - if( zOut==0 ){ - sqlite3_result_error(context, "unable to resolve path", -1); - return; +/* +** SQL function: realpath(X) +** +** Try to convert file or pathname X into its real, absolute pathname. +** Return NULL if unable. +** +** The file X is not required to exist. However, if any directory +** in the path to X does not exist, then the function returns NULL. +*/ +static void realpathFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + const char *zPath; + char *zOut; +#ifdef _WIN32 + const int isWin = 1; +#else + const int isWin = 0; +#endif + + (void)argc; + zPath = (const char*)sqlite3_value_text(argv[0]); + if( zPath==0 ) return; + if( zPath[0]==0 ) zPath = "."; + zOut = portable_realpath(zPath); + if( zOut==0 + && (strchr(zPath,'/') || (isWin && strchr(zPath,'\\'))) + ){ + char *zCopy = sqlite3_mprintf("%s", zPath); + size_t i; + char cSep = 0; + if( zCopy==0 ) return; + for(i = strlen(zCopy) - 1; i>0; i--){ + if( zCopy[i]=='/' || (isWin && zCopy[i]=='\\') ){ + cSep = zCopy[i]; + zCopy[i] = 0; + break; + } + } + if( cSep ){ + zOut = portable_realpath(zCopy); + if( zOut ){ + zOut = sqlite3_mprintf("%z%c%s",zOut,cSep,&zCopy[i+1]); + } + } + sqlite3_free(zCopy); + } + if( zOut ){ + sqlite3_result_text(context, zOut, -1, sqlite3_free); } - sqlite3_result_text(context, zOut, -1, sqlite3_free); } @@ -1153,6 +1194,5 @@ int sqlite3_fileio_init( SQLITE_UTF8, 0, realpathFunc, 0, 0); } - return rc; } diff --git a/manifest b/manifest index 93d063c618..f368ebcd13 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\srealpath()\sSQL\sfunction\sto\sthe\sfileio.c\sextension.\s\sAnd\sclean\sup\nthe\sUTF8\shandling\son\sthe\sWindows\sside\sof\sthat\sextension\swhile\swe\sare\sat\sit. -D 2026-02-22T20:44:52.610 +C Improved\simplementation\sof\srealpath()\sin\sthe\sfileio.c\sextension\sthat\sdoes\snot\srequire\nthe\slast\selement\sof\sthe\spath\sto\sactually\sexist. +D 2026-02-23T00:57:00.749 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -373,7 +373,7 @@ F ext/misc/dbdump.c 678f1b9ae2317b4473f65d03132a2482c3f4b08920799ed80feedd2941a0 F ext/misc/decimal.c e1da22eee70d7e3eaa99a6b761bc03c4d01d7ffa554bf3178b1f1f184932806c F ext/misc/eval.c 04bc9aada78c888394204b4ed996ab834b99726fb59603b0ee3ed6e049755dc1 F ext/misc/explain.c 606100185fb90d6a1eade1ed0414d53503c86820d8956a06e3b0a56291894f2b -F ext/misc/fileio.c 6bbde149252e989fce657bfba66754dd7c545311546292cf33976e6b455a658c +F ext/misc/fileio.c 43f44347a4b70d22a7c1a68f799dc4ec4c58e39d84f04cebc6f669c6eadcb09b F ext/misc/fossildelta.c 86dfa83f85f7ccd640591d8a5c6865346d0c2ee6a949d78591eceb892f1cbfec F ext/misc/fuzzer.c 6b231352815304ba60d8e9ec2ee73d4918e74d9b76bda8940ba2b64e8777515e F ext/misc/ieee754.c 2901d08a586d00a1d3c0fd89e03c57ee9e2b5f013b0daab9e49c7a48a9d5946b @@ -2195,8 +2195,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P c30cee1224904eb2092daa0ad9494aec7c7a8c6c1661f5b91b62c3ef0c5ea95b -R a026dfab96aebae2bd7cee1e81138b75 +P 8bb8941930378b436f1353603be194644568b55fe347475be0caddddad40efa3 +R 655393f8c2d5cab161b45421e875ddda U drh -Z 7731fd8c09c5128d6fba3a643ba9f80c +Z 730476000580ff31324acec73800a8e3 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 4077fe2836..dbb7963f69 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -8bb8941930378b436f1353603be194644568b55fe347475be0caddddad40efa3 +4df4999484d9008d8af3c9c340810e0cf5f57161ba053ed5501276b450577039