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); }
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)); }
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); }
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)); }
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"); } }
/// <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()); }
public bool InitializeFullNeeded() { return(!EncrDirectory.ChildExists(HelixConsts.HeaderFileName)); }
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}"))); }
public void ClearCache() { EncrDirectory.Reset(); SyncLog.Reload(); DecrDirectory.Reset(); }
public void Cleanup(ConsoleEx consoleEx) { EncrDirectory.Cleanup(consoleEx); DecrDirectory.Cleanup(consoleEx); }