/ Check-in [cb9d1ab3]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Add runtime version checking for winSectorSize.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | winSectorSize
Files: files | file ages | folders
SHA1: cb9d1ab33d4109e0712d1a9dd2e51861e168e418
User & Date: mistachkin 2017-01-18 01:11:03
Context
2017-01-18
19:06
Minimize the requested permissions when opening the volume on Windows 7 and Vista. check-in: 8d429a59 user: mistachkin tags: winSectorSize
01:11
Add runtime version checking for winSectorSize. check-in: cb9d1ab3 user: mistachkin tags: winSectorSize
00:27
When determining sector sizes on Windows 7 and Vista, make sure the target file is on the same volume as corresponding root directory. check-in: de699ead user: mistachkin tags: winSectorSize
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/os_win.c.

463
464
465
466
467
468
469


470
471


472
473
474
475
476
477
478
....
1139
1140
1141
1142
1143
1144
1145

1146
1147
1148
1149
1150
1151
1152
1153
1154
1155

1156
1157
1158
1159
1160
1161
1162
1163
1164
1165

1166
1167
1168
1169
1170
1171
1172
1173
....
1438
1439
1440
1441
1442
1443
1444

























































1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
....
3573
3574
3575
3576
3577
3578
3579

3580
3581
3582
3583
3584
3585
3586
3587
....
3616
3617
3618
3619
3620
3621
3622

3623
3624
3625
3626
3627
3628
3629
3630
3631
3632
3633
3634
3635
3636
3637




3638

3639
3640
3641
3642
3643
3644
3645
3646
3647
3648
3649
3650
3651
3652
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666






3667
3668
3669
3670
3671
3672
3673
3674
3675
3676
3677
3678
3679

3680
3681
3682
3683
3684
3685
3686
3687
3688
** 2:   Operating system is WinNT.
**
** In order to facilitate testing on a WinNT system, the test fixture
** can manually set this value to 1 to emulate Win98 behavior.
*/
#ifdef SQLITE_TEST
LONG SQLITE_WIN32_VOLATILE sqlite3_os_type = 0;


#else
static LONG SQLITE_WIN32_VOLATILE sqlite3_os_type = 0;


#endif

#ifndef SYSCALL
#  define SYSCALL sqlite3_syscall_ptr
#endif

