@@ -114,7 +114,7 @@ private static bool LastWriteTimesHaveChanged()
114114
115115if ( s_rootStoreFile != null )
116116{
117- _ = TryStatFile ( s_rootStoreFile , out DateTime lastModified ) ;
117+ _ = TryStatFile ( s_rootStoreFile , out DateTime lastModified , out _ ) ;
118118if ( lastModified != s_fileLastWrite )
119119{
120120return true ;
@@ -149,6 +149,7 @@ private static Tuple<SafeX509StackHandle, SafeX509StackHandle> LoadMachineStores
149149
150150var uniqueRootCerts = new HashSet < X509Certificate2 > ( ) ;
151151var uniqueIntermediateCerts = new HashSet < X509Certificate2 > ( ) ;
152+ var processedFiles = new HashSet < ( long Ino , long Dev ) > ( ) ;
152153bool firstLoad = ( s_nativeCollections == null ) ;
153154
154155if ( firstLoad )
@@ -197,23 +198,23 @@ bool ProcessDir(string dir, out DateTime lastModified)
197198
198199foreach ( string file in Directory . EnumerateFiles ( dir ) )
199200{
200- hasStoreData |= ProcessFile ( file , out _ , skipStat : true ) ;
201+ hasStoreData |= ProcessFile ( file , out _ ) ;
201202}
202203
203204return hasStoreData ;
204205}
205206
206- bool ProcessFile ( string file , out DateTime lastModified , bool skipStat = false )
207+ bool ProcessFile ( string file , out DateTime lastModified )
207208{
208209bool readData = false ;
209-
210- if ( skipStat )
210+ if ( ! TryStatFile ( file , out lastModified , out ( long , long ) fileId ) )
211211{
212- lastModified = default ;
212+ return false ;
213213}
214- else if ( ! TryStatFile ( file , out lastModified ) )
214+
215+ if ( processedFiles . Contains ( fileId ) )
215216{
216- return false ;
217+ return true ;
217218}
218219
219220using ( SafeBioHandle fileBio = Interop . Crypto . BioNewFile ( file , "rb" ) )
@@ -281,6 +282,11 @@ bool ProcessFile(string file, out DateTime lastModified, bool skipStat = false)
281282}
282283}
283284
285+ if ( readData )
286+ {
287+ processedFiles . Add ( fileId ) ;
288+ }
289+
284290return readData ;
285291}
286292
@@ -307,7 +313,6 @@ bool ProcessFile(string file, out DateTime lastModified, bool skipStat = false)
307313// In order to maintain "finalization-free" the GetNativeCollections method would need to
308314// DangerousAddRef, and the callers would need to DangerousRelease, adding more interlocked operations
309315// on every call.
310-
311316Volatile . Write ( ref s_nativeCollections , newCollections ) ;
312317s_recheckStopwatch . Restart ( ) ;
313318return newCollections ;
@@ -361,24 +366,24 @@ private static string[] GetRootStoreDirectories(out bool isDefault)
361366return directories ;
362367}
363368
364- private static bool TryStatFile ( string path , out DateTime lastModified )
365- => TryStat ( path , Interop . Sys . FileTypes . S_IFREG , out lastModified ) ;
366-
367369private static bool TryStatDirectory ( string path , out DateTime lastModified )
368- => TryStat ( path , Interop . Sys . FileTypes . S_IFDIR , out lastModified ) ;
370+ => TryStat ( path , Interop . Sys . FileTypes . S_IFDIR , out lastModified , out _ ) ;
369371
370- private static bool TryStat ( string path , int fileType , out DateTime lastModified )
372+ private static bool TryStatFile ( string path , out DateTime lastModified , out ( long , long ) fileId )
373+ => TryStat ( path , Interop . Sys . FileTypes . S_IFREG , out lastModified , out fileId ) ;
374+
375+ private static bool TryStat ( string path , int fileType , out DateTime lastModified , out ( long , long ) fileId )
371376{
372377lastModified = default ;
373-
374- Interop . Sys . FileStatus status ;
378+ fileId = default ;
375379// Use Stat to follow links.
376- if ( Interop . Sys . Stat ( path , out status ) < 0 ||
380+ if ( Interop . Sys . Stat ( path , out Interop . Sys . FileStatus status ) < 0 ||
377381( status . Mode & Interop . Sys . FileTypes . S_IFMT ) != fileType )
378382{
379383return false ;
380384}
381385
386+ fileId = ( status . Ino , status . Dev ) ;
382387lastModified = DateTime . UnixEpoch + TimeSpan . FromTicks ( status . MTime * TimeSpan . TicksPerSecond + status . MTimeNsec / TimeSpan . NanosecondsPerTick ) ;
383388return true ;
384389}