mirror of
https://github.com/rmcrackan/Libation.git
synced 2026-09-15 15:19:48 -04:00
fix: a directory that stops being readable no longer throws at whoever lists it
SaferEnumerateFiles returned a lazy sequence, so an I/O error was raised where the sequence was walked rather than where it was created - past the try/catch callers had wrapped around it. IgnoreInaccessible did not help either: it only forgives permissions, not a volume that has stopped answering. Walk the enumerator defensively instead, keeping what was read and reporting the reason, and let a caller ask whether a directory can be read at all. See issue #1984. Co-authored-by: rmcrackan <rmcrackan@gmail.com>
This commit is contained in:
5 files changed
+464
-14
No files matched your search
@@ -69,19 +69,33 @@ public class BackgroundFileSystem : IDisposable
|
||||
fsCache.AddRange(SafestEnumerateFiles(RootDirectory));
|
||||
}
|
||||
|
||||
directoryChangesEvents = new BlockingCollection<FileSystemEventArgs>();
|
||||
fileSystemWatcher = new FileSystemWatcher(RootDirectory)
|
||||
try
|
||||
{
|
||||
IncludeSubdirectories = true,
|
||||
EnableRaisingEvents = true
|
||||
};
|
||||
fileSystemWatcher.Created += FileSystemWatcher_Changed;
|
||||
fileSystemWatcher.Deleted += FileSystemWatcher_Changed;
|
||||
fileSystemWatcher.Renamed += FileSystemWatcher_Changed;
|
||||
fileSystemWatcher.Error += FileSystemWatcher_Error;
|
||||
directoryChangesEvents = new BlockingCollection<FileSystemEventArgs>();
|
||||
fileSystemWatcher = new FileSystemWatcher(RootDirectory)
|
||||
{
|
||||
IncludeSubdirectories = true,
|
||||
EnableRaisingEvents = true
|
||||
};
|
||||
fileSystemWatcher.Created += FileSystemWatcher_Changed;
|
||||
fileSystemWatcher.Deleted += FileSystemWatcher_Changed;
|
||||
fileSystemWatcher.Renamed += FileSystemWatcher_Changed;
|
||||
fileSystemWatcher.Error += FileSystemWatcher_Error;
|
||||
|
||||
backgroundScanner = new Task(BackgroundScanner);
|
||||
backgroundScanner.Start();
|
||||
backgroundScanner = new Task(BackgroundScanner);
|
||||
backgroundScanner.Start();
|
||||
}
|
||||
// Watching a directory fails for the same reasons reading one does, and a removable drive can be pulled
|
||||
// between the listing above and this. Constructing this type happens inside the static initializer that
|
||||
// builds the Books file cache, and the runtime caches a failed initializer for the life of the process:
|
||||
// one throw here would be rethrown at every later reader of the Books directory. Give up the live
|
||||
// updates instead. Dropping RootDirectory has the owner rebuild this once the directory works again.
|
||||
catch (Exception ex)
|
||||
{
|
||||
Serilog.Log.Logger.Error(ex, "Could not watch a directory for changes, so its file cache was abandoned: {@DebugText}", new { path = (string?)RootDirectory });
|
||||
Stop();
|
||||
RootDirectory = null;
|
||||
}
|
||||
}
|
||||
private void Stop()
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user