/*
................................................................................
#else
  { "FlushViewOfFile",          (SYSCALL)0,                      0 },
#endif

#define osFlushViewOfFile \
        ((BOOL(WINAPI*)(LPCVOID,SIZE_T))aSyscall[79].pCurrent)


#if defined(_WIN32_WINNT) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
  { "DeviceIoControl",          (SYSCALL)DeviceIoControl,        0 },
#else
  { "DeviceIoControl",          (SYSCALL)0,                      0 },
#endif

#define osDeviceIoControl ((BOOL(WINAPI*)( \
        HANDLE,DWORD,LPVOID,DWORD,LPVOID,DWORD,LPVOID, \
        LPOVERLAPPED))aSyscall[80].pCurrent)


#if defined(_WIN32_WINNT) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
  { "GetVolumeInformationByHandleW", (SYSCALL)GetVolumeInformationByHandleW, 0 },
#else
  { "GetVolumeInformationByHandleW", (SYSCALL)0,                 0 },
#endif

#define osGetVolumeInformationByHandleW ((BOOL(WINAPI*)( \
        HANDLE,LPWSTR,DWORD,LPDWORD,LPDWORD,LPDWORD,LPWSTR, \
        DWORD))aSyscall[81].pCurrent)


#if defined(_WIN32_WINNT) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
  { "GetVolumeInformationW",     (SYSCALL)GetVolumeInformationW, 0 },
#else
  { "GetVolumeInformationW",     (SYSCALL)0,                     0 },
#endif

#define osGetVolumeInformationW ((BOOL(WINAPI*)( \
        LPCWSTR,LPWSTR,DWORD,LPDWORD,LPDWORD,LPDWORD,LPWSTR, \
................................................................................
# define osIsNT()  (1)
#elif !defined(SQLITE_WIN32_HAS_WIDE)
# define osIsNT()  (0)
#else
# define osIsNT()  ((sqlite3_os_type==2) || sqlite3_win32_is_nt())
#endif


























































/*
** This function determines if the machine is running a version of Windows
** based on the NT kernel.
*/
int sqlite3_win32_is_nt(void){
#if SQLITE_OS_WINRT
  /*
  ** NOTE: The WinRT sub-platform is always assumed to be based on the NT
  **       kernel.
  */
  return 1;
#elif SQLITE_WIN32_GETVERSIONEX
  if( osInterlockedCompareExchange(&sqlite3_os_type, 0, 0)==0 ){
#if defined(SQLITE_WIN32_HAS_ANSI)
    OSVERSIONINFOA sInfo;
    sInfo.dwOSVersionInfoSize = sizeof(sInfo);
    osGetVersionExA(&sInfo);
    osInterlockedCompareExchange(&sqlite3_os_type,
        (sInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) ? 2 : 1, 0);
#elif defined(SQLITE_WIN32_HAS_WIDE)
    OSVERSIONINFOW sInfo;
    sInfo.dwOSVersionInfoSize = sizeof(sInfo);
    osGetVersionExW(&sInfo);
    osInterlockedCompareExchange(&sqlite3_os_type,
        (sInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) ? 2 : 1, 0);
#endif
  }
  return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2;
#elif SQLITE_TEST
  return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2;
#else
  /*
  ** NOTE: All sub-platforms where the GetVersionEx[AW] functions are
  **       deprecated are always assumed to be based on the NT kernel.
................................................................................
    }
#endif
  }
  OSTRACE(("FCNTL file=%p, rc=SQLITE_NOTFOUND\n", pFile->h));
  return SQLITE_NOTFOUND;
}


#if defined(_WIN32_WINNT) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
/*
** This function attempts to determine if the specified file resides on the
** same volume as the corresponding root directory.  If not, the specified
** file may be impacted by a hard link, symbolic link, or reparse point (e.g.
** junction).
**
** This function may return false even when the file is on the same volume
................................................................................
** SQLite code assumes this function cannot fail. It also assumes that
** if two files are created in the same file-system directory (i.e.
** a database and its journal file) that the sector size will be the
** same for both.
*/
static int winSectorSize(sqlite3_file *id){
#if defined(_WIN32_WINNT) && _WIN32_WINNT >= _WIN32_WINNT_WIN8

  winFile *pFile = (winFile*)id;
  FILE_STORAGE_INFO info;
  memset(&info, 0, sizeof(FILE_STORAGE_INFO));
  if( osGetFileInformationByHandleEx(pFile->h, FileStorageInfo,
                                   &info, sizeof(info)) ){
    ULONG size = info.FileSystemEffectivePhysicalBytesPerSectorForAtomicity;
    OSTRACE(("SECTOR file=%p, size=%lu\n", pFile->h, size));
    if( size>0 && size<=2147483647 ){
      return (int)size;
    }
  }else{
    pFile->lastErrno = osGetLastError();
    winLogError(SQLITE_IOERR_FSTAT, pFile->lastErrno,
                     "winSectorSize1", pFile->zPath);
  }




#elif defined(_WIN32_WINNT) && _WIN32_WINNT >= _WIN32_WINNT_VISTA

  winFile *pFile = (winFile*)id;
  if( winIsDriveLetterAndColon(pFile->zPath) && winIsOnSameVolume(pFile) ){
    WCHAR zDisk[] = L"\\\\.\\_:\0"; /* underscore will be drive letter */
    HANDLE hDisk;
    zDisk[4] = (WCHAR)pFile->zPath[0]; /* 'A' to 'Z' only, upper/lower case */
    assert( (zDisk[4]>=L'A' && zDisk[4]<=L'Z')
         || (zDisk[4]>=L'a' && zDisk[4]<=L'z')
    );
    hDisk = osCreateFileW(zDisk, STANDARD_RIGHTS_READ,
                          FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
                          OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if( hDisk!=NULL ){
      STORAGE_PROPERTY_QUERY query;
      STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR alignment;
      DWORD bytes = 0;
      memset(&query, 0, sizeof(STORAGE_PROPERTY_QUERY));
      memset(&alignment, 0, sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR));
      query.QueryType  = PropertyStandardQuery;
      query.PropertyId = StorageAccessAlignmentProperty;
      if( osDeviceIoControl(hDisk, IOCTL_STORAGE_QUERY_PROPERTY, &query,
                            sizeof(STORAGE_PROPERTY_QUERY), &alignment,
                            sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR),
                            &bytes, NULL) ){
        DWORD size = alignment.BytesPerPhysicalSector;
        OSTRACE(("SECTOR file=%p, size=%lu\n", pFile->h, size));
        if( size>0 && size<=2147483647 ){
          return (int)size;
        }






      }else{
        pFile->lastErrno = osGetLastError();
        winLogError(SQLITE_IOERR_FSTAT, pFile->lastErrno,
                    "winSectorSize2", pFile->zPath);
      }
      osCloseHandle(hDisk);
    }else{
      pFile->lastErrno = osGetLastError();
      winLogError(SQLITE_IOERR_FSTAT, pFile->lastErrno,
                  "winSectorSize3", pFile->zPath);
    }
  }
#else

  (void)id;
#endif
  return SQLITE_DEFAULT_SECTOR_SIZE;
}

