From: drh Date: Sat, 3 Jun 2006 18:02:15 +0000 (+0000) Subject: Added support for OS/2. Ticket #1817 (CVS 3198) X-Git-Tag: version-3.6.10~2969 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=60a1e4b6ce656d0344859341de4233d0b35a43ee;p=thirdparty%2Fsqlite.git Added support for OS/2. Ticket #1817 (CVS 3198) FossilOrigin-Name: 373246c2d1edaec1ce248ff875db48ce51d896f9 --- diff --git a/Makefile.in b/Makefile.in index 2c584c3c2a..81ea22e95e 100644 --- a/Makefile.in +++ b/Makefile.in @@ -125,7 +125,7 @@ TCC += -DSQLITE_OMIT_CURSOR LIBOBJ = alter.lo analyze.lo attach.lo auth.lo btree.lo build.lo \ callback.lo complete.lo date.lo \ delete.lo expr.lo func.lo hash.lo insert.lo \ - main.lo opcodes.lo os.lo os_unix.lo os_win.lo \ + main.lo opcodes.lo os.lo os_unix.lo os_win.lo os_os2.lo \ pager.lo parse.lo pragma.lo prepare.lo printf.lo random.lo \ select.lo table.lo tokenize.lo trigger.lo update.lo \ util.lo vacuum.lo \ @@ -156,6 +156,7 @@ SRC = \ $(TOP)/src/os.c \ $(TOP)/src/os_unix.c \ $(TOP)/src/os_win.c \ + $(TOP)/src/os_os2.c \ $(TOP)/src/pager.c \ $(TOP)/src/pager.h \ $(TOP)/src/parse.y \ @@ -193,6 +194,7 @@ TESTSRC = \ $(TOP)/src/os.c \ $(TOP)/src/os_unix.c \ $(TOP)/src/os_win.c \ + $(TOP)/src/os_os2.c \ $(TOP)/src/pager.c \ $(TOP)/src/pragma.c \ $(TOP)/src/printf.c \ @@ -257,7 +259,7 @@ libtclsqlite3.la: tclsqlite.lo libsqlite3.la sqlite3$(TEXE): $(TOP)/src/shell.c libsqlite3.la sqlite3.h $(LTLINK) $(READLINE_FLAGS) $(LIBPTHREAD) \ - -o sqlite3 $(TOP)/src/shell.c libsqlite3.la \ + -o $@ $(TOP)/src/shell.c libsqlite3.la \ $(LIBREADLINE) $(TLIBS) # This target creates a directory named "tsrc" and fills it with @@ -352,6 +354,9 @@ os_unix.lo: $(TOP)/src/os_unix.c $(HDR) os_win.lo: $(TOP)/src/os_win.c $(HDR) $(LTCOMPILE) -c $(TOP)/src/os_win.c +os_os2.lo: $(TOP)/src/os_os2.c $(HDR) + $(LTCOMPILE) -c $(TOP)/src/os_os2.c + parse.lo: parse.c $(HDR) $(LTCOMPILE) -c parse.c diff --git a/aclocal.m4 b/aclocal.m4 index 852eb3134b..b50b61e56a 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -151,7 +151,7 @@ ltmain="$ac_aux_dir/ltmain.sh" ofile="$default_ofile" with_gnu_ld="$lt_cv_prog_gnu_ld" -AC_CHECK_TOOL(AR, ar, false) +AC_CHECK_TOOL(AR, ar, AC_CHECK_TOOL(AR, emxomfar, false)) AC_CHECK_TOOL(RANLIB, ranlib, :) AC_CHECK_TOOL(STRIP, strip, :) diff --git a/configure b/configure index 39ee1c5b81..90b92b0540 100755 --- a/configure +++ b/configure @@ -463,7 +463,7 @@ ac_includes_default="\ # include #endif" -ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT EGREP LN_S ECHO AR ac_ct_AR RANLIB ac_ct_RANLIB STRIP ac_ct_STRIP CPP CXX CXXFLAGS ac_ct_CXX CXXCPP F77 FFLAGS ac_ct_F77 LIBTOOL INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA AWK program_prefix VERSION RELEASE VERSION_NUMBER BUILD_CC BUILD_CFLAGS BUILD_LIBS TARGET_CC TARGET_CFLAGS TARGET_LINK TARGET_LFLAGS TARGET_RANLIB TARGET_AR THREADSAFE TARGET_THREAD_LIB XTHREADCONNECT THREADSOVERRIDELOCKS ALLOWRELEASE TEMP_STORE BUILD_EXEEXT OS_UNIX OS_WIN TARGET_EXEEXT TCL_VERSION TCL_BIN_DIR TCL_SRC_DIR TCL_LIBS TCL_INCLUDE_SPEC TCL_LIB_FILE TCL_LIB_FLAG TCL_LIB_SPEC TCL_STUB_LIB_FILE TCL_STUB_LIB_FLAG TCL_STUB_LIB_SPEC HAVE_TCL TARGET_READLINE_LIBS TARGET_READLINE_INC TARGET_HAVE_READLINE TARGET_DEBUG TARGET_LIBS LIBOBJS LTLIBOBJS' +ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT EGREP LN_S ECHO AR ac_ct_AR RANLIB ac_ct_RANLIB STRIP ac_ct_STRIP CPP CXX CXXFLAGS ac_ct_CXX CXXCPP F77 FFLAGS ac_ct_F77 LIBTOOL INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA AWK program_prefix VERSION RELEASE VERSION_NUMBER BUILD_CC BUILD_CFLAGS BUILD_LIBS TARGET_CC TARGET_CFLAGS TARGET_LINK TARGET_LFLAGS TARGET_RANLIB TARGET_AR THREADSAFE TARGET_THREAD_LIB XTHREADCONNECT THREADSOVERRIDELOCKS ALLOWRELEASE TEMP_STORE BUILD_EXEEXT OS_UNIX OS_WIN OS_OS2 TARGET_EXEEXT TCL_VERSION TCL_BIN_DIR TCL_SRC_DIR TCL_LIBS TCL_INCLUDE_SPEC TCL_LIB_FILE TCL_LIB_FLAG TCL_LIB_SPEC TCL_STUB_LIB_FILE TCL_STUB_LIB_FLAG TCL_STUB_LIB_SPEC HAVE_TCL TARGET_READLINE_LIBS TARGET_READLINE_INC TARGET_HAVE_READLINE TARGET_DEBUG TARGET_LIBS LIBOBJS LTLIBOBJS' ac_subst_files='' # Initialize some variables set by options. @@ -1502,7 +1502,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu # The following RCS revision string applies to configure.in -# $Revision: 1.39 $ +# $Revision: 1.40 $ ######### # Programs needed @@ -19695,13 +19695,26 @@ else TARGET_EXEEXT=$config_TARGET_EXEEXT fi if test "$TARGET_EXEEXT" = ".exe"; then - OS_UNIX=0 - OS_WIN=1 - tclsubdir=win - TARGET_CFLAGS="$TARGET_CFLAGS -DOS_WIN=1" + if test $OS2_SHELL ; then + OS_UNIX=0 + OS_WIN=0 + OS_OS2=1 + TARGET_CFLAGS="$TARGET_CFLAGS -DOS_OS2=1" + if test "$ac_compiler_gnu" == "yes" ; then + TARGET_CFLAGS="$TARGET_CFLAGS -Zomf -Zexe -Zmap" + BUILD_CFLAGS="$BUILD_CFLAGS -Zomf -Zexe" + fi + else + OS_UNIX=0 + OS_WIN=1 + OS_OS2=0 + tclsubdir=win + TARGET_CFLAGS="$TARGET_CFLAGS -DOS_WIN=1" + fi else OS_UNIX=1 OS_WIN=0 + OS_OS2=0 tclsubdir=unix TARGET_CFLAGS="$TARGET_CFLAGS -DOS_UNIX=1" fi @@ -21378,6 +21391,7 @@ s,@TEMP_STORE@,$TEMP_STORE,;t t s,@BUILD_EXEEXT@,$BUILD_EXEEXT,;t t s,@OS_UNIX@,$OS_UNIX,;t t s,@OS_WIN@,$OS_WIN,;t t +s,@OS_OS2@,$OS_OS2,;t t s,@TARGET_EXEEXT@,$TARGET_EXEEXT,;t t s,@TCL_VERSION@,$TCL_VERSION,;t t s,@TCL_BIN_DIR@,$TCL_BIN_DIR,;t t diff --git a/configure.ac b/configure.ac index 47deadc2a9..85af8960d5 100644 --- a/configure.ac +++ b/configure.ac @@ -116,7 +116,7 @@ AC_INIT(src/sqlite.h.in) dnl Put the RCS revision string after AC_INIT so that it will also dnl show in in configure. # The following RCS revision string applies to configure.in -# $Revision: 1.25 $ +# $Revision: 1.26 $ ######### # Programs needed @@ -407,13 +407,26 @@ else TARGET_EXEEXT=$config_TARGET_EXEEXT fi if test "$TARGET_EXEEXT" = ".exe"; then - OS_UNIX=0 - OS_WIN=1 - tclsubdir=win - TARGET_CFLAGS="$TARGET_CFLAGS -DOS_WIN=1" + if test $OS2_SHELL ; then + OS_UNIX=0 + OS_WIN=0 + OS_OS2=1 + TARGET_CFLAGS="$TARGET_CFLAGS -DOS_OS2=1" + if test "$ac_compiler_gnu" == "yes" ; then + TARGET_CFLAGS="$TARGET_CFLAGS -Zomf -Zexe -Zmap" + BUILD_CFLAGS="$BUILD_CFLAGS -Zomf -Zexe" + fi + else + OS_UNIX=0 + OS_WIN=1 + OS_OS2=0 + tclsubdir=win + TARGET_CFLAGS="$TARGET_CFLAGS -DOS_WIN=1" + fi else OS_UNIX=1 OS_WIN=0 + OS_OS2=0 tclsubdir=unix TARGET_CFLAGS="$TARGET_CFLAGS -DOS_UNIX=1" fi @@ -421,6 +434,7 @@ fi AC_SUBST(BUILD_EXEEXT) AC_SUBST(OS_UNIX) AC_SUBST(OS_WIN) +AC_SUBST(OS_OS2) AC_SUBST(TARGET_EXEEXT) ########## diff --git a/main.mk b/main.mk index 504676531c..580835f289 100644 --- a/main.mk +++ b/main.mk @@ -58,7 +58,7 @@ TCCX = $(TCC) $(OPTS) $(THREADSAFE) $(USLEEP) -I. -I$(TOP)/src LIBOBJ+= alter.o analyze.o attach.o auth.o btree.o build.o \ callback.o complete.o date.o delete.o \ expr.o func.o hash.o insert.o \ - main.o opcodes.o os.o os_unix.o os_win.o \ + main.o opcodes.o os.o os_os2.o os_unix.o os_win.o \ pager.o parse.o pragma.o prepare.o printf.o random.o \ select.o table.o tclsqlite.o tokenize.o trigger.o \ update.o util.o vacuum.o \ @@ -87,6 +87,7 @@ SRC = \ $(TOP)/src/legacy.c \ $(TOP)/src/main.c \ $(TOP)/src/os.c \ + $(TOP)/src/os_os2.c \ $(TOP)/src/os_unix.c \ $(TOP)/src/os_win.c \ $(TOP)/src/pager.c \ @@ -124,6 +125,7 @@ TESTSRC = \ $(TOP)/src/date.c \ $(TOP)/src/func.c \ $(TOP)/src/os.c \ + $(TOP)/src/os_os2.c \ $(TOP)/src/os_unix.c \ $(TOP)/src/os_win.c \ $(TOP)/src/pager.c \ @@ -270,6 +272,9 @@ opcodes.h: parse.h $(TOP)/src/vdbe.c $(TOP)/mkopcodeh.awk os.o: $(TOP)/src/os.c $(HDR) $(TCCX) -c $(TOP)/src/os.c +os_os2.o: $(TOP)/src/os_os2.c $(HDR) + $(TCCX) -c $(TOP)/src/os_os2.c + os_unix.o: $(TOP)/src/os_unix.c $(HDR) $(TCCX) -c $(TOP)/src/os_unix.c diff --git a/manifest b/manifest index 5d59ed4b7e..2800f241dc 100644 --- a/manifest +++ b/manifest @@ -1,10 +1,10 @@ -C Do\snot\srecord\sblank\slines\sin\sthe\scommand-line\sediting\shistory\sof\sthe\sshell.\s(CVS\s3197) -D 2006-06-03T17:37:26 -F Makefile.in 5d8dff443383918b700e495de42ec65bc1c8865b +C Added\ssupport\sfor\sOS/2.\s\sTicket\s#1817\s(CVS\s3198) +D 2006-06-03T18:02:16 +F Makefile.in 87b6d483513ab8a4e763775bc5b434d6b5c34963 F Makefile.linux-gcc 74ba0eadf88748a9ce3fd03d2a3ede2e6715baec F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028 F VERSION 2bc3eace6a71bc4f2575679b944378b275e9412c -F aclocal.m4 7daea4c35e88de30d5a3f6f7a2ab99720e803bbd +F aclocal.m4 a8df0ae21d1ac797fa7d7eaa1703412bc61b973f F addopcodes.awk 701697fae48376375ec8532c3d04e910cfeef352 F art/2005osaward.gif 0d1851b2a7c1c9d0ccce545f3e14bca42d7fd248 F art/SQLite.eps 9b43cc99cfd2be687d386faea6862ea68d6a72b2 @@ -12,14 +12,14 @@ F art/SQLite.gif 1bbb94484963f1382e27e1c5e86dd0c1061eba2b F art/SQLiteLogo3.tiff b9e6bf022ae939bc986cddb8ab99583ca1b02cb3 F config.guess 2103e94b15dc57112d7b9ee152c6fac5288895b4 F config.sub 9bf686ec001ae7bc53f5b3563c90c62d4c6d48be -F configure d454f3ef3a1cf42e91e97d06c27179d56a77c005 x -F configure.ac f6c5246585d14bc1ee1773ae5b71ae6cafa7494a +F configure 6be7b37dd811c43f59c119aa5a713f688a2184c4 x +F configure.ac 83eaf11869cd893db6126c0ce77381a9cd264bad F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad F doc/lemon.html f0f682f50210928c07e562621c3b7e8ab912a538 F doc/report1.txt a031aaf37b185e4fa540223cb516d3bccec7eeac F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 F ltmain.sh f6b283068efa69f06eb8aa1fe4bddfdbdeb35826 -F main.mk 33144e8ccfa885a4b0c1c03e85131bd6c541f30c +F main.mk e3dd76266d1b62f1835b238bb0565900ab99fe14 F mkdll.sh 919df5efde876194e3102c6ebc60657d38949909 F mkopcodec.awk bd46ad001c98dfbab07b1713cb8e692fa0e5415d F mkopcodeh.awk cde995d269aa06c94adbf6455bea0acedb913fa5 @@ -51,8 +51,10 @@ F src/legacy.c fa15d505dd4e45044177ee4d1c6aeaf8c836d390 F src/main.c 928d93cfd5d72be3a619ee908182c9432151a99e F src/md5.c c5fdfa5c2593eaee2e32a5ce6c6927c986eaf217 F src/os.c 59f05de8c5777c34876607114a2fbe55ae578235 -F src/os.h 93035a0e3b9dd05cdd0aaef32ea28ca28e02fe78 +F src/os.h 46fad85c707ad8643622bab9d894a642940850aa F src/os_common.h 108cd719c96a2b714b64e02aeabbd40684274e6a +F src/os_os2.c 123cb394c069bc8c6a305830ffa2bc5f72e5b83a +F src/os_os2.h e5f17dd69333632bbc3112881ea407c37d245eb3 F src/os_test.c 49833426101f99aee4bb5f6a44b7c4b2029fda1c F src/os_test.h 903c93554c23d88f34f667f1979e4a1cee792af3 F src/os_unix.c 17d91581a0ab478a06cb6f257b707a4c4a93e5a7 @@ -356,7 +358,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513 -P 4bf03c3bbc1303ed9b4059917e8d6a613b1510f3 -R b3aa39403a9b5a900b82638a005965c6 +P 0eabda82cd0d476a7e05ba4b027b819318aef9c3 +R 6acf85d509c19fb60080d44405f8852c U drh -Z eb8ea770aee12d212e5ceb58cc64d4fe +Z b6f82a7c0122f6042d20b908e87d0aa6 diff --git a/manifest.uuid b/manifest.uuid index 9f28723c87..a1dee26ce0 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -0eabda82cd0d476a7e05ba4b027b819318aef9c3 \ No newline at end of file +373246c2d1edaec1ce248ff875db48ce51d896f9 \ No newline at end of file diff --git a/src/os.h b/src/os.h index b294346b05..8f7c650efc 100644 --- a/src/os.h +++ b/src/os.h @@ -27,12 +27,19 @@ # if defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__BORLANDC__) # define OS_WIN 1 # define OS_UNIX 0 +# define OS_OS2 0 +# elif defined(_EMX_) || defined(_OS2) || defined(OS2) || defined(OS_OS2) +# define OS_WIN 0 +# define OS_UNIX 0 +# define OS_OS2 1 # else # define OS_WIN 0 # define OS_UNIX 1 +# define OS_OS2 0 # endif # else # define OS_UNIX 0 +# define OS_OS2 0 # endif #else # ifndef OS_WIN @@ -47,6 +54,14 @@ #if OS_WIN # include # define SQLITE_TEMPNAME_SIZE (MAX_PATH+50) +#elif OS_OS2 +# define INCL_DOSDATETIME +# define INCL_DOSFILEMGR +# define INCL_DOSERRORS +# define INCL_DOSMISC +# define INCL_DOSPROCESS +# include +# define SQLITE_TEMPNAME_SIZE (CCHMAXPATHCOMP) #else # define SQLITE_TEMPNAME_SIZE 200 #endif @@ -72,7 +87,7 @@ #endif /* -** Define the interfaces for Unix and for Windows. +** Define the interfaces for Unix, Windows, and OS/2. */ #if OS_UNIX #define sqlite3OsOpenReadWrite sqlite3UnixOpenReadWrite @@ -118,6 +133,29 @@ #define sqlite3OsFree sqlite3GenericFree #define sqlite3OsAllocationSize sqlite3GenericAllocationSize #endif +#if OS_OS2 +#define sqlite3OsOpenReadWrite sqlite3Os2OpenReadWrite +#define sqlite3OsOpenExclusive sqlite3Os2OpenExclusive +#define sqlite3OsOpenReadOnly sqlite3Os2OpenReadOnly +#define sqlite3OsDelete sqlite3Os2Delete +#define sqlite3OsFileExists sqlite3Os2FileExists +#define sqlite3OsFullPathname sqlite3Os2FullPathname +#define sqlite3OsIsDirWritable sqlite3Os2IsDirWritable +#define sqlite3OsSyncDirectory sqlite3Os2SyncDirectory +#define sqlite3OsTempFileName sqlite3Os2TempFileName +#define sqlite3OsRandomSeed sqlite3Os2RandomSeed +#define sqlite3OsSleep sqlite3Os2Sleep +#define sqlite3OsCurrentTime sqlite3Os2CurrentTime +#define sqlite3OsEnterMutex sqlite3Os2EnterMutex +#define sqlite3OsLeaveMutex sqlite3Os2LeaveMutex +#define sqlite3OsInMutex sqlite3Os2InMutex +#define sqlite3OsThreadSpecificData sqlite3Os2ThreadSpecificData +#define sqlite3OsMalloc sqlite3GenericMalloc +#define sqlite3OsRealloc sqlite3GenericRealloc +#define sqlite3OsFree sqlite3GenericFree +#define sqlite3OsAllocationSize sqlite3GenericAllocationSize +#endif + /* ** If using an alternative OS interface, then we must have an "os_other.h" diff --git a/src/os_os2.c b/src/os_os2.c new file mode 100644 index 0000000000..ee68d5817f --- /dev/null +++ b/src/os_os2.c @@ -0,0 +1,965 @@ +/* +** 2006 Feb 14 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** This file contains code that is specific to OS/2. +*/ +#include "sqliteInt.h" +#include "os.h" + +#if OS_OS2 + +/* +** Macros used to determine whether or not to use threads. +*/ +#if defined(THREADSAFE) && THREADSAFE +# define SQLITE_OS2_THREADS 1 +#endif + +/* +** Include code that is common to all os_*.c files +*/ +#include "os_common.h" + +/* +** The os2File structure is subclass of OsFile specific for the OS/2 +** protability layer. +*/ +typedef struct os2File os2File; +struct os2File { + IoMethod const *pMethod; /* Always the first entry */ + HFILE h; /* Handle for accessing the file */ + int delOnClose; /* True if file is to be deleted on close */ + char* pathToDel; /* Name of file to delete on close */ + unsigned char locktype; /* Type of lock currently held on this file */ +}; + +/* +** Do not include any of the File I/O interface procedures if the +** SQLITE_OMIT_DISKIO macro is defined (indicating that there database +** will be in-memory only) +*/ +#ifndef SQLITE_OMIT_DISKIO + +/* +** Delete the named file +*/ +int sqlite3Os2Delete( const char *zFilename ){ + DosDelete( (PSZ)zFilename ); + TRACE2( "DELETE \"%s\"\n", zFilename ); + return SQLITE_OK; +} + +/* +** Return TRUE if the named file exists. +*/ +int sqlite3Os2FileExists( const char *zFilename ){ + FILESTATUS3 fsts3ConfigInfo; + memset(&fsts3ConfigInfo, 0, sizeof(fsts3ConfigInfo)); + return DosQueryPathInfo( (PSZ)zFilename, FIL_STANDARD, + &fsts3ConfigInfo, sizeof(FILESTATUS3) ) == NO_ERROR; +} + +/* Forward declaration */ +int allocateOs2File( os2File *pInit, OsFile **pld ); + +/* +** Attempt to open a file for both reading and writing. If that +** fails, try opening it read-only. If the file does not exist, +** try to create it. +** +** On success, a handle for the open file is written to *id +** and *pReadonly is set to 0 if the file was opened for reading and +** writing or 1 if the file was opened read-only. The function returns +** SQLITE_OK. +** +** On failure, the function returns SQLITE_CANTOPEN and leaves +** *id and *pReadonly unchanged. +*/ +int sqlite3Os2OpenReadWrite( + const char *zFilename, + OsFile **pld, + int *pReadonly +){ + os2File f; + HFILE hf; + ULONG ulAction; + APIRET rc; + + assert( *pld == 0 ); + rc = DosOpen( (PSZ)zFilename, &hf, &ulAction, 0L, + FILE_ARCHIVED | FILE_NORMAL, + OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS, + OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_RANDOM | + OPEN_SHARE_DENYNONE | OPEN_ACCESS_READWRITE, (PEAOP2)NULL ); + if( rc != NO_ERROR ){ + rc = DosOpen( (PSZ)zFilename, &hf, &ulAction, 0L, + FILE_ARCHIVED | FILE_NORMAL, + OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS, + OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_RANDOM | + OPEN_SHARE_DENYWRITE | OPEN_ACCESS_READONLY, (PEAOP2)NULL ); + if( rc != NO_ERROR ){ + return SQLITE_CANTOPEN; + } + *pReadonly = 1; + } + else{ + *pReadonly = 0; + } + f.h = hf; + f.locktype = NO_LOCK; + f.delOnClose = 0; + f.pathToDel = NULL; + OpenCounter(+1); + TRACE3( "OPEN R/W %d \"%s\"\n", hf, zFilename ); + return allocateOs2File( &f, pld ); +} + + +/* +** Attempt to open a new file for exclusive access by this process. +** The file will be opened for both reading and writing. To avoid +** a potential security problem, we do not allow the file to have +** previously existed. Nor do we allow the file to be a symbolic +** link. +** +** If delFlag is true, then make arrangements to automatically delete +** the file when it is closed. +** +** On success, write the file handle into *id and return SQLITE_OK. +** +** On failure, return SQLITE_CANTOPEN. +*/ +int sqlite3Os2OpenExclusive( const char *zFilename, OsFile **pld, int delFlag ){ + os2File f; + HFILE hf; + ULONG ulAction; + APIRET rc; + + assert( *pld == 0 ); + rc = DosOpen( (PSZ)zFilename, &hf, &ulAction, 0L, FILE_NORMAL, + OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_REPLACE_IF_EXISTS, + OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_RANDOM | + OPEN_SHARE_DENYREADWRITE | OPEN_ACCESS_READWRITE, (PEAOP2)NULL ); + if( rc != NO_ERROR ){ + return SQLITE_CANTOPEN; + } + + f.h = hf; + f.locktype = NO_LOCK; + f.delOnClose = delFlag ? 1 : 0; + f.pathToDel = delFlag ? sqlite3OsFullPathname( zFilename ) : NULL; + OpenCounter( +1 ); + if( delFlag ) DosForceDelete( sqlite3OsFullPathname( zFilename ) ); + TRACE3( "OPEN EX %d \"%s\"\n", hf, sqlite3OsFullPathname ( zFilename ) ); + return allocateOs2File( &f, pld ); +} + +/* +** Attempt to open a new file for read-only access. +** +** On success, write the file handle into *id and return SQLITE_OK. +** +** On failure, return SQLITE_CANTOPEN. +*/ +int sqlite3Os2OpenReadOnly( const char *zFilename, OsFile **pld ){ + os2File f; + HFILE hf; + ULONG ulAction; + APIRET rc; + + assert( *pld == 0 ); + rc = DosOpen( (PSZ)zFilename, &hf, &ulAction, 0L, + FILE_NORMAL, OPEN_ACTION_OPEN_IF_EXISTS, + OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_RANDOM | + OPEN_SHARE_DENYWRITE | OPEN_ACCESS_READONLY, (PEAOP2)NULL ); + if( rc != NO_ERROR ){ + return SQLITE_CANTOPEN; + } + f.h = hf; + f.locktype = NO_LOCK; + f.delOnClose = 0; + f.pathToDel = NULL; + OpenCounter( +1 ); + TRACE3( "OPEN RO %d \"%s\"\n", hf, zFilename ); + return allocateOs2File( &f, pld ); +} + +/* +** Attempt to open a file descriptor for the directory that contains a +** file. This file descriptor can be used to fsync() the directory +** in order to make sure the creation of a new file is actually written +** to disk. +** +** This routine is only meaningful for Unix. It is a no-op under +** OS/2 since OS/2 does not support hard links. +** +** On success, a handle for a previously open file is at *id is +** updated with the new directory file descriptor and SQLITE_OK is +** returned. +** +** On failure, the function returns SQLITE_CANTOPEN and leaves +** *id unchanged. +*/ +int os2OpenDirectory( + OsFile *id, + const char *zDirname +){ + return SQLITE_OK; +} + +/* +** If the following global variable points to a string which is the +** name of a directory, then that directory will be used to store +** temporary files. +*/ +char *sqlite3_temp_directory = 0; + +/* +** Create a temporary file name in zBuf. zBuf must be big enough to +** hold at least SQLITE_TEMPNAME_SIZE characters. +*/ +int sqlite3Os2TempFileName( char *zBuf ){ + static const unsigned char zChars[] = + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789"; + int i, j; + PSZ zTempPath = 0; + if( DosScanEnv( "TEMP", &zTempPath ) ){ + if( DosScanEnv( "TMP", &zTempPath ) ){ + if( DosScanEnv( "TMPDIR", &zTempPath ) ){ + ULONG ulDriveNum = 0, ulDriveMap = 0; + DosQueryCurrentDisk( &ulDriveNum, &ulDriveMap ); + sprintf( zTempPath, "%c:", (char)( 'A' + ulDriveNum - 1 ) ); + } + } + } + for(;;){ + sprintf( zBuf, "%s\\"TEMP_FILE_PREFIX, zTempPath ); + j = strlen( zBuf ); + sqlite3Randomness( 15, &zBuf[j] ); + for( i = 0; i < 15; i++, j++ ){ + zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ]; + } + zBuf[j] = 0; + if( !sqlite3OsFileExists( zBuf ) ) break; + } + TRACE2( "TEMP FILENAME: %s\n", zBuf ); + return SQLITE_OK; +} + +/* +** Close a file. +*/ +int os2Close( OsFile **pld ){ + os2File *pFile; + if( pld && (pFile = (os2File*)*pld)!=0 ){ + TRACE2( "CLOSE %d\n", pFile->h ); + DosClose( pFile->h ); + pFile->locktype = NO_LOCK; + if( pFile->delOnClose != 0 ){ + DosForceDelete( pFile->pathToDel ); + } + *pld = 0; + OpenCounter( -1 ); + } + + return SQLITE_OK; +} + +/* +** Read data from a file into a buffer. Return SQLITE_OK if all +** bytes were read successfully and SQLITE_IOERR if anything goes +** wrong. +*/ +int os2Read( OsFile *id, void *pBuf, int amt ){ + ULONG got; + assert( id!=0 ); + SimulateIOError( SQLITE_IOERR ); + TRACE3( "READ %d lock=%d\n", ((os2File*)id)->h, ((os2File*)id)->locktype ); + DosRead( ((os2File*)id)->h, pBuf, amt, &got ); + return (got == (ULONG)amt) ? SQLITE_OK : SQLITE_IOERR; +} + +/* +** Write data from a buffer into a file. Return SQLITE_OK on success +** or some other error code on failure. +*/ +int os2Write( OsFile *id, const void *pBuf, int amt ){ + APIRET rc=NO_ERROR; + ULONG wrote; + assert( id!=0 ); + SimulateIOError( SQLITE_IOERR ); + SimulateDiskfullError; + TRACE3( "WRITE %d lock=%d\n", ((os2File*)id)->h, ((os2File*)id)->locktype ); + while( amt > 0 && + (rc = DosWrite( ((os2File*)id)->h, (PVOID)pBuf, amt, &wrote )) && wrote > 0 ){ + amt -= wrote; + pBuf = &((char*)pBuf)[wrote]; + } + + return ( rc != NO_ERROR || amt > (int)wrote ) ? SQLITE_FULL : SQLITE_OK; +} + +/* +** Move the read/write pointer in a file. +*/ +int os2Seek( OsFile *id, i64 offset ){ + APIRET rc; + ULONG filePointer = 0L; + assert( id!=0 ); + rc = DosSetFilePtr( ((os2File*)id)->h, offset, FILE_BEGIN, &filePointer ); + TRACE3( "SEEK %d %lld\n", ((os2File*)id)->h, offset ); + return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR; +} + +/* +** Make sure all writes to a particular file are committed to disk. +*/ +int os2Sync( OsFile *id, int dataOnly ){ + assert( id!=0 ); + TRACE3( "SYNC %d lock=%d\n", ((os2File*)id)->h, ((os2File*)id)->locktype ); + return DosResetBuffer( ((os2File*)id)->h ) ? SQLITE_IOERR : SQLITE_OK; +} + +/* +** Sync the directory zDirname. This is a no-op on operating systems other +** than UNIX. +*/ +int sqlite3Os2SyncDirectory( const char *zDirname ){ + SimulateIOError( SQLITE_IOERR ); + return SQLITE_OK; +} + +/* +** Truncate an open file to a specified size +*/ +int os2Truncate( OsFile *id, i64 nByte ){ + APIRET rc; + ULONG upperBits = nByte>>32; + assert( id!=0 ); + TRACE3( "TRUNCATE %d %lld\n", ((os2File*)id)->h, nByte ); + SimulateIOError( SQLITE_IOERR ); + rc = DosSetFilePtr( ((os2File*)id)->h, nByte, FILE_BEGIN, &upperBits ); + if( rc != NO_ERROR ){ + return SQLITE_IOERR; + } + rc = DosSetFilePtr( ((os2File*)id)->h, 0L, FILE_END, &upperBits ); + return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR; +} + +/* +** Determine the current size of a file in bytes +*/ +int os2FileSize( OsFile *id, i64 *pSize ){ + APIRET rc; + FILESTATUS3 fsts3FileInfo; + memset(&fsts3FileInfo, 0, sizeof(fsts3FileInfo)); + assert( id!=0 ); + SimulateIOError( SQLITE_IOERR ); + rc = DosQueryFileInfo( ((os2File*)id)->h, FIL_STANDARD, &fsts3FileInfo, sizeof(FILESTATUS3) ); + if( rc == NO_ERROR ){ + *pSize = fsts3FileInfo.cbFile; + return SQLITE_OK; + } + else{ + return SQLITE_IOERR; + } +} + +/* +** Acquire a reader lock. +*/ +static int getReadLock( os2File *id ){ + FILELOCK LockArea, + UnlockArea; + memset(&LockArea, 0, sizeof(LockArea)); + memset(&UnlockArea, 0, sizeof(UnlockArea)); + LockArea.lOffset = SHARED_FIRST; + LockArea.lRange = SHARED_SIZE; + UnlockArea.lOffset = 0L; + UnlockArea.lRange = 0L; + return DosSetFileLocks( id->h, &UnlockArea, &LockArea, 2000L, 1L ); +} + +/* +** Undo a readlock +*/ +static int unlockReadLock( os2File *id ){ + FILELOCK LockArea, + UnlockArea; + memset(&LockArea, 0, sizeof(LockArea)); + memset(&UnlockArea, 0, sizeof(UnlockArea)); + LockArea.lOffset = 0L; + LockArea.lRange = 0L; + UnlockArea.lOffset = SHARED_FIRST; + UnlockArea.lRange = SHARED_SIZE; + return DosSetFileLocks( id->h, &UnlockArea, &LockArea, 2000L, 1L ); +} + +#ifndef SQLITE_OMIT_PAGER_PRAGMAS +/* +** Check that a given pathname is a directory and is writable +** +*/ +int sqlite3Os2IsDirWritable( char *zDirname ){ + FILESTATUS3 fsts3ConfigInfo; + APIRET rc = NO_ERROR; + memset(&fsts3ConfigInfo, 0, sizeof(fsts3ConfigInfo)); + if( zDirname==0 ) return 0; + if( strlen(zDirname)>CCHMAXPATH ) return 0; + rc = DosQueryPathInfo( (PSZ)zDirname, FIL_STANDARD, &fsts3ConfigInfo, sizeof(FILESTATUS3) ); + if( rc != NO_ERROR ) return 0; + if( (fsts3ConfigInfo.attrFile & FILE_DIRECTORY) != FILE_DIRECTORY ) return 0; + + return 1; +} +#endif /* SQLITE_OMIT_PAGER_PRAGMAS */ + +/* +** Lock the file with the lock specified by parameter locktype - one +** of the following: +** +** (1) SHARED_LOCK +** (2) RESERVED_LOCK +** (3) PENDING_LOCK +** (4) EXCLUSIVE_LOCK +** +** Sometimes when requesting one lock state, additional lock states +** are inserted in between. The locking might fail on one of the later +** transitions leaving the lock state different from what it started but +** still short of its goal. The following chart shows the allowed +** transitions and the inserted intermediate states: +** +** UNLOCKED -> SHARED +** SHARED -> RESERVED +** SHARED -> (PENDING) -> EXCLUSIVE +** RESERVED -> (PENDING) -> EXCLUSIVE +** PENDING -> EXCLUSIVE +** +** This routine will only increase a lock. The os2Unlock() routine +** erases all locks at once and returns us immediately to locking level 0. +** It is not possible to lower the locking level one step at a time. You +** must go straight to locking level 0. +*/ +int os2Lock( OsFile *id, int locktype ){ + APIRET rc = SQLITE_OK; /* Return code from subroutines */ + APIRET res = 1; /* Result of a windows lock call */ + int newLocktype; /* Set id->locktype to this value before exiting */ + int gotPendingLock = 0;/* True if we acquired a PENDING lock this time */ + FILELOCK LockArea, + UnlockArea; + os2File *pFile = (os2File*)id; + memset(&LockArea, 0, sizeof(LockArea)); + memset(&UnlockArea, 0, sizeof(UnlockArea)); + assert( pFile!=0 ); + TRACE4( "LOCK %d %d was %d\n", pFile->h, locktype, pFile->locktype ); + + /* If there is already a lock of this type or more restrictive on the + ** OsFile, do nothing. Don't use the end_lock: exit path, as + ** sqlite3OsEnterMutex() hasn't been called yet. + */ + if( pFile->locktype>=locktype ){ + return SQLITE_OK; + } + + /* Make sure the locking sequence is correct + */ + assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK ); + assert( locktype!=PENDING_LOCK ); + assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK ); + + /* Lock the PENDING_LOCK byte if we need to acquire a PENDING lock or + ** a SHARED lock. If we are acquiring a SHARED lock, the acquisition of + ** the PENDING_LOCK byte is temporary. + */ + newLocktype = pFile->locktype; + if( pFile->locktype==NO_LOCK + || (locktype==EXCLUSIVE_LOCK && pFile->locktype==RESERVED_LOCK) + ){ + int cnt = 3; + + LockArea.lOffset = PENDING_BYTE; + LockArea.lRange = 1L; + UnlockArea.lOffset = 0L; + UnlockArea.lRange = 0L; + + while( cnt-->0 && (res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 2000L, 1L) )!=NO_ERROR ){ + /* Try 3 times to get the pending lock. The pending lock might be + ** held by another reader process who will release it momentarily. + */ + TRACE2( "could not get a PENDING lock. cnt=%d\n", cnt ); + DosSleep(1); + } + gotPendingLock = res; + } + + /* Acquire a shared lock + */ + if( locktype==SHARED_LOCK && res ){ + assert( pFile->locktype==NO_LOCK ); + res = getReadLock(pFile); + if( res == NO_ERROR ){ + newLocktype = SHARED_LOCK; + } + } + + /* Acquire a RESERVED lock + */ + if( locktype==RESERVED_LOCK && res ){ + assert( pFile->locktype==SHARED_LOCK ); + LockArea.lOffset = RESERVED_BYTE; + LockArea.lRange = 1L; + UnlockArea.lOffset = 0L; + UnlockArea.lRange = 0L; + res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 2000L, 1L ); + if( res == NO_ERROR ){ + newLocktype = RESERVED_LOCK; + } + } + + /* Acquire a PENDING lock + */ + if( locktype==EXCLUSIVE_LOCK && res ){ + newLocktype = PENDING_LOCK; + gotPendingLock = 0; + } + + /* Acquire an EXCLUSIVE lock + */ + if( locktype==EXCLUSIVE_LOCK && res ){ + assert( pFile->locktype>=SHARED_LOCK ); + res = unlockReadLock(pFile); + TRACE2( "unreadlock = %d\n", res ); + LockArea.lOffset = SHARED_FIRST; + LockArea.lRange = SHARED_SIZE; + UnlockArea.lOffset = 0L; + UnlockArea.lRange = 0L; + res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 2000L, 1L ); + if( res == NO_ERROR ){ + newLocktype = EXCLUSIVE_LOCK; + }else{ + TRACE2( "error-code = %d\n", res ); + } + } + + /* If we are holding a PENDING lock that ought to be released, then + ** release it now. + */ + if( gotPendingLock && locktype==SHARED_LOCK ){ + LockArea.lOffset = 0L; + LockArea.lRange = 0L; + UnlockArea.lOffset = PENDING_BYTE; + UnlockArea.lRange = 1L; + DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 2000L, 1L ); + } + + /* Update the state of the lock has held in the file descriptor then + ** return the appropriate result code. + */ + if( res == NO_ERROR ){ + rc = SQLITE_OK; + }else{ + TRACE4( "LOCK FAILED %d trying for %d but got %d\n", pFile->h, + locktype, newLocktype ); + rc = SQLITE_BUSY; + } + pFile->locktype = newLocktype; + return rc; +} + +/* +** This routine checks if there is a RESERVED lock held on the specified +** file by this or any other process. If such a lock is held, return +** non-zero, otherwise zero. +*/ +int os2CheckReservedLock( OsFile *id ){ + APIRET rc; + os2File *pFile = (os2File*)id; + assert( pFile!=0 ); + if( pFile->locktype>=RESERVED_LOCK ){ + rc = 1; + TRACE3( "TEST WR-LOCK %d %d (local)\n", pFile->h, rc ); + }else{ + FILELOCK LockArea, + UnlockArea; + memset(&LockArea, 0, sizeof(LockArea)); + memset(&UnlockArea, 0, sizeof(UnlockArea)); + LockArea.lOffset = RESERVED_BYTE; + LockArea.lRange = 1L; + UnlockArea.lOffset = 0L; + UnlockArea.lRange = 0L; + rc = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 2000L, 1L ); + if( rc == NO_ERROR ){ + LockArea.lOffset = 0L; + LockArea.lRange = 0L; + UnlockArea.lOffset = RESERVED_BYTE; + UnlockArea.lRange = 1L; + rc = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 2000L, 1L ); + } + TRACE3( "TEST WR-LOCK %d %d (remote)\n", pFile->h, rc ); + } + return rc; +} + +/* +** Lower the locking level on file descriptor id to locktype. locktype +** must be either NO_LOCK or SHARED_LOCK. +** +** If the locking level of the file descriptor is already at or below +** the requested locking level, this routine is a no-op. +** +** It is not possible for this routine to fail if the second argument +** is NO_LOCK. If the second argument is SHARED_LOCK then this routine +** might return SQLITE_IOERR; +*/ +int os2Unlock( OsFile *id, int locktype ){ + int type; + APIRET rc = SQLITE_OK; + os2File *pFile = (os2File*)id; + FILELOCK LockArea, + UnlockArea; + memset(&LockArea, 0, sizeof(LockArea)); + memset(&UnlockArea, 0, sizeof(UnlockArea)); + assert( pFile!=0 ); + assert( locktype<=SHARED_LOCK ); + TRACE4( "UNLOCK %d to %d was %d\n", pFile->h, locktype, pFile->locktype ); + type = pFile->locktype; + if( type>=EXCLUSIVE_LOCK ){ + LockArea.lOffset = 0L; + LockArea.lRange = 0L; + UnlockArea.lOffset = SHARED_FIRST; + UnlockArea.lRange = SHARED_SIZE; + DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 2000L, 1L ); + if( locktype==SHARED_LOCK && getReadLock(pFile) != NO_ERROR ){ + /* This should never happen. We should always be able to + ** reacquire the read lock */ + rc = SQLITE_IOERR; + } + } + if( type>=RESERVED_LOCK ){ + LockArea.lOffset = 0L; + LockArea.lRange = 0L; + UnlockArea.lOffset = RESERVED_BYTE; + UnlockArea.lRange = 1L; + DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 2000L, 1L ); + } + if( locktype==NO_LOCK && type>=SHARED_LOCK ){ + unlockReadLock(pFile); + } + if( type>=PENDING_LOCK ){ + LockArea.lOffset = 0L; + LockArea.lRange = 0L; + UnlockArea.lOffset = PENDING_BYTE; + UnlockArea.lRange = 1L; + DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 2000L, 1L ); + } + pFile->locktype = locktype; + return rc; +} + +/* +** Turn a relative pathname into a full pathname. Return a pointer +** to the full pathname stored in space obtained from sqliteMalloc(). +** The calling function is responsible for freeing this space once it +** is no longer needed. +*/ +char *sqlite3Os2FullPathname( const char *zRelative ){ + char *zFull = 0; + if( strchr(zRelative, ':') ){ + sqlite3SetString( &zFull, zRelative, (char*)0 ); + }else{ + char zBuff[SQLITE_TEMPNAME_SIZE - 2] = {0}; + char zDrive[1] = {0}; + ULONG cbzFullLen = SQLITE_TEMPNAME_SIZE; + ULONG ulDriveNum = 0; + ULONG ulDriveMap = 0; + DosQueryCurrentDisk( &ulDriveNum, &ulDriveMap ); + DosQueryCurrentDir( 0L, zBuff, &cbzFullLen ); + zFull = sqliteMalloc( cbzFullLen ); + sprintf( zDrive, "%c", (char)('A' + ulDriveNum - 1) ); + sqlite3SetString( &zFull, zDrive, ":\\", zBuff, "\\", zRelative, (char*)0 ); + } + return zFull; +} + +/* +** The fullSync option is meaningless on os2, or correct me if I'm wrong. This is a no-op. +** From os_unix.c: Change the value of the fullsync flag in the given file descriptor. +** From os_unix.c: ((unixFile*)id)->fullSync = v; +*/ +static void os2SetFullSync( OsFile *id, int v ){ + return; +} + +/* +** Return the underlying file handle for an OsFile +*/ +static int os2FileHandle( OsFile *id ){ + return (int)((os2File*)id)->h; +} + +/* +** Return an integer that indices the type of lock currently held +** by this handle. (Used for testing and analysis only.) +*/ +static int os2LockState( OsFile *id ){ + return ((os2File*)id)->locktype; +} + +/* +** This vector defines all the methods that can operate on an OsFile +** for os2. +*/ +static const IoMethod sqlite3Os2IoMethod = { + os2Close, + os2OpenDirectory, + os2Read, + os2Write, + os2Seek, + os2Truncate, + os2Sync, + os2SetFullSync, + os2FileHandle, + os2FileSize, + os2Lock, + os2Unlock, + os2LockState, + os2CheckReservedLock, +}; + +/* +** Allocate memory for an OsFile. Initialize the new OsFile +** to the value given in pInit and return a pointer to the new +** OsFile. If we run out of memory, close the file and return NULL. +*/ +int allocateOs2File( os2File *pInit, OsFile **pld ){ + os2File *pNew; + pNew = sqliteMalloc( sizeof(*pNew) ); + if( pNew==0 ){ + DosClose( pInit->h ); + *pld = 0; + return SQLITE_NOMEM; + }else{ + *pNew = *pInit; + pNew->pMethod = &sqlite3Os2IoMethod; + pNew->locktype = NO_LOCK; + *pld = (OsFile*)pNew; + OpenCounter(+1); + return SQLITE_OK; + } +} + +#endif /* SQLITE_OMIT_DISKIO */ +/*************************************************************************** +** Everything above deals with file I/O. Everything that follows deals +** with other miscellanous aspects of the operating system interface +****************************************************************************/ + +/* +** Get information to seed the random number generator. The seed +** is written into the buffer zBuf[256]. The calling function must +** supply a sufficiently large buffer. +*/ +int sqlite3Os2RandomSeed( char *zBuf ){ + /* We have to initialize zBuf to prevent valgrind from reporting + ** errors. The reports issued by valgrind are incorrect - we would + ** prefer that the randomness be increased by making use of the + ** uninitialized space in zBuf - but valgrind errors tend to worry + ** some users. Rather than argue, it seems easier just to initialize + ** the whole array and silence valgrind, even if that means less randomness + ** in the random seed. + ** + ** When testing, initializing zBuf[] to zero is all we do. That means + ** that we always use the same random number sequence.* This makes the + ** tests repeatable. + */ + memset( zBuf, 0, 256 ); + DosGetDateTime( (PDATETIME)zBuf ); + return SQLITE_OK; +} + +/* +** Sleep for a little while. Return the amount of time slept. +*/ +int sqlite3Os2Sleep( int ms ){ + DosSleep( ms ); + return ms; +} + +/* +** Static variables used for thread synchronization +*/ +static int inMutex = 0; +#ifdef SQLITE_OS2_THREADS +static ULONG mutexOwner; +#endif + +/* +** The following pair of routines implement mutual exclusion for +** multi-threaded processes. Only a single thread is allowed to +** executed code that is surrounded by EnterMutex() and LeaveMutex(). +** +** SQLite uses only a single Mutex. There is not much critical +** code and what little there is executes quickly and without blocking. +*/ +void sqlite3Os2EnterMutex(){ + PTIB ptib; +#ifdef SQLITE_OS2_THREADS + DosEnterCritSec(); + DosGetInfoBlocks( &ptib, NULL ); + mutexOwner = ptib->tib_ptib2->tib2_ultid; +#endif + assert( !inMutex ); + inMutex = 1; +} +void sqlite3Os2LeaveMutex(){ + PTIB ptib; + assert( inMutex ); + inMutex = 0; +#ifdef SQLITE_OS2_THREADS + DosGetInfoBlocks( &ptib, NULL ); + assert( mutexOwner == ptib->tib_ptib2->tib2_ultid ); + DosExitCritSec(); +#endif +} + +/* +** Return TRUE if the mutex is currently held. +** +** If the thisThreadOnly parameter is true, return true if and only if the +** calling thread holds the mutex. If the parameter is false, return +** true if any thread holds the mutex. +*/ +int sqlite3Os2InMutex( int thisThreadOnly ){ +#ifdef SQLITE_OS2_THREADS + PTIB ptib; + DosGetInfoBlocks( &ptib, NULL ); + return inMutex>0 && (thisThreadOnly==0 || mutexOwner==ptib->tib_ptib2->tib2_ultid); +#else + return inMutex>0; +#endif +} + +/* +** The following variable, if set to a non-zero value, becomes the result +** returned from sqlite3OsCurrentTime(). This is used for testing. +*/ +#ifdef SQLITE_TEST +int sqlite3_current_time = 0; +#endif + +/* +** Find the current time (in Universal Coordinated Time). Write the +** current time and date as a Julian Day number into *prNow and +** return 0. Return 1 if the time and date cannot be found. +*/ +int sqlite3Os2CurrentTime( double *prNow ){ + double now; + USHORT second, minute, hour, + day, month, year; + DATETIME dt; + DosGetDateTime( &dt ); + second = (USHORT)dt.seconds; + minute = (USHORT)dt.minutes + dt.timezone; + hour = (USHORT)dt.hours; + day = (USHORT)dt.day; + month = (USHORT)dt.month; + year = (USHORT)dt.year; + + /* Calculations from http://www.astro.keele.ac.uk/~rno/Astronomy/hjd.html + http://www.astro.keele.ac.uk/~rno/Astronomy/hjd-0.1.c */ + /* Calculate the Julian days */ + now = day - 32076 + + 1461*(year + 4800 + (month - 14)/12)/4 + + 367*(month - 2 - (month - 14)/12*12)/12 - + 3*((year + 4900 + (month - 14)/12)/100)/4; + + /* Add the fractional hours, mins and seconds */ + now += (hour + 12.0)/24.0; + now += minute/1440.0; + now += second/86400.0; + *prNow = now; +#ifdef SQLITE_TEST + if( sqlite3_current_time ){ + *prNow = sqlite3_current_time/86400.0 + 2440587.5; + } +#endif + return 0; +} + +/* +** Remember the number of thread-specific-data blocks allocated. +** Use this to verify that we are not leaking thread-specific-data. +** Ticket #1601 +*/ +#ifdef SQLITE_TEST +int sqlite3_tsd_count = 0; +# define TSD_COUNTER_INCR InterlockedIncrement( &sqlite3_tsd_count ) +# define TSD_COUNTER_DECR InterlockedDecrement( &sqlite3_tsd_count ) +#else +# define TSD_COUNTER_INCR /* no-op */ +# define TSD_COUNTER_DECR /* no-op */ +#endif + +/* +** If called with allocateFlag>1, then return a pointer to thread +** specific data for the current thread. Allocate and zero the +** thread-specific data if it does not already exist necessary. +** +** If called with allocateFlag==0, then check the current thread +** specific data. Return it if it exists. If it does not exist, +** then return NULL. +** +** If called with allocateFlag<0, check to see if the thread specific +** data is allocated and is all zero. If it is then deallocate it. +** Return a pointer to the thread specific data or NULL if it is +** unallocated or gets deallocated. +*/ +ThreadData *sqlite3Os2ThreadSpecificData( int allocateFlag ){ + static ThreadData **s_ppTsd = NULL; + static const ThreadData zeroData = {0, 0, 0}; + ThreadData *pTsd; + + if( !s_ppTsd ){ + sqlite3OsEnterMutex(); + if( !s_ppTsd ){ + PULONG pul; + APIRET rc = DosAllocThreadLocalMemory(1, &pul); + if( rc != NO_ERROR ){ + sqlite3OsLeaveMutex(); + return 0; + } + s_ppTsd = (ThreadData **)pul; + } + sqlite3OsLeaveMutex(); + } + pTsd = *s_ppTsd; + if( allocateFlag>0 ){ + if( !pTsd ){ + pTsd = sqlite3OsMalloc( sizeof(zeroData) ); + if( pTsd ){ + *pTsd = zeroData; + *s_ppTsd = pTsd; + TSD_COUNTER_INCR; + } + } + }else if( pTsd!=0 && allocateFlag<0 + && memcmp( pTsd, &zeroData, sizeof(ThreadData) )==0 ){ + sqlite3OsFree(pTsd); + *s_ppTsd = NULL; + TSD_COUNTER_DECR; + pTsd = 0; + } + return pTsd; +} +#endif /* OS_OS2 */ diff --git a/src/os_os2.h b/src/os_os2.h new file mode 100644 index 0000000000..b7381857fa --- /dev/null +++ b/src/os_os2.h @@ -0,0 +1,73 @@ +/* +** 2004 May 22 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** This header file defined OS-specific features for OS/2. +*/ +#ifndef _SQLITE_OS_OS2_H_ +#define _SQLITE_OS_OS2_H_ + +/* +** standard include files. +*/ +#include +#include +#include +#include + +/* +** Macros used to determine whether or not to use threads. The +** SQLITE_UNIX_THREADS macro is defined if we are synchronizing for +** Posix threads and SQLITE_W32_THREADS is defined if we are +** synchronizing using Win32 threads. +*/ +/* this mutex implementation only available with EMX */ +#if defined(THREADSAFE) && THREADSAFE +# include +# include +# define SQLITE_OS2_THREADS 1 +#endif + +/* +** The OsFile structure is a operating-system independing representation +** of an open file handle. It is defined differently for each architecture. +** +** This is the definition for Unix. +** +** OsFile.locktype takes one of the values SHARED_LOCK, RESERVED_LOCK, +** PENDING_LOCK or EXCLUSIVE_LOCK. +*/ +typedef struct OsFile OsFile; +struct OsFile { + int h; /* The file descriptor (LHANDLE) */ + int locked; /* True if this user holds the lock */ + int delOnClose; /* True if file is to be deleted on close */ + char *pathToDel; /* Name of file to delete on close */ + unsigned char locktype; /* The type of lock held on this fd */ + unsigned char isOpen; /* True if needs to be closed */ + unsigned char fullSync; +}; + +/* +** Maximum number of characters in a temporary file name +*/ +#define SQLITE_TEMPNAME_SIZE 200 + +/* +** Minimum interval supported by sqlite3OsSleep(). +*/ +#define SQLITE_MIN_SLEEP_MS 1 + +#ifndef SQLITE_DEFAULT_FILE_PERMISSIONS +# define SQLITE_DEFAULT_FILE_PERMISSIONS 0600 +#endif + +#endif /* _SQLITE_OS_OS2_H_ */