4
4
using System . Diagnostics ;
5
5
using Dependencies . ClrPh ;
6
6
using System . ComponentModel ;
7
-
7
+ using System . Linq ;
8
+
8
9
namespace Dependencies
9
10
{
10
11
@@ -292,8 +293,7 @@ public class BinaryCacheImpl : BinaryCache
292
293
{
293
294
public BinaryCacheImpl ( string ApplicationAppDataPath , int _MaxBinaryCount )
294
295
{
295
-
296
- BinaryDatabase = new Dictionary < string , PE > ( ) ;
296
+ BinaryDatabase = new Dictionary < string , Lazy < PE > > ( ) ;
297
297
BinaryDatabaseLock = new Object ( ) ;
298
298
LruCache = new List < string > ( ) ;
299
299
@@ -306,10 +306,13 @@ public BinaryCacheImpl(string ApplicationAppDataPath, int _MaxBinaryCount)
306
306
307
307
public override void Load ( )
308
308
{
309
- // "warm up" the cache
310
- foreach ( var CachedBinary in Directory . EnumerateFiles ( BinaryCacheFolderPath ) )
311
- {
312
- GetBinaryAsync ( CachedBinary ) ;
309
+ // load cached file order by LastAccessTime to make LRU always available
310
+ foreach ( var cachedBinaryFile in new DirectoryInfo ( BinaryCacheFolderPath ) . EnumerateFiles ( )
311
+ . OrderByDescending ( fi => fi . LastAccessTime ) )
312
+ {
313
+ var peHash = cachedBinaryFile . Name ;
314
+ LruCache . Add ( peHash ) ;
315
+ BinaryDatabase . Add ( peHash , new Lazy < PE > ( ( ) => LoadCachedBinary ( peHash ) , true ) ) ;
313
316
}
314
317
315
318
string System32Folder = Environment . GetFolderPath ( Environment . SpecialFolder . System ) ;
@@ -339,9 +342,7 @@ public override void Load()
339
342
{
340
343
GetBinaryAsync ( Path . Combine ( SysWow64Folder , KnownDll ) ) ;
341
344
}
342
-
343
345
}
344
-
345
346
}
346
347
347
348
public override void Unload ( )
@@ -358,7 +359,11 @@ public override void Unload()
358
359
// Force map unloading before deleting file
359
360
if ( BinaryDatabase . ContainsKey ( PeHash ) )
360
361
{
361
- BinaryDatabase [ PeHash ] . Unload ( ) ;
362
+ var lazyPE = BinaryDatabase [ PeHash ] ;
363
+ if ( lazyPE . IsValueCreated )
364
+ {
365
+ lazyPE . Value . Unload ( ) ;
366
+ }
362
367
}
363
368
364
369
try
@@ -371,20 +376,53 @@ public override void Unload()
371
376
// so only the last one alive can clear the cache.
372
377
Debug . WriteLine ( "[BinaryCache] Could not unload file {0:s} : {1:s} " , CachedBinary , uae ) ;
373
378
}
374
-
375
379
}
376
380
}
377
381
378
-
379
382
// flush the cache
380
383
BinaryDatabase . Clear ( ) ;
381
384
}
382
385
386
+ private PE LoadCachedBinary ( string peHash )
387
+ {
388
+ var cachedBinaryFile = Path . Combine ( BinaryCacheFolderPath , peHash ) ;
389
+ if ( ! NativeFile . Exists ( cachedBinaryFile ) )
390
+ {
391
+ lock ( BinaryDatabaseLock )
392
+ {
393
+ LruCache . Remove ( peHash ) ;
394
+ BinaryDatabase . Remove ( peHash ) ;
395
+ }
396
+ return null ;
397
+ }
398
+
399
+ PE cachedPE = new PE ( cachedBinaryFile ) ;
400
+ try
401
+ {
402
+ // update LastAccessTime to save LRU to disk
403
+ // note: Windows from Vista disable updating LastAccessTime by default,
404
+ // so we have to update it manually.
405
+ new FileInfo ( cachedBinaryFile ) . LastAccessTime = DateTime . Now ;
406
+ }
407
+ catch { }
408
+
409
+ if ( ! cachedPE . Load ( ) )
410
+ {
411
+ lock ( BinaryDatabaseLock )
412
+ {
413
+ LruCache . Remove ( peHash ) ;
414
+ BinaryDatabase . Remove ( peHash ) ;
415
+ }
416
+ return null ;
417
+ }
418
+
419
+ return cachedPE ;
420
+ }
421
+
383
422
public void GetBinaryAsync ( string PePath , RunWorkerCompletedEventHandler Callback = null )
384
423
{
385
424
BackgroundWorker bw = new BackgroundWorker ( ) ;
386
425
bw . DoWork += ( sender , e ) => {
387
-
388
426
GetBinary ( PePath ) ;
389
427
} ;
390
428
@@ -393,7 +431,6 @@ public void GetBinaryAsync(string PePath, RunWorkerCompletedEventHandler Callbac
393
431
bw . RunWorkerCompleted += Callback ;
394
432
}
395
433
396
-
397
434
bw . RunWorkerAsync ( ) ;
398
435
}
399
436
@@ -419,25 +456,25 @@ public override PE GetBinary(string PePath)
419
456
// Cache "miss"
420
457
if ( ! hit )
421
458
{
422
-
423
459
string DestFilePath = Path . Combine ( BinaryCacheFolderPath , PeHash ) ;
424
460
if ( ! File . Exists ( DestFilePath ) && ( DestFilePath != PePath ) )
425
461
{
426
462
// Debug.WriteLine(String.Format("FileCopy from {0:s} to {1:s}", PePath, DestFilePath), "BinaryCache");
427
463
NativeFile . Copy ( PePath , DestFilePath ) ;
428
- }
429
-
430
- PE NewShadowBinary = new PE ( DestFilePath ) ;
431
- NewShadowBinary . Load ( ) ;
432
-
433
- LruCache . Add ( PeHash ) ;
434
- BinaryDatabase . Add ( PeHash , NewShadowBinary ) ;
464
+ }
465
+
466
+ LruCache . Add ( PeHash ) ;
467
+ BinaryDatabase . Add ( PeHash , new Lazy < PE > ( ( ) => LoadCachedBinary ( PeHash ) ) ) ;
435
468
}
436
469
}
437
470
438
471
// Cache "Hit"
439
472
UpdateLru ( PeHash ) ;
440
- PE ShadowBinary = BinaryDatabase [ PeHash ] ;
473
+ PE ShadowBinary = BinaryDatabase [ PeHash ] . Value ;
474
+ if ( ShadowBinary == null )
475
+ {
476
+ return null ;
477
+ }
441
478
ShadowBinary . Filepath = Path . GetFullPath ( PePath ) ; // convert any paths to an absolute one.
442
479
443
480
Debug . WriteLine ( String . Format ( "File {0:s} loaded from {1:s}" , PePath , Path . Combine ( BinaryCacheFolderPath , PeHash ) ) , "BinaryCache" ) ;
@@ -465,7 +502,7 @@ protected void UpdateLru(string PeHash)
465
502
466
503
#region Members
467
504
private List < string > LruCache ;
468
- private Dictionary < string , PE > BinaryDatabase ;
505
+ private Dictionary < string , Lazy < PE > > BinaryDatabase ;
469
506
private Object BinaryDatabaseLock ;
470
507
471
508
private string BinaryCacheFolderPath ;
0 commit comments