/// <summary>
 /// Enumerate all files listed as active, checking for status changes and take appropriate actions such as updating status
 /// in the FileSystemState, re-encrypting or deleting temporary plaintext copies.
 /// </summary>
 /// <param name="fileSystemState">The FileSystemState to enumerate and possibly update.</param>
 /// <param name="mode">Under what circumstances is the FileSystemState.Changed event raised.</param>
 /// <param name="progress">The ProgressContext to provide visual progress feedback via.</param>
 public static void CheckActiveFiles(this FileSystemState fileSystemState, ChangedEventMode mode, ProgressContext progress)
 {
     progress.NotifyLevelStart();
     progress.AddTotal(fileSystemState.ActiveFileCount);
     fileSystemState.ForEach(mode, (ActiveFile activeFile) =>
     {
         try
         {
             if (FileLock.IsLocked(activeFile.DecryptedFileInfo, activeFile.EncryptedFileInfo))
             {
                 return activeFile;
             }
             if (OS.Current.UtcNow - activeFile.LastActivityTimeUtc <= new TimeSpan(0, 0, 5))
             {
                 return activeFile;
             }
             activeFile = fileSystemState.CheckActiveFileActions(activeFile, progress);
             return activeFile;
         }
         finally
         {
             progress.AddCount(1);
         }
     });
     progress.NotifyLevelFinished();
 }
        public static void TestAddCountAfterFinished()
        {
            ProgressContext progress = new ProgressContext();
            progress.NotifyLevelStart();
            progress.NotifyLevelFinished();

            Assert.Throws<InvalidOperationException>(() => { progress.AddCount(1); });
        }
        private bool DecryptFileOperation()
        {
            _progress.NotifyLevelStart();
            try
            {
                AxCryptFile.Decrypt(_eventArgs.AxCryptDocument, OS.Current.FileInfo(_eventArgs.SaveFileFullName), AxCryptOptions.SetFileTimes, _progress);
            }
            finally
            {
                _eventArgs.AxCryptDocument.Dispose();
                _eventArgs.AxCryptDocument = null;
            }
            AxCryptFile.Wipe(OS.Current.FileInfo(_eventArgs.OpenFileFullName), _progress);
            _progress.NotifyLevelFinished();

            _eventArgs.Status = FileOperationStatus.Success;
            return(true);
        }
        public static void TestProgressWithSynchronizationContext()
        {
            SynchronizationContext synchronizationContext = new SynchronizationContext();
            StateForSynchronizationContext s = new StateForSynchronizationContext();
            s.WaitEvent = new ManualResetEvent(false);
            s.SynchronizationContext = synchronizationContext;
            synchronizationContext.Post(
                (object state) =>
                {
                    StateForSynchronizationContext ss = (StateForSynchronizationContext)state;
                    SynchronizationContext.SetSynchronizationContext(ss.SynchronizationContext);
                    ss.SynchronizationContext = SynchronizationContext.Current;

                    ProgressContext progress = new ProgressContext();
                    progress.NotifyLevelStart();
                    progress.Progressing += (object sender, ProgressEventArgs e) =>
                    {
                        ss.DidProgress = true;
                    };
                    progress.NotifyLevelFinished();
                    ss.WaitEvent.Set();
                }, s);
            bool waitOk = s.WaitEvent.WaitOne(TimeSpan.FromSeconds(10), false);
            Assert.That(waitOk, "The wait should not time-out");
            Assert.That(s.SynchronizationContext, Is.EqualTo(synchronizationContext), "The SynchronizationContext should be current in the code executed.");
            Assert.That(s.DidProgress, "There should always be one Progressing event after NotifyFinished().");
        }
 public static void TestProgressWithoutSynchronizationContext()
 {
     bool didProgress = false;
     SynchronizationContext currentContext = new SynchronizationContext();
     Thread thread = new Thread(
         (object state) =>
         {
             currentContext = SynchronizationContext.Current;
             ProgressContext progress = new ProgressContext();
             progress.NotifyLevelStart();
             progress.Progressing += (object sender, ProgressEventArgs e) =>
                 {
                     didProgress = true;
                 };
             progress.NotifyLevelFinished();
         }
         );
     thread.Start();
     thread.Join();
     Assert.That(didProgress, "There should always be one Progressing event after NotifyFinished().");
     Assert.That(currentContext, Is.Null, "There should be no SynchronizationContext here.");
 }
        public static void TestProgressTo100AndAboveShouldOnlyReturn99BeforeFinishedPercent()
        {
            FakeRuntimeEnvironment fakeEnvironment = (FakeRuntimeEnvironment)OS.Current;
            fakeEnvironment.CurrentTiming.CurrentTiming = TimeSpan.FromMilliseconds(1000);

            ProgressContext progress = new ProgressContext(TimeSpan.FromMilliseconds(1000));
            progress.NotifyLevelStart();
            int percent = 0;
            progress.Progressing += (object sender, ProgressEventArgs e) =>
                {
                    percent = e.Percent;
                };
            progress.AddTotal(2);
            Assert.That(percent, Is.EqualTo(0), "No progress yet - should be zero.");
            progress.AddCount(1);
            Assert.That(percent, Is.EqualTo(50), "Halfway should be 50 percent.");
            fakeEnvironment.CurrentTiming.CurrentTiming = TimeSpan.FromMilliseconds(2000);
            progress.AddCount(1);
            Assert.That(percent, Is.EqualTo(99), "Even at 100 should report 99 percent.");
            fakeEnvironment.CurrentTiming.CurrentTiming = TimeSpan.FromMilliseconds(3000);
            progress.AddCount(1000);
            Assert.That(percent, Is.EqualTo(99), "Even at very much above 100 should report 99 percent.");
            progress.NotifyLevelFinished();
            Assert.That(percent, Is.EqualTo(100), "Only when NotifyFinished() is called should 100 percent be reported.");
        }
        public static void TestDoubleNotifyFinished()
        {
            ProgressContext progress = new ProgressContext();
            progress.NotifyLevelStart();
            progress.NotifyLevelStart();
            progress.NotifyLevelFinished();

            Assert.DoesNotThrow(() => { progress.NotifyLevelFinished(); });
        }
 public static void TestCurrentAndMax()
 {
     ProgressContext progress = new ProgressContext();
     progress.NotifyLevelStart();
     int percent = -1;
     progress.Progressing += (object sender, ProgressEventArgs e) =>
     {
         percent = e.Percent;
     };
     progress.AddTotal(99);
     progress.NotifyLevelFinished();
     Assert.That(percent, Is.EqualTo(100), "After Finished(), Percent should always be 100.");
 }
        public static void TestWipeWithConfirmAll()
        {
            ProgressContext progress = new ProgressContext();
            FileOperationsController controller = new FileOperationsController(_fileSystemState, progress);
            int confirmationCount = 0;
            controller.WipeQueryConfirmation += (object sender, FileOperationEventArgs e) =>
            {
                if (confirmationCount++ > 0)
                {
                    throw new InvalidOperationException("The event should not be raised a second time.");
                }
                e.ConfirmAll = true;
            };
            progress.NotifyLevelStart();
            FileOperationStatus status = controller.WipeFile(_helloWorldAxxPath);
            Assert.That(status, Is.EqualTo(FileOperationStatus.Success), "The wipe should indicate success.");

            IRuntimeFileInfo fileInfo = OS.Current.FileInfo(_helloWorldAxxPath);
            Assert.That(!fileInfo.Exists, "The file should not exist after wiping.");

            Assert.DoesNotThrow(() => { status = controller.WipeFile(_davidCopperfieldTxtPath); });
            Assert.That(status, Is.EqualTo(FileOperationStatus.Success), "The wipe should indicate success.");
            progress.NotifyLevelFinished();

            fileInfo = OS.Current.FileInfo(_davidCopperfieldTxtPath);
            Assert.That(!fileInfo.Exists, "The file should not exist after wiping.");
        }
