Пример #1
0
        public long GetNextRecord(out SizeHashEntry record)
        {
            record = new SizeHashEntry();
            long beginPosition = this.Stream.Position;

            // Indicate that there are no next record
            if (this.Stream.Position >= this.Stream.Length)
                return -1;

            using (BinaryReader br = new BinaryReader(this.Stream, Encoding.UTF8, true))
            {
                record.Decided = br.ReadBoolean(); // 1
                int ptrCount = br.ReadInt32(); // 4
                record.Pointers = new List<HashPointers>(ptrCount);
                for (int i = 0; i < ptrCount; ++i)
                {
                    HashPointers hp = new HashPointers();
                    hp.Hash = Encoding.UTF8.GetString(br.ReadBytes(32)); // 32

                    int entryCount = br.ReadInt32(); // 4
                    hp.FileEntries = new List<long>(entryCount);
                    for (int j = 0; j < entryCount; ++j)
                        hp.FileEntries.Add(br.ReadInt64()); // 8

                    record.Pointers.Add(hp);
                }
            }

            return beginPosition;
        }
Пример #2
0
        static bool SelectFilesToKeep(HashPointers ptr, out List<int> toKeep)
        {
            bool selectionSuccess = false;
            toKeep = new List<int>(Enumerable.Range(1, ptr.FileEntries.Count));
            bool decided = false;
            int choice = 0;

            bool canAutoSelect = false;
            List<int> oldestIDs = new List<int>();
            List<int> newestIDs = new List<int>();
            {
                // Read and register the timestamp when the files were last accessed
                // The oldest file (lowest timestamp) will be on the top of the list
                SortedList<DateTime, List<int>> timeStamps = new SortedList<DateTime, List<int>>(ptr.FileEntries.Count);
                PathEntry entry = new PathEntry();
                int currentID = 1;
                foreach (long offset in ptr.FileEntries)
                {
                    PathsFile.GetRecordAt(offset, out entry);
                    FileInfo fi = new FileInfo(entry.Path);

                    IEnumerable<DateTime> tsRegistered = timeStamps.Select(ts => ts.Key)
                        .Where(ts => ts.Date == fi.LastAccessTime.Date
                            && ts.Hour == fi.LastAccessTime.Hour
                            && ts.Minute == fi.LastAccessTime.Minute
                            && ts.Second == fi.LastAccessTime.Second);
                    if (tsRegistered.Count() == 1)
                        timeStamps[tsRegistered.First()].Add(currentID);
                    else
                    {
                        List<int> idList = new List<int>(1);
                        idList.Add(currentID);
                        timeStamps.Add(fi.LastAccessTime, idList);
                    }
                    ++currentID;
                }

                // If the oldest and newest files are the same, don't select any of them
                if (timeStamps.Count == 1 && (AutoOldest || AutoNewest))
                    Console.WriteLine("The files' age are equal. Unable to select oldest and newest ones.");
                else
                {
                    oldestIDs.AddRange(timeStamps.First().Value);
                    newestIDs.AddRange(timeStamps.Last().Value);
                    canAutoSelect = true;
                }
            }

            while (!selectionSuccess)
            {
                Console.ForegroundColor = ConsoleColor.Cyan;
                Console.WriteLine(new String('-', Console.WindowWidth - 1));
                DuplicateFileLog.WriteLine(new String('-', 24));
                Console.WriteLine("The following " + ptr.FileEntries.Count + " files are duplicate of each other");
                DuplicateFileLog.WriteLine("The following " + ptr.FileEntries.Count + " files are duplicate of each other");
                Console.ResetColor();
                if (Verbose)
                {
                    Console.ForegroundColor = ConsoleColor.Cyan;
                    Console.WriteLine("Hash: " + ptr.Hash);
                    DuplicateFileLog.WriteLine("Hash: " + ptr.Hash);
                    Console.ResetColor();
                }

                if (!DryRun)
                {
                    Console.Write("Files marked ");
                    Console.ForegroundColor = ConsoleColor.White;
                    Console.Write("[ KEEP ]");
                    Console.ResetColor();
                    Console.Write(" will be kept. Files marked ");
                    Console.ForegroundColor = ConsoleColor.Red;
                    Console.Write("[DELETE]");
                    Console.ResetColor();
                    Console.WriteLine(" will be deleted.");

                    if (!AutoNewest && !AutoOldest)
                        Console.WriteLine("Please select the files you wish to keep or delete.");
                    else
                        if (!canAutoSelect)
                        {
                            Console.ForegroundColor = ConsoleColor.Yellow;
                            Console.WriteLine("Was unable to automatically select " + (AutoOldest ? "oldest" : "newest") + " file to keep");
                            Console.ResetColor();
                        }
                        else
                        {
                            Console.ForegroundColor = ConsoleColor.Yellow;
                            Console.WriteLine("Automatically selecting the " + (AutoOldest ? "OLDEST" : "NEWEST") + " file to keep");
                            Console.ResetColor();
                            toKeep.Clear();

                            if (AutoOldest)
                                toKeep.AddRange(oldestIDs);
                            else if (AutoNewest)
                                toKeep.AddRange(newestIDs);
                        }
                }

                // Print the file list with a choice
                int menuId = 1;
                PathEntry etr = new PathEntry();
                int totalLog10ofEntries = (int)Math.Floor(Math.Log10((double)ptr.FileEntries.Count)) + 1;
                if (totalLog10ofEntries < 3) // Make sure "-1." can be printed
                    totalLog10ofEntries = 3;
                foreach (long offset in ptr.FileEntries)
                {
                    PathsFile.GetRecordAt(offset, out etr);

                    // Create a little menu for the user to give a choice

                    // The length of the choice option printed, how many characters it takes in base 10
                    int strCurrentLength = (int)Math.Floor(Math.Log10((double)menuId)) + 1; // 0-9: 1 long, 10-99: 2 long, etc.
                    ++strCurrentLength; // The '.' (dot) takes up another character

                    if (!DryRun)
                    {
                        if (toKeep.Contains(menuId))
                        {
                            Console.ForegroundColor = ConsoleColor.White;
                            Console.Write("[ KEEP ] ");
                            Console.ResetColor();
                        }
                        else
                        {
                            Console.ForegroundColor = ConsoleColor.Red;
                            Console.Write("[DELETE] ");
                            Console.ResetColor();
                        }
                    }

                    Console.ForegroundColor = ConsoleColor.Cyan;
                    Console.Write(new String(' ', totalLog10ofEntries - strCurrentLength + 1) + menuId + ". ");

                    bool oldestOrNewest = false;
                    if (oldestIDs.Contains(menuId))
                    {
                        Console.ForegroundColor = ConsoleColor.White;
                        Console.Write("[OLDEST] ");
                        DuplicateFileLog.Write("[OLDEST] ");
                        oldestOrNewest = true;
                    }
                    else if (newestIDs.Contains(menuId))
                    {
                        Console.ForegroundColor = ConsoleColor.White;
                        Console.Write("[NEWEST] ");
                        DuplicateFileLog.Write("[NEWEST] ");
                        oldestOrNewest = true;
                    }

                    DuplicateFileLog.Write(new String(' ', (!oldestOrNewest ? 9 : 0) +
                        totalLog10ofEntries - strCurrentLength + 1) + menuId + ". ");
                    Console.ResetColor();
                    Console.WriteLine(etr.Path);
                    DuplicateFileLog.WriteLine(etr.Path);

                    ++menuId;
                }

                if (!AutoNewest && !AutoOldest && !DryRun)
                {
                    Console.ForegroundColor = ConsoleColor.Magenta;
                    Console.Write("  [DONE] " + new String(' ', totalLog10ofEntries - 2 + 1) + "0. ");
                    Console.ResetColor();
                    Console.WriteLine("Finalise the choices");

                    Console.ForegroundColor = ConsoleColor.Green;
                    Console.Write("  [SKIP] " + new String(' ', totalLog10ofEntries - 3 + 1) + "-1. ");
                    Console.ResetColor();
                    Console.WriteLine("Keep everything for now, decide later");

                    Console.ForegroundColor = ConsoleColor.DarkRed;
                    Console.Write("  [NUKE] " + new String(' ', totalLog10ofEntries - 3 + 1) + "-2. ");
                    Console.Write("Delete ALL FILES!");
                    Console.ResetColor();
                    Console.WriteLine();
                }

                // Read the user's choice
                if (!AutoNewest && !AutoOldest && !DryRun)
                {
                    Console.WriteLine("Please select an option from above. If you select a file, its status will be togged between keep and delete.");
                    Console.Write("? ");
                    try
                    {
                        choice = Convert.ToInt32(Console.ReadLine());
                        selectionSuccess = true; // Attempt to say that the user successfully selected

                        if (choice >= menuId || choice < -2)
                            throw new ArgumentOutOfRangeException("The entered choice is invalid.");
                    }
                    catch (Exception)
                    {
                        Console.ForegroundColor = ConsoleColor.Red;
                        Console.Write("Invalid input. ");
                        Console.ResetColor();
                        Console.WriteLine("The enterd input is not a number or is out of range. Please select from the presented choices!");

                        selectionSuccess = false;
                    }
                }
                else
                    // If the user decided to automatically keep oldest or newest file, the selection was successful.
                    // Either the oldest or the newest file were selected, or if not, all files were selected to be kept.
                    selectionSuccess = true;

                if (selectionSuccess)
                {
                    // Change the buffer list of which files to keep or don't
                    if (choice >= 1)
                    {
                        if (toKeep.Contains(choice))
                            toKeep.Remove(choice);
                        else
                            toKeep.Add(choice);

                        selectionSuccess = false; // Let the user make further changes
                        decided = false;
                    }
                    else if (choice == -2)
                    {
                        toKeep.Clear();
                        decided = true;
                    }
                    else
                        decided = (choice == 0); // If -1, tell that the user hasn't decided
                }
            }

            toKeep.Sort();
            return decided;
        }