@@ -236,10 +236,12 @@ try_init_from_cache(Request *req, char *hostname, char *filePath, INTERNET_SCHEM
236236 DWORD contentLength ;
237237 DWORD flags ;
238238 bool success ;
239- bool deleteCache ;
239+ bool hasCacheEntry ;
240+ size_t lockRetryCount ;
240241
241242 success = false;
242- deleteCache = false;
243+ hasCacheEntry = false;
244+ hFile = INVALID_HANDLE_VALUE ;
243245 hConn = NULL ;
244246 hReq = NULL ;
245247 lenlen = sizeof (INTERNET_CACHE_ENTRY_INFOA ) + MAX_URL_LENGTH + MAX_PATH ;
@@ -259,6 +261,12 @@ try_init_from_cache(Request *req, char *hostname, char *filePath, INTERNET_SCHEM
259261 }
260262 goto cleanup ;
261263 }
264+ hasCacheEntry = true;
265+
266+ hFile = CreateFileA (cacheData -> lpszLocalFileName , GENERIC_READ , FILE_SHARE_READ , NULL , OPEN_EXISTING , FILE_ATTRIBUTE_NORMAL , NULL );
267+ if (hFile == INVALID_HANDLE_VALUE ) {
268+ goto cleanup ;
269+ }
262270
263271 /* Send a HEAD request to validate the cached entry without downloading. */
264272 if (hInternet != NULL ) {
@@ -281,11 +289,6 @@ try_init_from_cache(Request *req, char *hostname, char *filePath, INTERNET_SCHEM
281289 }
282290 }
283291
284- hFile = CreateFileA (cacheData -> lpszLocalFileName , GENERIC_READ , FILE_SHARE_READ , NULL , OPEN_EXISTING , FILE_ATTRIBUTE_NORMAL , NULL );
285- if (hFile == INVALID_HANDLE_VALUE ) {
286- goto cleanup ;
287- }
288-
289292 /* Compare actual file size on disk against Content-Length to catch truncation. */
290293 if (hReq != NULL ) {
291294 DWORD fileSize = GetFileSize (hFile , NULL );
@@ -295,8 +298,6 @@ try_init_from_cache(Request *req, char *hostname, char *filePath, INTERNET_SCHEM
295298 && fileSize != contentLength ) {
296299 logmsg ("Cache file truncated for %s: on disk %d, expected %d\n" ,
297300 req -> url , fileSize , contentLength );
298- CloseHandle (hFile );
299- deleteCache = true;
300301 goto cleanup ;
301302 }
302303 }
@@ -317,10 +318,33 @@ try_init_from_cache(Request *req, char *hostname, char *filePath, INTERNET_SCHEM
317318 InternetCloseHandle (hConn );
318319 }
319320 if (!success ) {
320- UnlockUrlCacheEntryFileA (req -> url , 0 );
321- if (deleteCache ) {
322- DeleteUrlCacheEntryA (req -> url );
323- logmsg ("Deleted cache entry for %s\n" , req -> url );
321+ if (hasCacheEntry ) {
322+ /*
323+ * The lock count on disk may be polluted, so try to drain a
324+ * reasonable amount of them here. If we still ultimately fail to
325+ * unlock, that's fine; it just means the bad cache entry will be checked
326+ * again on the next request, which will drain the locks even more.
327+ */
328+ lockRetryCount = 64 ;
329+ while (UnlockUrlCacheEntryFileA (req -> url , 0 ))
330+ {
331+ lockRetryCount -- ;
332+ if (lockRetryCount == 0 ) {
333+ logmsg ("Cache entry for %s is hard locked\n" , req -> url );
334+ break ;
335+ }
336+ }
337+ if (DeleteUrlCacheEntryA (req -> url )) {
338+ logmsg ("Deleted cache entry for %s\n" , req -> url );
339+ } else {
340+ logmsg ("Failed to delete cache entry for %s: %d\n" , req -> url , GetLastError ());
341+ }
342+ }
343+
344+ if (hFile != INVALID_HANDLE_VALUE ) {
345+ CloseHandle (hFile );
346+ /* deleting the cache entry doesn't delete the file */
347+ DeleteFileA (cacheData -> lpszLocalFileName );
324348 }
325349 }
326350 free (cacheData );
0 commit comments