Example #10
0
        public static void Wipe(IRuntimeFileInfo fileInfo, ProgressContext progress)
        {
            if (fileInfo == null)
            {
                throw new ArgumentNullException("fileInfo");
            }
            if (!fileInfo.Exists)
            {
                return;
            }
            if (OS.Log.IsInfoEnabled)
            {
                OS.Log.LogInfo("Wiping '{0}'.".InvariantFormat(fileInfo.Name));
            }
            bool cancelPending = false;
            progress.NotifyLevelStart();
            using (Stream stream = fileInfo.OpenWrite())
            {
                long length = stream.Length + OS.Current.StreamBufferSize - stream.Length % OS.Current.StreamBufferSize;
                progress.AddTotal(length);
                for (long position = 0; position < length; position += OS.Current.StreamBufferSize)
                {
                    byte[] random = OS.Current.GetRandomBytes(OS.Current.StreamBufferSize);
                    stream.Write(random, 0, random.Length);
                    stream.Flush();
                    try
                    {
                        progress.AddCount(random.Length);
                    }
                    catch (OperationCanceledException)
                    {
                        cancelPending = true;
                        progress.Cancel = false;
                        progress.AddCount(random.Length);
                    }
                }
            }
            string randomName;
            do
            {
                randomName = GenerateRandomFileName(fileInfo.FullName);
            } while (OS.Current.FileInfo(randomName).Exists);

            IRuntimeFileInfo moveToFileInfo = OS.Current.FileInfo(fileInfo.FullName);
            moveToFileInfo.MoveTo(randomName);
            moveToFileInfo.Delete();
            progress.NotifyLevelFinished();
            if (cancelPending)
            {
                progress.Cancel = true;
                throw new OperationCanceledException("Delayed cancel during wipe.");
            }
        }