/*
** Return a vector of device characteristics.
*/
static int winDeviceCharacteristics(sqlite3_file *id){







>
>


>
>







 







>
|









>
|









>
|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>












<
<
<
<
|
<
<
<
<
<
<
<
<
<
<







 







>
|







 







>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>
>
>
>
|
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>
>
>
>
>
>



|

<
<
<
<
<


|
>

<







463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
....
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
....
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520




1521










1522
1523
1524
1525
1526
1527
1528
....
3623
3624
3625
3626
3627
3628
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
....
3667
3668
3669
3670
3671
3672
3673
3674
3675
3676
3677
3678
3679
3680
3681
3682
3683
3684
3685
3686
3687
3688
3689
3690
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
3710
3711
3712
3713
3714
3715
3716
3717
3718
3719
3720
3721
3722
3723
3724
3725
3726
3727
3728
3729
3730
3731
3732
3733
3734





3735
3736
3737
3738
3739

3740
3741
3742
3743
3744
3745
3746
** 2:   Operating system is WinNT.
**
** In order to facilitate testing on a WinNT system, the test fixture
** can manually set this value to 1 to emulate Win98 behavior.
*/
#ifdef SQLITE_TEST
LONG SQLITE_WIN32_VOLATILE sqlite3_os_type = 0;
LONG SQLITE_WIN32_VOLATILE sqlite3_os_major = 0;
LONG SQLITE_WIN32_VOLATILE sqlite3_os_minor = 0;
#else
static LONG SQLITE_WIN32_VOLATILE sqlite3_os_type = 0;
static LONG SQLITE_WIN32_VOLATILE sqlite3_os_major = 0;
static LONG SQLITE_WIN32_VOLATILE sqlite3_os_minor = 0;
#endif

#ifndef SYSCALL
#  define SYSCALL sqlite3_syscall_ptr
#endif

/*
................................................................................
#else
  { "FlushViewOfFile",          (SYSCALL)0,                      0 },
#endif

#define osFlushViewOfFile \
        ((BOOL(WINAPI*)(LPCVOID,SIZE_T))aSyscall[79].pCurrent)

#if defined(SQLITE_WIN32_VISTA_SECTOR_SIZE) && defined(_WIN32_WINNT) && \
        _WIN32_WINNT >= _WIN32_WINNT_VISTA
  { "DeviceIoControl",          (SYSCALL)DeviceIoControl,        0 },
#else
  { "DeviceIoControl",          (SYSCALL)0,                      0 },
#endif

#define osDeviceIoControl ((BOOL(WINAPI*)( \
        HANDLE,DWORD,LPVOID,DWORD,LPVOID,DWORD,LPVOID, \
        LPOVERLAPPED))aSyscall[80].pCurrent)

#if defined(SQLITE_WIN32_VISTA_SECTOR_SIZE) && defined(_WIN32_WINNT) && \
        _WIN32_WINNT >= _WIN32_WINNT_VISTA
  { "GetVolumeInformationByHandleW", (SYSCALL)GetVolumeInformationByHandleW, 0 },
#else
  { "GetVolumeInformationByHandleW", (SYSCALL)0,                 0 },
#endif

#define osGetVolumeInformationByHandleW ((BOOL(WINAPI*)( \
        HANDLE,LPWSTR,DWORD,LPDWORD,LPDWORD,LPDWORD,LPWSTR, \
        DWORD))aSyscall[81].pCurrent)

#if defined(SQLITE_WIN32_VISTA_SECTOR_SIZE) && defined(_WIN32_WINNT) && \
        _WIN32_WINNT >= _WIN32_WINNT_VISTA
  { "GetVolumeInformationW",     (SYSCALL)GetVolumeInformationW, 0 },
#else
  { "GetVolumeInformationW",     (SYSCALL)0,                     0 },
#endif

#define osGetVolumeInformationW ((BOOL(WINAPI*)( \
        LPCWSTR,LPWSTR,DWORD,LPDWORD,LPDWORD,LPDWORD,LPWSTR, \
................................................................................
# define osIsNT()  (1)
#elif !defined(SQLITE_WIN32_HAS_WIDE)
# define osIsNT()  (0)
#else
# define osIsNT()  ((sqlite3_os_type==2) || sqlite3_win32_is_nt())
#endif

/*
** This following version checking macros should evaluate to non-zero only
** when running on Windows Vista (or higher) or Windows 8 (or higher).
*/

#if !SQLITE_WIN32_GETVERSIONEX
# define osIsVistaPlus()  (1)
# define osIsWin8Plus()   (1)
#elif SQLITE_OS_WINCE
# define osIsVistaPlus()  (0)
# define osIsWin8Plus()   (0)
#elif SQLITE_OS_WINRT
# define osIsVistaPlus()  (1)
# define osIsWin8Plus()   (1)
#else
# define osIsVistaPlus()  (winGetVersionEx() && ((sqlite3_os_major>6) || \
    ((sqlite3_os_major==6) && (sqlite3_os_minor>=0))))
