Example #1
0
        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;
        }