Index: src/os_win.c ================================================================== --- src/os_win.c +++ src/os_win.c @@ -3028,10 +3028,39 @@ zBuf[j+1] = 0; OSTRACE(("TEMP FILENAME: %s\n", zBuf)); return SQLITE_OK; } + +/* +** Return TRUE if the named file is really a directory. Return false if +** it is something other than a directory, or if there is any kind of memory +** allocation failure. +*/ +static int winIsDir(const void *zConverted){ + DWORD attr; + int rc = 0; + DWORD lastErrno; + + if( isNT() ){ + int cnt = 0; + WIN32_FILE_ATTRIBUTE_DATA sAttrData; + memset(&sAttrData, 0, sizeof(sAttrData)); + while( !(rc = osGetFileAttributesExW((LPCWSTR)zConverted, + GetFileExInfoStandard, + &sAttrData)) && retryIoerr(&cnt, &lastErrno) ){} + if( !rc ){ + return 0; /* Invalid name? */ + } + attr = sAttrData.dwFileAttributes; +#if SQLITE_OS_WINCE==0 + }else{ + attr = osGetFileAttributesA((char*)zConverted); +#endif + } + return (attr!=INVALID_FILE_ATTRIBUTES) && (attr&FILE_ATTRIBUTE_DIRECTORY); +} /* ** Open a file. */ static int winOpen( @@ -3134,10 +3163,15 @@ /* Convert the filename to the system encoding. */ zConverted = convertUtf8Filename(zUtf8Name); if( zConverted==0 ){ return SQLITE_IOERR_NOMEM; } + + if( winIsDir(zConverted) ){ + sqlite3_free(zConverted); + return SQLITE_CANTOPEN_ISDIR; + } if( isReadWrite ){ dwDesiredAccess = GENERIC_READ | GENERIC_WRITE; }else{ dwDesiredAccess = GENERIC_READ; @@ -3184,24 +3218,24 @@ dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL))==INVALID_HANDLE_VALUE && - retryIoerr(&cnt, &lastErrno) ){} -/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed. -** Since the ANSI version of these Windows API do not exist for WINCE, -** it's important to not reference them for WINCE builds. -*/ + retryIoerr(&cnt, &lastErrno) ){ + /* Noop */ + } #if SQLITE_OS_WINCE==0 }else{ while( (h = osCreateFileA((LPCSTR)zConverted, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL))==INVALID_HANDLE_VALUE && - retryIoerr(&cnt, &lastErrno) ){} + retryIoerr(&cnt, &lastErrno) ){ + /* Noop */ + } #endif } logIoerr(cnt); @@ -3277,10 +3311,11 @@ const char *zFilename, /* Name of file to delete */ int syncDir /* Not used on win32 */ ){ int cnt = 0; int rc; + DWORD attr; DWORD lastErrno; void *zConverted; UNUSED_PARAMETER(pVfs); UNUSED_PARAMETER(syncDir); @@ -3288,24 +3323,54 @@ zConverted = convertUtf8Filename(zFilename); if( zConverted==0 ){ return SQLITE_IOERR_NOMEM; } if( isNT() ){ - rc = 1; - while( osGetFileAttributesW(zConverted)!=INVALID_FILE_ATTRIBUTES && - (rc = osDeleteFileW(zConverted))==0 && retryIoerr(&cnt, &lastErrno) ){} - rc = rc ? SQLITE_OK : SQLITE_ERROR; + do { + attr = osGetFileAttributesW(zConverted); + if ( attr==INVALID_FILE_ATTRIBUTES ){ + rc = SQLITE_OK; /* Already gone? */ + break; + } + if ( attr&FILE_ATTRIBUTE_DIRECTORY ){ + rc = SQLITE_ERROR; /* Files only. */ + break; + } + if ( osDeleteFileW(zConverted) ){ + rc = SQLITE_OK; /* Deleted OK. */ + break; + } + if ( !retryIoerr(&cnt, &lastErrno) ){ + rc = SQLITE_ERROR; /* No more retries. */ + break; + } + } while(1); /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed. ** Since the ANSI version of these Windows API do not exist for WINCE, ** it's important to not reference them for WINCE builds. */ #if SQLITE_OS_WINCE==0 }else{ - rc = 1; - while( osGetFileAttributesA(zConverted)!=INVALID_FILE_ATTRIBUTES && - (rc = osDeleteFileA(zConverted))==0 && retryIoerr(&cnt, &lastErrno) ){} - rc = rc ? SQLITE_OK : SQLITE_ERROR; + do { + attr = osGetFileAttributesA(zConverted); + if ( attr==INVALID_FILE_ATTRIBUTES ){ + rc = SQLITE_OK; /* Already gone? */ + break; + } + if ( attr&FILE_ATTRIBUTE_DIRECTORY ){ + rc = SQLITE_ERROR; /* Files only. */ + break; + } + if ( osDeleteFileA(zConverted) ){ + rc = SQLITE_OK; /* Deleted OK. */ + break; + } + if ( !retryIoerr(&cnt, &lastErrno) ){ + rc = SQLITE_ERROR; /* No more retries. */ + break; + } + } while(1); #endif } if( rc ){ rc = winLogError(SQLITE_IOERR_DELETE, lastErrno, "winDelete", zFilename); Index: src/sqlite.h.in ================================================================== --- src/sqlite.h.in +++ src/sqlite.h.in @@ -451,10 +451,11 @@ #define SQLITE_IOERR_SHMMAP (SQLITE_IOERR | (21<<8)) #define SQLITE_IOERR_SEEK (SQLITE_IOERR | (22<<8)) #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) #define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8)) +#define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8)) #define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8)) #define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8)) #define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8)) #define SQLITE_ABORT_ROLLBACK (SQLITE_ABORT | (2<<8))