public static void ScanFile(TextWriter writer, SQLiteConnection connection, List <Volume> volumes, List <Archive> archives, FileInfo file) { // identify this file writer.WriteLine(); writer.WriteLine("Identifying {0}...", file.FullName); FileIdentity identity = FileOperations.IdentifyFile(file.FullName); DateTime timestamp; using (IDbTransaction t = connection.BeginTransaction()) { timestamp = FileOperations.InsertOrGetFile(t, identity.Filesize, identity.Hash, identity.ShortHash, file.LastWriteTimeUtc).timestamp; t.Commit(); } // with this canonical timestamp, find all archive patterns that match this file string name = file.Name; List <Archive> matchingArchives = new List <Archive>(); foreach (Archive a in archives) { foreach (ArchivePattern p in a.Patterns) { if (timestamp >= p.TimestampBegin && timestamp <= p.TimestampEnd && MatchPattern(name, p.Pattern)) { matchingArchives.Add(a); break; } } } if (matchingArchives.Count == 0) { writer.WriteLine("File {0} does not fit into any archive.", file.FullName); return; } if (matchingArchives.Count > 1) { writer.WriteLine("File {0} does fit into {1} archives. Archive configuration error?", file.FullName, matchingArchives.Count); return; } if (matchingArchives.Count != 1) { throw new Exception("???"); } Archive matchingArchive = matchingArchives[0]; if (matchingArchive.Paths.Count <= 0) { writer.WriteLine("File {0} fits into archive, but archive has no defined paths.", file.FullName); return; } writer.WriteLine("File {0} fits into archive {1}", file.FullName, matchingArchive.ArchiveId); // alright now we have to // - copy this file into every path // - if and only if the file was successfully copied into every path, delete it from the source, otherwise leave it alone // be sure to special case things like current file == target file!! long successfulCopies = 0; bool allowDelete = true; string sourcePath = file.FullName; foreach (ArchivePath p in matchingArchive.Paths) { try { Volume vol = volumes.FirstOrDefault(x => x.ID == p.VolumeId); if (vol == null) { writer.WriteLine("Volume {0} appears to not be attached.", p.VolumeId); allowDelete = false; continue; } string targetPath = CreateFilePath(vol.DeviceID, p.Path, name); bool existedBefore = File.Exists(targetPath); if (!existedBefore) { // file does not exist at target yet, copy over writer.WriteLine("Copying file to {0}...", targetPath); File.Copy(sourcePath, targetPath); } if (File.Exists(targetPath)) { writer.WriteLine("Identifying {0}...", targetPath); FileIdentity existingTargetIdentity = FileOperations.IdentifyFile(targetPath); if (identity == existingTargetIdentity) { if (existedBefore) { // TODO: check here if source file == target file!!! // for now to be safe just inhibit delete //allowDelete = false; } writer.WriteLine("File at {0} exists and matches.", targetPath); ++successfulCopies; continue; } else { writer.WriteLine("File at {0} exists and DOES NOT match!", targetPath); allowDelete = false; continue; } } else { writer.WriteLine("File at {0} somehow disappeared???", targetPath); allowDelete = false; continue; } } catch (Exception ex) { writer.WriteLine("Failed to process file to path {0}/{1}: {2}", p.VolumeId, p.Path, ex.ToString()); allowDelete = false; } } if (successfulCopies == matchingArchive.Paths.Count) { if (matchingArchive.Paths.Count >= 2) { if (allowDelete) { writer.WriteLine("Deleting {0}", sourcePath); File.Delete(sourcePath); } else { writer.WriteLine("Inhibited delete of {0} despite all targets existing.", sourcePath); } } else { writer.WriteLine("Inhibited delete of {0} because only one target path is defined.", sourcePath); } } else { writer.WriteLine("Could not copy or confirm all targets of {0}", sourcePath); } return; }