Example #1
0
        public void InitializeFull(ConsoleEx consoleEx, HelixFileVersion fileVersion = null)
        {
            PreInitializationCheck();

            //Initialize Encr Directory
            consoleEx?.WriteLine(VerbosityLevel.Detailed, 0, "Initializing Encrypted Directory...");
            Header = DirectoryHeader.New();

            EncrDirectory.Create();
            if (WhatIf)
            {
                EncrDirectory.WhatIfAddFile(HelixConsts.HeaderFileName, 10);
            }
            else
            {
                Header.Save(EncrDirectory.PathFull(HelixConsts.HeaderFileName), DerivedBytesProvider, fileVersion);
                EncrDirectory.RefreshEntry(HelixConsts.HeaderFileName);
            }

            this.FileNameEncoder = new FileNameEncoder(Header.FileNameKey);
            consoleEx?.WriteLine(VerbosityLevel.Detailed, 1, "Encrypted Directory Initialized (" + Header.DirectoryId.Substring(0, 6) + "...)");


            InitializeDecr(consoleEx);
        }
Example #2
0
        public SyncLogEntry CreateNewLogEntryFromDecrPath(string decrFileName)
        {
            FSEntry decrEntry = DecrDirectory.TryGetEntry(decrFileName);

            string  encrFileName = FileNameEncoder.EncodeName(decrFileName);
            FSEntry encrEntry    = EncrDirectory.TryGetEntry(encrFileName);

            return(new SyncLogEntry(decrEntry.EntryType, decrEntry.RelativePath, decrEntry.LastWriteTimeUtc, encrEntry.RelativePath, encrEntry.LastWriteTimeUtc));
        }
Example #3
0
 public void OpenEncr(ConsoleEx consoleEx)
 {
     if (Header == null)
     {
         consoleEx?.WriteLine(VerbosityLevel.Detailed, 0, "Opening Encrypted Directory...");
         Header = DirectoryHeader.Load(EncrDirectory.PathFull(HelixConsts.HeaderFileName), DerivedBytesProvider);
         consoleEx?.WriteLine(VerbosityLevel.Detailed, 0, "Opened Encrypted Directory (" + Header.DirectoryId.Substring(0, 6) + "...)");
     }
     this.FileNameEncoder = new FileNameEncoder(Header.FileNameKey);
 }
Example #4
0
        public SyncLogEntry CreateNewLogEntryFromEncrPath(string encrFileName)
        {
            string encrFilePath = Path.Combine(EncrDirectory.FullName, encrFileName);

            FSEntry encrEntry = EncrDirectory.TryGetEntry(encrFileName);

            FileEntry header       = HelixFile.DecryptHeader(encrFilePath, DerivedBytesProvider);
            var       decrFileName = header.FileName;

            if (encrFileName != FileNameEncoder.EncodeName(decrFileName))
            {
                throw new HelixException("Encrypted file name does not match"); //todo: prompt for action
            }
            return(new SyncLogEntry(header.EntryType, header.FileName, header.LastWriteTimeUtc, encrEntry.RelativePath, encrEntry.LastWriteTimeUtc));
        }
Example #5
0
        public void PreInitializationCheck()
        {
            if (!EncrDirectory.Exists &&
                !Directory.Exists(Path.GetDirectoryName(EncrDirectory.FullName)))
            {
                throw new Exception("Encrypted directory (and parent) does not exist");
            }

            if (Directory.Exists(EncrDirectory.FullName) &&
                !EncrDirectory.ChildExists(HelixConsts.HeaderFileName) &&
                EncrDirectory.GetEntries().Any())
            {
                throw new Exception($"Unable to initialize, encrypted directory ({EncrDirectory.Name}) is not empty");
            }


            if (!DecrDirectory.Exists &&
                !Directory.Exists(Path.GetDirectoryName(Path.GetFullPath(DecrDirectory.FullName))))
            {
                throw new Exception("Decrypted directory (and parent) does not exist");
            }
        }
