Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Merge the improved anti-virus defenses into the trunk. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
0207fd9b0c0f6baa3c2cb8ba588ad585 |
User & Date: | drh 2011-07-12 14:38:25.733 |
Context
2011-07-13
| ||
16:03 | Added the SQLITE_FCNTL_WIN32_AV_RETRY file control for configuring the retry counts and delays in the windows VFS. (check-in: 7aaf0a6ae1 user: drh tags: trunk) | |
2011-07-12
| ||
14:38 | Merge the improved anti-virus defenses into the trunk. (check-in: 0207fd9b0c user: drh tags: trunk) | |
14:02 | Revise logic in winDelete to check the file prior to attempting to delete it. (Closed-Leaf check-in: 36f11acc53 user: mistachkin tags: av-defense) | |
2011-07-11
| ||
23:45 | Update the TCL commands for setting windows manditory locks. Add test cases for manditory lock delays under windows. (check-in: 03af4c175c user: drh tags: trunk) | |
Changes
Changes to src/os_win.c.
︙ | ︙ | |||
399 400 401 402 403 404 405 | iLine, iErrno, zFunc, zPath, zMsg ); return errcode; } /* | | | > > | > > > > > | | > > > > > > > > > > > > | 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 | iLine, iErrno, zFunc, zPath, zMsg ); return errcode; } /* ** The number of times that a ReadFile(), WriteFile(), and DeleteFile() ** will be retried following a locking error - probably caused by ** antivirus software. Also the initial delay before the first retry. ** The delay increases linearly with each retry. */ #ifndef SQLITE_WIN32_IOERR_RETRY # define SQLITE_WIN32_IOERR_RETRY 10 #endif #ifndef SQLITE_WIN32_IOERR_RETRY_DELAY # define SQLITE_WIN32_IOERR_RETRY_DELAY 25 #endif /* ** If a ReadFile() or WriteFile() error occurs, invoke this routine ** to see if it should be retried. Return TRUE to retry. Return FALSE ** to give up with an error. */ static int retryIoerr(int *pnRetry){ DWORD e; if( *pnRetry>=SQLITE_WIN32_IOERR_RETRY ){ return 0; } e = GetLastError(); if( e==ERROR_ACCESS_DENIED || e==ERROR_LOCK_VIOLATION || e==ERROR_SHARING_VIOLATION ){ Sleep(SQLITE_WIN32_IOERR_RETRY_DELAY*(1+*pnRetry)); ++*pnRetry; return 1; } return 0; } /* ** Log a I/O error retry episode. */ static void logIoerr(int nRetry){ if( nRetry ){ sqlite3_log(SQLITE_IOERR, "delayed %dms for lock/sharing conflict", SQLITE_WIN32_IOERR_RETRY_DELAY*nRetry*(nRetry+1)/2 ); } } #if SQLITE_OS_WINCE /************************************************************************* ** This section contains code for WinCE only. */ /* ** WindowsCE does not have a localtime() function. So create a |
︙ | ︙ | |||
857 858 859 860 861 862 863 864 865 866 867 868 869 870 | return SQLITE_FULL; } while( !ReadFile(pFile->h, pBuf, amt, &nRead, 0) ){ if( retryIoerr(&nRetry) ) continue; pFile->lastErrno = GetLastError(); return winLogError(SQLITE_IOERR_READ, "winRead", pFile->zPath); } if( nRead<(DWORD)amt ){ /* Unread parts of the buffer must be zero-filled */ memset(&((char*)pBuf)[nRead], 0, amt-nRead); return SQLITE_IOERR_SHORT_READ; } return SQLITE_OK; | > | 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 | return SQLITE_FULL; } while( !ReadFile(pFile->h, pBuf, amt, &nRead, 0) ){ if( retryIoerr(&nRetry) ) continue; pFile->lastErrno = GetLastError(); return winLogError(SQLITE_IOERR_READ, "winRead", pFile->zPath); } logIoerr(nRetry); if( nRead<(DWORD)amt ){ /* Unread parts of the buffer must be zero-filled */ memset(&((char*)pBuf)[nRead], 0, amt-nRead); return SQLITE_IOERR_SHORT_READ; } return SQLITE_OK; |
︙ | ︙ | |||
878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 | sqlite3_file *id, /* File to write into */ const void *pBuf, /* The bytes to be written */ int amt, /* Number of bytes to write */ sqlite3_int64 offset /* Offset into the file to begin writing at */ ){ int rc; /* True if error has occured, else false */ winFile *pFile = (winFile*)id; /* File handle */ assert( amt>0 ); assert( pFile ); SimulateIOError(return SQLITE_IOERR_WRITE); SimulateDiskfullError(return SQLITE_FULL); OSTRACE(("WRITE %d lock=%d\n", pFile->h, pFile->locktype)); rc = seekWinFile(pFile, offset); if( rc==0 ){ u8 *aRem = (u8 *)pBuf; /* Data yet to be written */ int nRem = amt; /* Number of bytes yet to be written */ DWORD nWrite; /* Bytes written by each WriteFile() call */ | > < | 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 | sqlite3_file *id, /* File to write into */ const void *pBuf, /* The bytes to be written */ int amt, /* Number of bytes to write */ sqlite3_int64 offset /* Offset into the file to begin writing at */ ){ int rc; /* True if error has occured, else false */ winFile *pFile = (winFile*)id; /* File handle */ int nRetry = 0; /* Number of retries */ assert( amt>0 ); assert( pFile ); SimulateIOError(return SQLITE_IOERR_WRITE); SimulateDiskfullError(return SQLITE_FULL); OSTRACE(("WRITE %d lock=%d\n", pFile->h, pFile->locktype)); rc = seekWinFile(pFile, offset); if( rc==0 ){ u8 *aRem = (u8 *)pBuf; /* Data yet to be written */ int nRem = amt; /* Number of bytes yet to be written */ DWORD nWrite; /* Bytes written by each WriteFile() call */ while( nRem>0 ){ if( !WriteFile(pFile->h, aRem, nRem, &nWrite, 0) ){ if( retryIoerr(&nRetry) ) continue; break; } if( nWrite<=0 ) break; |
︙ | ︙ | |||
914 915 916 917 918 919 920 921 922 923 924 925 926 927 | if( rc ){ if( ( pFile->lastErrno==ERROR_HANDLE_DISK_FULL ) || ( pFile->lastErrno==ERROR_DISK_FULL )){ return SQLITE_FULL; } return winLogError(SQLITE_IOERR_WRITE, "winWrite", pFile->zPath); } return SQLITE_OK; } /* ** Truncate an open file to a specified size */ | > > | 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 | if( rc ){ if( ( pFile->lastErrno==ERROR_HANDLE_DISK_FULL ) || ( pFile->lastErrno==ERROR_DISK_FULL )){ return SQLITE_FULL; } return winLogError(SQLITE_IOERR_WRITE, "winWrite", pFile->zPath); }else{ logIoerr(nRetry); } return SQLITE_OK; } /* ** Truncate an open file to a specified size */ |
︙ | ︙ | |||
2347 2348 2349 2350 2351 2352 2353 | ** will open a journal file shortly after it is created in order to do ** whatever it does. While this other process is holding the ** file open, we will be unable to delete it. To work around this ** problem, we delay 100 milliseconds and try to delete again. Up ** to MX_DELETION_ATTEMPTs deletion attempts are run before giving ** up and returning an error. */ | < | < < > > | < | < < < > > | < | < < > > > > > | < < < | < < | 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 | ** will open a journal file shortly after it is created in order to do ** whatever it does. While this other process is holding the ** file open, we will be unable to delete it. To work around this ** problem, we delay 100 milliseconds and try to delete again. Up ** to MX_DELETION_ATTEMPTs deletion attempts are run before giving ** up and returning an error. */ static int winDelete( sqlite3_vfs *pVfs, /* Not used on win32 */ const char *zFilename, /* Name of file to delete */ int syncDir /* Not used on win32 */ ){ int cnt = 0; int rc; void *zConverted; UNUSED_PARAMETER(pVfs); UNUSED_PARAMETER(syncDir); SimulateIOError(return SQLITE_IOERR_DELETE); zConverted = convertUtf8Filename(zFilename); if( zConverted==0 ){ return SQLITE_NOMEM; } if( isNT() ){ rc = 1; while( GetFileAttributesW(zConverted)!=INVALID_FILE_ATTRIBUTES && (rc = DeleteFileW(zConverted))==0 && retryIoerr(&cnt) ){} rc = rc ? SQLITE_OK : SQLITE_ERROR; /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed. ** Since the ASCII version of these Windows API do not exist for WINCE, ** it's important to not reference them for WINCE builds. */ #if SQLITE_OS_WINCE==0 }else{ rc = 1; while( GetFileAttributesA(zConverted)!=INVALID_FILE_ATTRIBUTES && (rc = DeleteFileA(zConverted))==0 && retryIoerr(&cnt) ){} rc = rc ? SQLITE_OK : SQLITE_ERROR; #endif } if( rc ){ rc = winLogError(SQLITE_IOERR_DELETE, "winDelete", zFilename); }else{ logIoerr(cnt); } free(zConverted); OSTRACE(("DELETE \"%s\" %s\n", zFilename, (rc ? "failed" : "ok" ))); return rc; } /* ** Check the existance and status of a file. */ static int winAccess( sqlite3_vfs *pVfs, /* Not used on win32 */ |
︙ | ︙ |
Changes to test/wal6.test.
︙ | ︙ | |||
39 40 41 42 43 44 45 | CREATE TABLE t1(a INTEGER PRIMARY KEY, b); INSERT INTO t1 VALUES(1,2); SELECT * FROM t1; } } {1 2} # Under Windows, you'll get an error trying to delete | | < < < < < < < < | | 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | CREATE TABLE t1(a INTEGER PRIMARY KEY, b); INSERT INTO t1 VALUES(1,2); SELECT * FROM t1; } } {1 2} # Under Windows, you'll get an error trying to delete # a file this is already opened. Close the first connection # so the other tests work. if {$tcl_platform(platform)=="windows"} { if {$jmode=="persist" || $jmode=="truncate"} { db close } } do_test wal6-1.2.$jmode { sqlite3 db2 test.db execsql { PRAGMA journal_mode=WAL; |
︙ | ︙ | |||
83 84 85 86 87 88 89 | db close db2 close forcedelete test.db } finish_test | < | 75 76 77 78 79 80 81 | db close db2 close forcedelete test.db } finish_test |
Changes to test/win32lock.test.
︙ | ︙ | |||
16 17 18 19 20 21 22 23 24 25 26 27 28 29 | if {$tcl_platform(platform)!="windows"} return set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix win32lock do_test win32lock-1.1 { db eval { PRAGMA cache_size=10; CREATE TABLE t1(x,y); INSERT INTO t1 VALUES(1,randomblob(100000)); INSERT INTO t1 VALUES(2,randomblob(50000)); INSERT INTO t1 VALUES(3,randomblob(25000)); | > > > > > > > > | 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | if {$tcl_platform(platform)!="windows"} return set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix win32lock db close sqlite3_shutdown test_sqlite3_log xLog proc xLog {error_code msg} { lappend ::log $msg } sqlite3 db test.db do_test win32lock-1.1 { db eval { PRAGMA cache_size=10; CREATE TABLE t1(x,y); INSERT INTO t1 VALUES(1,randomblob(100000)); INSERT INTO t1 VALUES(2,randomblob(50000)); INSERT INTO t1 VALUES(3,randomblob(25000)); |
︙ | ︙ | |||
45 46 47 48 49 50 51 52 53 54 55 | set ::msg } {disk I/O error} break } else { do_test win32lock-1.2-$delay1 { set ::msg } {1 100000 2 50000 3 25000 4 12500} incr delay1 50 } } sqlite3_test_control_pending_byte $old_pending_byte | > > > > > > > | > > | 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | set ::msg } {disk I/O error} break } else { do_test win32lock-1.2-$delay1 { set ::msg } {1 100000 2 50000 3 25000 4 12500} if {$::log!=""} { do_test win32lock-1.2-$delay1-log1 { regsub {\d+} $::log # x set x } {{delayed #ms for lock/sharing conflict}} } incr delay1 50 } set ::log {} } sqlite3_test_control_pending_byte $old_pending_byte sqlite3_shutdown test_sqlite3_log sqlite3_initialize finish_test |