# define osIsWin8Plus()   (winGetVersionEx() && ((sqlite3_os_major>6) || \
    ((sqlite3_os_major==6) && (sqlite3_os_minor>=2))))
#endif

/*
** This function populates the Windows version information needed by this
** module.  Use of the GetVersionExA or GetVersionExW function is required.
** The return value will be non-zero if version information was queried.
*/
#if SQLITE_WIN32_GETVERSIONEX
static int winGetVersionEx(){
  if( osInterlockedCompareExchange(&sqlite3_os_type, 0, 0)==0 ){
#if defined(SQLITE_WIN32_HAS_ANSI)
    OSVERSIONINFOA sInfo;
    sInfo.dwOSVersionInfoSize = sizeof(sInfo);
    osGetVersionExA(&sInfo);
    osInterlockedCompareExchange(&sqlite3_os_type,
        (sInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) ? 2 : 1, 0);
    osInterlockedCompareExchange(&sqlite3_os_major,
        (LONG)sInfo.dwMajorVersion, 0);
    osInterlockedCompareExchange(&sqlite3_os_minor,
        (LONG)sInfo.dwMinorVersion, 0);
    return 1;
#elif defined(SQLITE_WIN32_HAS_WIDE)
    OSVERSIONINFOW sInfo;
    sInfo.dwOSVersionInfoSize = sizeof(sInfo);
    osGetVersionExW(&sInfo);
    osInterlockedCompareExchange(&sqlite3_os_type,
        (sInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) ? 2 : 1, 0);
    osInterlockedCompareExchange(&sqlite3_os_major,
        (LONG)sInfo.dwMajorVersion, 0);
    osInterlockedCompareExchange(&sqlite3_os_minor,
        (LONG)sInfo.dwMinorVersion, 0);
    return 1;
#endif
  }
  return 0;
}
#endif