Example #6
0
        /// <summary>
        /// Returns a list of changes that need to be performed as part of the sync.
        /// </summary>
        public List <PreSyncDetails> FindChanges(bool clearCache = true, ConsoleEx console = null)
        {
            //todo: disable default for reset
            console?.WriteLine(VerbosityLevel.Diagnostic, 0, "Finding Changes...");
            if (clearCache)
            {
                ClearCache();
            }

            using var rng = RandomNumberGenerator.Create();

            console?.WriteLine(VerbosityLevel.Diagnostic, 1, "Enumerating Encr Directory...");
            List <FSEntry> encrDirectoryFiles = EncrDirectory.GetEntries(SearchOption.AllDirectories).Where(EncrFilter).ToList();

            console?.WriteLine(VerbosityLevel.Diagnostic, 2, $"{encrDirectoryFiles.Count} files found");

            console?.WriteLine(VerbosityLevel.Diagnostic, 1, $"Enumerating Decr Directory...");
            console?.WriteLine(VerbosityLevel.Diagnostic, 2, $"Path: {DecrDirectory.FullName}");
            List <FSEntry> decrDirectoryFiles = DecrDirectory.GetEntries(SearchOption.AllDirectories).Where(DecrFilter).ToList();

            console?.WriteLine(VerbosityLevel.Diagnostic, 2, $"{decrDirectoryFiles.Count} files found");

            console?.WriteLine(VerbosityLevel.Diagnostic, 1, "Reading sync log (decr side)...");
            console?.WriteLine(VerbosityLevel.Diagnostic, 2, $"{SyncLog.Count()} entries found");
            //todo: filter out log entries where the decr file name and the encr file name does not match


            console?.WriteLine(VerbosityLevel.Diagnostic, 1, "Performing 3 way join...");
            List <ChangeBuilder> changes = FindChanges_St04_ThreeWayJoin(encrDirectoryFiles, decrDirectoryFiles, SyncLog, console).ToList();


            console?.WriteLine(VerbosityLevel.Diagnostic, 1, "Refreshing EncrHeaders...");
            FindChanges_St05_RefreshEncrHeaders(console, changes);


            //todo: detect conflicts

            console?.WriteLine(VerbosityLevel.Diagnostic, 1, "Adding Relationships...");
            FindChanges_St06_AddRelationships(changes);

#if DEBUG
            Debug.Assert(changes.All(c => c.RelationParents != null));
            Debug.Assert(changes.All(c => c.RelationChildren != null));
            Debug.Assert(changes.All(c => c.RelationCaseDifference != null));
#endif


            console?.WriteLine(VerbosityLevel.Diagnostic, 1, "Calculating Operation...");
            FindChanges_St07_CalculateOperation(changes);

            console?.WriteLine(VerbosityLevel.Diagnostic, 1, "Calculating Sync Mode...");
            FindChanges_St08_CalculateSyncMode(changes);

            console?.WriteLine(VerbosityLevel.Diagnostic, 1, "Calculating Dependencies...");
            FindChanges_St09_CalculateDependencies(changes);

            console?.WriteLine(VerbosityLevel.Diagnostic, 1, "Sorting...");
            changes = FindChanges_St10_Sort(rng, changes);



            return(changes
                   .Where(m => m.SyncMode != PreSyncMode.Unchanged)
                   .Select(m => m.ToSyncEntry())
                   .ToList());
        }
Example #7
0
 public bool InitializeFullNeeded()
 {
     return(!EncrDirectory.ChildExists(HelixConsts.HeaderFileName));
 }
