modernc.org/cc@v1.0.1/v2/testdata/_sqlite/ext/lsm1/lsm_win32.c (about)

     1  /*
     2  ** 2011-12-03
     3  **
     4  ** The author disclaims copyright to this source code.  In place of
     5  ** a legal notice, here is a blessing:
     6  **
     7  **    May you do good and not evil.
     8  **    May you find forgiveness for yourself and forgive others.
     9  **    May you share freely, never taking more than you give.
    10  **
    11  *************************************************************************
    12  **
    13  ** Win32-specific run-time environment implementation for LSM.
    14  */
    15  
    16  #ifdef _WIN32
    17  
    18  #include <assert.h>
    19  #include <string.h>
    20  
    21  #include <stdlib.h>
    22  #include <stdarg.h>
    23  #include <stdio.h>
    24  #include <ctype.h>
    25  
    26  #include "windows.h"
    27  
    28  #include "lsmInt.h"
    29  
    30  /*
    31  ** An open file is an instance of the following object
    32  */
    33  typedef struct Win32File Win32File;
    34  struct Win32File {
    35    lsm_env *pEnv;                  /* The run-time environment */
    36    const char *zName;              /* Full path to file */
    37  
    38    HANDLE hFile;                   /* Open file handle */
    39    HANDLE hShmFile;                /* File handle for *-shm file */
    40  
    41    SYSTEM_INFO sysInfo;            /* Operating system information */
    42    HANDLE hMap;                    /* File handle for mapping */
    43    LPVOID pMap;                    /* Pointer to mapping of file fd */
    44    size_t nMap;                    /* Size of mapping at pMap in bytes */
    45    int nShm;                       /* Number of entries in ahShm[]/apShm[] */
    46    LPHANDLE ahShm;                 /* Array of handles for shared mappings */
    47    LPVOID *apShm;                  /* Array of 32K shared memory segments */
    48  };
    49  
    50  static char *win32ShmFile(Win32File *pWin32File){
    51    char *zShm;
    52    int nName = strlen(pWin32File->zName);
    53    zShm = (char *)lsmMallocZero(pWin32File->pEnv, nName+4+1);
    54    if( zShm ){
    55      memcpy(zShm, pWin32File->zName, nName);
    56      memcpy(&zShm[nName], "-shm", 5);
    57    }
    58    return zShm;
    59  }
    60  
    61  static int win32Sleep(int us){
    62    Sleep((us + 999) / 1000);
    63    return LSM_OK;
    64  }
    65  
    66  /*
    67  ** The number of times that an I/O operation will be retried following a
    68  ** locking error - probably caused by antivirus software.  Also the initial
    69  ** delay before the first retry.  The delay increases linearly with each
    70  ** retry.
    71  */
    72  #ifndef LSM_WIN32_IOERR_RETRY
    73  # define LSM_WIN32_IOERR_RETRY 10
    74  #endif
    75  #ifndef LSM_WIN32_IOERR_RETRY_DELAY
    76  # define LSM_WIN32_IOERR_RETRY_DELAY 25000
    77  #endif
    78  static int win32IoerrRetry = LSM_WIN32_IOERR_RETRY;
    79  static int win32IoerrRetryDelay = LSM_WIN32_IOERR_RETRY_DELAY;
    80  
    81  /*
    82  ** The "win32IoerrCanRetry1" macro is used to determine if a particular
    83  ** I/O error code obtained via GetLastError() is eligible to be retried.
    84  ** It must accept the error code DWORD as its only argument and should
    85  ** return non-zero if the error code is transient in nature and the
    86  ** operation responsible for generating the original error might succeed
    87  ** upon being retried.  The argument to this macro should be a variable.
    88  **
    89  ** Additionally, a macro named "win32IoerrCanRetry2" may be defined.  If
    90  ** it is defined, it will be consulted only when the macro
    91  ** "win32IoerrCanRetry1" returns zero.  The "win32IoerrCanRetry2" macro
    92  ** is completely optional and may be used to include additional error
    93  ** codes in the set that should result in the failing I/O operation being
    94  ** retried by the caller.  If defined, the "win32IoerrCanRetry2" macro
    95  ** must exhibit external semantics identical to those of the
    96  ** "win32IoerrCanRetry1" macro.
    97  */
    98  #if !defined(win32IoerrCanRetry1)
    99  #define win32IoerrCanRetry1(a) (((a)==ERROR_ACCESS_DENIED)        || \
   100                                  ((a)==ERROR_SHARING_VIOLATION)    || \
   101                                  ((a)==ERROR_LOCK_VIOLATION)       || \
   102                                  ((a)==ERROR_DEV_NOT_EXIST)        || \
   103                                  ((a)==ERROR_NETNAME_DELETED)      || \
   104                                  ((a)==ERROR_SEM_TIMEOUT)          || \
   105                                  ((a)==ERROR_NETWORK_UNREACHABLE))
   106  #endif
   107  
   108  /*
   109  ** If an I/O error occurs, invoke this routine to see if it should be
   110  ** retried.  Return TRUE to retry.  Return FALSE to give up with an
   111  ** error.
   112  */
   113  static int win32RetryIoerr(
   114    lsm_env *pEnv,
   115    int *pnRetry
   116  ){
   117    DWORD lastErrno;
   118    if( *pnRetry>=win32IoerrRetry ){
   119      return 0;
   120    }
   121    lastErrno = GetLastError();
   122    if( win32IoerrCanRetry1(lastErrno) ){
   123      win32Sleep(win32IoerrRetryDelay*(1+*pnRetry));
   124      ++*pnRetry;
   125      return 1;
   126    }
   127  #if defined(win32IoerrCanRetry2)
   128    else if( win32IoerrCanRetry2(lastErrno) ){
   129      win32Sleep(win32IoerrRetryDelay*(1+*pnRetry));
   130      ++*pnRetry;
   131      return 1;
   132    }
   133  #endif
   134    return 0;
   135  }
   136  
   137  /*
   138  ** Convert a UTF-8 string to Microsoft Unicode.
   139  **
   140  ** Space to hold the returned string is obtained from lsmMalloc().
   141  */
   142  static LPWSTR win32Utf8ToUnicode(lsm_env *pEnv, const char *zText){
   143    int nChar;
   144    LPWSTR zWideText;
   145  
   146    nChar = MultiByteToWideChar(CP_UTF8, 0, zText, -1, NULL, 0);
   147    if( nChar==0 ){
   148      return 0;
   149    }
   150    zWideText = lsmMallocZero(pEnv, nChar * sizeof(WCHAR));
   151    if( zWideText==0 ){
   152      return 0;
   153    }
   154    nChar = MultiByteToWideChar(CP_UTF8, 0, zText, -1, zWideText, nChar);
   155    if( nChar==0 ){
   156      lsmFree(pEnv, zWideText);
   157      zWideText = 0;
   158    }
   159    return zWideText;
   160  }
   161  
   162  /*
   163  ** Convert a Microsoft Unicode string to UTF-8.
   164  **
   165  ** Space to hold the returned string is obtained from lsmMalloc().
   166  */
   167  static char *win32UnicodeToUtf8(lsm_env *pEnv, LPCWSTR zWideText){
   168    int nByte;
   169    char *zText;
   170  
   171    nByte = WideCharToMultiByte(CP_UTF8, 0, zWideText, -1, 0, 0, 0, 0);
   172    if( nByte == 0 ){
   173      return 0;
   174    }
   175    zText = lsmMallocZero(pEnv, nByte);
   176    if( zText==0 ){
   177      return 0;
   178    }
   179    nByte = WideCharToMultiByte(CP_UTF8, 0, zWideText, -1, zText, nByte, 0, 0);
   180    if( nByte == 0 ){
   181      lsmFree(pEnv, zText);
   182      zText = 0;
   183    }
   184    return zText;
   185  }
   186  
   187  #if !defined(win32IsNotFound)
   188  #define win32IsNotFound(a) (((a)==ERROR_FILE_NOT_FOUND)  || \
   189                              ((a)==ERROR_PATH_NOT_FOUND))
   190  #endif
   191  
   192  static int win32Open(
   193    lsm_env *pEnv,
   194    const char *zFile,
   195    int flags,
   196    LPHANDLE phFile
   197  ){
   198    int rc;
   199    LPWSTR zConverted;
   200  
   201    zConverted = win32Utf8ToUnicode(pEnv, zFile);
   202    if( zConverted==0 ){
   203      rc = LSM_NOMEM_BKPT;
   204    }else{
   205      int bReadonly = (flags & LSM_OPEN_READONLY);
   206      DWORD dwDesiredAccess;
   207      DWORD dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
   208      DWORD dwCreationDisposition;
   209      DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
   210      HANDLE hFile;
   211      int nRetry = 0;
   212      if( bReadonly ){
   213        dwDesiredAccess = GENERIC_READ;
   214        dwCreationDisposition = OPEN_EXISTING;
   215      }else{
   216        dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
   217        dwCreationDisposition = OPEN_ALWAYS;
   218      }
   219      while( (hFile = CreateFileW((LPCWSTR)zConverted,
   220                                  dwDesiredAccess,
   221                                  dwShareMode, NULL,
   222                                  dwCreationDisposition,
   223                                  dwFlagsAndAttributes,
   224                                  NULL))==INVALID_HANDLE_VALUE &&
   225                                  win32RetryIoerr(pEnv, &nRetry) ){
   226        /* Noop */
   227      }
   228      lsmFree(pEnv, zConverted);
   229      if( hFile!=INVALID_HANDLE_VALUE ){
   230        *phFile = hFile;
   231        rc = LSM_OK;
   232      }else{
   233        if( win32IsNotFound(GetLastError()) ){
   234          rc = lsmErrorBkpt(LSM_IOERR_NOENT);
   235        }else{
   236          rc = LSM_IOERR_BKPT;
   237        }
   238      }
   239    }
   240    return rc;
   241  }
   242  
   243  static int lsmWin32OsOpen(
   244    lsm_env *pEnv,
   245    const char *zFile,
   246    int flags,
   247    lsm_file **ppFile
   248  ){
   249    int rc = LSM_OK;
   250    Win32File *pWin32File;
   251  
   252    pWin32File = lsmMallocZero(pEnv, sizeof(Win32File));
   253    if( pWin32File==0 ){
   254      rc = LSM_NOMEM_BKPT;
   255    }else{
   256      HANDLE hFile = NULL;
   257  
   258      rc = win32Open(pEnv, zFile, flags, &hFile);
   259      if( rc==LSM_OK ){
   260        memset(&pWin32File->sysInfo, 0, sizeof(SYSTEM_INFO));
   261        GetSystemInfo(&pWin32File->sysInfo);
   262        pWin32File->pEnv = pEnv;
   263        pWin32File->zName = zFile;
   264        pWin32File->hFile = hFile;
   265      }else{
   266        lsmFree(pEnv, pWin32File);
   267        pWin32File = 0;
   268      }
   269    }
   270    *ppFile = (lsm_file *)pWin32File;
   271    return rc;
   272  }
   273  
   274  static int lsmWin32OsWrite(
   275    lsm_file *pFile, /* File to write to */
   276    lsm_i64 iOff,    /* Offset to write to */
   277    void *pData,     /* Write data from this buffer */
   278    int nData        /* Bytes of data to write */
   279  ){
   280    Win32File *pWin32File = (Win32File *)pFile;
   281    OVERLAPPED overlapped;  /* The offset for WriteFile. */
   282    u8 *aRem = (u8 *)pData; /* Data yet to be written */
   283    int nRem = nData;       /* Number of bytes yet to be written */
   284    int nRetry = 0;         /* Number of retrys */
   285  
   286    memset(&overlapped, 0, sizeof(OVERLAPPED));
   287    overlapped.Offset = (LONG)(iOff & 0XFFFFFFFF);
   288    overlapped.OffsetHigh = (LONG)((iOff>>32) & 0x7FFFFFFF);
   289    while( nRem>0 ){
   290      DWORD nWrite = 0; /* Bytes written using WriteFile */
   291      if( !WriteFile(pWin32File->hFile, aRem, nRem, &nWrite, &overlapped) ){
   292        if( win32RetryIoerr(pWin32File->pEnv, &nRetry) ) continue;
   293        break;
   294      }
   295      assert( nWrite==0 || nWrite<=(DWORD)nRem );
   296      if( nWrite==0 || nWrite>(DWORD)nRem ){
   297        break;
   298      }
   299      iOff += nWrite;
   300      overlapped.Offset = (LONG)(iOff & 0xFFFFFFFF);
   301      overlapped.OffsetHigh = (LONG)((iOff>>32) & 0x7FFFFFFF);
   302      aRem += nWrite;
   303      nRem -= nWrite;
   304    }
   305    if( nRem!=0 ) return LSM_IOERR_BKPT;
   306    return LSM_OK;
   307  }
   308  
   309  static int win32Truncate(
   310    HANDLE hFile,
   311    lsm_i64 nSize
   312  ){
   313    LARGE_INTEGER offset;
   314    offset.QuadPart = nSize;
   315    if( !SetFilePointerEx(hFile, offset, 0, FILE_BEGIN) ){
   316      return LSM_IOERR_BKPT;
   317    }
   318    if (!SetEndOfFile(hFile) ){
   319      return LSM_IOERR_BKPT;
   320    }
   321    return LSM_OK;
   322  }
   323  
   324  static int lsmWin32OsTruncate(
   325    lsm_file *pFile, /* File to write to */
   326    lsm_i64 nSize    /* Size to truncate file to */
   327  ){
   328    Win32File *pWin32File = (Win32File *)pFile;
   329    return win32Truncate(pWin32File->hFile, nSize);
   330  }
   331  
   332  static int lsmWin32OsRead(
   333    lsm_file *pFile, /* File to read from */
   334    lsm_i64 iOff,    /* Offset to read from */
   335    void *pData,     /* Read data into this buffer */
   336    int nData        /* Bytes of data to read */
   337  ){
   338    Win32File *pWin32File = (Win32File *)pFile;
   339    OVERLAPPED overlapped; /* The offset for ReadFile */
   340    DWORD nRead = 0;       /* Bytes read using ReadFile */
   341    int nRetry = 0;        /* Number of retrys */
   342  
   343    memset(&overlapped, 0, sizeof(OVERLAPPED));
   344    overlapped.Offset = (LONG)(iOff & 0XFFFFFFFF);
   345    overlapped.OffsetHigh = (LONG)((iOff>>32) & 0X7FFFFFFF);
   346    while( !ReadFile(pWin32File->hFile, pData, nData, &nRead, &overlapped) &&
   347           GetLastError()!=ERROR_HANDLE_EOF ){
   348      if( win32RetryIoerr(pWin32File->pEnv, &nRetry) ) continue;
   349      return LSM_IOERR_BKPT;
   350    }
   351    if( nRead<(DWORD)nData ){
   352      /* Unread parts of the buffer must be zero-filled */
   353      memset(&((char*)pData)[nRead], 0, nData - nRead);
   354    }
   355    return LSM_OK;
   356  }
   357  
   358  static int lsmWin32OsSync(lsm_file *pFile){
   359    int rc = LSM_OK;
   360  
   361  #ifndef LSM_NO_SYNC
   362    Win32File *pWin32File = (Win32File *)pFile;
   363  
   364    if( pWin32File->pMap!=NULL ){
   365      if( !FlushViewOfFile(pWin32File->pMap, 0) ){
   366        rc = LSM_IOERR_BKPT;
   367      }
   368    }
   369    if( rc==LSM_OK && !FlushFileBuffers(pWin32File->hFile) ){
   370      rc = LSM_IOERR_BKPT;
   371    }
   372  #else
   373    unused_parameter(pFile);
   374  #endif
   375  
   376    return rc;
   377  }
   378  
   379  static int lsmWin32OsSectorSize(lsm_file *pFile){
   380    return 512;
   381  }
   382  
   383  static void win32Unmap(Win32File *pWin32File){
   384    if( pWin32File->pMap!=NULL ){
   385      UnmapViewOfFile(pWin32File->pMap);
   386      pWin32File->pMap = NULL;
   387      pWin32File->nMap = 0;
   388    }
   389    if( pWin32File->hMap!=NULL ){
   390      CloseHandle(pWin32File->hMap);
   391      pWin32File->hMap = NULL;
   392    }
   393  }
   394  
   395  static int lsmWin32OsRemap(
   396    lsm_file *pFile,
   397    lsm_i64 iMin,
   398    void **ppOut,
   399    lsm_i64 *pnOut
   400  ){
   401    Win32File *pWin32File = (Win32File *)pFile;
   402  
   403    /* If the file is between 0 and 2MB in size, extend it in chunks of 256K.
   404    ** Thereafter, in chunks of 1MB at a time.  */
   405    const int aIncrSz[] = {256*1024, 1024*1024};
   406    int nIncrSz = aIncrSz[iMin>(2*1024*1024)];
   407  
   408    *ppOut = NULL;
   409    *pnOut = 0;
   410  
   411    win32Unmap(pWin32File);
   412    if( iMin>=0 ){
   413      LARGE_INTEGER fileSize;
   414      DWORD dwSizeHigh;
   415      DWORD dwSizeLow;
   416      HANDLE hMap;
   417      LPVOID pMap;
   418      memset(&fileSize, 0, sizeof(LARGE_INTEGER));
   419      if( !GetFileSizeEx(pWin32File->hFile, &fileSize) ){
   420        return LSM_IOERR_BKPT;
   421      }
   422      assert( fileSize.QuadPart>=0 );
   423      if( fileSize.QuadPart<iMin ){
   424        int rc;
   425        fileSize.QuadPart = ((iMin + nIncrSz-1) / nIncrSz) * nIncrSz;
   426        rc = lsmWin32OsTruncate(pFile, fileSize.QuadPart);
   427        if( rc!=LSM_OK ){
   428          return rc;
   429        }
   430      }
   431      dwSizeLow = (DWORD)(fileSize.QuadPart & 0xFFFFFFFF);
   432      dwSizeHigh = (DWORD)((fileSize.QuadPart & 0x7FFFFFFFFFFFFFFF) >> 32);
   433      hMap = CreateFileMappingW(pWin32File->hFile, NULL, PAGE_READWRITE,
   434                                dwSizeHigh, dwSizeLow, NULL);
   435      if( hMap==NULL ){
   436        return LSM_IOERR_BKPT;
   437      }
   438      pWin32File->hMap = hMap;
   439      assert( fileSize.QuadPart<=0xFFFFFFFF );
   440      pMap = MapViewOfFile(hMap, FILE_MAP_WRITE | FILE_MAP_READ, 0, 0,
   441                           (SIZE_T)fileSize.QuadPart);
   442      if( pMap==NULL ){
   443        return LSM_IOERR_BKPT;
   444      }
   445      pWin32File->pMap = pMap;
   446      pWin32File->nMap = (SIZE_T)fileSize.QuadPart;
   447    }
   448    *ppOut = pWin32File->pMap;
   449    *pnOut = pWin32File->nMap;
   450    return LSM_OK;
   451  }
   452  
   453  static BOOL win32IsDriveLetterAndColon(
   454    const char *zPathname
   455  ){
   456    return ( isalpha(zPathname[0]) && zPathname[1]==':' );
   457  }
   458  
   459  static int lsmWin32OsFullpath(
   460    lsm_env *pEnv,
   461    const char *zName,
   462    char *zOut,
   463    int *pnOut
   464  ){
   465    DWORD nByte;
   466    void *zConverted;
   467    LPWSTR zTempWide;
   468    char *zTempUtf8;
   469  
   470    if( zName[0]=='/' && win32IsDriveLetterAndColon(zName+1) ){
   471      zName++;
   472    }
   473    zConverted = win32Utf8ToUnicode(pEnv, zName);
   474    if( zConverted==0 ){
   475      return LSM_NOMEM_BKPT;
   476    }
   477    nByte = GetFullPathNameW((LPCWSTR)zConverted, 0, 0, 0);
   478    if( nByte==0 ){
   479      lsmFree(pEnv, zConverted);
   480      return LSM_IOERR_BKPT;
   481    }
   482    nByte += 3;
   483    zTempWide = lsmMallocZero(pEnv, nByte * sizeof(zTempWide[0]));
   484    if( zTempWide==0 ){
   485      lsmFree(pEnv, zConverted);
   486      return LSM_NOMEM_BKPT;
   487    }
   488    nByte = GetFullPathNameW((LPCWSTR)zConverted, nByte, zTempWide, 0);
   489    if( nByte==0 ){
   490      lsmFree(pEnv, zConverted);
   491      lsmFree(pEnv, zTempWide);
   492      return LSM_IOERR_BKPT;
   493    }
   494    lsmFree(pEnv, zConverted);
   495    zTempUtf8 = win32UnicodeToUtf8(pEnv, zTempWide);
   496    lsmFree(pEnv, zTempWide);
   497    if( zTempUtf8 ){
   498      int nOut = *pnOut;
   499      int nLen = strlen(zTempUtf8) + 1;
   500      if( nLen<=nOut ){
   501        snprintf(zOut, nOut, "%s", zTempUtf8);
   502      }
   503      lsmFree(pEnv, zTempUtf8);
   504      *pnOut = nLen;
   505      return LSM_OK;
   506    }else{
   507      return LSM_NOMEM_BKPT;
   508    }
   509  }
   510  
   511  static int lsmWin32OsFileid(
   512    lsm_file *pFile,
   513    void *pBuf,
   514    int *pnBuf
   515  ){
   516    int nBuf;
   517    int nReq;
   518    u8 *pBuf2 = (u8 *)pBuf;
   519    Win32File *pWin32File = (Win32File *)pFile;
   520    BY_HANDLE_FILE_INFORMATION fileInfo;
   521  
   522    nBuf = *pnBuf;
   523    nReq = (sizeof(fileInfo.dwVolumeSerialNumber) +
   524            sizeof(fileInfo.nFileIndexHigh) +
   525            sizeof(fileInfo.nFileIndexLow));
   526    *pnBuf = nReq;
   527    if( nReq>nBuf ) return LSM_OK;
   528    memset(&fileInfo, 0, sizeof(BY_HANDLE_FILE_INFORMATION));
   529    if( !GetFileInformationByHandle(pWin32File->hFile, &fileInfo) ){
   530      return LSM_IOERR_BKPT;
   531    }
   532    nReq = sizeof(fileInfo.dwVolumeSerialNumber);
   533    memcpy(pBuf2, &fileInfo.dwVolumeSerialNumber, nReq);
   534    pBuf2 += nReq;
   535    nReq = sizeof(fileInfo.nFileIndexHigh);
   536    memcpy(pBuf, &fileInfo.nFileIndexHigh, nReq);
   537    pBuf2 += nReq;
   538    nReq = sizeof(fileInfo.nFileIndexLow);
   539    memcpy(pBuf2, &fileInfo.nFileIndexLow, nReq);
   540    return LSM_OK;
   541  }
   542  
   543  static int win32Delete(
   544    lsm_env *pEnv,
   545    const char *zFile
   546  ){
   547    int rc;
   548    LPWSTR zConverted;
   549  
   550    zConverted = win32Utf8ToUnicode(pEnv, zFile);
   551    if( zConverted==0 ){
   552      rc = LSM_NOMEM_BKPT;
   553    }else{
   554      int nRetry = 0;
   555      DWORD attr;
   556  
   557      do {
   558        attr = GetFileAttributesW(zConverted);
   559        if ( attr==INVALID_FILE_ATTRIBUTES ){
   560          rc = LSM_IOERR_BKPT;
   561          break;
   562        }
   563        if ( attr&FILE_ATTRIBUTE_DIRECTORY ){
   564          rc = LSM_IOERR_BKPT; /* Files only. */
   565          break;
   566        }
   567        if ( DeleteFileW(zConverted) ){
   568          rc = LSM_OK; /* Deleted OK. */
   569          break;
   570        }
   571        if ( !win32RetryIoerr(pEnv, &nRetry) ){
   572          rc = LSM_IOERR_BKPT; /* No more retries. */
   573          break;
   574        }
   575      }while( 1 );
   576    }
   577    lsmFree(pEnv, zConverted);
   578    return rc;
   579  }
   580  
   581  static int lsmWin32OsUnlink(lsm_env *pEnv, const char *zFile){
   582    return win32Delete(pEnv, zFile);
   583  }
   584  
   585  #if !defined(win32IsLockBusy)
   586  #define win32IsLockBusy(a) (((a)==ERROR_LOCK_VIOLATION) || \
   587                              ((a)==ERROR_IO_PENDING))
   588  #endif
   589  
   590  static int win32LockFile(
   591    Win32File *pWin32File,
   592    int iLock,
   593    int nLock,
   594    int eType
   595  ){
   596    OVERLAPPED ovlp;
   597  
   598    assert( LSM_LOCK_UNLOCK==0 );
   599    assert( LSM_LOCK_SHARED==1 );
   600    assert( LSM_LOCK_EXCL==2 );
   601    assert( eType>=LSM_LOCK_UNLOCK && eType<=LSM_LOCK_EXCL );
   602    assert( nLock>=0 );
   603    assert( iLock>0 && iLock<=32 );
   604  
   605    memset(&ovlp, 0, sizeof(OVERLAPPED));
   606    ovlp.Offset = (4096-iLock-nLock+1);
   607    if( eType>LSM_LOCK_UNLOCK ){
   608      DWORD flags = LOCKFILE_FAIL_IMMEDIATELY;
   609      if( eType>=LSM_LOCK_EXCL ) flags |= LOCKFILE_EXCLUSIVE_LOCK;
   610      if( !LockFileEx(pWin32File->hFile, flags, 0, (DWORD)nLock, 0, &ovlp) ){
   611        if( win32IsLockBusy(GetLastError()) ){
   612          return LSM_BUSY;
   613        }else{
   614          return LSM_IOERR_BKPT;
   615        }
   616      }
   617    }else{
   618      if( !UnlockFileEx(pWin32File->hFile, 0, (DWORD)nLock, 0, &ovlp) ){
   619        return LSM_IOERR_BKPT;
   620      }
   621    }
   622    return LSM_OK;
   623  }
   624  
   625  static int lsmWin32OsLock(lsm_file *pFile, int iLock, int eType){
   626    Win32File *pWin32File = (Win32File *)pFile;
   627    return win32LockFile(pWin32File, iLock, 1, eType);
   628  }
   629  
   630  static int lsmWin32OsTestLock(lsm_file *pFile, int iLock, int nLock, int eType){
   631    int rc;
   632    Win32File *pWin32File = (Win32File *)pFile;
   633    rc = win32LockFile(pWin32File, iLock, nLock, eType);
   634    if( rc!=LSM_OK ) return rc;
   635    win32LockFile(pWin32File, iLock, nLock, LSM_LOCK_UNLOCK);
   636    return LSM_OK;
   637  }
   638  
   639  static int lsmWin32OsShmMap(lsm_file *pFile, int iChunk, int sz, void **ppShm){
   640    int rc;
   641    Win32File *pWin32File = (Win32File *)pFile;
   642    int iOffset = iChunk * sz;
   643    int iOffsetShift = iOffset % pWin32File->sysInfo.dwAllocationGranularity;
   644    int nNew = iChunk + 1;
   645    lsm_i64 nReq = nNew * sz;
   646  
   647    *ppShm = NULL;
   648    assert( sz>=0 );
   649    assert( sz==LSM_SHM_CHUNK_SIZE );
   650    if( iChunk>=pWin32File->nShm ){
   651      LPHANDLE ahNew;
   652      LPVOID *apNew;
   653      LARGE_INTEGER fileSize;
   654  
   655      /* If the shared-memory file has not been opened, open it now. */
   656      if( pWin32File->hShmFile==NULL ){
   657        char *zShm = win32ShmFile(pWin32File);
   658        if( !zShm ) return LSM_NOMEM_BKPT;
   659        rc = win32Open(pWin32File->pEnv, zShm, 0, &pWin32File->hShmFile);
   660        lsmFree(pWin32File->pEnv, zShm);
   661        if( rc!=LSM_OK ){
   662          return rc;
   663        }
   664      }
   665  
   666      /* If the shared-memory file is not large enough to contain the
   667      ** requested chunk, cause it to grow.  */
   668      memset(&fileSize, 0, sizeof(LARGE_INTEGER));
   669      if( !GetFileSizeEx(pWin32File->hShmFile, &fileSize) ){
   670        return LSM_IOERR_BKPT;
   671      }
   672      assert( fileSize.QuadPart>=0 );
   673      if( fileSize.QuadPart<nReq ){
   674        rc = win32Truncate(pWin32File->hShmFile, nReq);
   675        if( rc!=LSM_OK ){
   676          return rc;
   677        }
   678      }
   679  
   680      ahNew = (LPHANDLE)lsmMallocZero(pWin32File->pEnv, sizeof(HANDLE) * nNew);
   681      if( !ahNew ) return LSM_NOMEM_BKPT;
   682      apNew = (LPVOID *)lsmMallocZero(pWin32File->pEnv, sizeof(LPVOID) * nNew);
   683      if( !apNew ){
   684        lsmFree(pWin32File->pEnv, ahNew);
   685        return LSM_NOMEM_BKPT;
   686      }
   687      memcpy(ahNew, pWin32File->ahShm, sizeof(HANDLE) * pWin32File->nShm);
   688      memcpy(apNew, pWin32File->apShm, sizeof(LPVOID) * pWin32File->nShm);
   689      lsmFree(pWin32File->pEnv, pWin32File->ahShm);
   690      pWin32File->ahShm = ahNew;
   691      lsmFree(pWin32File->pEnv, pWin32File->apShm);
   692      pWin32File->apShm = apNew;
   693      pWin32File->nShm = nNew;
   694    }
   695  
   696    if( pWin32File->ahShm[iChunk]==NULL ){
   697      HANDLE hMap;
   698      assert( nReq<=0xFFFFFFFF );
   699      hMap = CreateFileMappingW(pWin32File->hShmFile, NULL, PAGE_READWRITE, 0,
   700                                (DWORD)nReq, NULL);
   701      if( hMap==NULL ){
   702        return LSM_IOERR_BKPT;
   703      }
   704      pWin32File->ahShm[iChunk] = hMap;
   705    }
   706    if( pWin32File->apShm[iChunk]==NULL ){
   707      LPVOID pMap;
   708      pMap = MapViewOfFile(pWin32File->ahShm[iChunk],
   709                           FILE_MAP_WRITE | FILE_MAP_READ, 0,
   710                           iOffset - iOffsetShift, sz + iOffsetShift);
   711      if( pMap==NULL ){
   712        return LSM_IOERR_BKPT;
   713      }
   714      pWin32File->apShm[iChunk] = pMap;
   715    }
   716    if( iOffsetShift!=0 ){
   717      char *p = (char *)pWin32File->apShm[iChunk];
   718      *ppShm = (void *)&p[iOffsetShift];
   719    }else{
   720      *ppShm = pWin32File->apShm[iChunk];
   721    }
   722    return LSM_OK;
   723  }
   724  
   725  static void lsmWin32OsShmBarrier(void){
   726    MemoryBarrier();
   727  }
   728  
   729  static int lsmWin32OsShmUnmap(lsm_file *pFile, int bDelete){
   730    Win32File *pWin32File = (Win32File *)pFile;
   731  
   732    if( pWin32File->hShmFile!=NULL ){
   733      int i;
   734      for(i=0; i<pWin32File->nShm; i++){
   735        if( pWin32File->apShm[i]!=NULL ){
   736          UnmapViewOfFile(pWin32File->apShm[i]);
   737          pWin32File->apShm[i] = NULL;
   738        }
   739        if( pWin32File->ahShm[i]!=NULL ){
   740          CloseHandle(pWin32File->ahShm[i]);
   741          pWin32File->ahShm[i] = NULL;
   742        }
   743      }
   744      CloseHandle(pWin32File->hShmFile);
   745      pWin32File->hShmFile = NULL;
   746      if( bDelete ){
   747        char *zShm = win32ShmFile(pWin32File);
   748        if( zShm ){ win32Delete(pWin32File->pEnv, zShm); }
   749        lsmFree(pWin32File->pEnv, zShm);
   750      }
   751    }
   752    return LSM_OK;
   753  }
   754  
   755  #define MX_CLOSE_ATTEMPT 3
   756  static int lsmWin32OsClose(lsm_file *pFile){
   757    int rc;
   758    int nRetry = 0;
   759    Win32File *pWin32File = (Win32File *)pFile;
   760    lsmWin32OsShmUnmap(pFile, 0);
   761    win32Unmap(pWin32File);
   762    do{
   763      if( pWin32File->hFile==NULL ){
   764        rc = LSM_IOERR_BKPT;
   765        break;
   766      }
   767      rc = CloseHandle(pWin32File->hFile);
   768      if( rc ){
   769        pWin32File->hFile = NULL;
   770        rc = LSM_OK;
   771        break;
   772      }
   773      if( ++nRetry>=MX_CLOSE_ATTEMPT ){
   774        rc = LSM_IOERR_BKPT;
   775        break;
   776      }
   777    }while( 1 );
   778    lsmFree(pWin32File->pEnv, pWin32File->ahShm);
   779    lsmFree(pWin32File->pEnv, pWin32File->apShm);
   780    lsmFree(pWin32File->pEnv, pWin32File);
   781    return rc;
   782  }
   783  
   784  static int lsmWin32OsSleep(lsm_env *pEnv, int us){
   785    unused_parameter(pEnv);
   786    return win32Sleep(us);
   787  }
   788  
   789  /****************************************************************************
   790  ** Memory allocation routines.
   791  */
   792  
   793  static void *lsmWin32OsMalloc(lsm_env *pEnv, size_t N){
   794    assert( HeapValidate(GetProcessHeap(), 0, NULL) );
   795    return HeapAlloc(GetProcessHeap(), 0, (SIZE_T)N);
   796  }
   797  
   798  static void lsmWin32OsFree(lsm_env *pEnv, void *p){
   799    assert( HeapValidate(GetProcessHeap(), 0, NULL) );
   800    if( p ){
   801      HeapFree(GetProcessHeap(), 0, p);
   802    }
   803  }
   804  
   805  static void *lsmWin32OsRealloc(lsm_env *pEnv, void *p, size_t N){
   806    unsigned char *m = (unsigned char *)p;
   807    assert( HeapValidate(GetProcessHeap(), 0, NULL) );
   808    if( 1>N ){
   809      lsmWin32OsFree(pEnv, p);
   810      return NULL;
   811    }else if( NULL==p ){
   812      return lsmWin32OsMalloc(pEnv, N);
   813    }else{
   814  #if 0 /* arguable: don't shrink */
   815      SIZE_T sz = HeapSize(GetProcessHeap(), 0, m);
   816      if( sz>=(SIZE_T)N ){
   817        return p;
   818      }
   819  #endif
   820      return HeapReAlloc(GetProcessHeap(), 0, m, N);
   821    }
   822  }
   823  
   824  static size_t lsmWin32OsMSize(lsm_env *pEnv, void *p){
   825    assert( HeapValidate(GetProcessHeap(), 0, NULL) );
   826    return (size_t)HeapSize(GetProcessHeap(), 0, p);
   827  }
   828  
   829  
   830  #ifdef LSM_MUTEX_WIN32
   831  /*************************************************************************
   832  ** Mutex methods for Win32 based systems.  If LSM_MUTEX_WIN32 is
   833  ** missing then a no-op implementation of mutexes found below will be
   834  ** used instead.
   835  */
   836  #include "windows.h"
   837  
   838  typedef struct Win32Mutex Win32Mutex;
   839  struct Win32Mutex {
   840    lsm_env *pEnv;
   841    CRITICAL_SECTION mutex;
   842  #ifdef LSM_DEBUG
   843    DWORD owner;
   844  #endif
   845  };
   846  
   847  #ifndef WIN32_MUTEX_INITIALIZER
   848  # define WIN32_MUTEX_INITIALIZER { 0 }
   849  #endif
   850  
   851  #ifdef LSM_DEBUG
   852  # define LSM_WIN32_STATIC_MUTEX { 0, WIN32_MUTEX_INITIALIZER, 0 }
   853  #else
   854  # define LSM_WIN32_STATIC_MUTEX { 0, WIN32_MUTEX_INITIALIZER }
   855  #endif
   856  
   857  static int lsmWin32OsMutexStatic(
   858    lsm_env *pEnv,
   859    int iMutex,
   860    lsm_mutex **ppStatic
   861  ){
   862    static volatile LONG initialized = 0;
   863    static Win32Mutex sMutex[2] = {
   864      LSM_WIN32_STATIC_MUTEX,
   865      LSM_WIN32_STATIC_MUTEX
   866    };
   867  
   868    assert( iMutex==LSM_MUTEX_GLOBAL || iMutex==LSM_MUTEX_HEAP );
   869    assert( LSM_MUTEX_GLOBAL==1 && LSM_MUTEX_HEAP==2 );
   870  
   871    if( InterlockedCompareExchange(&initialized, 1, 0)==0 ){
   872      int i;
   873      for(i=0; i<array_size(sMutex); i++){
   874        InitializeCriticalSection(&sMutex[i].mutex);
   875      }
   876    }
   877    *ppStatic = (lsm_mutex *)&sMutex[iMutex-1];
   878    return LSM_OK;
   879  }
   880  
   881  static int lsmWin32OsMutexNew(lsm_env *pEnv, lsm_mutex **ppNew){
   882    Win32Mutex *pMutex;           /* Pointer to new mutex */
   883  
   884    pMutex = (Win32Mutex *)lsmMallocZero(pEnv, sizeof(Win32Mutex));
   885    if( !pMutex ) return LSM_NOMEM_BKPT;
   886  
   887    pMutex->pEnv = pEnv;
   888    InitializeCriticalSection(&pMutex->mutex);
   889  
   890    *ppNew = (lsm_mutex *)pMutex;
   891    return LSM_OK;
   892  }
   893  
   894  static void lsmWin32OsMutexDel(lsm_mutex *p){
   895    Win32Mutex *pMutex = (Win32Mutex *)p;
   896    DeleteCriticalSection(&pMutex->mutex);
   897    lsmFree(pMutex->pEnv, pMutex);
   898  }
   899  
   900  static void lsmWin32OsMutexEnter(lsm_mutex *p){
   901    Win32Mutex *pMutex = (Win32Mutex *)p;
   902    EnterCriticalSection(&pMutex->mutex);
   903  
   904  #ifdef LSM_DEBUG
   905    assert( pMutex->owner!=GetCurrentThreadId() );
   906    pMutex->owner = GetCurrentThreadId();
   907    assert( pMutex->owner==GetCurrentThreadId() );
   908  #endif
   909  }
   910  
   911  static int lsmWin32OsMutexTry(lsm_mutex *p){
   912    BOOL bRet;
   913    Win32Mutex *pMutex = (Win32Mutex *)p;
   914    bRet = TryEnterCriticalSection(&pMutex->mutex);
   915  #ifdef LSM_DEBUG
   916    if( bRet ){
   917      assert( pMutex->owner!=GetCurrentThreadId() );
   918      pMutex->owner = GetCurrentThreadId();
   919      assert( pMutex->owner==GetCurrentThreadId() );
   920    }
   921  #endif
   922    return !bRet;
   923  }
   924  
   925  static void lsmWin32OsMutexLeave(lsm_mutex *p){
   926    Win32Mutex *pMutex = (Win32Mutex *)p;
   927  #ifdef LSM_DEBUG
   928    assert( pMutex->owner==GetCurrentThreadId() );
   929    pMutex->owner = 0;
   930    assert( pMutex->owner!=GetCurrentThreadId() );
   931  #endif
   932    LeaveCriticalSection(&pMutex->mutex);
   933  }
   934  
   935  #ifdef LSM_DEBUG
   936  static int lsmWin32OsMutexHeld(lsm_mutex *p){
   937    Win32Mutex *pMutex = (Win32Mutex *)p;
   938    return pMutex ? pMutex->owner==GetCurrentThreadId() : 1;
   939  }
   940  static int lsmWin32OsMutexNotHeld(lsm_mutex *p){
   941    Win32Mutex *pMutex = (Win32Mutex *)p;
   942    return pMutex ? pMutex->owner!=GetCurrentThreadId() : 1;
   943  }
   944  #endif
   945  /*
   946  ** End of Win32 mutex implementation.
   947  *************************************************************************/
   948  #else
   949  /*************************************************************************
   950  ** Noop mutex implementation
   951  */
   952  typedef struct NoopMutex NoopMutex;
   953  struct NoopMutex {
   954    lsm_env *pEnv;                  /* Environment handle (for xFree()) */
   955    int bHeld;                      /* True if mutex is held */
   956    int bStatic;                    /* True for a static mutex */
   957  };
   958  static NoopMutex aStaticNoopMutex[2] = {
   959    {0, 0, 1},
   960    {0, 0, 1},
   961  };
   962  
   963  static int lsmWin32OsMutexStatic(
   964    lsm_env *pEnv,
   965    int iMutex,
   966    lsm_mutex **ppStatic
   967  ){
   968    assert( iMutex>=1 && iMutex<=(int)array_size(aStaticNoopMutex) );
   969    *ppStatic = (lsm_mutex *)&aStaticNoopMutex[iMutex-1];
   970    return LSM_OK;
   971  }
   972  static int lsmWin32OsMutexNew(lsm_env *pEnv, lsm_mutex **ppNew){
   973    NoopMutex *p;
   974    p = (NoopMutex *)lsmMallocZero(pEnv, sizeof(NoopMutex));
   975    if( p ) p->pEnv = pEnv;
   976    *ppNew = (lsm_mutex *)p;
   977    return (p ? LSM_OK : LSM_NOMEM_BKPT);
   978  }
   979  static void lsmWin32OsMutexDel(lsm_mutex *pMutex)  {
   980    NoopMutex *p = (NoopMutex *)pMutex;
   981    assert( p->bStatic==0 && p->pEnv );
   982    lsmFree(p->pEnv, p);
   983  }
   984  static void lsmWin32OsMutexEnter(lsm_mutex *pMutex){
   985    NoopMutex *p = (NoopMutex *)pMutex;
   986    assert( p->bHeld==0 );
   987    p->bHeld = 1;
   988  }
   989  static int lsmWin32OsMutexTry(lsm_mutex *pMutex){
   990    NoopMutex *p = (NoopMutex *)pMutex;
   991    assert( p->bHeld==0 );
   992    p->bHeld = 1;
   993    return 0;
   994  }
   995  static void lsmWin32OsMutexLeave(lsm_mutex *pMutex){
   996    NoopMutex *p = (NoopMutex *)pMutex;
   997    assert( p->bHeld==1 );
   998    p->bHeld = 0;
   999  }
  1000  #ifdef LSM_DEBUG
  1001  static int lsmWin32OsMutexHeld(lsm_mutex *pMutex){
  1002    NoopMutex *p = (NoopMutex *)pMutex;
  1003    return p ? p->bHeld : 1;
  1004  }
  1005  static int lsmWin32OsMutexNotHeld(lsm_mutex *pMutex){
  1006    NoopMutex *p = (NoopMutex *)pMutex;
  1007    return p ? !p->bHeld : 1;
  1008  }
  1009  #endif
  1010  /***************************************************************************/
  1011  #endif /* else LSM_MUTEX_NONE */
  1012  
  1013  /* Without LSM_DEBUG, the MutexHeld tests are never called */
  1014  #ifndef LSM_DEBUG
  1015  # define lsmWin32OsMutexHeld    0
  1016  # define lsmWin32OsMutexNotHeld 0
  1017  #endif
  1018  
  1019  lsm_env *lsm_default_env(void){
  1020    static lsm_env win32_env = {
  1021      sizeof(lsm_env),         /* nByte */
  1022      1,                       /* iVersion */
  1023      /***** file i/o ******************/
  1024      0,                       /* pVfsCtx */
  1025      lsmWin32OsFullpath,      /* xFullpath */
  1026      lsmWin32OsOpen,          /* xOpen */
  1027      lsmWin32OsRead,          /* xRead */
  1028      lsmWin32OsWrite,         /* xWrite */
  1029      lsmWin32OsTruncate,      /* xTruncate */
  1030      lsmWin32OsSync,          /* xSync */
  1031      lsmWin32OsSectorSize,    /* xSectorSize */
  1032      lsmWin32OsRemap,         /* xRemap */
  1033      lsmWin32OsFileid,        /* xFileid */
  1034      lsmWin32OsClose,         /* xClose */
  1035      lsmWin32OsUnlink,        /* xUnlink */
  1036      lsmWin32OsLock,          /* xLock */
  1037      lsmWin32OsTestLock,      /* xTestLock */
  1038      lsmWin32OsShmMap,        /* xShmMap */
  1039      lsmWin32OsShmBarrier,    /* xShmBarrier */
  1040      lsmWin32OsShmUnmap,      /* xShmUnmap */
  1041      /***** memory allocation *********/
  1042      0,                       /* pMemCtx */
  1043      lsmWin32OsMalloc,        /* xMalloc */
  1044      lsmWin32OsRealloc,       /* xRealloc */
  1045      lsmWin32OsFree,          /* xFree */
  1046      lsmWin32OsMSize,         /* xSize */
  1047      /***** mutexes *********************/
  1048      0,                       /* pMutexCtx */
  1049      lsmWin32OsMutexStatic,   /* xMutexStatic */
  1050      lsmWin32OsMutexNew,      /* xMutexNew */
  1051      lsmWin32OsMutexDel,      /* xMutexDel */
  1052      lsmWin32OsMutexEnter,    /* xMutexEnter */
  1053      lsmWin32OsMutexTry,      /* xMutexTry */
  1054      lsmWin32OsMutexLeave,    /* xMutexLeave */
  1055      lsmWin32OsMutexHeld,     /* xMutexHeld */
  1056      lsmWin32OsMutexNotHeld,  /* xMutexNotHeld */
  1057      /***** other *********************/
  1058      lsmWin32OsSleep,         /* xSleep */
  1059    };
  1060    return &win32_env;
  1061  }
  1062  
  1063  #endif