/*
** This function determines if the machine is running a version of Windows
** based on the NT kernel.
*/
int sqlite3_win32_is_nt(void){
#if SQLITE_OS_WINRT
  /*
  ** NOTE: The WinRT sub-platform is always assumed to be based on the NT
  **       kernel.
  */
  return 1;
#elif SQLITE_WIN32_GETVERSIONEX




  winGetVersionEx();










  return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2;
#elif SQLITE_TEST
  return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2;
#else
  /*
  ** NOTE: All sub-platforms where the GetVersionEx[AW] functions are
  **       deprecated are always assumed to be based on the NT kernel.
................................................................................
    }
#endif
  }
  OSTRACE(("FCNTL file=%p, rc=SQLITE_NOTFOUND\n", pFile->h));
  return SQLITE_NOTFOUND;
}

#if defined(SQLITE_WIN32_VISTA_SECTOR_SIZE) && \
    defined(_WIN32_WINNT) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
/*
** This function attempts to determine if the specified file resides on the
** same volume as the corresponding root directory.  If not, the specified
** file may be impacted by a hard link, symbolic link, or reparse point (e.g.
** junction).
**
** This function may return false even when the file is on the same volume
................................................................................
** SQLite code assumes this function cannot fail. It also assumes that
** if two files are created in the same file-system directory (i.e.
** a database and its journal file) that the sector size will be the
** same for both.
*/
static int winSectorSize(sqlite3_file *id){
#if defined(_WIN32_WINNT) && _WIN32_WINNT >= _WIN32_WINNT_WIN8
  if( osIsWin8Plus() ){
    winFile *pFile = (winFile*)id;
    FILE_STORAGE_INFO info;
    memset(&info, 0, sizeof(FILE_STORAGE_INFO));
    if( osGetFileInformationByHandleEx(pFile->h, FileStorageInfo,
                                       &info, sizeof(info)) ){
      ULONG size = info.FileSystemEffectivePhysicalBytesPerSectorForAtomicity;
      OSTRACE(("SECTOR file=%p, size=%lu\n", pFile->h, size));
      if( size>0 && size<=2147483647 ){
        return (int)size;
      }
    }else{
      pFile->lastErrno = osGetLastError();
      winLogError(SQLITE_IOERR_FSTAT, pFile->lastErrno,
                  "winSectorSize1", pFile->zPath);
    }
  }
#endif

#if defined(SQLITE_WIN32_VISTA_SECTOR_SIZE) && \
    defined(_WIN32_WINNT) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
  if( osIsVistaPlus() ){
    winFile *pFile = (winFile*)id;
    if( winIsDriveLetterAndColon(pFile->zPath) && winIsOnSameVolume(pFile) ){
      WCHAR zDisk[] = L"\\\\.\\_:\0"; /* underscore will be drive letter */
      HANDLE hDisk;
      zDisk[4] = (WCHAR)pFile->zPath[0]; /* 'A' to 'Z' only, upper/lower case */
      assert( (zDisk[4]>=L'A' && zDisk[4]<=L'Z')
           || (zDisk[4]>=L'a' && zDisk[4]<=L'z')
      );
      hDisk = osCreateFileW(zDisk, STANDARD_RIGHTS_READ,
                            FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
                            OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
      if( hDisk!=NULL ){
        STORAGE_PROPERTY_QUERY query;
        STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR alignment;
        DWORD bytes = 0;
        memset(&query, 0, sizeof(STORAGE_PROPERTY_QUERY));
        memset(&alignment, 0, sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR));
        query.QueryType  = PropertyStandardQuery;
        query.PropertyId = StorageAccessAlignmentProperty;
        if( osDeviceIoControl(hDisk, IOCTL_STORAGE_QUERY_PROPERTY, &query,
                              sizeof(STORAGE_PROPERTY_QUERY), &alignment,
                              sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR),
                              &bytes, NULL) ){
          DWORD size = alignment.BytesPerPhysicalSector;
          OSTRACE(("SECTOR file=%p, size=%lu\n", pFile->h, size));
          if( size>0 && size<=2147483647 ){
            return (int)size;
          }
        }else{
          pFile->lastErrno = osGetLastError();
          winLogError(SQLITE_IOERR_FSTAT, pFile->lastErrno,
                      "winSectorSize2", pFile->zPath);
        }
        osCloseHandle(hDisk);
      }else{
        pFile->lastErrno = osGetLastError();
        winLogError(SQLITE_IOERR_FSTAT, pFile->lastErrno,
                    "winSectorSize3", pFile->zPath);
      }





    }
  }
#endif

  (void)id;

  return SQLITE_DEFAULT_SECTOR_SIZE;
}

/*
** Return a vector of device characteristics.
*/
static int winDeviceCharacteristics(sqlite3_file *id){