Example #8
0
        public SyncResults TrySync(PreSyncDetails entry, ConsoleEx console = null)
        {
            const int encrTimespanPrecisionMS = 1000;

            //todo: ensure the entry direction and operation end up being the same
            //todo: ensure all the calling methods do something with the results

            //if (WhatIf)
            //    throw new InvalidOperationException("Unable to perform sync when WhatIf mode is set to true");
            if (entry == null)
            {
                throw new ArgumentNullException(nameof(entry));
            }

            if (entry.SyncMode == PreSyncMode.DecryptedSide)
            {
                SyncLogEntry logEntry = entry.LogEntry;


                string             encrPath = Path.Combine(EncrDirectory.FullName, HelixUtil.PathNative(entry.EncrFileName));
                string             decrPath = Path.Combine(DecrDirectory.FullName, HelixUtil.PathNative(entry.DecrFileName));
                FileEncryptOptions options  = new FileEncryptOptions();
                FileEntry          header   = null;
                options.BeforeWriteHeader = (h) => header = h;
                options.StoredFileName    = entry.DecrFileName;
                options.FileVersion       = Header.FileVersion;
                options.Log = (s) => console?.WriteLine(VerbosityLevel.Diagnostic, 1, s);

                if (WhatIf)
                {
                    EncrDirectory.WhatIfReplaceFile(encrPath, entry.DisplayFileLength);
                    if (entry.DecrInfo == null)
                    {
                        header = new FileEntry()
                        {
                            EntryType = FileEntryType.Removed,
                            FileName  = entry.DecrFileName,
                        };
                    }
                    else
                    {
                        header = entry.DecrInfo.ToFileEntry();
                    }
                }
                else
                {
                    HelixFile.Encrypt(decrPath, encrPath, DerivedBytesProvider, options);


                    //forces a change if the file was modified to quickly
                    if (logEntry != null && (File.GetLastWriteTimeUtc(encrPath) - logEntry.EncrModified).TotalMilliseconds < encrTimespanPrecisionMS)
                    {
                        File.SetLastWriteTimeUtc(encrPath, logEntry.EncrModified + TimeSpan.FromMilliseconds(encrTimespanPrecisionMS));
                    }

                    EncrDirectory.RefreshEntry(encrPath);
                }
                var newLogEntry = CreateEntryFromHeader(header, EncrDirectory.TryGetEntry(entry.EncrFileName));
                SyncLog.Add(newLogEntry);


                return(SyncResults.Success());
            }
            else if (entry.SyncMode == PreSyncMode.EncryptedSide)
            {
                if (entry.DisplayOperation == PreSyncOperation.Purge)
                {
                    SyncLog.Add(entry.GetUpdatedLogEntry());
                    return(SyncResults.Success());
                }
                else
                {
                    //todo: use the DisplayOperation to determine what to do (ensures the counts stay consistant)

                    SyncLogEntry logEntry        = entry.LogEntry;
                    SyncLogEntry fileSystemEntry = CreateNewLogEntryFromEncrPath(entry.EncrFileName);
                    if (logEntry?.ToString() == fileSystemEntry?.ToString())
                    {
                        return(SyncResults.Success()); //Unchanged
                    }
                    //todo: test to see if there are illegal characters
                    //todo: check if the name matches

                    string encrPath = HelixUtil.JoinNative(EncrDirectory.FullName, fileSystemEntry.EncrFileName);
                    string decrPath = HelixUtil.JoinNative(DecrDirectory.FullName, fileSystemEntry.DecrFileName);

                    //todo: if file exists with different case - skip file
                    var     exactPath = HelixUtil.GetExactPathName(decrPath);
                    FSEntry decrEntry = DecrDirectory.TryGetEntry(fileSystemEntry.DecrFileName);

                    if (decrEntry != null && decrEntry.RelativePath != fileSystemEntry.DecrFileName)
                    {
                        //todo: throw more specific exception
                        return(SyncResults.Failure(new HelixException($"Case only conflict file \"{decrPath}\" exists as \"{exactPath}\".")));
                    }

                    if (WhatIf)
                    {
                        if (entry.EncrHeader.EntryType == FileEntryType.File)
                        {
                            DecrDirectory.WhatIfReplaceFile(decrPath, entry.EncrHeader.Length, entry.EncrHeader.LastWriteTimeUtc);
                        }
                        else if (entry.EncrHeader.EntryType == FileEntryType.Removed)
                        {
                            DecrDirectory.WhatIfDeleteFile(decrPath);
                        }
                        else if (entry.EncrHeader.EntryType == FileEntryType.Directory)
                        {
                            DecrDirectory.WhatIfAddDirectory(decrPath);
                        }
                        else
                        {
                            throw new NotSupportedException();
                        }
                    }
                    else
                    {
                        HelixFile.Decrypt(encrPath, decrPath, DerivedBytesProvider);
                        //todo: get the date on the file system (needed if the filesystem has less precision
                        DecrDirectory.RefreshEntry(decrPath);
                    }

                    SyncLog.Add(fileSystemEntry);

                    return(SyncResults.Success());
                }
            }
            else if (entry.SyncMode == PreSyncMode.Match)
            {
                //Add to Log file (changed to be equal on both sides)
                SyncLogEntry fileSystemEntry = CreateNewLogEntryFromDecrPath(entry.DecrFileName);
                SyncLog.Add(fileSystemEntry);
                return(SyncResults.Success());
            }
            else if (entry.SyncMode == PreSyncMode.Unchanged)
            {
                //do nothing
                return(SyncResults.Success());
            }

            return(SyncResults.Failure(new HelixException($"Invalid sync mode {entry.SyncMode}")));
        }
Example #9
0
 public void ClearCache()
 {
     EncrDirectory.Reset();
     SyncLog.Reload();
     DecrDirectory.Reset();
 }
Example #10
0
 public void Cleanup(ConsoleEx consoleEx)
 {
     EncrDirectory.Cleanup(consoleEx);
     DecrDirectory.Cleanup(consoleEx);
 }