Example #11
0
        private static long CopyToWithCount(Stream inputStream, Stream outputStream, Stream realInputStream, ProgressContext progress)
        {
            progress.NotifyLevelStart();
            if (realInputStream.CanSeek)
            {
                progress.AddTotal(realInputStream.Length - realInputStream.Position);
            }

            long totalCount = 0;
            byte[] buffer = new byte[OS.Current.StreamBufferSize];
            int offset = 0;
            int length = buffer.Length;
            while (true)
            {
                int count = inputStream.Read(buffer, offset, length);
                offset += count;
                length -= count;
                if (length > 0 && count > 0)
                {
                    continue;
                }
                if (offset == 0)
                {
                    break;
                }
                outputStream.Write(buffer, 0, offset);
                outputStream.Flush();
                progress.AddCount(offset);
                totalCount += offset;
                offset = 0;
                length = buffer.Length;
            }
            progress.NotifyLevelFinished();
            return totalCount;
        }
Example #12
0
 /// <summary>
 /// Instantiates a worker group with specified maximum concurrency and external progress reporting. Progress
 /// will be reported on the thread instantiating the ProgressContext used.
 /// </summary>
 /// <param name="maxConcurrent">The maximum number of worker threads active at any one time</param>
 /// <param name="progress">The ProgressContext that receives progress notifications</param>
 public WorkerGroup(int maxConcurrent, ProgressContext progress)
 {
     _concurrencyControlSemaphore = new Semaphore(maxConcurrent, maxConcurrent);
     _maxConcurrencyCount = maxConcurrent;
     FirstError = FileOperationStatus.Success;
     progress.NotifyLevelStart();
     Progress = progress;
 }
 public static void CheckWatchedFolders(this FileSystemState fileSystemState, ProgressContext progress)
 {
     if (fileSystemState == null)
     {
         throw new ArgumentNullException("fileSystemState");
     }
     AesKey encryptionKey = fileSystemState.KnownKeys.DefaultEncryptionKey;
     if (encryptionKey == null)
     {
         return;
     }
     IEnumerable<IRuntimeFileInfo> files = fileSystemState.DecryptedFilesInWatchedFolders();
     progress.NotifyLevelStart();
     try
     {
         progress.AddTotal(files.Count());
         foreach (IRuntimeFileInfo fileInfo in files)
         {
             IRuntimeFileInfo destinationFileInfo = fileInfo.CreateEncryptedName();
             AxCryptFile.EncryptFileWithBackupAndWipe(fileInfo, destinationFileInfo, encryptionKey, progress);
             progress.AddCount(1);
         }
     }
     finally
     {
         progress.NotifyLevelFinished();
     }
 }
 public static void RemoveRecentFiles(this FileSystemState fileSystemState, IEnumerable<string> encryptedPaths, ProgressContext progress)
 {
     progress.NotifyLevelStart();
     progress.AddTotal(encryptedPaths.Count());
     foreach (string encryptedPath in encryptedPaths)
     {
         ActiveFile activeFile = fileSystemState.FindEncryptedPath(encryptedPath);
         if (activeFile != null)
         {
             fileSystemState.Remove(activeFile);
         }
         progress.AddCount(1);
     }
     fileSystemState.Save();
     progress.NotifyLevelFinished();
 }
 /// <summary>
 /// Try do delete files that have been decrypted temporarily, if the conditions are met for such a deletion,
 /// i.e. it is apparently not locked or in use etc.
 /// </summary>
 /// <param name="fileSystemState">The instance of FileSystemState where active files are recorded.</param>
 /// <param name="progress">The context where progress may be reported.</param>
 public static void PurgeActiveFiles(this FileSystemState fileSystemState, ProgressContext progress)
 {
     progress.NotifyLevelStart();
     fileSystemState.ForEach(ChangedEventMode.RaiseOnlyOnModified, (ActiveFile activeFile) =>
     {
         if (FileLock.IsLocked(activeFile.DecryptedFileInfo))
         {
             if (OS.Log.IsInfoEnabled)
             {
                 OS.Log.LogInfo("Not deleting '{0}' because it is marked as locked.".InvariantFormat(activeFile.DecryptedFileInfo.FullName));
             }
             return activeFile;
         }
         if (activeFile.IsModified)
         {
             if (activeFile.Status.HasMask(ActiveFileStatus.NotShareable))
             {
                 activeFile = new ActiveFile(activeFile, activeFile.Status & ~ActiveFileStatus.NotShareable);
             }
             activeFile = CheckIfTimeToUpdate(activeFile, progress);
         }
         if (activeFile.Status.HasMask(ActiveFileStatus.AssumedOpenAndDecrypted))
         {
             activeFile = TryDelete(activeFile, progress);
         }
         return activeFile;
     });
     progress.NotifyLevelFinished();
 }
 public static void TestCancel()
 {
     ProgressContext progress = new ProgressContext();
     progress.NotifyLevelStart();
     progress.AddTotal(100);
     progress.AddCount(10);
     progress.Cancel = true;
     Assert.Throws<OperationCanceledException>(() => { progress.NotifyLevelStart(); });
     Assert.Throws<OperationCanceledException>(() => { progress.NotifyLevelFinished(); });
     Assert.Throws<OperationCanceledException>(() => { progress.AddTotal(50); });
     Assert.Throws<OperationCanceledException>(() => { progress.AddCount(10); });
 }
Example #17
0
 public static void EncryptFileWithBackupAndWipe(IRuntimeFileInfo sourceFileInfo, IRuntimeFileInfo destinationFileInfo, AesKey key, ProgressContext progress)
 {
     if (sourceFileInfo == null)
     {
         throw new ArgumentNullException("sourceFileInfo");
     }
     if (destinationFileInfo == null)
     {
         throw new ArgumentNullException("destinationFileInfo");
     }
     if (key == null)
     {
         throw new ArgumentNullException("key");
     }
     if (progress == null)
     {
         throw new ArgumentNullException("progress");
     }
     progress.NotifyLevelStart();
     using (Stream activeFileStream = sourceFileInfo.OpenRead())
     {
         WriteToFileWithBackup(destinationFileInfo, (Stream destination) =>
         {
             Encrypt(sourceFileInfo, destination, key, AxCryptOptions.EncryptWithCompression, progress);
         }, progress);
     }
     Wipe(sourceFileInfo, progress);
     progress.NotifyLevelFinished();
 }