diff --git a/Makefile.msc b/Makefile.msc index d03e9cfd8b..d8f01d650f 100644 --- a/Makefile.msc +++ b/Makefile.msc @@ -15,6 +15,12 @@ USE_AMALGAMATION = 1 # USE_ICU = 0 +# Set this non-0 to compile binaries suitable for the WinRT environment. +# This setting does not apply to any binaries that require Tcl to operate +# properly (i.e. the text fixture, etc). +# +FOR_WINRT = 0 + # Set this to non-0 to create and use PDBs. # SYMBOLS = 1 @@ -32,16 +38,10 @@ SYMBOLS = 1 # DEBUG = 0 -# Version numbers and release number for the SQLite being compiled. -# -VERSION = 3.7 -VERSION_NUMBER = 3007009 -RELEASE = 3.7.9 - # C Compiler and options for use in building executables that # will run on the platform that is doing the build. # -BCC = cl.exe +BCC = cl.exe -W3 # C Compile and options for use in building executables that # will run on the target platform. (BCC and TCC are usually the @@ -49,7 +49,18 @@ BCC = cl.exe # TCC = cl.exe -W3 -DSQLITE_OS_WIN=1 -I. -I$(TOP)\src -fp:precise -# The mksqlite3c.tcl and mksqlite3h.tcl scripts will pull in +# When compiling the library for use in the WinRT environment, +# the following compile-time options must be used as well to +# disable use of Win32 APIs that are not available and to enable +# use of Win32 APIs that are specific to Windows 8 and/or WinRT. +# Also, we need to dynamically link to the MSVC runtime when +# compiling for WinRT. +# +!IF $(FOR_WINRT)!=0 +TCC = $(TCC) -DSQLITE_OS_WINRT=1 -MD +!ENDIF + +# The mksqlite3c.tcl and mksqlite3h.tcl scripts will pull in # any extension header files by default. For non-amalgamation # builds, we need to make sure the compiler can find these. # @@ -64,6 +75,7 @@ TCC = $(TCC) -I$(TOP)\ext\rtree # !IF $(DEBUG)==0 TCC = $(TCC) -DNDEBUG +BCC = $(BCC) -DNDEBUG !ENDIF !IF $(DEBUG)>1 @@ -82,6 +94,7 @@ TCC = $(TCC) -DSQLITE_ENABLE_IOTRACE # Prevent warnings about "insecure" runtime library functions being used. # TCC = $(TCC) -D_CRT_SECURE_NO_DEPRECATE -D_CRT_SECURE_NO_WARNINGS +BCC = $(BCC) -D_CRT_SECURE_NO_DEPRECATE -D_CRT_SECURE_NO_WARNINGS # # Use native Win32 heap instead of malloc/free? @@ -194,12 +207,15 @@ TCC = $(TCC) $(OPTS) # If debugging is enabled, disable all optimizations and enable PDBs. !IF $(DEBUG)>0 TCC = $(TCC) -Od -D_DEBUG +BCC = $(BCC) -Od -D_DEBUG !ELSE TCC = $(TCC) -O2 +BCC = $(BCC) -O2 !ENDIF !IF $(DEBUG)>0 || $(SYMBOLS)!=0 TCC = $(TCC) -Zi +BCC = $(BCC) -Zi !ENDIF # If ICU support is enabled, add the compiler options for it. @@ -223,9 +239,18 @@ LTLINKOPTS = /MACHINE:$(PLATFORM) LTLIBOPTS = /MACHINE:$(PLATFORM) !ENDIF -# If debugging is enabled, enable PDBs. +# When compiling for use in the WinRT environment, the following +# linker option must be used to mark the executable as runnable +# only in the context of an application container. +# +!IF $(FOR_WINRT)!=0 +LTLINKOPTS = $(LTLINKOPTS) /APPCONTAINER +!ENDIF + +# If either debugging or symbols are enabled, enable PDBs. !IF $(DEBUG)>0 || $(SYMBOLS)!=0 LTLINKOPTS = $(LTLINKOPTS) /DEBUG +BCC = $(BCC) /DEBUG !ENDIF # Start with the Tcl related linker options. diff --git a/manifest b/manifest index 5ff19581aa..1c81e6070a 100644 --- a/manifest +++ b/manifest @@ -1,9 +1,9 @@ -C Disable\sFTS\sunicode61\sby\sdefault.\sIt\sis\senabled\sby\sspecifying\scompile\stime\soption\sSQLITE_ENABLE_FTS4_UNICODE61. -D 2012-06-06T19:51:27.734 +C Merge\sthe\schanges\sneed\sto\scompile\son\sWinRT\sinto\strunk. +D 2012-06-06T23:23:23.374 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 4f37eb61be9d38643cdd839a74b8e3bad724cfcf F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 -F Makefile.msc 0891f992d012d6b2976f86e80a82ae6839fa9ded +F Makefile.msc fd86027849a59a2f621b791b79eabf3f8ffbd684 F Makefile.vxworks 3b7fe7a0571fdadc61363ebc1b23732d2d6363ca F README cd04a36fbc7ea56932a4052d7d0b7f09f27c33d6 F VERSION 3e857b9b826e818eec9411eafe2c3fa22c1dbb8a @@ -129,7 +129,7 @@ F src/btreeInt.h 38a639c0542c29fe8331a221c4aed0cb8686249e F src/build.c 47c4506afe4bcb4ed1f4b5357582d1cb3402f8ad F src/callback.c 0cb4228cdcd827dcc5def98fb099edcc9142dbcd F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac -F src/ctime.c a9c26822515f81ec21588cbb482ca6724be02e33 +F src/ctime.c 500d019da966631ad957c37705642be87524463b F src/date.c 067a81c9942c497aafd2c260e13add8a7d0c7dd4 F src/delete.c 4c20ea4f6213b3bc1c6a510586864b679946e05e F src/expr.c 06a7733d19dc725dc46ba51afd9feadb4b85d991 @@ -145,7 +145,7 @@ F src/journal.c 552839e54d1bf76fb8f7abe51868b66acacf6a0e F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f F src/lempar.c 0ee69fca0be54cd93939df98d2aca4ca46f44416 F src/loadext.c f20382fbaeec832438a1ba7797bee3d3c8a6d51d -F src/main.c 41bfe7e14319b44f6322332bce2b48599e524f75 +F src/main.c 81e75dd5b37122369927b400b9e1322b73d725a7 F src/malloc.c fe085aa851b666b7c375c1ff957643dc20a04bf6 F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c b3677415e69603d6a0e7c5410a1b3731d55beda1 @@ -158,21 +158,21 @@ F src/mutex.h 2a79e0c10c26412546b501ee0f3d92b42decf63e F src/mutex_noop.c 7682796b7d8d39bf1c138248858efcd10c9e1553 F src/mutex_os2.c 882d735098c07c8c6a5472b8dd66e19675fe117f F src/mutex_unix.c c3a4e00f96ba068a8dbef34084465979aaf369cc -F src/mutex_w32.c 5e54f3ba275bcb5d00248b8c23107df2e2f73e33 +F src/mutex_w32.c 1170f64d08dc35cd43f6d0bfa833cac5da979279 F src/notify.c 976dd0f6171d4588e89e874fcc765e92914b6d30 F src/os.c e1acdc09ff3ac2412945cca9766e2dcf4675f31c -F src/os.h 59beba555b65a450bd1d804220532971d4299f60 +F src/os.h 38aabd5e3ecd4162332076f55bb09cec02165cca F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04 F src/os_os2.c 4a75888ba3dfc820ad5e8177025972d74d7f2440 F src/os_unix.c d7c96b5d140f550f07345870112fae5d7ef99757 -F src/os_win.c 412d6434133c7c81dc48b7702f3ea5e61c309e5c +F src/os_win.c e3d3d3e26b65a35d4293d753137a58510bd3299b F src/pager.c 9d4d6406512002d9a243ec27b9c01e93fda43e36 F src/pager.h 8b8c9bc065a3c66769df8724dfdf492ee1aab3c5 F src/parse.y f29df90bd3adc64b33114ab1de9fb7768fcf2099 F src/pcache.c f8043b433a57aba85384a531e3937a804432a346 F src/pcache.h 1b5dcc3dc8103d03e625b177023ee67764fa6b7c F src/pcache1.c b30b1c35908346ecc43d8d9d17f2ddf6817f8f60 -F src/pragma.c 28d7955a9e9a27d41cb462690228d39e3cec231c +F src/pragma.c eee3e3161f82a1e06f632a8d2a82b29ba3c45889 F src/prepare.c 33291b83cca285718048d219c67b8298501fa3a5 F src/printf.c 7ffb4ebb8b341f67e049695ba031da717b3d2699 F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50 @@ -180,14 +180,14 @@ F src/resolve.c b3c70ab28cac60de33684c9aa9e5138dcf71d6dd F src/rowset.c f6a49f3e9579428024662f6e2931832511f831a1 F src/select.c f6c4833c4d8e94714761d99013d74f381e084f1d F src/shell.c c16f72e34f611f060546709564c121a67cb2b31b -F src/sqlite.h.in 922d2907cc2b0177b2c4a3b462f04937750d6edd +F src/sqlite.h.in f801a04e1ebd1c7f958017661545422ada06b9ce F src/sqlite3ext.h 6904f4aadf976f95241311fbffb00823075d9477 F src/sqliteInt.h 29b5348f0056d9b46d0bb94d4853db21568afde9 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c 35939e7e03abf1b7577ce311f48f682c40de3208 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e F src/tclsqlite.c fe5406573e1527957e00dcaf51edd9d8bd31b918 -F src/test1.c a808bfa548a501b513579bdbaf83901c98e059c9 +F src/test1.c fc2acf0a2db517c8d19e5e55bda8e1237db77378 F src/test2.c 4178056dd1e7d70f954ad8a1e3edb71a2a784daf F src/test3.c 3c3c2407fa6ec7a19e24ae23f7cb439d0275a60d F src/test4.c d1e5a5e904d4b444cf572391fdcb017638e36ff7 @@ -200,7 +200,7 @@ F src/test_async.c 0612a752896fad42d55c3999a5122af10dcf22ad F src/test_autoext.c 30e7bd98ab6d70a62bb9ba572e4c7df347fe645e F src/test_backup.c c129c91127e9b46e335715ae2e75756e25ba27de F src/test_btree.c 5b89601dcb42a33ba8b820a6b763cc9cb48bac16 -F src/test_config.c 86c4b1897fab385c949db398995eef3b75a2f1ad +F src/test_config.c 4f7b8030287d62fe56a1d99e68b41760feae381a F src/test_demovfs.c 20a4975127993f4959890016ae9ce5535a880094 F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc F src/test_func.c 090f2c3339e85c2c964435f99aed6f3da9d59525 @@ -296,8 +296,8 @@ F test/badutf.test d5360fc31f643d37a973ab0d8b4fb85799c3169f F test/badutf2.test f5bc7f2d280670ecd79b9cf4f0f1760c607fe51f F test/bc_common.tcl 5c8689cc6d2fb44b7c0968ae4f85eb26d50022fa F test/between.test 16b1776c6323faadb097a52d673e8e3d8be7d070 -F test/bigfile.test 82dfe93ee7eb9e2e05641afa2b39ffd947a92ff1 -F test/bigfile2.test 852f948cb492aadab45b58f4d2f3b0832a115cb0 +F test/bigfile.test 8f88b5ef065e31c615c49d725ede94155fbe9609 +F test/bigfile2.test 8a3c242c3c3481e7cde5a6ef2a66fdc367a095f7 F test/bigrow.test f0aeb7573dcb8caaafea76454be3ade29b7fc747 F test/bind.test 3c7b320969000c441a70952b0b15938fbb66237c F test/bindxfer.test efecd12c580c14df5f4ad3b3e83c667744a4f7e0 @@ -389,7 +389,7 @@ F test/e_resolve.test dcce9308fb13b934ce29591105d031d3e14fbba6 F test/e_select.test f5d4b81205701deacfae42051ae200969c41d2c0 F test/e_select2.test 5c3d3da19c7b3e90ae444579db2b70098599ab92 F test/e_update.test 161d5dc6a3ed9dd08f5264d13e20735d7a89f00c -F test/e_uri.test cd2ddb4494c7ebf30b6e3539645bb4e54c0104b9 +F test/e_uri.test 32b8e0b99a0e215f25996516c64b90c525810d02 F test/e_vacuum.test 331da289ae186656cf5f2eb27f577a89c0c221af F test/enc.test e54531cd6bf941ee6760be041dff19a104c7acea F test/enc2.test 796c59832e2b9a52842f382ffda8f3e989db03ad @@ -611,7 +611,7 @@ F test/minmax.test 722d80816f7e096bf2c04f4111f1a6c1ba65453d F test/minmax2.test 33504c01a03bd99226144e4b03f7631a274d66e0 F test/minmax3.test cc1e8b010136db0d01a6f2a29ba5a9f321034354 F test/minmax4.test 536a3360470633a177e42fbc19660d146b51daef -F test/misc1.test 55cb2bfbf4a8cd61f4be1effc30426ad41696bff +F test/misc1.test 889b40722442380a2f6575f30831b32b2372d70e F test/misc2.test 00d7de54eda90e237fc9a38b9e5ccc769ebf6d4d F test/misc3.test fe55130a43e444ee75e2156ff75dc96e964b5738 F test/misc4.test 9c078510fbfff05a9869a0b6d8b86a623ad2c4f6 @@ -632,7 +632,7 @@ F test/notnull.test cc7c78340328e6112a13c3e311a9ab3127114347 F test/null.test a8b09b8ed87852742343b33441a9240022108993 F test/openv2.test 0d3040974bf402e19b7df4b783e447289d7ab394 F test/oserror.test 50417780d0e0d7cd23cf12a8277bb44024765df3 -F test/pager1.test 31fef8ff6d5cbb4643f430e31756312d361ecfdf +F test/pager1.test 2163c6ef119f497a71a84137c957c63763e640ab F test/pager2.test 745b911dde3d1f24ae0870bd433dfa83d7c658c1 F test/pager3.test 3856d9c80839be0668efee1b74811b1b7f7fc95f F test/pagerfault.test 452f2cc23e3bfcfa935f4442aec1da4fe1dc0442 @@ -643,15 +643,15 @@ F test/pagesize.test 1dd51367e752e742f58e861e65ed7390603827a0 F test/pcache.test 065aa286e722ab24f2e51792c1f093bf60656b16 F test/pcache2.test a83efe2dec0d392f814bfc998def1d1833942025 F test/permutations.test ea7b6948eaa22993fcfa662eb704ce29ddb24b2a -F test/pragma.test c51c148defe32bf4a419a522f95d26838d5cf677 +F test/pragma.test cb736bcc75b8b629af21ac0ad83ba1d054a2107b F test/pragma2.test 3a55f82b954242c642f8342b17dffc8b47472947 F test/printf.test ec9870c4dce8686a37818e0bf1aba6e6a1863552 F test/progress.test 5b075c3c790c7b2a61419bc199db87aaf48b8301 F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc F test/quick.test 1681febc928d686362d50057c642f77a02c62e57 F test/quota-glob.test 32901e9eed6705d68ca3faee2a06b73b57cb3c26 -F test/quota.test c2f778dab4c7fb07bcfa962cc5c762f36d8061dc -F test/quota2.test 52175f1c94fb01711da38095a7d3988d0c7d6575 +F test/quota.test b5b3eec55a059e0fe493c66c6e27bd2c07676cfd +F test/quota2.test 6d2bd57e8a4da28817f46db9da18551211cd325f F test/quote.test 215897dbe8de1a6f701265836d6601cc6ed103e6 F test/randexpr1.tcl 40dec52119ed3a2b8b2a773bce24b63a3a746459 F test/randexpr1.test eda062a97e60f9c38ae8d806b03b0ddf23d796df @@ -689,7 +689,7 @@ F test/selectA.test 06d1032fa9009314c95394f2ca2e60d9f7ae8532 F test/selectB.test 954e4e49cf1f896d61794e440669e03a27ceea25 F test/selectC.test 871fb55d884d3de5943c4057ebd22c2459e71977 F test/server1.test 46803bd3fe8b99b30dbc5ff38ffc756f5c13a118 -F test/shared.test 64fe647f17b2de0622437829a9e9823c20439fce +F test/shared.test 1acdf03fef43ea13604786424de8c4908170eece F test/shared2.test 03eb4a8d372e290107d34b6ce1809919a698e879 F test/shared3.test ebf77f023f4bdaa8f74f65822b559e86ce5c6257 F test/shared4.test 72d90821e8d2fc918a08f16d32880868d8ee8e9d @@ -698,7 +698,7 @@ F test/shared7.test 960760bc8d03e1419e70dea69cf41db62853616e F test/shared8.test b27befbefbe7f4517f1d6b7ff8f64a41ec74165d F test/shared_err.test 91e26ec4f3fbe07951967955585137e2f18993de F test/sharedlock.test ffa0a3c4ac192145b310f1254f8afca4d553eabf -F test/shell1.test 6e3013bc50e2b73f00d17e491f776decc82a71c8 +F test/shell1.test 9895ee3013742a02e5afd8d77793729967ffd195 F test/shell2.test 037d6ad16e873354195d30bb2dc4b5321788154a F test/shell3.test 9196c42772d575685e722c92b4b39053c6ebba59 F test/shell4.test aa4eef8118b412d1a01477a53426ece169ea86a9 @@ -734,7 +734,7 @@ F test/tclsqlite.test 1597d353308531527583481d14d9da52ea8ed0af F test/tempdb.test 19d0f66e2e3eeffd68661a11c83ba5e6ace9128c F test/temptable.test 51edd31c65ed1560dd600b1796e8325df96318e2 F test/temptrigger.test 26670ed7a39cf2296a7f0a9e0a1d7bdb7abe936d -F test/tester.tcl a55e066251bc05e26f9da00e76644ab649b26f3c +F test/tester.tcl 2665f64c9ce71944b4d41269114e658fb81bda05 F test/thread001.test 7cc2ce08f9cde95964736d11e91f9ab610f82f91 F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58 F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7 @@ -898,7 +898,7 @@ F test/unique.test 083c7fff74695bcc27a71d75699deba3595bc9c2 F test/unixexcl.test a9870e46cc6f8390a494513d4f2bf55b5a8b3e46 F test/unordered.test f53095cee37851bf30130fa1bf299a8845e837bb F test/update.test 8bc86fd7ef1a00014f76dc6a6a7c974df4aef172 -F test/uri.test 78e869db1ff6331157b08ef089b1b3e65819c74c +F test/uri.test 63e03df051620a18f794b4f4adcdefb3c23b6751 F test/utf16align.test 54cd35a27c005a9b6e7815d887718780b6a462ae F test/vacuum.test ce91c39f7f91a4273bf620efad21086b5aa6ef1d F test/vacuum2.test af432e6e3bfc0ea20a80cb86a03c7d9876d38324 @@ -925,7 +925,7 @@ F test/vtabF.test fd5ad376f5a34fe0891df1f3cddb4fe7c3eb077e F test/vtab_alter.test 9e374885248f69e251bdaacf480b04a197f125e5 F test/vtab_err.test 0d4d8eb4def1d053ac7c5050df3024fd47a3fbd8 F test/vtab_shared.test 82f463886e18d7f8395a4b6167c91815efe54839 -F test/wal.test b3d28d655371bf3f6500c679f526e9860544fe70 +F test/wal.test a040047d7f2b9f34bc4d597964e5e7c09609c635 F test/wal2.test d5021064bebfc717fe2bf4db2536ea030b76a773 F test/wal3.test 6504bbf348b2d6dfade64a064f1050fd617e8706 F test/wal4.test 4744e155cd6299c6bd99d3eab1c82f77db9cdb3c @@ -1005,7 +1005,7 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/warnings-clang.sh a8a0a3babda96dfb1ff51adda3cbbf3dfb7266c2 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 -P 790f76a5898dad1a955d40edddf11f7b0fec0ccd -R b3b020dfaa40a6b886085c7104befb05 -U dan -Z abcc18c27a4be2466863f9b79938e60e +P eccd6b6580637084495b80e9232262188ba0cf8d 8e8590a4dc8d9b0fa12ce288cdfd0146223fee6c +R e54f5d64d1e08d0a0f77f7e82ee4ca4c +U drh +Z b901cb0ca598db2780e99899aea938ab diff --git a/manifest.uuid b/manifest.uuid index 19e951b739..ba2b7d5362 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -eccd6b6580637084495b80e9232262188ba0cf8d \ No newline at end of file +61360ca6ca3448477d5c662d3642beef6dd2079e \ No newline at end of file diff --git a/src/ctime.c b/src/ctime.c index 1688069cb3..61cf4e3df1 100644 --- a/src/ctime.c +++ b/src/ctime.c @@ -48,6 +48,9 @@ static const char * const azCompileOpt[] = { #ifdef SQLITE_COVERAGE_TEST "COVERAGE_TEST", #endif +#ifdef SQLITE_CURDIR + "CURDIR", +#endif #ifdef SQLITE_DEBUG "DEBUG", #endif diff --git a/src/main.c b/src/main.c index f1ac2542d9..8906592dfc 100644 --- a/src/main.c +++ b/src/main.c @@ -74,6 +74,15 @@ void (*sqlite3IoTrace)(const char*, ...) = 0; */ char *sqlite3_temp_directory = 0; +/* +** If the following global variable points to a string which is the +** name of a directory, then that directory will be used to store +** all database files specified with a relative pathname. +** +** See also the "PRAGMA data_store_directory" SQL command. +*/ +char *sqlite3_data_directory = 0; + /* ** Initialize SQLite. ** @@ -272,6 +281,18 @@ int sqlite3_shutdown(void){ if( sqlite3GlobalConfig.isMallocInit ){ sqlite3MallocEnd(); sqlite3GlobalConfig.isMallocInit = 0; + +#ifndef SQLITE_OMIT_SHUTDOWN_DIRECTORIES + /* The heap subsystem has now been shutdown and these values are supposed + ** to be NULL or point to memory that was obtained from sqlite3_malloc(), + ** which would rely on that heap subsystem; therefore, make sure these + ** values cannot refer to heap memory that was just invalidated when the + ** heap subsystem was shutdown. This is only done if the current call to + ** this function resulted in the heap subsystem actually being shutdown. + */ + sqlite3_data_directory = 0; + sqlite3_temp_directory = 0; +#endif } if( sqlite3GlobalConfig.isMutexInit ){ sqlite3MutexEnd(); diff --git a/src/mutex_w32.c b/src/mutex_w32.c index bfd9dacf6c..3717900608 100644 --- a/src/mutex_w32.c +++ b/src/mutex_w32.c @@ -109,18 +109,24 @@ static int winMutex_isInit = 0; */ static long winMutex_lock = 0; +extern void sqlite3_win32_sleep(DWORD milliseconds); /* os_win.c */ + static int winMutexInit(void){ /* The first to increment to 1 does actual initialization */ if( InterlockedCompareExchange(&winMutex_lock, 1, 0)==0 ){ int i; for(i=0; iid = iType; #endif +#if SQLITE_OS_WINRT + InitializeCriticalSectionEx(&p->mutex, 0, 0); +#else InitializeCriticalSection(&p->mutex); +#endif } break; } diff --git a/src/os.h b/src/os.h index 7dc0c8c2fb..2efffff9b6 100644 --- a/src/os.h +++ b/src/os.h @@ -65,13 +65,11 @@ # endif #endif -/* -** Define the maximum size of a temporary filename -*/ #if SQLITE_OS_WIN # include -# define SQLITE_TEMPNAME_SIZE (MAX_PATH+50) -#elif SQLITE_OS_OS2 +#endif + +#if SQLITE_OS_OS2 # if (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ >= 3) && defined(OS2_HIGH_MEMORY) # include /* has to be included before os2.h for linking to work */ # endif @@ -84,9 +82,6 @@ # define INCL_DOSSEMAPHORES # include # include -# define SQLITE_TEMPNAME_SIZE (CCHMAXPATHCOMP) -#else -# define SQLITE_TEMPNAME_SIZE 200 #endif /* @@ -120,6 +115,22 @@ # define SQLITE_OS_WINCE 0 #endif +/* +** Determine if we are dealing with WindowsRT (Metro) as this has a different and +** incompatible API from win32. +*/ +#if !defined(SQLITE_OS_WINRT) +# define SQLITE_OS_WINRT 0 +#endif + +/* +** When compiled for WinCE or WinRT, there is no concept of the current +** directory. + */ +#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT +# define SQLITE_CURDIR 1 +#endif + /* If the SET_FULLSYNC macro is not defined above, then make it ** a no-op */ diff --git a/src/os_win.c b/src/os_win.c index fcfe0118ed..8509e9272d 100644 --- a/src/os_win.c +++ b/src/os_win.c @@ -24,6 +24,13 @@ */ #include "os_common.h" +/* +** Macro to find the minimum of two numeric values. +*/ +#ifndef MIN +# define MIN(x,y) ((x)<(y)?(x):(y)) +#endif + /* ** Some Microsoft compilers lack this definition. */ @@ -31,6 +38,14 @@ # define INVALID_FILE_ATTRIBUTES ((DWORD)-1) #endif +#ifndef FILE_FLAG_MASK +# define FILE_FLAG_MASK (0xFF3C0000) +#endif + +#ifndef FILE_ATTRIBUTE_MASK +# define FILE_ATTRIBUTE_MASK (0x0003FFF7) +#endif + /* Forward references */ typedef struct winShm winShm; /* A connection to shared-memory */ typedef struct winShmNode winShmNode; /* A region of shared-memory */ @@ -79,11 +94,37 @@ struct winFile { #define WINFILE_PERSIST_WAL 0x04 /* Persistent WAL mode */ #define WINFILE_PSOW 0x10 /* SQLITE_IOCAP_POWERSAFE_OVERWRITE */ +/* + * The size of the buffer used by sqlite3_win32_write_debug(). + */ +#ifndef SQLITE_WIN32_DBG_BUF_SIZE +# define SQLITE_WIN32_DBG_BUF_SIZE ((int)(4096-sizeof(DWORD))) +#endif + /* * If compiled with SQLITE_WIN32_MALLOC on Windows, we will use the * various Win32 API heap functions instead of our own. */ #ifdef SQLITE_WIN32_MALLOC + +/* + * If this is non-zero, an isolated heap will be created by the native Win32 + * allocator subsystem; otherwise, the default process heap will be used. This + * setting has no effect when compiling for WinRT. By default, this is enabled + * and an isolated heap will be created to store all allocated data. + * + ****************************************************************************** + * WARNING: It is important to note that when this setting is non-zero and the + * winMemShutdown function is called (e.g. by the sqlite3_shutdown + * function), all data that was allocated using the isolated heap will + * be freed immediately and any attempt to access any of that freed + * data will almost certainly result in an immediate access violation. + ****************************************************************************** + */ +#ifndef SQLITE_WIN32_HEAP_CREATE +# define SQLITE_WIN32_HEAP_CREATE (TRUE) +#endif + /* * The initial size of the Win32-specific heap. This value may be zero. */ @@ -168,17 +209,11 @@ int sqlite3_os_type = 0; static int sqlite3_os_type = 0; #endif -/* -** Many system calls are accessed through pointer-to-functions so that -** they may be overridden at runtime to facilitate fault injection during -** testing and sandboxing. The following array holds the names and pointers -** to all overrideable system calls. -*/ -#if !SQLITE_OS_WINCE +#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT # define SQLITE_WIN32_HAS_ANSI #endif -#if SQLITE_OS_WINCE || SQLITE_OS_WINNT +#if SQLITE_OS_WINCE || SQLITE_OS_WINNT || SQLITE_OS_WINRT # define SQLITE_WIN32_HAS_WIDE #endif @@ -186,40 +221,35 @@ static int sqlite3_os_type = 0; # define SYSCALL sqlite3_syscall_ptr #endif -#if SQLITE_OS_WINCE /* -** These macros are necessary because Windows CE does not natively support the -** Win32 APIs LockFile, UnlockFile, and LockFileEx. - */ - -# define LockFile(a,b,c,d,e) winceLockFile(&a, b, c, d, e) -# define UnlockFile(a,b,c,d,e) winceUnlockFile(&a, b, c, d, e) -# define LockFileEx(a,b,c,d,e,f) winceLockFileEx(&a, b, c, d, e, f) - -/* -** These are the special syscall hacks for Windows CE. The locking related -** defines here refer to the macros defined just above. +** This function is not available on Windows CE or WinRT. */ +#if SQLITE_OS_WINCE || SQLITE_OS_WINRT # define osAreFileApisANSI() 1 -# define osLockFile LockFile -# define osUnlockFile UnlockFile -# define osLockFileEx LockFileEx #endif +/* +** Many system calls are accessed through pointer-to-functions so that +** they may be overridden at runtime to facilitate fault injection during +** testing and sandboxing. The following array holds the names and pointers +** to all overrideable system calls. +*/ static struct win_syscall { const char *zName; /* Name of the sytem call */ sqlite3_syscall_ptr pCurrent; /* Current value of the system call */ sqlite3_syscall_ptr pDefault; /* Default value */ } aSyscall[] = { -#if !SQLITE_OS_WINCE +#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT { "AreFileApisANSI", (SYSCALL)AreFileApisANSI, 0 }, - -#define osAreFileApisANSI ((BOOL(WINAPI*)(VOID))aSyscall[0].pCurrent) #else { "AreFileApisANSI", (SYSCALL)0, 0 }, #endif +#ifndef osAreFileApisANSI +#define osAreFileApisANSI ((BOOL(WINAPI*)(VOID))aSyscall[0].pCurrent) +#endif + #if SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_WIDE) { "CharLowerW", (SYSCALL)CharLowerW, 0 }, #else @@ -249,7 +279,7 @@ static struct win_syscall { #define osCreateFileA ((HANDLE(WINAPI*)(LPCSTR,DWORD,DWORD, \ LPSECURITY_ATTRIBUTES,DWORD,DWORD,HANDLE))aSyscall[4].pCurrent) -#if defined(SQLITE_WIN32_HAS_WIDE) +#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) { "CreateFileW", (SYSCALL)CreateFileW, 0 }, #else { "CreateFileW", (SYSCALL)0, 0 }, @@ -258,28 +288,23 @@ static struct win_syscall { #define osCreateFileW ((HANDLE(WINAPI*)(LPCWSTR,DWORD,DWORD, \ LPSECURITY_ATTRIBUTES,DWORD,DWORD,HANDLE))aSyscall[5].pCurrent) - { "CreateFileMapping", (SYSCALL)CreateFileMapping, 0 }, - -#define osCreateFileMapping ((HANDLE(WINAPI*)(HANDLE,LPSECURITY_ATTRIBUTES, \ - DWORD,DWORD,DWORD,LPCTSTR))aSyscall[6].pCurrent) - -#if defined(SQLITE_WIN32_HAS_WIDE) +#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) { "CreateFileMappingW", (SYSCALL)CreateFileMappingW, 0 }, #else { "CreateFileMappingW", (SYSCALL)0, 0 }, #endif #define osCreateFileMappingW ((HANDLE(WINAPI*)(HANDLE,LPSECURITY_ATTRIBUTES, \ - DWORD,DWORD,DWORD,LPCWSTR))aSyscall[7].pCurrent) + DWORD,DWORD,DWORD,LPCWSTR))aSyscall[6].pCurrent) -#if defined(SQLITE_WIN32_HAS_WIDE) +#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) { "CreateMutexW", (SYSCALL)CreateMutexW, 0 }, #else { "CreateMutexW", (SYSCALL)0, 0 }, #endif #define osCreateMutexW ((HANDLE(WINAPI*)(LPSECURITY_ATTRIBUTES,BOOL, \ - LPCWSTR))aSyscall[8].pCurrent) + LPCWSTR))aSyscall[7].pCurrent) #if defined(SQLITE_WIN32_HAS_ANSI) { "DeleteFileA", (SYSCALL)DeleteFileA, 0 }, @@ -287,7 +312,7 @@ static struct win_syscall { { "DeleteFileA", (SYSCALL)0, 0 }, #endif -#define osDeleteFileA ((BOOL(WINAPI*)(LPCSTR))aSyscall[9].pCurrent) +#define osDeleteFileA ((BOOL(WINAPI*)(LPCSTR))aSyscall[8].pCurrent) #if defined(SQLITE_WIN32_HAS_WIDE) { "DeleteFileW", (SYSCALL)DeleteFileW, 0 }, @@ -295,7 +320,7 @@ static struct win_syscall { { "DeleteFileW", (SYSCALL)0, 0 }, #endif -#define osDeleteFileW ((BOOL(WINAPI*)(LPCWSTR))aSyscall[10].pCurrent) +#define osDeleteFileW ((BOOL(WINAPI*)(LPCWSTR))aSyscall[9].pCurrent) #if SQLITE_OS_WINCE { "FileTimeToLocalFileTime", (SYSCALL)FileTimeToLocalFileTime, 0 }, @@ -304,7 +329,7 @@ static struct win_syscall { #endif #define osFileTimeToLocalFileTime ((BOOL(WINAPI*)(CONST FILETIME*, \ - LPFILETIME))aSyscall[11].pCurrent) + LPFILETIME))aSyscall[10].pCurrent) #if SQLITE_OS_WINCE { "FileTimeToSystemTime", (SYSCALL)FileTimeToSystemTime, 0 }, @@ -313,11 +338,11 @@ static struct win_syscall { #endif #define osFileTimeToSystemTime ((BOOL(WINAPI*)(CONST FILETIME*, \ - LPSYSTEMTIME))aSyscall[12].pCurrent) + LPSYSTEMTIME))aSyscall[11].pCurrent) { "FlushFileBuffers", (SYSCALL)FlushFileBuffers, 0 }, -#define osFlushFileBuffers ((BOOL(WINAPI*)(HANDLE))aSyscall[13].pCurrent) +#define osFlushFileBuffers ((BOOL(WINAPI*)(HANDLE))aSyscall[12].pCurrent) #if defined(SQLITE_WIN32_HAS_ANSI) { "FormatMessageA", (SYSCALL)FormatMessageA, 0 }, @@ -326,7 +351,7 @@ static struct win_syscall { #endif #define osFormatMessageA ((DWORD(WINAPI*)(DWORD,LPCVOID,DWORD,DWORD,LPSTR, \ - DWORD,va_list*))aSyscall[14].pCurrent) + DWORD,va_list*))aSyscall[13].pCurrent) #if defined(SQLITE_WIN32_HAS_WIDE) { "FormatMessageW", (SYSCALL)FormatMessageW, 0 }, @@ -335,15 +360,15 @@ static struct win_syscall { #endif #define osFormatMessageW ((DWORD(WINAPI*)(DWORD,LPCVOID,DWORD,DWORD,LPWSTR, \ - DWORD,va_list*))aSyscall[15].pCurrent) + DWORD,va_list*))aSyscall[14].pCurrent) { "FreeLibrary", (SYSCALL)FreeLibrary, 0 }, -#define osFreeLibrary ((BOOL(WINAPI*)(HMODULE))aSyscall[16].pCurrent) +#define osFreeLibrary ((BOOL(WINAPI*)(HMODULE))aSyscall[15].pCurrent) { "GetCurrentProcessId", (SYSCALL)GetCurrentProcessId, 0 }, -#define osGetCurrentProcessId ((DWORD(WINAPI*)(VOID))aSyscall[17].pCurrent) +#define osGetCurrentProcessId ((DWORD(WINAPI*)(VOID))aSyscall[16].pCurrent) #if !SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_ANSI) { "GetDiskFreeSpaceA", (SYSCALL)GetDiskFreeSpaceA, 0 }, @@ -352,16 +377,16 @@ static struct win_syscall { #endif #define osGetDiskFreeSpaceA ((BOOL(WINAPI*)(LPCSTR,LPDWORD,LPDWORD,LPDWORD, \ - LPDWORD))aSyscall[18].pCurrent) + LPDWORD))aSyscall[17].pCurrent) -#if !SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_WIDE) +#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) { "GetDiskFreeSpaceW", (SYSCALL)GetDiskFreeSpaceW, 0 }, #else { "GetDiskFreeSpaceW", (SYSCALL)0, 0 }, #endif #define osGetDiskFreeSpaceW ((BOOL(WINAPI*)(LPCWSTR,LPDWORD,LPDWORD,LPDWORD, \ - LPDWORD))aSyscall[19].pCurrent) + LPDWORD))aSyscall[18].pCurrent) #if defined(SQLITE_WIN32_HAS_ANSI) { "GetFileAttributesA", (SYSCALL)GetFileAttributesA, 0 }, @@ -369,15 +394,15 @@ static struct win_syscall { { "GetFileAttributesA", (SYSCALL)0, 0 }, #endif -#define osGetFileAttributesA ((DWORD(WINAPI*)(LPCSTR))aSyscall[20].pCurrent) +#define osGetFileAttributesA ((DWORD(WINAPI*)(LPCSTR))aSyscall[19].pCurrent) -#if defined(SQLITE_WIN32_HAS_WIDE) +#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) { "GetFileAttributesW", (SYSCALL)GetFileAttributesW, 0 }, #else { "GetFileAttributesW", (SYSCALL)0, 0 }, #endif -#define osGetFileAttributesW ((DWORD(WINAPI*)(LPCWSTR))aSyscall[21].pCurrent) +#define osGetFileAttributesW ((DWORD(WINAPI*)(LPCWSTR))aSyscall[20].pCurrent) #if defined(SQLITE_WIN32_HAS_WIDE) { "GetFileAttributesExW", (SYSCALL)GetFileAttributesExW, 0 }, @@ -386,11 +411,15 @@ static struct win_syscall { #endif #define osGetFileAttributesExW ((BOOL(WINAPI*)(LPCWSTR,GET_FILEEX_INFO_LEVELS, \ - LPVOID))aSyscall[22].pCurrent) + LPVOID))aSyscall[21].pCurrent) +#if !SQLITE_OS_WINRT { "GetFileSize", (SYSCALL)GetFileSize, 0 }, +#else + { "GetFileSize", (SYSCALL)0, 0 }, +#endif -#define osGetFileSize ((DWORD(WINAPI*)(HANDLE,LPDWORD))aSyscall[23].pCurrent) +#define osGetFileSize ((DWORD(WINAPI*)(HANDLE,LPDWORD))aSyscall[22].pCurrent) #if !SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_ANSI) { "GetFullPathNameA", (SYSCALL)GetFullPathNameA, 0 }, @@ -399,20 +428,20 @@ static struct win_syscall { #endif #define osGetFullPathNameA ((DWORD(WINAPI*)(LPCSTR,DWORD,LPSTR, \ - LPSTR*))aSyscall[24].pCurrent) + LPSTR*))aSyscall[23].pCurrent) -#if !SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_WIDE) +#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) { "GetFullPathNameW", (SYSCALL)GetFullPathNameW, 0 }, #else { "GetFullPathNameW", (SYSCALL)0, 0 }, #endif #define osGetFullPathNameW ((DWORD(WINAPI*)(LPCWSTR,DWORD,LPWSTR, \ - LPWSTR*))aSyscall[25].pCurrent) + LPWSTR*))aSyscall[24].pCurrent) { "GetLastError", (SYSCALL)GetLastError, 0 }, -#define osGetLastError ((DWORD(WINAPI*)(VOID))aSyscall[26].pCurrent) +#define osGetLastError ((DWORD(WINAPI*)(VOID))aSyscall[25].pCurrent) #if SQLITE_OS_WINCE /* The GetProcAddressA() routine is only available on Windows CE. */ @@ -424,15 +453,19 @@ static struct win_syscall { #endif #define osGetProcAddressA ((FARPROC(WINAPI*)(HMODULE, \ - LPCSTR))aSyscall[27].pCurrent) + LPCSTR))aSyscall[26].pCurrent) +#if !SQLITE_OS_WINRT { "GetSystemInfo", (SYSCALL)GetSystemInfo, 0 }, +#else + { "GetSystemInfo", (SYSCALL)0, 0 }, +#endif -#define osGetSystemInfo ((VOID(WINAPI*)(LPSYSTEM_INFO))aSyscall[28].pCurrent) +#define osGetSystemInfo ((VOID(WINAPI*)(LPSYSTEM_INFO))aSyscall[27].pCurrent) { "GetSystemTime", (SYSCALL)GetSystemTime, 0 }, -#define osGetSystemTime ((VOID(WINAPI*)(LPSYSTEMTIME))aSyscall[29].pCurrent) +#define osGetSystemTime ((VOID(WINAPI*)(LPSYSTEMTIME))aSyscall[28].pCurrent) #if !SQLITE_OS_WINCE { "GetSystemTimeAsFileTime", (SYSCALL)GetSystemTimeAsFileTime, 0 }, @@ -441,7 +474,7 @@ static struct win_syscall { #endif #define osGetSystemTimeAsFileTime ((VOID(WINAPI*)( \ - LPFILETIME))aSyscall[30].pCurrent) + LPFILETIME))aSyscall[29].pCurrent) #if defined(SQLITE_WIN32_HAS_ANSI) { "GetTempPathA", (SYSCALL)GetTempPathA, 0 }, @@ -449,19 +482,23 @@ static struct win_syscall { { "GetTempPathA", (SYSCALL)0, 0 }, #endif -#define osGetTempPathA ((DWORD(WINAPI*)(DWORD,LPSTR))aSyscall[31].pCurrent) +#define osGetTempPathA ((DWORD(WINAPI*)(DWORD,LPSTR))aSyscall[30].pCurrent) -#if defined(SQLITE_WIN32_HAS_WIDE) +#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) { "GetTempPathW", (SYSCALL)GetTempPathW, 0 }, #else { "GetTempPathW", (SYSCALL)0, 0 }, #endif -#define osGetTempPathW ((DWORD(WINAPI*)(DWORD,LPWSTR))aSyscall[32].pCurrent) +#define osGetTempPathW ((DWORD(WINAPI*)(DWORD,LPWSTR))aSyscall[31].pCurrent) +#if !SQLITE_OS_WINRT { "GetTickCount", (SYSCALL)GetTickCount, 0 }, +#else + { "GetTickCount", (SYSCALL)0, 0 }, +#endif -#define osGetTickCount ((DWORD(WINAPI*)(VOID))aSyscall[33].pCurrent) +#define osGetTickCount ((DWORD(WINAPI*)(VOID))aSyscall[32].pCurrent) #if defined(SQLITE_WIN32_HAS_ANSI) { "GetVersionExA", (SYSCALL)GetVersionExA, 0 }, @@ -470,40 +507,52 @@ static struct win_syscall { #endif #define osGetVersionExA ((BOOL(WINAPI*)( \ - LPOSVERSIONINFOA))aSyscall[34].pCurrent) + LPOSVERSIONINFOA))aSyscall[33].pCurrent) { "HeapAlloc", (SYSCALL)HeapAlloc, 0 }, #define osHeapAlloc ((LPVOID(WINAPI*)(HANDLE,DWORD, \ - SIZE_T))aSyscall[35].pCurrent) + SIZE_T))aSyscall[34].pCurrent) +#if !SQLITE_OS_WINRT { "HeapCreate", (SYSCALL)HeapCreate, 0 }, +#else + { "HeapCreate", (SYSCALL)0, 0 }, +#endif #define osHeapCreate ((HANDLE(WINAPI*)(DWORD,SIZE_T, \ - SIZE_T))aSyscall[36].pCurrent) + SIZE_T))aSyscall[35].pCurrent) +#if !SQLITE_OS_WINRT { "HeapDestroy", (SYSCALL)HeapDestroy, 0 }, +#else + { "HeapDestroy", (SYSCALL)0, 0 }, +#endif -#define osHeapDestroy ((BOOL(WINAPI*)(HANDLE))aSyscall[37].pCurrent) +#define osHeapDestroy ((BOOL(WINAPI*)(HANDLE))aSyscall[36].pCurrent) { "HeapFree", (SYSCALL)HeapFree, 0 }, -#define osHeapFree ((BOOL(WINAPI*)(HANDLE,DWORD,LPVOID))aSyscall[38].pCurrent) +#define osHeapFree ((BOOL(WINAPI*)(HANDLE,DWORD,LPVOID))aSyscall[37].pCurrent) { "HeapReAlloc", (SYSCALL)HeapReAlloc, 0 }, #define osHeapReAlloc ((LPVOID(WINAPI*)(HANDLE,DWORD,LPVOID, \ - SIZE_T))aSyscall[39].pCurrent) + SIZE_T))aSyscall[38].pCurrent) { "HeapSize", (SYSCALL)HeapSize, 0 }, #define osHeapSize ((SIZE_T(WINAPI*)(HANDLE,DWORD, \ - LPCVOID))aSyscall[40].pCurrent) + LPCVOID))aSyscall[39].pCurrent) +#if !SQLITE_OS_WINRT { "HeapValidate", (SYSCALL)HeapValidate, 0 }, +#else + { "HeapValidate", (SYSCALL)0, 0 }, +#endif #define osHeapValidate ((BOOL(WINAPI*)(HANDLE,DWORD, \ - LPCVOID))aSyscall[41].pCurrent) + LPCVOID))aSyscall[40].pCurrent) #if defined(SQLITE_WIN32_HAS_ANSI) { "LoadLibraryA", (SYSCALL)LoadLibraryA, 0 }, @@ -511,107 +560,247 @@ static struct win_syscall { { "LoadLibraryA", (SYSCALL)0, 0 }, #endif -#define osLoadLibraryA ((HMODULE(WINAPI*)(LPCSTR))aSyscall[42].pCurrent) +#define osLoadLibraryA ((HMODULE(WINAPI*)(LPCSTR))aSyscall[41].pCurrent) -#if defined(SQLITE_WIN32_HAS_WIDE) +#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) { "LoadLibraryW", (SYSCALL)LoadLibraryW, 0 }, #else { "LoadLibraryW", (SYSCALL)0, 0 }, #endif -#define osLoadLibraryW ((HMODULE(WINAPI*)(LPCWSTR))aSyscall[43].pCurrent) +#define osLoadLibraryW ((HMODULE(WINAPI*)(LPCWSTR))aSyscall[42].pCurrent) +#if !SQLITE_OS_WINRT { "LocalFree", (SYSCALL)LocalFree, 0 }, +#else + { "LocalFree", (SYSCALL)0, 0 }, +#endif -#define osLocalFree ((HLOCAL(WINAPI*)(HLOCAL))aSyscall[44].pCurrent) +#define osLocalFree ((HLOCAL(WINAPI*)(HLOCAL))aSyscall[43].pCurrent) -#if !SQLITE_OS_WINCE +#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT { "LockFile", (SYSCALL)LockFile, 0 }, - -#define osLockFile ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \ - DWORD))aSyscall[45].pCurrent) #else { "LockFile", (SYSCALL)0, 0 }, #endif +#ifndef osLockFile +#define osLockFile ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \ + DWORD))aSyscall[44].pCurrent) +#endif + #if !SQLITE_OS_WINCE { "LockFileEx", (SYSCALL)LockFileEx, 0 }, - -#define osLockFileEx ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD,DWORD, \ - LPOVERLAPPED))aSyscall[46].pCurrent) #else { "LockFileEx", (SYSCALL)0, 0 }, #endif +#ifndef osLockFileEx +#define osLockFileEx ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD,DWORD, \ + LPOVERLAPPED))aSyscall[45].pCurrent) +#endif + +#if !SQLITE_OS_WINRT { "MapViewOfFile", (SYSCALL)MapViewOfFile, 0 }, +#else + { "MapViewOfFile", (SYSCALL)0, 0 }, +#endif #define osMapViewOfFile ((LPVOID(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \ - SIZE_T))aSyscall[47].pCurrent) + SIZE_T))aSyscall[46].pCurrent) { "MultiByteToWideChar", (SYSCALL)MultiByteToWideChar, 0 }, #define osMultiByteToWideChar ((int(WINAPI*)(UINT,DWORD,LPCSTR,int,LPWSTR, \ - int))aSyscall[48].pCurrent) + int))aSyscall[47].pCurrent) { "QueryPerformanceCounter", (SYSCALL)QueryPerformanceCounter, 0 }, #define osQueryPerformanceCounter ((BOOL(WINAPI*)( \ - LARGE_INTEGER*))aSyscall[49].pCurrent) + LARGE_INTEGER*))aSyscall[48].pCurrent) { "ReadFile", (SYSCALL)ReadFile, 0 }, #define osReadFile ((BOOL(WINAPI*)(HANDLE,LPVOID,DWORD,LPDWORD, \ - LPOVERLAPPED))aSyscall[50].pCurrent) + LPOVERLAPPED))aSyscall[49].pCurrent) { "SetEndOfFile", (SYSCALL)SetEndOfFile, 0 }, -#define osSetEndOfFile ((BOOL(WINAPI*)(HANDLE))aSyscall[51].pCurrent) +#define osSetEndOfFile ((BOOL(WINAPI*)(HANDLE))aSyscall[50].pCurrent) +#if !SQLITE_OS_WINRT { "SetFilePointer", (SYSCALL)SetFilePointer, 0 }, +#else + { "SetFilePointer", (SYSCALL)0, 0 }, +#endif #define osSetFilePointer ((DWORD(WINAPI*)(HANDLE,LONG,PLONG, \ - DWORD))aSyscall[52].pCurrent) + DWORD))aSyscall[51].pCurrent) +#if !SQLITE_OS_WINRT { "Sleep", (SYSCALL)Sleep, 0 }, +#else + { "Sleep", (SYSCALL)0, 0 }, +#endif -#define osSleep ((VOID(WINAPI*)(DWORD))aSyscall[53].pCurrent) +#define osSleep ((VOID(WINAPI*)(DWORD))aSyscall[52].pCurrent) { "SystemTimeToFileTime", (SYSCALL)SystemTimeToFileTime, 0 }, #define osSystemTimeToFileTime ((BOOL(WINAPI*)(CONST SYSTEMTIME*, \ - LPFILETIME))aSyscall[54].pCurrent) + LPFILETIME))aSyscall[53].pCurrent) -#if !SQLITE_OS_WINCE +#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT { "UnlockFile", (SYSCALL)UnlockFile, 0 }, - -#define osUnlockFile ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \ - DWORD))aSyscall[55].pCurrent) #else { "UnlockFile", (SYSCALL)0, 0 }, #endif +#ifndef osUnlockFile +#define osUnlockFile ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \ + DWORD))aSyscall[54].pCurrent) +#endif + #if !SQLITE_OS_WINCE { "UnlockFileEx", (SYSCALL)UnlockFileEx, 0 }, - -#define osUnlockFileEx ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \ - LPOVERLAPPED))aSyscall[56].pCurrent) #else { "UnlockFileEx", (SYSCALL)0, 0 }, #endif +#define osUnlockFileEx ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \ + LPOVERLAPPED))aSyscall[55].pCurrent) + { "UnmapViewOfFile", (SYSCALL)UnmapViewOfFile, 0 }, -#define osUnmapViewOfFile ((BOOL(WINAPI*)(LPCVOID))aSyscall[57].pCurrent) +#define osUnmapViewOfFile ((BOOL(WINAPI*)(LPCVOID))aSyscall[56].pCurrent) { "WideCharToMultiByte", (SYSCALL)WideCharToMultiByte, 0 }, #define osWideCharToMultiByte ((int(WINAPI*)(UINT,DWORD,LPCWSTR,int,LPSTR,int, \ - LPCSTR,LPBOOL))aSyscall[58].pCurrent) + LPCSTR,LPBOOL))aSyscall[57].pCurrent) { "WriteFile", (SYSCALL)WriteFile, 0 }, #define osWriteFile ((BOOL(WINAPI*)(HANDLE,LPCVOID,DWORD,LPDWORD, \ - LPOVERLAPPED))aSyscall[59].pCurrent) + LPOVERLAPPED))aSyscall[58].pCurrent) + +#if SQLITE_OS_WINRT + { "CreateEventExW", (SYSCALL)CreateEventExW, 0 }, +#else + { "CreateEventExW", (SYSCALL)0, 0 }, +#endif + +#define osCreateEventExW ((HANDLE(WINAPI*)(LPSECURITY_ATTRIBUTES,LPCWSTR, \ + DWORD,DWORD))aSyscall[59].pCurrent) + +#if !SQLITE_OS_WINRT + { "WaitForSingleObject", (SYSCALL)WaitForSingleObject, 0 }, +#else + { "WaitForSingleObject", (SYSCALL)0, 0 }, +#endif + +#define osWaitForSingleObject ((DWORD(WINAPI*)(HANDLE, \ + DWORD))aSyscall[60].pCurrent) + +#if !SQLITE_OS_WINCE + { "WaitForSingleObjectEx", (SYSCALL)WaitForSingleObjectEx, 0 }, +#else + { "WaitForSingleObjectEx", (SYSCALL)0, 0 }, +#endif + +#define osWaitForSingleObjectEx ((DWORD(WINAPI*)(HANDLE,DWORD, \ + BOOL))aSyscall[61].pCurrent) + +#if !SQLITE_OS_WINCE + { "SetFilePointerEx", (SYSCALL)SetFilePointerEx, 0 }, +#else + { "SetFilePointerEx", (SYSCALL)0, 0 }, +#endif + +#define osSetFilePointerEx ((BOOL(WINAPI*)(HANDLE,LARGE_INTEGER, \ + PLARGE_INTEGER,DWORD))aSyscall[62].pCurrent) + +#if SQLITE_OS_WINRT + { "GetFileInformationByHandleEx", (SYSCALL)GetFileInformationByHandleEx, 0 }, +#else + { "GetFileInformationByHandleEx", (SYSCALL)0, 0 }, +#endif + +#define osGetFileInformationByHandleEx ((BOOL(WINAPI*)(HANDLE, \ + FILE_INFO_BY_HANDLE_CLASS,LPVOID,DWORD))aSyscall[63].pCurrent) + +#if SQLITE_OS_WINRT + { "MapViewOfFileFromApp", (SYSCALL)MapViewOfFileFromApp, 0 }, +#else + { "MapViewOfFileFromApp", (SYSCALL)0, 0 }, +#endif + +#define osMapViewOfFileFromApp ((LPVOID(WINAPI*)(HANDLE,ULONG,ULONG64, \ + SIZE_T))aSyscall[64].pCurrent) + +#if SQLITE_OS_WINRT + { "CreateFile2", (SYSCALL)CreateFile2, 0 }, +#else + { "CreateFile2", (SYSCALL)0, 0 }, +#endif + +#define osCreateFile2 ((HANDLE(WINAPI*)(LPCWSTR,DWORD,DWORD,DWORD, \ + LPCREATEFILE2_EXTENDED_PARAMETERS))aSyscall[65].pCurrent) + +#if SQLITE_OS_WINRT + { "LoadPackagedLibrary", (SYSCALL)LoadPackagedLibrary, 0 }, +#else + { "LoadPackagedLibrary", (SYSCALL)0, 0 }, +#endif + +#define osLoadPackagedLibrary ((HMODULE(WINAPI*)(LPCWSTR, \ + DWORD))aSyscall[66].pCurrent) + +#if SQLITE_OS_WINRT + { "GetTickCount64", (SYSCALL)GetTickCount64, 0 }, +#else + { "GetTickCount64", (SYSCALL)0, 0 }, +#endif + +#define osGetTickCount64 ((ULONGLONG(WINAPI*)(VOID))aSyscall[67].pCurrent) + +#if SQLITE_OS_WINRT + { "GetNativeSystemInfo", (SYSCALL)GetNativeSystemInfo, 0 }, +#else + { "GetNativeSystemInfo", (SYSCALL)0, 0 }, +#endif + +#define osGetNativeSystemInfo ((VOID(WINAPI*)( \ + LPSYSTEM_INFO))aSyscall[68].pCurrent) + +#if defined(SQLITE_WIN32_HAS_ANSI) + { "OutputDebugStringA", (SYSCALL)OutputDebugStringA, 0 }, +#else + { "OutputDebugStringA", (SYSCALL)0, 0 }, +#endif + +#define osOutputDebugStringA ((VOID(WINAPI*)(LPCSTR))aSyscall[69].pCurrent) + +#if defined(SQLITE_WIN32_HAS_WIDE) + { "OutputDebugStringW", (SYSCALL)OutputDebugStringW, 0 }, +#else + { "OutputDebugStringW", (SYSCALL)0, 0 }, +#endif + +#define osOutputDebugStringW ((VOID(WINAPI*)(LPCWSTR))aSyscall[70].pCurrent) + + { "GetProcessHeap", (SYSCALL)GetProcessHeap, 0 }, + +#define osGetProcessHeap ((HANDLE(WINAPI*)(VOID))aSyscall[71].pCurrent) + +#if SQLITE_OS_WINRT + { "CreateFileMappingFromApp", (SYSCALL)CreateFileMappingFromApp, 0 }, +#else + { "CreateFileMappingFromApp", (SYSCALL)0, 0 }, +#endif + +#define osCreateFileMappingFromApp ((HANDLE(WINAPI*)(HANDLE, \ + LPSECURITY_ATTRIBUTES,ULONG,ULONG64,LPCWSTR))aSyscall[72].pCurrent) }; /* End of the overrideable system calls */ @@ -698,6 +887,64 @@ static const char *winNextSystemCall(sqlite3_vfs *p, const char *zName){ return 0; } +/* +** This function outputs the specified (ANSI) string to the Win32 debugger +** (if available). +*/ + +void sqlite3_win32_write_debug(char *zBuf, int nBuf){ + char zDbgBuf[SQLITE_WIN32_DBG_BUF_SIZE]; + int nMin = MIN(nBuf, (SQLITE_WIN32_DBG_BUF_SIZE - 1)); /* may be negative. */ + if( nMin<-1 ) nMin = -1; /* all negative values become -1. */ + assert( nMin==-1 || nMin==0 || nMin0 ){ + memset(zDbgBuf, 0, SQLITE_WIN32_DBG_BUF_SIZE); + memcpy(zDbgBuf, zBuf, nMin); + osOutputDebugStringA(zDbgBuf); + }else{ + osOutputDebugStringA(zBuf); + } +#elif defined(SQLITE_WIN32_HAS_WIDE) + memset(zDbgBuf, 0, SQLITE_WIN32_DBG_BUF_SIZE); + if ( osMultiByteToWideChar( + osAreFileApisANSI() ? CP_ACP : CP_OEMCP, 0, zBuf, + nMin, (LPWSTR)zDbgBuf, SQLITE_WIN32_DBG_BUF_SIZE/sizeof(WCHAR))<=0 ){ + return; + } + osOutputDebugStringW((LPCWSTR)zDbgBuf); +#else + if( nMin>0 ){ + memset(zDbgBuf, 0, SQLITE_WIN32_DBG_BUF_SIZE); + memcpy(zDbgBuf, zBuf, nMin); + fprintf(stderr, "%s", zDbgBuf); + }else{ + fprintf(stderr, "%s", zBuf); + } +#endif +} + +/* +** The following routine suspends the current thread for at least ms +** milliseconds. This is equivalent to the Win32 Sleep() interface. +*/ +#if SQLITE_OS_WINRT +static HANDLE sleepObj = NULL; +#endif + +void sqlite3_win32_sleep(DWORD milliseconds){ +#if SQLITE_OS_WINRT + if ( sleepObj==NULL ){ + sleepObj = osCreateEventExW(NULL, NULL, CREATE_EVENT_MANUAL_RESET, + SYNCHRONIZE); + } + assert( sleepObj!=NULL ); + osWaitForSingleObjectEx(sleepObj, milliseconds, FALSE); +#else + osSleep(milliseconds); +#endif +} + /* ** Return true (non-zero) if we are running under WinNT, Win2K, WinXP, ** or WinCE. Return false (zero) for Win95, Win98, or WinME. @@ -709,7 +956,7 @@ static const char *winNextSystemCall(sqlite3_vfs *p, const char *zName){ ** WinNT/2K/XP so that we will know whether or not we can safely call ** the LockFileEx() API. */ -#if SQLITE_OS_WINCE +#if SQLITE_OS_WINCE || SQLITE_OS_WINRT # define isNT() (1) #else static int isNT(void){ @@ -735,7 +982,7 @@ static void *winMemMalloc(int nBytes){ hHeap = winMemGetHeap(); assert( hHeap!=0 ); assert( hHeap!=INVALID_HANDLE_VALUE ); -#ifdef SQLITE_WIN32_MALLOC_VALIDATE +#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE) assert ( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) ); #endif assert( nBytes>=0 ); @@ -757,7 +1004,7 @@ static void winMemFree(void *pPrior){ hHeap = winMemGetHeap(); assert( hHeap!=0 ); assert( hHeap!=INVALID_HANDLE_VALUE ); -#ifdef SQLITE_WIN32_MALLOC_VALIDATE +#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE) assert ( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior) ); #endif if( !pPrior ) return; /* Passing NULL to HeapFree is undefined. */ @@ -778,7 +1025,7 @@ static void *winMemRealloc(void *pPrior, int nBytes){ hHeap = winMemGetHeap(); assert( hHeap!=0 ); assert( hHeap!=INVALID_HANDLE_VALUE ); -#ifdef SQLITE_WIN32_MALLOC_VALIDATE +#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE) assert ( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior) ); #endif assert( nBytes>=0 ); @@ -806,7 +1053,7 @@ static int winMemSize(void *p){ hHeap = winMemGetHeap(); assert( hHeap!=0 ); assert( hHeap!=INVALID_HANDLE_VALUE ); -#ifdef SQLITE_WIN32_MALLOC_VALIDATE +#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE) assert ( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) ); #endif if( !p ) return 0; @@ -834,6 +1081,8 @@ static int winMemInit(void *pAppData){ if( !pWinMemData ) return SQLITE_ERROR; assert( pWinMemData->magic==WINMEM_MAGIC ); + +#if !SQLITE_OS_WINRT && SQLITE_WIN32_HEAP_CREATE if( !pWinMemData->hHeap ){ pWinMemData->hHeap = osHeapCreate(SQLITE_WIN32_HEAP_FLAGS, SQLITE_WIN32_HEAP_INIT_SIZE, @@ -846,10 +1095,21 @@ static int winMemInit(void *pAppData){ return SQLITE_NOMEM; } pWinMemData->bOwned = TRUE; + assert( pWinMemData->bOwned ); } +#else + pWinMemData->hHeap = osGetProcessHeap(); + if( !pWinMemData->hHeap ){ + sqlite3_log(SQLITE_NOMEM, + "failed to GetProcessHeap (%d)", osGetLastError()); + return SQLITE_NOMEM; + } + pWinMemData->bOwned = FALSE; + assert( !pWinMemData->bOwned ); +#endif assert( pWinMemData->hHeap!=0 ); assert( pWinMemData->hHeap!=INVALID_HANDLE_VALUE ); -#ifdef SQLITE_WIN32_MALLOC_VALIDATE +#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE) assert( osHeapValidate(pWinMemData->hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) ); #endif return SQLITE_OK; @@ -864,7 +1124,7 @@ static void winMemShutdown(void *pAppData){ if( !pWinMemData ) return; if( pWinMemData->hHeap ){ assert( pWinMemData->hHeap!=INVALID_HANDLE_VALUE ); -#ifdef SQLITE_WIN32_MALLOC_VALIDATE +#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE) assert( osHeapValidate(pWinMemData->hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) ); #endif if( pWinMemData->bOwned ){ @@ -1064,6 +1324,17 @@ static int getLastErrorMsg(DWORD lastErrno, int nBuf, char *zBuf){ char *zOut = 0; if( isNT() ){ +#if SQLITE_OS_WINRT + WCHAR zTempWide[MAX_PATH+1]; /* NOTE: Somewhat arbitrary. */ + dwLen = osFormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + lastErrno, + 0, + zTempWide, + MAX_PATH, + 0); +#else LPWSTR zTempWide = NULL; dwLen = osFormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | @@ -1074,20 +1345,20 @@ static int getLastErrorMsg(DWORD lastErrno, int nBuf, char *zBuf){ (LPWSTR) &zTempWide, 0, 0); +#endif if( dwLen > 0 ){ /* allocate a buffer and convert to UTF8 */ sqlite3BeginBenignMalloc(); zOut = unicodeToUtf8(zTempWide); sqlite3EndBenignMalloc(); +#if !SQLITE_OS_WINRT /* free the system buffer allocated by FormatMessage */ osLocalFree(zTempWide); +#endif } -/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed. -** Since the ANSI version of these Windows API do not exist for WINCE, -** it's important to not reference them for WINCE builds. -*/ -#if SQLITE_OS_WINCE==0 - }else{ + } +#ifdef SQLITE_WIN32_HAS_ANSI + else{ char *zTemp = NULL; dwLen = osFormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | @@ -1106,8 +1377,8 @@ static int getLastErrorMsg(DWORD lastErrno, int nBuf, char *zBuf){ /* free the system buffer allocated by FormatMessage */ osLocalFree(zTemp); } -#endif } +#endif if( 0 == dwLen ){ sqlite3_snprintf(nBuf, zBuf, "OsError 0x%x (%u)", lastErrno, lastErrno); }else{ @@ -1190,7 +1461,7 @@ static int retryIoerr(int *pnRetry, DWORD *pError){ if( e==ERROR_ACCESS_DENIED || e==ERROR_LOCK_VIOLATION || e==ERROR_SHARING_VIOLATION ){ - osSleep(win32IoerrRetryDelay*(1+*pnRetry)); + sqlite3_win32_sleep(win32IoerrRetryDelay*(1+*pnRetry)); ++*pnRetry; return 1; } @@ -1251,7 +1522,7 @@ struct tm *__cdecl localtime(const time_t *t) static void winceMutexAcquire(HANDLE h){ DWORD dwErr; do { - dwErr = WaitForSingleObject(h, INFINITE); + dwErr = osWaitForSingleObject(h, INFINITE); } while (dwErr != WAIT_OBJECT_0 && dwErr != WAIT_ABANDONED); } /* @@ -1382,7 +1653,7 @@ static void winceDestroyLock(winFile *pFile){ ** An implementation of the LockFile() API of Windows for CE */ static BOOL winceLockFile( - HANDLE *phFile, + LPHANDLE phFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh, DWORD nNumberOfBytesToLockLow, @@ -1446,7 +1717,7 @@ static BOOL winceLockFile( ** An implementation of the UnlockFile API of Windows for CE */ static BOOL winceUnlockFile( - HANDLE *phFile, + LPHANDLE phFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh, DWORD nNumberOfBytesToUnlockLow, @@ -1503,35 +1774,74 @@ static BOOL winceUnlockFile( winceMutexRelease(pFile->hMutex); return bReturn; } - -/* -** An implementation of the LockFileEx() API of Windows for CE -*/ -static BOOL winceLockFileEx( - HANDLE *phFile, - DWORD dwFlags, - DWORD dwReserved, - DWORD nNumberOfBytesToLockLow, - DWORD nNumberOfBytesToLockHigh, - LPOVERLAPPED lpOverlapped -){ - UNUSED_PARAMETER(dwReserved); - UNUSED_PARAMETER(nNumberOfBytesToLockHigh); - - /* If the caller wants a shared read lock, forward this call - ** to winceLockFile */ - if (lpOverlapped->Offset == (DWORD)SHARED_FIRST && - dwFlags == 1 && - nNumberOfBytesToLockLow == (DWORD)SHARED_SIZE){ - return winceLockFile(phFile, SHARED_FIRST, 0, 1, 0); - } - return FALSE; -} /* ** End of the special code for wince *****************************************************************************/ #endif /* SQLITE_OS_WINCE */ +/* +** Lock a file region. +*/ +static BOOL winLockFile( + LPHANDLE phFile, + DWORD flags, + DWORD offsetLow, + DWORD offsetHigh, + DWORD numBytesLow, + DWORD numBytesHigh +){ +#if SQLITE_OS_WINCE + /* + ** NOTE: Windows CE is handled differently here due its lack of the Win32 + ** API LockFile. + */ + return winceLockFile(phFile, offsetLow, offsetHigh, + numBytesLow, numBytesHigh); +#else + if( isNT() ){ + OVERLAPPED ovlp; + memset(&ovlp, 0, sizeof(OVERLAPPED)); + ovlp.Offset = offsetLow; + ovlp.OffsetHigh = offsetHigh; + return osLockFileEx(*phFile, flags, 0, numBytesLow, numBytesHigh, &ovlp); + }else{ + return osLockFile(*phFile, offsetLow, offsetHigh, numBytesLow, + numBytesHigh); + } +#endif +} + +/* +** Unlock a file region. + */ +static BOOL winUnlockFile( + LPHANDLE phFile, + DWORD offsetLow, + DWORD offsetHigh, + DWORD numBytesLow, + DWORD numBytesHigh +){ +#if SQLITE_OS_WINCE + /* + ** NOTE: Windows CE is handled differently here due its lack of the Win32 + ** API UnlockFile. + */ + return winceUnlockFile(phFile, offsetLow, offsetHigh, + numBytesLow, numBytesHigh); +#else + if( isNT() ){ + OVERLAPPED ovlp; + memset(&ovlp, 0, sizeof(OVERLAPPED)); + ovlp.Offset = offsetLow; + ovlp.OffsetHigh = offsetHigh; + return osUnlockFileEx(*phFile, 0, numBytesLow, numBytesHigh, &ovlp); + }else{ + return osUnlockFile(*phFile, offsetLow, offsetHigh, numBytesLow, + numBytesHigh); + } +#endif +} + /***************************************************************************** ** The next group of routines implement the I/O methods specified ** by the sqlite3_io_methods object. @@ -1550,6 +1860,7 @@ static BOOL winceLockFileEx( ** Otherwise, set pFile->lastErrno and return non-zero. */ static int seekWinFile(winFile *pFile, sqlite3_int64 iOffset){ +#if !SQLITE_OS_WINRT LONG upperBits; /* Most sig. 32 bits of new offset */ LONG lowerBits; /* Least sig. 32 bits of new offset */ DWORD dwRet; /* Value returned by SetFilePointer() */ @@ -1576,6 +1887,26 @@ static int seekWinFile(winFile *pFile, sqlite3_int64 iOffset){ } return 0; +#else + /* + ** Same as above, except that this implementation works for WinRT. + */ + + LARGE_INTEGER x; /* The new offset */ + BOOL bRet; /* Value returned by SetFilePointerEx() */ + + x.QuadPart = iOffset; + bRet = osSetFilePointerEx(pFile->h, x, 0, FILE_BEGIN); + + if(!bRet){ + pFile->lastErrno = osGetLastError(); + winLogError(SQLITE_IOERR_SEEK, pFile->lastErrno, + "seekWinFile", pFile->zPath); + return 1; + } + + return 0; +#endif } /* @@ -1599,7 +1930,7 @@ static int winClose(sqlite3_file *id){ do{ rc = osCloseHandle(pFile->h); /* SimulateIOError( rc=0; cnt=MX_CLOSE_ATTEMPT; ); */ - }while( rc==0 && ++cnt < MX_CLOSE_ATTEMPT && (osSleep(100), 1) ); + }while( rc==0 && ++cnt < MX_CLOSE_ATTEMPT && (sqlite3_win32_sleep(100), 1) ); #if SQLITE_OS_WINCE #define WINCE_DELETION_ATTEMPTS 3 winceDestroyLock(pFile); @@ -1610,7 +1941,7 @@ static int winClose(sqlite3_file *id){ && osGetFileAttributesW(pFile->zDeleteOnClose)!=0xffffffff && cnt++ < WINCE_DELETION_ATTEMPTS ){ - osSleep(100); /* Wait a little before trying again */ + sqlite3_win32_sleep(100); /* Wait a little before trying again */ } sqlite3_free(pFile->zDeleteOnClose); } @@ -1865,23 +2196,40 @@ static int winSync(sqlite3_file *id, int flags){ ** Determine the current size of a file in bytes */ static int winFileSize(sqlite3_file *id, sqlite3_int64 *pSize){ - DWORD upperBits; - DWORD lowerBits; winFile *pFile = (winFile*)id; - DWORD lastErrno; + int rc = SQLITE_OK; assert( id!=0 ); SimulateIOError(return SQLITE_IOERR_FSTAT); - lowerBits = osGetFileSize(pFile->h, &upperBits); - if( (lowerBits == INVALID_FILE_SIZE) - && ((lastErrno = osGetLastError())!=NO_ERROR) ) +#if SQLITE_OS_WINRT { - pFile->lastErrno = lastErrno; - return winLogError(SQLITE_IOERR_FSTAT, pFile->lastErrno, - "winFileSize", pFile->zPath); + FILE_STANDARD_INFO info; + if( osGetFileInformationByHandleEx(pFile->h, FileStandardInfo, + &info, sizeof(info)) ){ + *pSize = info.EndOfFile.QuadPart; + }else{ + pFile->lastErrno = osGetLastError(); + rc = winLogError(SQLITE_IOERR_FSTAT, pFile->lastErrno, + "winFileSize", pFile->zPath); + } } - *pSize = (((sqlite3_int64)upperBits)<<32) + lowerBits; - return SQLITE_OK; +#else + { + DWORD upperBits; + DWORD lowerBits; + DWORD lastErrno; + + lowerBits = osGetFileSize(pFile->h, &upperBits); + *pSize = (((sqlite3_int64)upperBits)<<32) + lowerBits; + if( (lowerBits == INVALID_FILE_SIZE) + && ((lastErrno = osGetLastError())!=NO_ERROR) ){ + pFile->lastErrno = lastErrno; + rc = winLogError(SQLITE_IOERR_FSTAT, pFile->lastErrno, + "winFileSize", pFile->zPath); + } + } +#endif + return rc; } /* @@ -1891,6 +2239,30 @@ static int winFileSize(sqlite3_file *id, sqlite3_int64 *pSize){ # define LOCKFILE_FAIL_IMMEDIATELY 1 #endif +#ifndef LOCKFILE_EXCLUSIVE_LOCK +# define LOCKFILE_EXCLUSIVE_LOCK 2 +#endif + +/* +** Historically, SQLite has used both the LockFile and LockFileEx functions. +** When the LockFile function was used, it was always expected to fail +** immediately if the lock could not be obtained. Also, it always expected to +** obtain an exclusive lock. These flags are used with the LockFileEx function +** and reflect those expectations; therefore, they should not be changed. +*/ +#ifndef SQLITE_LOCKFILE_FLAGS +# define SQLITE_LOCKFILE_FLAGS (LOCKFILE_FAIL_IMMEDIATELY | \ + LOCKFILE_EXCLUSIVE_LOCK) +#endif + +/* +** Currently, SQLite never calls the LockFileEx function without wanting the +** call to fail immediately if the lock cannot be obtained. +*/ +#ifndef SQLITE_LOCKFILEEX_FLAGS +# define SQLITE_LOCKFILEEX_FLAGS (LOCKFILE_FAIL_IMMEDIATELY) +#endif + /* ** Acquire a reader lock. ** Different API routines are called depending on whether or not this @@ -1899,22 +2271,26 @@ static int winFileSize(sqlite3_file *id, sqlite3_int64 *pSize){ static int getReadLock(winFile *pFile){ int res; if( isNT() ){ - OVERLAPPED ovlp; - ovlp.Offset = SHARED_FIRST; - ovlp.OffsetHigh = 0; - ovlp.hEvent = 0; - res = osLockFileEx(pFile->h, LOCKFILE_FAIL_IMMEDIATELY, - 0, SHARED_SIZE, 0, &ovlp); -/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed. -*/ -#if SQLITE_OS_WINCE==0 - }else{ +#if SQLITE_OS_WINCE + /* + ** NOTE: Windows CE is handled differently here due its lack of the Win32 + ** API LockFileEx. + */ + res = winceLockFile(&pFile->h, SHARED_FIRST, 0, 1, 0); +#else + res = winLockFile(&pFile->h, SQLITE_LOCKFILEEX_FLAGS, SHARED_FIRST, 0, + SHARED_SIZE, 0); +#endif + } +#ifdef SQLITE_WIN32_HAS_ANSI + else{ int lk; sqlite3_randomness(sizeof(lk), &lk); pFile->sharedLockByte = (short)((lk & 0x7fffffff)%(SHARED_SIZE - 1)); - res = osLockFile(pFile->h, SHARED_FIRST+pFile->sharedLockByte, 0, 1, 0); -#endif + res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS, + SHARED_FIRST+pFile->sharedLockByte, 0, 1, 0); } +#endif if( res == 0 ){ pFile->lastErrno = osGetLastError(); /* No need to log a failure to lock */ @@ -1929,14 +2305,13 @@ static int unlockReadLock(winFile *pFile){ int res; DWORD lastErrno; if( isNT() ){ - res = osUnlockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0); -/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed. -*/ -#if SQLITE_OS_WINCE==0 - }else{ - res = osUnlockFile(pFile->h, SHARED_FIRST + pFile->sharedLockByte, 0, 1, 0); -#endif + res = winUnlockFile(&pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0); } +#ifdef SQLITE_WIN32_HAS_ANSI + else{ + res = winUnlockFile(&pFile->h, SHARED_FIRST+pFile->sharedLockByte, 0, 1, 0); + } +#endif if( res==0 && ((lastErrno = osGetLastError())!=ERROR_NOT_LOCKED) ){ pFile->lastErrno = lastErrno; winLogError(SQLITE_IOERR_UNLOCK, pFile->lastErrno, @@ -2007,7 +2382,8 @@ static int winLock(sqlite3_file *id, int locktype){ && (pFile->locktype==RESERVED_LOCK)) ){ int cnt = 3; - while( cnt-->0 && (res = osLockFile(pFile->h, PENDING_BYTE, 0, 1, 0))==0 ){ + while( cnt-->0 && (res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS, + PENDING_BYTE, 0, 1, 0))==0 ){ /* Try 3 times to get the pending lock. This is needed to work ** around problems caused by indexing and/or anti-virus software on ** Windows systems. @@ -2015,7 +2391,7 @@ static int winLock(sqlite3_file *id, int locktype){ ** copy this retry logic. It is a hack intended for Windows only. */ OSTRACE(("could not get a PENDING lock. cnt=%d\n", cnt)); - if( cnt ) osSleep(1); + if( cnt ) sqlite3_win32_sleep(1); } gotPendingLock = res; if( !res ){ @@ -2039,7 +2415,7 @@ static int winLock(sqlite3_file *id, int locktype){ */ if( locktype==RESERVED_LOCK && res ){ assert( pFile->locktype==SHARED_LOCK ); - res = osLockFile(pFile->h, RESERVED_BYTE, 0, 1, 0); + res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS, RESERVED_BYTE, 0, 1, 0); if( res ){ newLocktype = RESERVED_LOCK; }else{ @@ -2060,7 +2436,8 @@ static int winLock(sqlite3_file *id, int locktype){ assert( pFile->locktype>=SHARED_LOCK ); res = unlockReadLock(pFile); OSTRACE(("unreadlock = %d\n", res)); - res = osLockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0); + res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS, SHARED_FIRST, 0, + SHARED_SIZE, 0); if( res ){ newLocktype = EXCLUSIVE_LOCK; }else{ @@ -2074,7 +2451,7 @@ static int winLock(sqlite3_file *id, int locktype){ ** release it now. */ if( gotPendingLock && locktype==SHARED_LOCK ){ - osUnlockFile(pFile->h, PENDING_BYTE, 0, 1, 0); + winUnlockFile(&pFile->h, PENDING_BYTE, 0, 1, 0); } /* Update the state of the lock has held in the file descriptor then @@ -2108,9 +2485,9 @@ static int winCheckReservedLock(sqlite3_file *id, int *pResOut){ rc = 1; OSTRACE(("TEST WR-LOCK %d %d (local)\n", pFile->h, rc)); }else{ - rc = osLockFile(pFile->h, RESERVED_BYTE, 0, 1, 0); + rc = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS, RESERVED_BYTE, 0, 1, 0); if( rc ){ - osUnlockFile(pFile->h, RESERVED_BYTE, 0, 1, 0); + winUnlockFile(&pFile->h, RESERVED_BYTE, 0, 1, 0); } rc = !rc; OSTRACE(("TEST WR-LOCK %d %d (remote)\n", pFile->h, rc)); @@ -2140,7 +2517,7 @@ static int winUnlock(sqlite3_file *id, int locktype){ pFile->locktype, pFile->sharedLockByte)); type = pFile->locktype; if( type>=EXCLUSIVE_LOCK ){ - osUnlockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0); + winUnlockFile(&pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0); if( locktype==SHARED_LOCK && !getReadLock(pFile) ){ /* This should never happen. We should always be able to ** reacquire the read lock */ @@ -2149,13 +2526,13 @@ static int winUnlock(sqlite3_file *id, int locktype){ } } if( type>=RESERVED_LOCK ){ - osUnlockFile(pFile->h, RESERVED_BYTE, 0, 1, 0); + winUnlockFile(&pFile->h, RESERVED_BYTE, 0, 1, 0); } if( locktype==NO_LOCK && type>=SHARED_LOCK ){ unlockReadLock(pFile); } if( type>=PENDING_LOCK ){ - osUnlockFile(pFile->h, PENDING_BYTE, 0, 1, 0); + winUnlockFile(&pFile->h, PENDING_BYTE, 0, 1, 0); } pFile->locktype = (u8)locktype; return rc; @@ -2393,25 +2770,19 @@ static int winShmSystemLock( int ofst, /* Offset to first byte to be locked/unlocked */ int nByte /* Number of bytes to lock or unlock */ ){ - OVERLAPPED ovlp; - DWORD dwFlags; int rc = 0; /* Result code form Lock/UnlockFileEx() */ /* Access to the winShmNode object is serialized by the caller */ assert( sqlite3_mutex_held(pFile->mutex) || pFile->nRef==0 ); - /* Initialize the locking parameters */ - dwFlags = LOCKFILE_FAIL_IMMEDIATELY; - if( lockType == _SHM_WRLCK ) dwFlags |= LOCKFILE_EXCLUSIVE_LOCK; - - memset(&ovlp, 0, sizeof(OVERLAPPED)); - ovlp.Offset = ofst; - /* Release/Acquire the system-level lock */ if( lockType==_SHM_UNLCK ){ - rc = osUnlockFileEx(pFile->hFile.h, 0, nByte, 0, &ovlp); + rc = winUnlockFile(&pFile->hFile.h, ofst, 0, nByte, 0); }else{ - rc = osLockFileEx(pFile->hFile.h, dwFlags, 0, nByte, 0, &ovlp); + /* Initialize the locking parameters */ + DWORD dwFlags = LOCKFILE_FAIL_IMMEDIATELY; + if( lockType == _SHM_WRLCK ) dwFlags |= LOCKFILE_EXCLUSIVE_LOCK; + rc = winLockFile(&pFile->hFile.h, dwFlags, ofst, 0, nByte, 0); } if( rc!= 0 ){ @@ -2849,18 +3220,30 @@ static int winShmMap( HANDLE hMap; /* file-mapping handle */ void *pMap = 0; /* Mapped memory region */ - hMap = osCreateFileMapping(pShmNode->hFile.h, +#if SQLITE_OS_WINRT + hMap = osCreateFileMappingFromApp(pShmNode->hFile.h, + NULL, PAGE_READWRITE, nByte, NULL + ); +#else + hMap = osCreateFileMappingW(pShmNode->hFile.h, NULL, PAGE_READWRITE, 0, nByte, NULL ); +#endif OSTRACE(("SHM-MAP pid-%d create region=%d nbyte=%d %s\n", (int)osGetCurrentProcessId(), pShmNode->nRegion, nByte, hMap ? "ok" : "failed")); if( hMap ){ int iOffset = pShmNode->nRegion*szRegion; int iOffsetShift = iOffset % winSysInfo.dwAllocationGranularity; +#if SQLITE_OS_WINRT + pMap = osMapViewOfFileFromApp(hMap, FILE_MAP_WRITE | FILE_MAP_READ, + iOffset - iOffsetShift, szRegion + iOffsetShift + ); +#else pMap = osMapViewOfFile(hMap, FILE_MAP_WRITE | FILE_MAP_READ, 0, iOffset - iOffsetShift, szRegion + iOffsetShift ); +#endif OSTRACE(("SHM-MAP pid-%d map region=%d offset=%d size=%d %s\n", (int)osGetCurrentProcessId(), pShmNode->nRegion, iOffset, szRegion, pMap ? "ok" : "failed")); @@ -2946,13 +3329,12 @@ static void *convertUtf8Filename(const char *zFilename){ void *zConverted = 0; if( isNT() ){ zConverted = utf8ToUnicode(zFilename); -/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed. -*/ -#if SQLITE_OS_WINCE==0 - }else{ - zConverted = sqlite3_win32_utf8_to_mbcs(zFilename); -#endif } +#ifdef SQLITE_WIN32_HAS_ANSI + else{ + zConverted = sqlite3_win32_utf8_to_mbcs(zFilename); + } +#endif /* caller will handle out of memory */ return zConverted; } @@ -2967,6 +3349,7 @@ static int getTempname(int nBuf, char *zBuf){ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789"; size_t i, j; + int nTempPath; char zTempPath[MAX_PATH+2]; /* It's odd to simulate an io-error here, but really this is just @@ -2975,9 +3358,13 @@ static int getTempname(int nBuf, char *zBuf){ */ SimulateIOError( return SQLITE_IOERR ); + memset(zTempPath, 0, MAX_PATH+2); + if( sqlite3_temp_directory ){ sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", sqlite3_temp_directory); - }else if( isNT() ){ + } +#if !SQLITE_OS_WINRT + else if( isNT() ){ char *zMulti; WCHAR zWidePath[MAX_PATH]; osGetTempPathW(MAX_PATH-30, zWidePath); @@ -2988,12 +3375,9 @@ static int getTempname(int nBuf, char *zBuf){ }else{ return SQLITE_IOERR_NOMEM; } -/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed. -** Since the ANSI version of these Windows API do not exist for WINCE, -** it's important to not reference them for WINCE builds. -*/ -#if SQLITE_OS_WINCE==0 - }else{ + } +#ifdef SQLITE_WIN32_HAS_ANSI + else{ char *zUtf8; char zMbcsPath[MAX_PATH]; osGetTempPathA(MAX_PATH-30, zMbcsPath); @@ -3004,21 +3388,25 @@ static int getTempname(int nBuf, char *zBuf){ }else{ return SQLITE_IOERR_NOMEM; } -#endif } +#endif +#endif /* Check that the output buffer is large enough for the temporary file ** name. If it is not, return SQLITE_ERROR. */ - if( (sqlite3Strlen30(zTempPath) + sqlite3Strlen30(SQLITE_TEMP_FILE_PREFIX) + 18) >= nBuf ){ + nTempPath = sqlite3Strlen30(zTempPath); + + if( (nTempPath + sqlite3Strlen30(SQLITE_TEMP_FILE_PREFIX) + 18) >= nBuf ){ return SQLITE_ERROR; } - for(i=sqlite3Strlen30(zTempPath); i>0 && zTempPath[i-1]=='\\'; i--){} + for(i=nTempPath; i>0 && zTempPath[i-1]=='\\'; i--){} zTempPath[i] = 0; - sqlite3_snprintf(nBuf-18, zBuf, - "%s\\"SQLITE_TEMP_FILE_PREFIX, zTempPath); + sqlite3_snprintf(nBuf-18, zBuf, (nTempPath > 0) ? + "%s\\"SQLITE_TEMP_FILE_PREFIX : SQLITE_TEMP_FILE_PREFIX, + zTempPath); j = sqlite3Strlen30(zBuf); sqlite3_randomness(15, &zBuf[j]); for(i=0; i<15; i++, j++){ @@ -3214,18 +3602,25 @@ static int winOpen( #endif if( isNT() ){ - while( (h = osCreateFileW((LPCWSTR)zConverted, +#if SQLITE_OS_WINRT + CREATEFILE2_EXTENDED_PARAMETERS extendedParameters; + extendedParameters.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS); + extendedParameters.dwFileAttributes = + dwFlagsAndAttributes & FILE_ATTRIBUTE_MASK; + extendedParameters.dwFileFlags = dwFlagsAndAttributes & FILE_FLAG_MASK; + extendedParameters.dwSecurityQosFlags = SECURITY_ANONYMOUS; + extendedParameters.lpSecurityAttributes = NULL; + extendedParameters.hTemplateFile = NULL; + while( (h = osCreateFile2((LPCWSTR)zConverted, dwDesiredAccess, - dwShareMode, NULL, + dwShareMode, dwCreationDisposition, - dwFlagsAndAttributes, - NULL))==INVALID_HANDLE_VALUE && + &extendedParameters))==INVALID_HANDLE_VALUE && retryIoerr(&cnt, &lastErrno) ){ /* Noop */ } -#if SQLITE_OS_WINCE==0 - }else{ - while( (h = osCreateFileA((LPCSTR)zConverted, +#else + while( (h = osCreateFileW((LPCWSTR)zConverted, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, @@ -3236,7 +3631,19 @@ static int winOpen( } #endif } - +#ifdef SQLITE_WIN32_HAS_ANSI + else{ + while( (h = osCreateFileA((LPCSTR)zConverted, + dwDesiredAccess, + dwShareMode, NULL, + dwCreationDisposition, + dwFlagsAndAttributes, + NULL))==INVALID_HANDLE_VALUE && + retryIoerr(&cnt, &lastErrno) ){ + /* Noop */ + } + } +#endif logIoerr(cnt); OSTRACE(("OPEN %d %s 0x%lx %s\n", @@ -3326,7 +3733,19 @@ static int winDelete( } if( isNT() ){ do { +#if SQLITE_OS_WINRT + WIN32_FILE_ATTRIBUTE_DATA sAttrData; + memset(&sAttrData, 0, sizeof(sAttrData)); + if ( osGetFileAttributesExW(zConverted, GetFileExInfoStandard, + &sAttrData) ){ + attr = sAttrData.dwFileAttributes; + }else{ + rc = SQLITE_OK; /* Already gone? */ + break; + } +#else attr = osGetFileAttributesW(zConverted); +#endif if ( attr==INVALID_FILE_ATTRIBUTES ){ rc = SQLITE_OK; /* Already gone? */ break; @@ -3344,12 +3763,9 @@ static int winDelete( break; } } while(1); -/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed. -** Since the ANSI version of these Windows API do not exist for WINCE, -** it's important to not reference them for WINCE builds. -*/ -#if SQLITE_OS_WINCE==0 - }else{ + } +#ifdef SQLITE_WIN32_HAS_ANSI + else{ do { attr = osGetFileAttributesA(zConverted); if ( attr==INVALID_FILE_ATTRIBUTES ){ @@ -3369,8 +3785,8 @@ static int winDelete( break; } } while(1); -#endif } +#endif if( rc ){ rc = winLogError(SQLITE_IOERR_DELETE, lastErrno, "winDelete", zFilename); @@ -3430,15 +3846,12 @@ static int winAccess( attr = INVALID_FILE_ATTRIBUTES; } } -/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed. -** Since the ANSI version of these Windows API do not exist for WINCE, -** it's important to not reference them for WINCE builds. -*/ -#if SQLITE_OS_WINCE==0 - }else{ - attr = osGetFileAttributesA((char*)zConverted); -#endif } +#ifdef SQLITE_WIN32_HAS_ANSI + else{ + attr = osGetFileAttributesA((char*)zConverted); + } +#endif sqlite3_free(zConverted); switch( flags ){ case SQLITE_ACCESS_READ: @@ -3457,6 +3870,43 @@ static int winAccess( } +/* +** Returns non-zero if the specified path name should be used verbatim. If +** non-zero is returned from this function, the calling function must simply +** use the provided path name verbatim -OR- resolve it into a full path name +** using the GetFullPathName Win32 API function (if available). +*/ +static BOOL winIsVerbatimPathname( + const char *zPathname +){ + /* + ** If the path name starts with a forward slash or a backslash, it is either + ** a legal UNC name, a volume relative path, or an absolute path name in the + ** "Unix" format on Windows. There is no easy way to differentiate between + ** the final two cases; therefore, we return the safer return value of TRUE + ** so that callers of this function will simply use it verbatim. + */ + if ( zPathname[0]=='/' || zPathname[0]=='\\' ){ + return TRUE; + } + + /* + ** If the path name starts with a letter and a colon it is either a volume + ** relative path or an absolute path. Callers of this function must not + ** attempt to treat it as a relative path name (i.e. they should simply use + ** it verbatim). + */ + if ( sqlite3Isalpha(zPathname[0]) && zPathname[1]==':' ){ + return TRUE; + } + + /* + ** If we get to this point, the path name should almost certainly be a purely + ** relative one (i.e. not a UNC name, not absolute, and not volume relative). + */ + return FALSE; +} + /* ** Turn a relative pathname into a full pathname. Write the full ** pathname into zOut[]. zOut[] will be at least pVfs->mxPathname @@ -3472,19 +3922,51 @@ static int winFullPathname( #if defined(__CYGWIN__) SimulateIOError( return SQLITE_ERROR ); UNUSED_PARAMETER(nFull); - cygwin_conv_to_full_win32_path(zRelative, zFull); + assert( pVfs->mxPathname>=MAX_PATH ); + assert( nFull>=pVfs->mxPathname ); + if ( sqlite3_data_directory && !winIsVerbatimPathname(zRelative) ){ + /* + ** NOTE: We are dealing with a relative path name and the data + ** directory has been set. Therefore, use it as the basis + ** for converting the relative path name to an absolute + ** one by prepending the data directory and a slash. + */ + char zOut[MAX_PATH+1]; + memset(zOut, 0, MAX_PATH+1); + cygwin_conv_to_win32_path(zRelative, zOut); /* POSIX to Win32 */ + sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s\\%s", + sqlite3_data_directory, zOut); + }else{ + /* + ** NOTE: The Cygwin docs state that the maximum length needed + ** for the buffer passed to cygwin_conv_to_full_win32_path + ** is MAX_PATH. + */ + cygwin_conv_to_full_win32_path(zRelative, zFull); + } return SQLITE_OK; #endif -#if SQLITE_OS_WINCE +#if (SQLITE_OS_WINCE || SQLITE_OS_WINRT) && !defined(__CYGWIN__) SimulateIOError( return SQLITE_ERROR ); - UNUSED_PARAMETER(nFull); /* WinCE has no concept of a relative pathname, or so I am told. */ - sqlite3_snprintf(pVfs->mxPathname, zFull, "%s", zRelative); + /* WinRT has no way to convert a relative path to an absolute one. */ + if ( sqlite3_data_directory && !winIsVerbatimPathname(zRelative) ){ + /* + ** NOTE: We are dealing with a relative path name and the data + ** directory has been set. Therefore, use it as the basis + ** for converting the relative path name to an absolute + ** one by prepending the data directory and a backslash. + */ + sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s\\%s", + sqlite3_data_directory, zRelative); + }else{ + sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zRelative); + } return SQLITE_OK; #endif -#if !SQLITE_OS_WINCE && !defined(__CYGWIN__) +#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && !defined(__CYGWIN__) int nByte; void *zConverted; char *zOut; @@ -3502,7 +3984,17 @@ static int winFullPathname( ** current working directory has been unlinked. */ SimulateIOError( return SQLITE_ERROR ); - UNUSED_PARAMETER(nFull); + if ( sqlite3_data_directory && !winIsVerbatimPathname(zRelative) ){ + /* + ** NOTE: We are dealing with a relative path name and the data + ** directory has been set. Therefore, use it as the basis + ** for converting the relative path name to an absolute + ** one by prepending the data directory and a backslash. + */ + sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s\\%s", + sqlite3_data_directory, zRelative); + return SQLITE_OK; + } zConverted = convertUtf8Filename(zRelative); if( zConverted==0 ){ return SQLITE_IOERR_NOMEM; @@ -3519,12 +4011,9 @@ static int winFullPathname( sqlite3_free(zConverted); zOut = unicodeToUtf8(zTemp); sqlite3_free(zTemp); -/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed. -** Since the ANSI version of these Windows API do not exist for WINCE, -** it's important to not reference them for WINCE builds. -*/ -#if SQLITE_OS_WINCE==0 - }else{ + } +#ifdef SQLITE_WIN32_HAS_ANSI + else{ char *zTemp; nByte = osGetFullPathNameA((char*)zConverted, 0, 0, 0) + 3; zTemp = sqlite3_malloc( nByte*sizeof(zTemp[0]) ); @@ -3536,10 +4025,10 @@ static int winFullPathname( sqlite3_free(zConverted); zOut = sqlite3_win32_mbcs_to_utf8(zTemp); sqlite3_free(zTemp); -#endif } +#endif if( zOut ){ - sqlite3_snprintf(pVfs->mxPathname, zFull, "%s", zOut); + sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zOut); sqlite3_free(zOut); return SQLITE_OK; }else{ @@ -3565,16 +4054,17 @@ static void *winDlOpen(sqlite3_vfs *pVfs, const char *zFilename){ return 0; } if( isNT() ){ +#if SQLITE_OS_WINRT + h = osLoadPackagedLibrary((LPCWSTR)zConverted, 0); +#else h = osLoadLibraryW((LPCWSTR)zConverted); -/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed. -** Since the ANSI version of these Windows API do not exist for WINCE, -** it's important to not reference them for WINCE builds. -*/ -#if SQLITE_OS_WINCE==0 - }else{ - h = osLoadLibraryA((char*)zConverted); #endif } +#ifdef SQLITE_WIN32_HAS_ANSI + else{ + h = osLoadLibraryA((char*)zConverted); + } +#endif sqlite3_free(zConverted); return (void*)h; } @@ -3619,11 +4109,19 @@ static int winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){ memcpy(&zBuf[n], &pid, sizeof(pid)); n += sizeof(pid); } +#if SQLITE_OS_WINRT + if( sizeof(ULONGLONG)<=nBuf-n ){ + ULONGLONG cnt = osGetTickCount64(); + memcpy(&zBuf[n], &cnt, sizeof(cnt)); + n += sizeof(cnt); + } +#else if( sizeof(DWORD)<=nBuf-n ){ DWORD cnt = osGetTickCount(); memcpy(&zBuf[n], &cnt, sizeof(cnt)); n += sizeof(cnt); } +#endif if( sizeof(LARGE_INTEGER)<=nBuf-n ){ LARGE_INTEGER i; osQueryPerformanceCounter(&i); @@ -3639,7 +4137,7 @@ static int winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){ ** Sleep for a little while. Return the amount of time slept. */ static int winSleep(sqlite3_vfs *pVfs, int microsec){ - osSleep((microsec+999)/1000); + sqlite3_win32_sleep((microsec+999)/1000); UNUSED_PARAMETER(pVfs); return ((microsec+999)/1000)*1000; } @@ -3781,12 +4279,16 @@ int sqlite3_os_init(void){ /* Double-check that the aSyscall[] array has been constructed ** correctly. See ticket [bb3a86e890c8e96ab] */ - assert( ArraySize(aSyscall)==60 ); + assert( ArraySize(aSyscall)==73 ); #ifndef SQLITE_OMIT_WAL /* get memory map allocation granularity */ memset(&winSysInfo, 0, sizeof(SYSTEM_INFO)); +#if SQLITE_OS_WINRT + osGetNativeSystemInfo(&winSysInfo); +#else osGetSystemInfo(&winSysInfo); +#endif assert(winSysInfo.dwAllocationGranularity > 0); #endif @@ -3795,6 +4297,12 @@ int sqlite3_os_init(void){ } int sqlite3_os_end(void){ +#if SQLITE_OS_WINRT + if( sleepObj != NULL ){ + osCloseHandle(sleepObj); + sleepObj = NULL; + } +#endif return SQLITE_OK; } diff --git a/src/pragma.c b/src/pragma.c index 3401c73c1b..b66290c0e8 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -804,6 +804,50 @@ void sqlite3Pragma( } }else +#if SQLITE_OS_WIN + /* + ** PRAGMA data_store_directory + ** PRAGMA data_store_directory = ""|"directory_name" + ** + ** Return or set the local value of the data_store_directory flag. Changing + ** the value sets a specific directory to be used for database files that + ** were specified with a relative pathname. Setting to a null string reverts + ** to the default database directory, which for database files specified with + ** a relative path will probably be based on the current directory for the + ** process. Database file specified with an absolute path are not impacted + ** by this setting, regardless of its value. + ** + */ + if( sqlite3StrICmp(zLeft, "data_store_directory")==0 ){ + if( !zRight ){ + if( sqlite3_data_directory ){ + sqlite3VdbeSetNumCols(v, 1); + sqlite3VdbeSetColName(v, 0, COLNAME_NAME, + "data_store_directory", SQLITE_STATIC); + sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, sqlite3_data_directory, 0); + sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1); + } + }else{ +#ifndef SQLITE_OMIT_WSD + if( zRight[0] ){ + int res; + rc = sqlite3OsAccess(db->pVfs, zRight, SQLITE_ACCESS_READWRITE, &res); + if( rc!=SQLITE_OK || res==0 ){ + sqlite3ErrorMsg(pParse, "not a writable directory"); + goto pragma_out; + } + } + sqlite3_free(sqlite3_data_directory); + if( zRight[0] ){ + sqlite3_data_directory = sqlite3_mprintf("%s", zRight); + }else{ + sqlite3_data_directory = 0; + } +#endif /* SQLITE_OMIT_WSD */ + } + }else +#endif + #if !defined(SQLITE_ENABLE_LOCKING_STYLE) # if defined(__APPLE__) # define SQLITE_ENABLE_LOCKING_STYLE 1 diff --git a/src/sqlite.h.in b/src/sqlite.h.in index e96c196802..19ada7d90a 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -2165,12 +2165,12 @@ char *sqlite3_vsnprintf(int,char*,const char*, va_list); ** implementation of these routines to be omitted. That capability ** is no longer provided. Only built-in memory allocators can be used. ** -** The Windows OS interface layer calls +** Prior to SQLite version 3.7.10, the Windows OS interface layer called ** the system malloc() and free() directly when converting ** filenames between the UTF-8 encoding used by SQLite ** and whatever filename encoding is used by the particular Windows -** installation. Memory allocation errors are detected, but -** they are reported back as [SQLITE_CANTOPEN] or +** installation. Memory allocation errors were detected, but +** they were reported back as [SQLITE_CANTOPEN] or ** [SQLITE_IOERR] rather than [SQLITE_NOMEM]. ** ** The pointer arguments to [sqlite3_free()] and [sqlite3_realloc()] @@ -4447,6 +4447,42 @@ int sqlite3_sleep(int); */ SQLITE_EXTERN char *sqlite3_temp_directory; +/* +** CAPI3REF: Name Of The Folder Holding Database Files +** +** ^(If this global variable is made to point to a string which is +** the name of a folder (a.k.a. directory), then all database files +** specified with a relative pathname and created or accessed by +** SQLite when using a built-in [sqlite3_vfs | VFS] will be assumed +** to be relative to that directory.)^ ^If this variable is a NULL +** pointer, then SQLite assumes that all database files specified +** with a relative pathname are relative to the current directory +** for the process. +** +** Changing the value of this variable while a database connection is +** open can result in a corrupt database. +** +** It is not safe to read or modify this variable in more than one +** thread at a time. It is not safe to read or modify this variable +** if a [database connection] is being used at the same time in a separate +** thread. +** It is intended that this variable be set once +** as part of process initialization and before any SQLite interface +** routines have been called and that this variable remain unchanged +** thereafter. +** +** ^The [data_store_directory pragma] may modify this variable and cause +** it to point to memory obtained from [sqlite3_malloc]. ^Furthermore, +** the [data_store_directory pragma] always assumes that any string +** that this variable points to is held in memory obtained from +** [sqlite3_malloc] and the pragma may attempt to free that memory +** using [sqlite3_free]. +** Hence, if this variable is modified directly, either it should be +** made NULL or made to point to memory obtained from [sqlite3_malloc] +** or else the use of the [data_store_directory pragma] should be avoided. +*/ +SQLITE_EXTERN char *sqlite3_data_directory; + /* ** CAPI3REF: Test For Auto-Commit Mode ** KEYWORDS: {autocommit mode} diff --git a/src/test1.c b/src/test1.c index 6849b5c716..445f4f2bf5 100644 --- a/src/test1.c +++ b/src/test1.c @@ -6287,6 +6287,8 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ (char*)&sqlite_static_bind_nbyte, TCL_LINK_INT); Tcl_LinkVar(interp, "sqlite_temp_directory", (char*)&sqlite3_temp_directory, TCL_LINK_STRING); + Tcl_LinkVar(interp, "sqlite_data_directory", + (char*)&sqlite3_data_directory, TCL_LINK_STRING); Tcl_LinkVar(interp, "bitmask_size", (char*)&bitmask_size, TCL_LINK_INT|TCL_LINK_READ_ONLY); Tcl_LinkVar(interp, "sqlite_sync_count", diff --git a/src/test_config.c b/src/test_config.c index e784bbef03..c04eb99a10 100644 --- a/src/test_config.c +++ b/src/test_config.c @@ -57,6 +57,12 @@ static void set_options(Tcl_Interp *interp){ Tcl_SetVar2(interp, "sqlite_options","casesensitivelike","0",TCL_GLOBAL_ONLY); #endif +#ifdef SQLITE_CURDIR + Tcl_SetVar2(interp, "sqlite_options", "curdir", "1", TCL_GLOBAL_ONLY); +#else + Tcl_SetVar2(interp, "sqlite_options", "curdir", "0", TCL_GLOBAL_ONLY); +#endif + #ifdef SQLITE_DEBUG Tcl_SetVar2(interp, "sqlite_options", "debug", "1", TCL_GLOBAL_ONLY); #else diff --git a/test/bigfile.test b/test/bigfile.test index d9470acfba..59e9f18c95 100644 --- a/test/bigfile.test +++ b/test/bigfile.test @@ -15,6 +15,8 @@ # $Id: bigfile.test,v 1.12 2009/03/05 04:27:08 shane Exp $ # +if {[file exists skip-big-file]} return + set testdir [file dirname $argv0] source $testdir/tester.tcl diff --git a/test/bigfile2.test b/test/bigfile2.test index b13b75641b..1f0ea85e51 100644 --- a/test/bigfile2.test +++ b/test/bigfile2.test @@ -13,6 +13,8 @@ # files larger than 4GB. # +if {[file exists skip-big-file]} return + set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix bigfile2 diff --git a/test/e_uri.test b/test/e_uri.test index c2b544919c..428c266256 100644 --- a/test/e_uri.test +++ b/test/e_uri.test @@ -131,10 +131,10 @@ sqlite3_config_uri 1 if {$tcl_platform(platform) == "unix"} { set flags [list SQLITE_OPEN_READWRITE SQLITE_OPEN_CREATE SQLITE_OPEN_URI] foreach {tn uri error} " - 1 {file://localhost[get_pwd]/test.db} {not an error} - 2 {file://[get_pwd]/test.db} {not an error} - 3 {file://x[get_pwd]/test.db} {invalid uri authority: x} - 4 {file://invalid[get_pwd]/test.db} {invalid uri authority: invalid} + 1 {file://localhost[test_pwd /]test.db} {not an error} + 2 {file://[test_pwd /]test.db} {not an error} + 3 {file://x[test_pwd /]test.db} {invalid uri authority: x} + 4 {file://invalid[test_pwd /]test.db} {invalid uri authority: invalid} " { do_test 2.$tn { set DB [sqlite3_open_v2 $uri $flags ""] @@ -153,9 +153,9 @@ if {$tcl_platform(platform) == "unix"} { # parameters passed through to the VFS xOpen() methods. # foreach {tn uri parse} " - 1 {file:test.db#abc} {[get_pwd]/test.db {}} - 2 {file:test.db?a=b#abc} {[get_pwd]/test.db {a b}} - 3 {file:test.db?a=b#?c=d} {[get_pwd]/test.db {a b}} + 1 {file:test.db#abc} {[test_pwd / {}]test.db {}} + 2 {file:test.db?a=b#abc} {[test_pwd / {}]test.db {a b}} + 3 {file:test.db?a=b#?c=d} {[test_pwd / {}]test.db {a b}} " { do_filepath_test 3.$tn { parse_uri $uri } $parse } @@ -171,7 +171,7 @@ foreach {tn uri parse} " # path is interpreted as a relative path. # foreach {tn uri parse} " - 1 {file:test.db} {[get_pwd]/test.db {}} + 1 {file:test.db} {[test_pwd / {}]test.db {}} 2 {file:/test.db} {/test.db {}} 3 {file:///test.db} {/test.db {}} 4 {file://localhost/test.db} {/test.db {}} diff --git a/test/misc1.test b/test/misc1.test index e3f1b9555a..188a2837ba 100644 --- a/test/misc1.test +++ b/test/misc1.test @@ -472,6 +472,11 @@ ifcapable subquery { } {1 2 3 4 5 6 7 8 9 10 11} } +# +# The following tests can only work if the current SQLite VFS has the concept +# of a current directory. +# +ifcapable curdir { # Make sure a database connection still works after changing the # working directory. # @@ -495,6 +500,7 @@ do_test misc1-14.3 { execsql {COMMIT} file exists ./test.db-journal } {0} +} # A failed create table should not leave the table in the internal # data structures. Ticket #238. diff --git a/test/pager1.test b/test/pager1.test index 9c62e877fb..61a0c0ccdb 100644 --- a/test/pager1.test +++ b/test/pager1.test @@ -524,18 +524,27 @@ db close # file-system is saved just before the xDelete() call to remove the # master journal file from the file-system. # +set pwd [get_pwd] testvfs tv -default 1 tv script copy_on_mj_delete set ::mj_filename_length 0 proc copy_on_mj_delete {method filename args} { if {[string match *mj* [file tail $filename]]} { - set ::mj_filename_length [string length $filename] + # + # NOTE: Is the file name relative? If so, add the length of the current + # directory. + # + if {[is_relative_file $filename]} { + set ::mj_filename_length \ + [expr {[string length $filename] + [string length $::pwd]}] + } else { + set ::mj_filename_length [string length $filename] + } faultsim_save } return SQLITE_OK } -set pwd [get_pwd] foreach {tn1 tcl} { 1 { set prefix "test.db" } 2 { @@ -1019,8 +1028,17 @@ do_test pager1-5.4.1 { # the master-journal name encoded as utf-8 with no nul term. # set mj_pointer [expr { - 20 + [string length [get_pwd]] + [string length "/test.db-mjXXXXXX9XX"] + 20 + [string length "test.db-mjXXXXXX9XX"] }] + # + # NOTE: For item 3 above, if the current SQLite VFS lacks the concept of a + # current directory, the length of the current directory name plus 1 + # character for the directory separator character are NOT counted as + # part of the total size; otherwise, they are. + # + ifcapable curdir { + set mj_pointer [expr {$mj_pointer + [string length [get_pwd]] + 1}] + } expr {$::max_journal==(512+2*(1024+8)+$mj_pointer)} } 1 do_test pager1-5.4.2 { @@ -1038,8 +1056,17 @@ do_test pager1-5.4.2 { # written starting at the next (in this case 512 byte) sector boundary. # set mj_pointer [expr { - 20 + [string length [get_pwd]] + [string length "/test.db-mjXXXXXX9XX"] + 20 + [string length "test.db-mjXXXXXX9XX"] }] + # + # NOTE: If the current SQLite VFS lacks the concept of a current directory, + # the length of the current directory name plus 1 character for the + # directory separator character are NOT counted as part of the total + # size; otherwise, they are. + # + ifcapable curdir { + set mj_pointer [expr {$mj_pointer + [string length [get_pwd]] + 1}] + } expr {$::max_journal==(((512+2*(1024+8)+511)/512)*512 + $mj_pointer)} } 1 db close diff --git a/test/pragma.test b/test/pragma.test index bb10327c3a..e249897fe3 100644 --- a/test/pragma.test +++ b/test/pragma.test @@ -40,6 +40,7 @@ do_not_use_codec # pragma-15.*: Test that the value set using the cache_size pragma is not # reset when the schema is reloaded. # pragma-16.*: Test proxy locking +# pragma-20.*: Test data_store_directory. # ifcapable !pragma { @@ -1510,5 +1511,47 @@ do_test pragma-19.5 { file tail [lindex [execsql {PRAGMA filename}] 0] } {test.db} +if {$tcl_platform(platform)=="windows"} { +# Test data_store_directory pragma +# +db close +sqlite3 db test.db +file mkdir data_dir +do_test pragma-20.1 { + catchsql {PRAGMA data_store_directory} +} {0 {}} +do_test pragma-20.2 { + set pwd [string map {' ''} [file nativename [get_pwd]]] + catchsql "PRAGMA data_store_directory='$pwd';" +} {0 {}} +do_test pragma-20.3 { + catchsql {PRAGMA data_store_directory} +} [list 0 [list [file nativename [get_pwd]]]] +do_test pragma-20.4 { + set pwd [string map {' ''} [file nativename \ + [file join [get_pwd] data_dir]]] + catchsql "PRAGMA data_store_directory='$pwd';" +} {0 {}} +do_test pragma-20.5 { + sqlite3 db2 test2.db + catchsql "PRAGMA database_list;" db2 +} [list 0 [list 0 main [file nativename \ + [file join [get_pwd] data_dir test2.db]]]] +catch {db2 close} +do_test pragma-20.6 { + sqlite3 db2 [file join [get_pwd] test2.db] + catchsql "PRAGMA database_list;" db2 +} [list 0 [list 0 main [file nativename \ + [file join [get_pwd] test2.db]]]] +catch {db2 close} +do_test pragma-20.7 { + catchsql "PRAGMA data_store_directory='';" +} {0 {}} +do_test pragma-20.8 { + catchsql {PRAGMA data_store_directory} +} {0 {}} + +forcedelete data_dir +} ;# endif windows finish_test diff --git a/test/quota.test b/test/quota.test index ec89086d35..816dec8b8f 100644 --- a/test/quota.test +++ b/test/quota.test @@ -12,6 +12,13 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl + +# If SQLITE_CURDIR is not defined, omit this file. +ifcapable !curdir { + finish_test + return +} + source $testdir/malloc_common.tcl unset -nocomplain defaultVfs diff --git a/test/quota2.test b/test/quota2.test index 202cdacf1c..1482db69e0 100644 --- a/test/quota2.test +++ b/test/quota2.test @@ -12,6 +12,13 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl + +# If SQLITE_CURDIR is not defined, omit this file. +ifcapable !curdir { + finish_test + return +} + source $testdir/malloc_common.tcl db close diff --git a/test/shared.test b/test/shared.test index 44df2b4691..e297be678e 100644 --- a/test/shared.test +++ b/test/shared.test @@ -904,9 +904,11 @@ do_test shared-$av.11.8 { set res } {1 4 {} 7} if {[llength [info command sqlite3_shared_cache_report]]==1} { - do_test shared-$av.11.9 { - string tolower [sqlite3_shared_cache_report] - } [string tolower [list [file nativename [file normalize test.db]] 2]] + ifcapable curdir { + do_test shared-$av.11.9 { + string tolower [sqlite3_shared_cache_report] + } [string tolower [list [file nativename [file normalize test.db]] 2]] + } } do_test shared-$av.11.11 { diff --git a/test/shell1.test b/test/shell1.test index 0cafc35ae5..47f9e41d02 100644 --- a/test/shell1.test +++ b/test/shell1.test @@ -283,7 +283,7 @@ do_test shell1-3.2.4 { # .databases List names and files of attached databases do_test shell1-3.3.1 { catchcmd "-csv test.db" ".databases" -} "/0 +.*main +[string map {/ .} [string range [pwd] 0 10]].*/" +} "/0 +.*main +[string map {/ .} [string range [get_pwd] 0 10]].*/" do_test shell1-3.3.2 { # too many arguments catchcmd "test.db" ".databases BAD" diff --git a/test/tester.tcl b/test/tester.tcl index 07eebcbf5f..68b2c8df4c 100644 --- a/test/tester.tcl +++ b/test/tester.tcl @@ -19,6 +19,8 @@ # # Commands to manipulate the db and the file-system at a high level: # +# is_relative_file +# test_pwd # get_pwd # copy_file FROM TO # delete_file FILENAME @@ -212,6 +214,34 @@ proc do_copy_file {force from to} { } } +# Check if a file name is relative +# +proc is_relative_file { file } { + return [expr {[file pathtype $file] != "absolute"}] +} + +# If the VFS supports using the current directory, returns [pwd]; +# otherwise, it returns only the provided suffix string (which is +# empty by default). +# +proc test_pwd { args } { + if {[llength $args] > 0} { + set suffix1 [lindex $args 0] + if {[llength $args] > 1} { + set suffix2 [lindex $args 1] + } else { + set suffix2 $suffix1 + } + } else { + set suffix1 ""; set suffix2 "" + } + ifcapable curdir { + return "[get_pwd]$suffix1" + } else { + return $suffix2 + } +} + # Delete a file or directory # proc delete_file {args} { diff --git a/test/uri.test b/test/uri.test index 93a32b773e..af1ad67250 100644 --- a/test/uri.test +++ b/test/uri.test @@ -52,11 +52,24 @@ foreach {tn uri file} { 16 file://localhostPWD/test.db%3Fhello test.db?hello } { + + ifcapable !curdir { if {$tn==3} break } + if {$tcl_platform(platform)=="windows"} { + # + # NOTE: Due to limits on legal characters for file names imposed by + # Windows, we must skip the final two tests here (i.e. the + # question mark is illegal in a file name on Windows). + # if {$tn>14} break - set uri [string map [list PWD /[get_pwd]] $uri] + + # + # NOTE: On Windows, we need to account for the fact that the current + # directory does not start with a forward slash. + # + set uri [string map [list PWD/ /[test_pwd /]] $uri] } else { - set uri [string map [list PWD [get_pwd]] $uri] + set uri [string map [list PWD/ [test_pwd /]] $uri] } if {[file isdir $file]} {error "$file is a directory"} diff --git a/test/wal.test b/test/wal.test index 32b2608d2a..24ce5f86a3 100644 --- a/test/wal.test +++ b/test/wal.test @@ -1478,7 +1478,11 @@ foreach pgsz {512 1024 2048 4096 8192 16384 32768 65536} { # Test that when 1 or more pages are recovered from a WAL file, # sqlite3_log() is invoked to report this to the user. # -set walfile [file nativename [file join [get_pwd] test.db-wal]] +ifcapable curdir { + set walfile [file nativename [file join [get_pwd] test.db-wal]] +} else { + set walfile test.db-wal +} catch {db close} forcedelete test.db do_test wal-23.1 {