Example #1
0
        /// <summary>得到文件目录对应列表</summary>
        /// <param name="list"></param>
        /// <returns></returns>
        public static bool GetNamePathList(out List <NamePath> list)
        {
            List <DriveInfo> listVolume = GetNTFSDrives();

            list = new List <NamePath>();
            try
            {
                foreach (DriveInfo di in listVolume)
                {
                    var usnJournal = new NtfsUsnJournal(di);
                    List <WINAPI.UsnEntry> listFile; //本卷的全部Usn信息表
                    var rtnCode = usnJournal.GetNtfsVolumeFiles(out listFile);
                    var dicPath = usnJournal.GetFilePaths(listFile);

                    list.AddRange(from entry in listFile
                                  where dicPath.ContainsKey(entry.FileReferenceNumber)
                                  select new NamePath(entry.Name, dicPath[entry.FileReferenceNumber]));
                }
            }
            catch (Exception ex)
            {
                string strErr = ex.Message.Contains("Access is denied")
                    ? @"请使用管理员权限重新打开本程序!"
                    : @"未能成功打开磁盘!";
                LogHelper.WriteErrLog(strErr, ex);
                return(false);
            }
            return(true);
        }
Example #2
0
        public void ChangeDisplay(double top, double left, Win32Api.UsnEntry usnEntry, UsnEntryDetail.EntryDetail entryDetail)
        {
            Top  = top;
            Left = left;

            MainWindow     mainWin    = (MainWindow)Application.Current.MainWindow;
            NtfsUsnJournal usnJournal = mainWin.Journal;
            StringBuilder  sb         = new StringBuilder();

            if (usnEntry.IsFolder)
            {
                sb.AppendFormat("Directory: {0}", usnEntry.Name);
            }
            else if (usnEntry.IsFile)
            {
                sb.AppendFormat("File: {0}", usnEntry.Name);
            }
            _nameLbl.Content = sb.ToString();
            sb = new StringBuilder();
            string path;

            NtfsUsnJournal.UsnJournalReturnCode usnRtnCode = usnJournal.GetPathFromFileReference(usnEntry.ParentFileReferenceNumber, out path);
            if (usnRtnCode == NtfsUsnJournal.UsnJournalReturnCode.USN_JOURNAL_SUCCESS && 0 != string.Compare(path, "Unavailable", true))
            {
                sb.AppendFormat("  Path:    {0}{1}\\", usnJournal.VolumeName.TrimEnd('\\'), path);
            }
            else
            {
                sb.AppendFormat("  Path:    {0}", path);
            }
            _pathLbl.Content = sb.ToString();
            sb = new StringBuilder();
            sb.AppendFormat("  File Ref No: {0}", usnEntry.FileReferenceNumber);
            sb.AppendFormat("\n  Parent FRN   {0}", usnEntry.ParentFileReferenceNumber);

            if (entryDetail == EntryDetail.UsnEntry)
            {
                sb.AppendFormat("\n  Length:  {0}", usnEntry.RecordLength);
                sb.AppendFormat("\n  USN:     {0}", usnEntry.USN);
                AddReasonData(sb, usnEntry);
            }
            if (usnEntry.IsFile)
            {
                string fullPath = System.IO.Path.Combine(path, usnEntry.Name);
                if (File.Exists(fullPath))
                {
                    FileInfo fi = new FileInfo(fullPath);
                    sb.AppendFormat("\n  File Length:   {0} (bytes)", fi.Length);
                    sb.AppendFormat("\n  Creation Time: {0} - {1}", fi.CreationTime.ToShortDateString(), fi.CreationTime.ToShortTimeString());
                    sb.AppendFormat("\n  Last Modify:   {0} - {1}", fi.LastWriteTime.ToShortDateString(), fi.LastWriteTime.ToShortTimeString());
                    sb.AppendFormat("\n  Last Access:   {0} - {1}", fi.LastAccessTime.ToShortDateString(), fi.LastAccessTime.ToShortTimeString());
                }
            }
            _entryDetailLbl.Content = sb.ToString();
            Visibility = Visibility.Visible;
        }
Example #3
0
 public void SignalBackup()          // to be called when full is performed
 //Console.WriteLine ("brd snapshot type="+brd.Snapshot.);
 {
     using (usnJ = new NtfsUsnJournal(brd /*.Snapshot.MountPoint*/)){
         Win32Api.USN_JOURNAL_DATA journal = new Win32Api.USN_JOURNAL_DATA();
         usnJ.GetUsnJournalState(ref journal);
         Logger.Append(Severity.DEBUG, "Current USN journal for '" + brd.Snapshot.MountPoint + "' " + journal.UsnJournalID + ", USN no: " + journal.NextUsn + ", maxSize=" + journal.MaximumSize / 1024 + "k, FirstEntry=" + journal.FirstUsn);
         journalId     = (ulong)journal.UsnJournalID;
         transactionId = journal.NextUsn;
         journalMinUsn = journal.FirstUsn;
     }
 }
Example #4
0
        public void Position(string Path)
        {
            NtfsUsnJournal journal = new NtfsUsnJournal(Path);

            Win32Api.USN_JOURNAL_DATA journalData = new Win32Api.USN_JOURNAL_DATA();
            var usnJournalReturnCode = journal.GetUsnJournalState(ref journalData);

            if (usnJournalReturnCode == NtfsUsnJournal.UsnJournalReturnCode.USN_JOURNAL_SUCCESS)
            {
                Console.WriteLine("Next USN: " + journalData.NextUsn);
            }
        }
        private void SelectVolume_Click(object sender, RoutedEventArgs e)
        {
            _usnEntryDetail.Visibility = Visibility.Hidden;
            resultsLb.ItemsSource      = null;
            resultsLb.Items.Clear();

            VolumeSelectDialog selectVolumeDlg = new VolumeSelectDialog(this);

            bool?rtn = selectVolumeDlg.ShowDialog();

            if (rtn != null && rtn.Value)
            {
                DriveInfo volume = selectVolumeDlg.Volume;
                try
                {
                    _usnJournal = new NtfsUsnJournal(volume);
                    FunctionElapsedTime.Content = string.Format("{0} elapsed time {1}(ms) - Volume: {2}",
                                                                "NtfsUsnJournal() constructor", NtfsUsnJournal.ElapsedTime.Milliseconds.ToString(), volume.Name);
                    QueryUsnJournal.IsEnabled  = true;
                    CreateUsnJournal.IsEnabled = true;
                    DeleteUsnJournal.IsEnabled = true;
                    SaveUsnState.IsEnabled     = true;
                    ViewUsnChanges.IsEnabled   = true;
                    ListFiles.IsEnabled        = true;
                    ListFolders.IsEnabled      = true;
                }
                catch (Exception excptn)
                {
                    if (excptn.Message.Contains("Access is denied"))
                    {
                        ListBoxItem lbItem = new ListBoxItem();
                        lbItem.Content    = string.Format("'Access Denied' exception caught attempting to select volume.  \nYou need 'Admin' rights to run this application.");
                        lbItem.Foreground = Brushes.Red;
                        resultsLb.Items.Add(lbItem);
                    }
                    else
                    {
                        ListBoxItem lbItem = new ListBoxItem();
                        lbItem.Content    = string.Format("{0} exception caught attempting to select volume. \n{1}", excptn.GetType().ToString(), excptn.Message);
                        lbItem.Foreground = Brushes.Red;
                        resultsLb.Items.Add(lbItem);
                    }
                }
            }
            else
            {
                ListBoxItem lbItem = new ListBoxItem();
                lbItem.Content    = string.Format("Select Volume -- No Volume Selected");
                lbItem.Foreground = Brushes.Red;
                resultsLb.Items.Add(lbItem);
            }
        }
        /// <summary>
        /// Scans the NTFS Master File Table entries for a matching file.
        /// </summary>
        /// <param name="drive">The partition to scan.</param>
        /// <param name="paths">The paths to which the search should be limited.</param>
        private void ScanNtfsMftForFile(DriveInfo drive, IEnumerable <string> paths = null)
        {
            FileSearchProgressChanged.Fire(this, "Reading the MFT records of the " + drive.Name[0] + " partition...");

            IEnumerable <string> list;

            Log.Debug("Reading the MFT records of the " + drive.Name[0] + " partition...");

            try
            {
                _cts.Token.ThrowIfCancellationRequested();
                var usn = new NtfsUsnJournal(drive);

                _cts.Token.ThrowIfCancellationRequested();
                list = usn.GetParsedPaths(ShowNames.Regexes.KnownVideo, paths);

                _cts.Token.ThrowIfCancellationRequested();
            }
            catch (OperationCanceledException)
            {
                throw;
            }
            catch (Exception ex)
            {
                Log.Error("Error while reading the MFT records of the " + drive.Name[0] + " partition.", ex);
                return;
            }

            FileSearchProgressChanged.Fire(this, "Searching for matching files in the " + drive.Name[0] + " partition...");

            foreach (var file in list)
            {
                _cts.Token.ThrowIfCancellationRequested();

                try
                {
                    if (_checkFile(file))
                    {
                        _files.Add(file);
                    }
                }
                catch (PathTooLongException)        { }
                catch (SecurityException)           { }
                catch (UnauthorizedAccessException) { }
                catch (DirectoryNotFoundException)  { }
                catch (Exception ex)
                {
                    Log.Error("Error while checking file.", ex);
                }
            }
        }
Example #7
0
        public void ChangeDisplay(NtfsUsnJournal usnJournal, double top, double left, Win32Api.UsnEntry usnEntry, EntryDetail entryDetail)
        {
            Top  = top;
            Left = left;

            _nameLbl.Text = string.Format(CultureInfo.InvariantCulture, usnEntry.IsFolder ? "Directory: {0}" : "File: {0}", usnEntry.Name);

            string path;

            var lastError = usnJournal.GetPathFromFileReference(usnEntry.ParentFileReferenceNumber, out path);

            if (lastError == (int)NtfsUsnJournal.UsnJournalReturnCode.USN_JOURNAL_SUCCESS && null != path)
            {
                path = string.Format(CultureInfo.InvariantCulture, "{0}{1}\\", usnJournal.VolumeName.TrimEnd('\\'), path);
            }

            _pathLbl.Text = path;


            var sb = new StringBuilder();

            sb.AppendFormat("  File Ref No: {0}", usnEntry.FileReferenceNumber);
            sb.AppendFormat("\n  Parent FRN   {0}", usnEntry.ParentFileReferenceNumber);

            if (entryDetail == EntryDetail.UsnEntry)
            {
                sb.AppendFormat("\n  Length:  {0}", usnEntry.RecordLength);
                sb.AppendFormat("\n  USN:     {0}", usnEntry.USN);
                AddReasonData(sb, usnEntry);
            }

            if (!usnEntry.IsFolder)
            {
                var fullPath = Path.Combine(_pathLbl.Text, usnEntry.Name);
                if (File.Exists(fullPath))
                {
                    var fi = new FileInfo(fullPath);
                    sb.AppendFormat("\n  File Length:   {0} (bytes)", fi.Length);
                    sb.AppendFormat("\n  Creation Time: {0} - {1}", fi.CreationTime.ToShortDateString(), fi.CreationTime.ToShortTimeString());
                    sb.AppendFormat("\n  Last Modify:   {0} - {1}", fi.LastWriteTime.ToShortDateString(), fi.LastWriteTime.ToShortTimeString());
                    sb.AppendFormat("\n  Last Access:   {0} - {1}", fi.LastAccessTime.ToShortDateString(), fi.LastAccessTime.ToShortTimeString());
                }
            }

            _entryDetailLbl.Content = sb.ToString();
            Visibility = Visibility.Visible;
        }
Example #8
0
        /// <summary>
        /// Checks if we have all the required reference information (ref backup usn metadata)
        /// and if the usn journal is available (existing and usable from reference journal & transaction ids)
        /// </summary>
        /// <returns>
        /// A <see cref="System.Boolean"/>
        /// </returns>
        public bool CheckCapability()
        {
            if (Utilities.PlatForm.IsUnixClient())
            {
                return(false);
            }
            try{
                if (prevJournalId == 0 || prevTransactionId == 0 /*|| brd.SystemDrive.DriveFormat.ToLower() != "ntfs"*/)
                {
                    Logger.Append(Severity.DEBUG, "No reference USN journal found. Either this is the first backup, either SetMetadata() has not been called yet, or drive is not NTFS/ReFS");
                    return(false);
                }

                using (NtfsUsnJournal jtest = new NtfsUsnJournal(brd /*.Snapshot.MountPoint*/)){
                    Console.WriteLine("CheckCapability() : instanciated usn j");
                    if (!jtest.IsUsnJournalActive())
                    {
                        Logger.Append(Severity.INFO, "the drive " + brd.SystemDrive.OriginalMountPoint + " doesn't have an USN tracking journal."
                                      + " It can be manually created using the command 'fsutil usn createjournal m=400000 a=100 " + brd.SystemDrive.OriginalMountPoint + "'");
                    }


                    if (journalId != prevJournalId /*|| transactionId < prevTransactionId*/)                      // journal has been reset, can't rely on it
                    {
                        Logger.Append(Severity.WARNING, "Drive " + brd.SystemDrive.OriginalMountPoint + " USN Journal has been reset since last time we checked it. Can't be used :"
                                      + "transaction id " + transactionId + "/" + prevTransactionId + ", journal " + journalId + "/" + prevJournalId);

                        /*Console.WriteLine ("********************************");
                        *  Console.WriteLine ("***MAKE IT RETURN FALSE!!!      *");
                        *  Console.WriteLine ("********************************");*/
                        return(false);
                    }
                    if (prevTransactionId < journalMinUsn)                    // some space has been freeed inside the journal, we cannot read back to wanted transaction
                    {
                        Logger.Append(Severity.WARNING, "Drive " + brd.SystemDrive.MountPoint + " Wanted start USN (" + prevTransactionId + ")is too old, has been recycled by the journal (min usable USN is " + journalMinUsn + "). Unable to use USN. If this occurs frequently, consider growing the USN journal max size.");
                        return(false);
                    }
                }
                return(true);
            }
            catch (Exception e) {
                Logger.Append(Severity.WARNING, "Drive '" + brd.SystemDrive.MountPoint + " (snap " + brd.Snapshot.MountPoint + ")' : can't use UsnJournal incremental/differential provider : " + e.ToString()
                              + ". Journal may not be accessed, not available for this kind of filesystem, or doesn't exist. You can create one using 'fsutil usn createjournal' command");
                return(false);
            }
        }
Example #9
0
        public static Win32Api.USN_JOURNAL_DATA GetCurrentUSNJournalData(string DriveLetter)
        {
            NtfsUsnJournal journal = new NtfsUsnJournal(DriveLetter);

            Win32Api.USN_JOURNAL_DATA journalState = new Win32Api.USN_JOURNAL_DATA();

            NtfsUsnJournal.UsnJournalReturnCode rtn = journal.GetUsnJournalState(ref journalState);

            if (rtn == NtfsUsnJournal.UsnJournalReturnCode.USN_JOURNAL_SUCCESS)
            {
                return(journalState);
            }
            else
            {
                throw new UsnJournalException(rtn);
            }
        }
Example #10
0
        public static Win32Api.USN_JOURNAL_DATA GetCurrentUSNJournalData(string DriveLetter)
        {
            NtfsUsnJournal journal = new NtfsUsnJournal(DriveLetter);

            Win32Api.USN_JOURNAL_DATA journalState = new Win32Api.USN_JOURNAL_DATA();

            NtfsUsnJournal.UsnJournalReturnCode rtn = journal.GetUsnJournalState(ref journalState);

            if (rtn == NtfsUsnJournal.UsnJournalReturnCode.USN_JOURNAL_SUCCESS)
            {

                return journalState;
            }
            else
            {
                throw new UsnJournalException(rtn);
            }
        }
        private static string GetActualPath(NtfsUsnJournal journal, Win32Api.UsnEntry item)
        {
            string actualPath = null;

            string rawPath;
            var    usnRtnCode = journal.GetPathFromFileReference(item.ParentFileReferenceNumber, out rawPath);

            if (usnRtnCode == NtfsUsnJournal.UsnJournalReturnCode.USN_JOURNAL_SUCCESS && 0 != String.Compare(rawPath, "Unavailable", StringComparison.OrdinalIgnoreCase))
            {
                actualPath = $"{journal.MountPoint.TrimEnd('\\')}{rawPath.TrimEnd('\\')}\\{item.Name}";
            }
            else
            {
                return(actualPath);
            }
            if (actualPath.ToLowerInvariant().StartsWith($"{journal.MountPoint.TrimEnd('\\')}\\System Volume Information".ToLowerInvariant()))
            {
                return(actualPath);
            }
            return(actualPath);
        }
Example #12
0
        private void btnSelectVolume_Click(object sender, EventArgs e)
        {
            lbResults.DataSource = null;
            lbResults.Items.Clear();

            FrmVolumeSelect frmVolumeSelect = new FrmVolumeSelect();

            frmVolumeSelect.ShowDialog();
            if (frmVolumeSelect.DialogResult == System.Windows.Forms.DialogResult.OK)
            {
                try
                {
                    _usnJournal = new NtfsUsnJournal(frmVolumeSelect.SelectedDriveInfo);
                }
                catch (Exception ex)
                {
                    lblSelectedVolume.Visible = true;
                    lblElapsedTime.Visible    = false;
                    lblSelectedVolume.Text    = ex.Message.Contains("Access is denied")
                        ? @"请使用管理员权限重新打开本程序!"
                        : @"未能成功打开磁盘!";
                    return;
                }

                lblSelectedVolume.Visible = true;
                lblElapsedTime.Visible    = true;
                lblSelectedVolume.Text    = string.Format("当前索引磁盘:{0}盘", frmVolumeSelect.SelectedDriveInfo.Name);
                lblElapsedTime.Text       = string.Format("执行用时:{0}ms", NtfsUsnJournal.ElapsedTime.Milliseconds.ToString());

                btnQueryUsnJournal.Enabled  = true;
                btnFindFiles.Enabled        = true;
                btnSearchAllFolders.Enabled = true;
            }
            else
            {
                lblSelectedVolume.Visible = true;
                lblSelectedVolume.Text    = @"未能打开任何磁盘。";
            }
        }
Example #13
0
 public void GetUSNDetails(string Mountpoint)
 {
     using (var journal = new NtfsUsnJournal(Mountpoint))
     {
         Win32Api.USN_JOURNAL_DATA data = new Win32Api.USN_JOURNAL_DATA();
         var usnJournalReturnCode       = journal.GetUsnJournalState(ref data);
         if (usnJournalReturnCode == NtfsUsnJournal.UsnJournalReturnCode.USN_JOURNAL_SUCCESS)
         {
             Console.WriteLine("Journal ID: " + data.UsnJournalID);
             Console.WriteLine("Allocation Delta: " + data.AllocationDelta);
             Console.WriteLine("First USN: " + data.FirstUsn);
             Console.WriteLine("Lowest Valid USN: " + data.LowestValidUsn);
             Console.WriteLine("Max USN: " + data.MaxUsn);
             Console.WriteLine("Maximum Size: " + data.MaximumSize);
             Console.WriteLine("Next Usn: " + data.NextUsn);
         }
         else
         {
             Console.WriteLine("ERROR: " + usnJournalReturnCode.ToString());
         }
     }
 }
        public void Execute(IJobExecutionContext context)
        {
            if (Singleton.Instance.SourceMountpoints == null || Singleton.Instance.SourceMountpoints.Count == 0)
            {
                return;
            }

            try
            {
                foreach (var sourceMount in Singleton.Instance.SourceMountpoints)
                {
                    var construct = new DriveConstruct(sourceMount.MountPoint);
                    Win32Api.USN_JOURNAL_DATA newUsnState;
                    List <Win32Api.UsnEntry>  usnEntries;
                    NtfsUsnJournal            journal = new NtfsUsnJournal(construct.DriveLetter);

                    var drivePath = Path.Get(construct.DriveLetter);

                    logger.Trace("Polling for changes from " + sourceMount.CurrentUSNLocation);

                    var rtn = journal.GetUsnJournalEntries(construct.CurrentJournalData, reasonMask, out usnEntries, out newUsnState, OverrideLastUsn: sourceMount.CurrentUSNLocation);

                    if (rtn == NtfsUsnJournal.UsnJournalReturnCode.USN_JOURNAL_SUCCESS)
                    {
                        List <RawUSNEntry> entries = new List <RawUSNEntry>();
                        if (usnEntries.Any())
                        {
                            logger.Debug("USN returned with " + usnEntries.Count + " entries");
                            logger.Trace($"fsutil usn readjournal {construct.Volume} startusn={sourceMount.CurrentUSNLocation}");
                        }

                        List <USNChangeRange> changeRange = new List <USNChangeRange>();

                        foreach (var frn in usnEntries.Select(e => e.FileReferenceNumber).Distinct())
                        {
                            var entriesForFile = usnEntries.Where(f => f.FileReferenceNumber == frn).ToList();

                            if (entriesForFile.All(e => e.SourceInfo == Win32Api.UsnEntry.USNJournalSourceInfo.DataManagement || e.SourceInfo == Win32Api.UsnEntry.USNJournalSourceInfo.ReplicationManagement))
                            {
                                continue;
                            }

                            var actualPath = GetActualPath(journal, entriesForFile.FirstOrDefault());

                            if (actualPath == "Unavailable" || String.IsNullOrWhiteSpace(actualPath))
                            {
                                continue;
                            }

                            if (sourceMount.IgnoreList != null && sourceMount.IgnoreList.Any() && sourceMount.IgnoreList.Any(ignore => new Regex(ignore).IsMatch(actualPath)))
                            {
                                continue;
                            }

                            USNChangeRange range = new USNChangeRange
                            {
                                FRN        = frn,
                                Min        = entriesForFile.Min(e => e.TimeStamp),
                                Max        = entriesForFile.Max(e => e.TimeStamp),
                                Closed     = entriesForFile.OrderBy(f => f.TimeStamp).LastOrDefault() != null ? (entriesForFile.OrderBy(f => f.TimeStamp).LastOrDefault().Reason & Win32Api.USN_REASON_CLOSE) != 0 : false,
                                RenameFrom = entriesForFile.FirstOrDefault(e => (e.Reason & Win32Api.USN_REASON_RENAME_OLD_NAME) != 0),
                                Entry      = entriesForFile.OrderBy(f => f.TimeStamp).LastOrDefault()
                            };

                            bool alreadyCopiedItem = entriesForFile.GroupBy(r => r.ParentFileReferenceNumber).Select(r => r.First()).Distinct().Any(pfrn => GetActualPath(journal, pfrn).Contains("\\.proximaTemp\\"));

                            if (alreadyCopiedItem || ShouldIgnore(actualPath, drivePath, range, journal))
                            {
                                continue;
                            }

                            changeRange.Add(range);
                        }


                        foreach (var item in changeRange)
                        {
                            var actualPath = GetActualPath(journal, item.Entry);

                            if (actualPath == "Unavailable")
                            {
                                continue;
                            }

                            string relativePath;
                            try
                            {
                                Uri drivePathUri  = new Uri(drivePath.FullPath, UriKind.Absolute);
                                Uri actualPathUri = new Uri(actualPath, UriKind.Absolute);

                                relativePath = Uri.UnescapeDataString(drivePathUri.MakeRelativeUri(actualPathUri).ToString());
                            }
                            catch (Exception e)
                            {
                                relativePath = "#ERROR#";
                            }

                            if (relativePath == "#ERROR#" || relativePath.StartsWith("System Volume Information"))
                            {
                                continue;
                            }


                            string renameFromRelativePath = "";
                            if (item.RenameFrom != null)
                            {
                                string renameFromPath = GetActualPath(journal, ((Win32Api.UsnEntry)item.RenameFrom));

                                try
                                {
                                    Uri drivePathUri  = new Uri(drivePath.FullPath, UriKind.Absolute);
                                    Uri actualPathUri = new Uri(actualPath, UriKind.Absolute);

                                    renameFromRelativePath = Uri.UnescapeDataString(drivePathUri.MakeRelativeUri(actualPathUri).ToString());
                                }
                                catch (Exception e)
                                {
                                    renameFromRelativePath = "";
                                }
                            }

                            if (!String.IsNullOrWhiteSpace(renameFromRelativePath) && renameFromRelativePath.StartsWith(".proximaTemp"))
                            {
                                continue;
                            }

                            var dbEntry = new RawUSNEntry();

                            PopulateFlags(dbEntry, item.Entry);

                            dbEntry.Path         = actualPath;
                            dbEntry.RelativePath = relativePath;
                            dbEntry.File         = item.Entry.IsFile;
                            dbEntry.Directory    = item.Entry.IsFolder;
                            dbEntry.FRN          = item.Entry.FileReferenceNumber;
                            dbEntry.PFRN         = item.Entry.ParentFileReferenceNumber;
                            dbEntry.RecordLength = item.Entry.RecordLength;
                            dbEntry.USN          = item.Entry.USN;
                            dbEntry.Mountpoint   = sourceMount;

                            dbEntry.TimeStamp   = item.Entry.TimeStamp.Truncate(TimeSpan.TicksPerMillisecond);
                            dbEntry.SourceInfo  = item.Entry.SourceInfo.ToString();
                            dbEntry.ChangeRange = item;

                            if (actualPath != null && actualPath != "Unavailable" && actualPath.ToLowerInvariant().StartsWith($"{journal.MountPoint.TrimEnd('\\')}\\$".ToLowerInvariant()))
                            {
                                dbEntry.SystemFile = true;
                            }


                            if (item.RenameFrom != null)
                            {
                                dbEntry.RenameFromPath = GetActualPath(journal, ((Win32Api.UsnEntry)item.RenameFrom));
                                if (!string.IsNullOrWhiteSpace(dbEntry.RenameFromPath) && dbEntry.RenameFromPath != "Unavailable")
                                {
                                    dbEntry.RenameFromRelativePath = new Regex(Regex.Escape(drivePath.FullPath), RegexOptions.IgnoreCase).Replace(dbEntry.RenameFromPath, "", 1);
                                }
                            }

                            entries.Add(dbEntry);
                        }


                        if (changeRange.Any())
                        {
                            Singleton.Instance.Repository.Add <USNChangeRange>(changeRange);
                            Singleton.Instance.Repository.Add <RawUSNEntry>(entries);

                            var performRollup = RollupService.PerformRollup(entries, sourceMount, Singleton.Instance.Repository);
                            logger.Info(string.Format("[{3}] Adding [{2}CHANGE/{1}USN/{0}File]", performRollup.Count, entries.Count, changeRange.Count, sourceMount.Id));
                            foreach (var fileAction in performRollup)
                            {
                                //  logger.Trace("ADD: " + fileAction.RelativePath + ", USN:" + fileAction.USN);
                            }
                            Singleton.Instance.Repository.Add <FileAction>(performRollup);

                            //performRollup.ForEach(f=> logger.Debug("Added " + f.Id));
                        }

                        construct.CurrentJournalData   = newUsnState;
                        sourceMount.CurrentUSNLocation = newUsnState.NextUsn;
                        sourceMount.Volume             = construct.Volume;

                        Singleton.Instance.Repository.Update(sourceMount);
                    }
                    else
                    {
                        logger.Error("Error on Monitor - " + rtn.ToString());
                        throw new UsnJournalException(rtn);
                    }
                }
            }

            catch (Exception e)
            {
                logger.Error(e, "Error in USNJournalMonitor");
            }
        }
 public UsnJournalException(NtfsUsnJournal.UsnJournalReturnCode rtn)
 {
     ReturnCode = rtn;
 }
        private bool ShouldIgnore(string actualPath, Path drivePath, USNChangeRange range, NtfsUsnJournal journal)
        {
            if (actualPath == "Unavailable")
            {
                return(true);
            }

            string relativePath;

            try
            {
                Uri drivePathUri  = new Uri(drivePath.FullPath, UriKind.Absolute);
                Uri actualPathUri = new Uri(actualPath, UriKind.Absolute);

                relativePath = Uri.UnescapeDataString(drivePathUri.MakeRelativeUri(actualPathUri).ToString());
            }
            catch (Exception e)
            {
                relativePath = "#ERROR#";
            }

            if (relativePath == "#ERROR#" || relativePath.StartsWith("System Volume Information") || relativePath.StartsWith("$RECYCLE.BIN"))
            {
                return(true);
            }

            string renameFromRelativePath = "";

            if (range.RenameFrom != null)
            {
                string renameFromPath = GetActualPath(journal, range.RenameFrom);

                try
                {
                    Uri drivePathUri  = new Uri(drivePath.FullPath, UriKind.Absolute);
                    Uri actualPathUri = new Uri(renameFromPath, UriKind.Absolute);

                    renameFromRelativePath = Uri.UnescapeDataString(drivePathUri.MakeRelativeUri(actualPathUri).ToString());
                }
                catch (Exception e)
                {
                    renameFromRelativePath = "";
                }
            }

            if (!String.IsNullOrWhiteSpace(renameFromRelativePath) && renameFromRelativePath.StartsWith(".proximaTemp"))
            {
                return(true);
            }

            return(false);
        }
        private void SelectVolume_Click(object sender, RoutedEventArgs e)
        {
            e.Handled = true;

            _usnEntryDetail.Visibility = Visibility.Hidden;
            resultsLb.ItemsSource      = null;
            resultsLb.Items.Clear();

            var selectVolumeDlg = new VolumeSelectDialog(this);

            var rtn = selectVolumeDlg.ShowDialog();

            if (null != rtn && rtn.Value)
            {
                var driveInfo = selectVolumeDlg.Volume;
                try
                {
                    Journal = new NtfsUsnJournal(driveInfo);
                    FunctionElapsedTime.Content = string.Format(CultureInfo.InvariantCulture, "{0} duration: {1} (ms) - Volume: {2}", "NtfsUsnJournal constructor", NtfsUsnJournal.ElapsedTime.TotalMilliseconds, driveInfo.Name);
                    QueryUsnJournal.IsEnabled   = true;
                    CreateUsnJournal.IsEnabled  = true;
                    DeleteUsnJournal.IsEnabled  = true;
                    SaveUsnState.IsEnabled      = true;
                    ViewUsnChanges.IsEnabled    = true;
                    ListFiles.IsEnabled         = true;
                    ListFolders.IsEnabled       = true;
                }
                catch (Exception ex)
                {
                    if (ex.Message.Contains("Access is denied"))
                    {
                        var lbItem = new ListBoxItem
                        {
                            Content    = "\'Access Denied\' exception caught attempting to select volume.  \nYou need \'Admin\' rights to run this application.",
                            Foreground = Brushes.Red
                        };

                        resultsLb.Items.Add(lbItem);
                    }

                    else
                    {
                        var lbItem = new ListBoxItem
                        {
                            Content    = string.Format(CultureInfo.InvariantCulture, "{0} exception caught attempting to select volume. \n{1}", ex.GetType(), ex.Message),
                            Foreground = Brushes.Red
                        };

                        resultsLb.Items.Add(lbItem);
                    }
                }
            }

            else
            {
                var lbItem = new ListBoxItem
                {
                    Content    = "Select Volume -- No Volume Selected",
                    Foreground = Brushes.Red
                };

                resultsLb.Items.Add(lbItem);
            }
        }
Example #18
0
        public void BeginScan()
        {
            //clear
            parentFileReferenceIdentifiers.Clear();
            USNEntries.Clear();
            USNDirectories.Clear();

            usnCurrentJournalState = new Win32Api.USN_JOURNAL_DATA();
            //1 phase; handle
            try
            {
                usnJournal = new NtfsUsnJournal(selectedVolume);
                OnEntryAmountUpdate(true);
            }
            catch (Exception)
            {
                OnEntryAmountUpdate(false);
                return;
            }

            //2 phase; current state
            Win32Api.USN_JOURNAL_DATA           journalState = new Win32Api.USN_JOURNAL_DATA();
            NtfsUsnJournal.UsnJournalReturnCode rtn          = usnJournal.GetUsnJournalState(ref journalState);
            if (rtn == NtfsUsnJournal.UsnJournalReturnCode.USN_JOURNAL_SUCCESS)
            {
                usnCurrentJournalState = journalState;
                OnEntryAmountUpdate(true);
            }
            else
            {
                OnEntryAmountUpdate(false);
                return;
            }

            //3 phase; query
            uint reasonMask = Win32Api.USN_REASON_DATA_OVERWRITE |
                              Win32Api.USN_REASON_DATA_EXTEND |
                              Win32Api.USN_REASON_NAMED_DATA_OVERWRITE |
                              Win32Api.USN_REASON_NAMED_DATA_TRUNCATION |
                              Win32Api.USN_REASON_FILE_CREATE |
                              Win32Api.USN_REASON_FILE_DELETE |
                              Win32Api.USN_REASON_EA_CHANGE |
                              Win32Api.USN_REASON_SECURITY_CHANGE |
                              Win32Api.USN_REASON_RENAME_OLD_NAME |
                              Win32Api.USN_REASON_RENAME_NEW_NAME |
                              Win32Api.USN_REASON_INDEXABLE_CHANGE |
                              Win32Api.USN_REASON_BASIC_INFO_CHANGE |
                              Win32Api.USN_REASON_HARD_LINK_CHANGE |
                              Win32Api.USN_REASON_COMPRESSION_CHANGE |
                              Win32Api.USN_REASON_ENCRYPTION_CHANGE |
                              Win32Api.USN_REASON_OBJECT_ID_CHANGE |
                              Win32Api.USN_REASON_REPARSE_POINT_CHANGE |
                              Win32Api.USN_REASON_STREAM_CHANGE |
                              Win32Api.USN_REASON_CLOSE;

            OldestUSN = usnCurrentJournalState.FirstUsn;
            NtfsUsnJournal.UsnJournalReturnCode rtnCode = usnJournal.GetUsnJournalEntries(usnCurrentJournalState, reasonMask, out List <Win32Api.UsnEntry> usnEntries, out usnCurrentJournalState);

            if (rtnCode == NtfsUsnJournal.UsnJournalReturnCode.USN_JOURNAL_SUCCESS)
            {
                OnEntryAmountUpdate(true);

                //4 phase
                ResolveIdentifiers(usnEntries);
                OnEntryAmountUpdate(true);

                //5 phase
                AddEntries(usnEntries);
                OnEntryAmountUpdate(true);

                OnWorkEnded();
            }
            else
            {
                OnEntryAmountUpdate(false);
                return;
            }
        }
Example #19
0
        /// <summary>
        /// Scans the NTFS Master File Table entries for a matching file.
        /// </summary>
        /// <param name="drive">The partition to scan.</param>
        /// <param name="paths">The paths to which the search should be limited.</param>
        private void ScanNtfsMftForFile(DriveInfo drive, IEnumerable<string> paths = null)
        {
            FileSearchProgressChanged.Fire(this, "Reading the MFT records of the " + drive.Name[0] + " partition...");

            var usn  = new NtfsUsnJournal(drive);
            var list = usn.GetParsedPaths(ShowNames.Regexes.KnownVideo, paths);

            FileSearchProgressChanged.Fire(this, "Searching for matching files in the " + drive.Name[0] + " partition...");

            foreach (var file in list)
            {
                try
                {
                    CheckFile(file);
                }
                catch (PathTooLongException)        { }
                catch (SecurityException)           { }
                catch (UnauthorizedAccessException) { }
                catch (DirectoryNotFoundException)  { }
                catch (Exception ex)
                {
                    MainWindow.HandleUnexpectedException(ex);
                }
            }
        }
Example #20
0
        private Dictionary <int, Win32Api.UsnEntry> GetUsnRecordsDictionary()
        {
            PrivilegesManager pm = new PrivilegesManager();

            pm.Grant();
            Dictionary <int, Win32Api.UsnEntry> uEntries = new Dictionary <int, Win32Api.UsnEntry>();

            using (usnJ = new NtfsUsnJournal(/*brd.SystemDrive.MountPoint*/ brd /*.Snapshot.MountPoint*/)){
                Logger.Append(Severity.DEBUG, "Reading USN journal " + journalId + " for '" + brd.SystemDrive.MountPoint
                              + "' from seq " + prevTransactionId + " to seq " + transactionId
                              + " (changed entries from " + Utilities.Utils.GetLocalDateTimeFromUnixTime(refTimeStamp).ToString()
                              + " to " + Utilities.Utils.GetLocalDateTimeFromUnixTime(brd.Snapshot.TimeStamp).ToLocalTime().ToString() + ")");
                Win32Api.USN_JOURNAL_DATA stateJd = new Win32Api.USN_JOURNAL_DATA();
                stateJd.UsnJournalID = journalId;
                stateJd.NextUsn      = prevTransactionId;
                Win32Api.USN_JOURNAL_DATA newState          = new Win32Api.USN_JOURNAL_DATA();        // unused, as we maintain our own state
                List <Win32Api.UsnEntry>  changedUsnEntries = new List <Win32Api.UsnEntry>();
                usnJ.GetUsnJournalState(ref newState);
                NtfsUsnJournal.UsnJournalReturnCode retCode = usnJ.GetUsnJournalEntries(stateJd, refTimeStamp, 0xFFFFFFFF, out changedUsnEntries, out newState);

                if (retCode != NtfsUsnJournal.UsnJournalReturnCode.USN_JOURNAL_SUCCESS)
                {
                    throw new Exception(retCode.ToString());
                }

                int entryId = 0;
                foreach (Win32Api.UsnEntry ue in changedUsnEntries)
                {
                    if (ue != null && ue.Reason > 0)
                    {
                        entryId = (int)(ue.FileReferenceNumber);

                        //if(ue.Name.StartsWith("grut"))
                        //Console.WriteLine ("|--------| USN seq="+ue.USN+", item "+entryId+" ("+ue.Name+") "+((NtfsUsnJournal.UsnReasonCode)ue.Reason).ToString());

                        if (!uEntries.ContainsKey(entryId))
                        {
                            uEntries[entryId] = ue;
                        }
                        else                          // cumulate reason flags
                                                      // ignore created+deleted (temporary or short-lived (between 2 backups) items
                        {
                            if (
                                ((Win32Api.UsnReasonCode)ue.Reason).HasFlag(Win32Api.UsnReasonCode.USN_REASON_FILE_DELETE) &&
                                ((Win32Api.UsnReasonCode)uEntries[entryId].Reason).HasFlag(Win32Api.UsnReasonCode.USN_REASON_FILE_CREATE)
                                )
                            {
                                Console.WriteLine("***  item " + ue.Name + " CREATED+DELETED");
                                continue;
                            }

                            // file ID reused (file delete + new create) : totally replace previous entry
                            else if (
                                ((Win32Api.UsnReasonCode)ue.Reason).HasFlag(Win32Api.UsnReasonCode.USN_REASON_FILE_CREATE) &&
                                ((Win32Api.UsnReasonCode)uEntries[entryId].Reason).HasFlag(Win32Api.UsnReasonCode.USN_REASON_FILE_DELETE)
                                )
                            {
                                uEntries[entryId] = ue;
                            }

                            // cumulate flags
                            else if (!((Win32Api.UsnReasonCode)uEntries[entryId].Reason).HasFlag(((Win32Api.UsnReasonCode)ue.Reason)))
                            {
                                Win32Api.UsnReasonCode newReason = ((Win32Api.UsnReasonCode)uEntries[entryId].Reason) | ((Win32Api.UsnReasonCode)ue.Reason);
                                uEntries[entryId]        = ue;
                                uEntries[entryId].Reason = (uint)newReason;
                            }
                            // only keep the last rename operation

                            /*if(((NtfsUsnJournal.UsnReasonCode)ue.Reason).HasFlag(NtfsUsnJournal.UsnReasonCode.USN_REASON_RENAME_NEW_NAME) ){
                             *      Console.WriteLine ("***  item "+ue.Name+" RENAMED (reasons="+((NtfsUsnJournal.UsnReasonCode)ue.Reason).ToString());
                             *      NtfsUsnJournal.UsnReasonCode newReason = ((NtfsUsnJournal.UsnReasonCode)entries[entryId].Reason) ;
                             *      if(!((NtfsUsnJournal.UsnReasonCode)entries[entryId].Reason).HasFlag(NtfsUsnJournal.UsnReasonCode.USN_REASON_RENAME_NEW_NAME) )
                             *              newReason |=  NtfsUsnJournal.UsnReasonCode.USN_REASON_RENAME_NEW_NAME;
                             *      entries[entryId] = ue;
                             *      entries[entryId].Reason = (uint)newReason;
                             * }*/
                        }
                    }
                }
                Logger.Append(Severity.TRIVIA, "Done reading USN journal " + journalId + " for '" + brd.SystemDrive.MountPoint);
            }            //end using
            return(uEntries);
        }
        public void Execute(IJobExecutionContext context)
        {
            if (Singleton.Instance.SourceMountpoints == null || Singleton.Instance.SourceMountpoints.Count == 0)
            {
                return;
            }

            try
            {
                using (Repository repo = new Repository())
                {

                    foreach (var sourceMount in Singleton.Instance.SourceMountpoints)
                    {
                        var construct = new DriveConstruct(sourceMount.MountPoint);
                        Win32Api.USN_JOURNAL_DATA newUsnState;
                        List<Win32Api.UsnEntry> usnEntries;
                        NtfsUsnJournal journal = new NtfsUsnJournal(construct.DriveLetter);

                        var drivePath = Path.Get(construct.DriveLetter);

                        logger.Trace("Polling for changes from " + sourceMount.CurrentUSNLocation);

                        var rtn = journal.GetUsnJournalEntries(construct.CurrentJournalData, reasonMask, out usnEntries, out newUsnState, OverrideLastUsn: sourceMount.CurrentUSNLocation);

                        if (rtn == NtfsUsnJournal.UsnJournalReturnCode.USN_JOURNAL_SUCCESS)
                        {
                            List<RawUSNEntry> entries = new List<RawUSNEntry>();
                            if (usnEntries.Any())
                            {
                                logger.Debug("USN returned with " + usnEntries.Count + " entries");
                            }

                            List<USNChangeRange> changeRange = new List<USNChangeRange>();

                            foreach (var frn in usnEntries.Select(e=>e.FileReferenceNumber).Distinct())
                            {

                                var entriesForFile = usnEntries.Where(f => f.FileReferenceNumber == frn).ToList();

                                if (entriesForFile.All(e => e.SourceInfo == Win32Api.UsnEntry.USNJournalSourceInfo.DataManagement || e.SourceInfo == Win32Api.UsnEntry.USNJournalSourceInfo.ReplicationManagement))
                                {
                                    continue;
                                }

                                var actualPath = GetActualPath(journal, entriesForFile.FirstOrDefault());

                                if (actualPath == "Unavailable" ||  String.IsNullOrWhiteSpace(actualPath) )
                                {
                                    continue;
                                }

                                if (sourceMount.IgnoreList != null && sourceMount.IgnoreList.Any() && sourceMount.IgnoreList.Any(ignore => new Regex(ignore).IsMatch(actualPath)))
                                {
                                    continue;
                                }

                                USNChangeRange range = new USNChangeRange
                                {
                                    FRN = frn,
                                    Min = entriesForFile.Min(e => e.TimeStamp),
                                    Max = entriesForFile.Max(e => e.TimeStamp),
                                    Closed = entriesForFile.OrderBy(f => f.TimeStamp).LastOrDefault() != null ? (entriesForFile.OrderBy(f => f.TimeStamp).LastOrDefault().Reason & Win32Api.USN_REASON_CLOSE) != 0 : false,
                                    RenameFrom = entriesForFile.FirstOrDefault(e => (e.Reason & Win32Api.USN_REASON_RENAME_OLD_NAME) != 0),
                                    Entry = entriesForFile.OrderBy(f => f.TimeStamp).LastOrDefault()
                                };

                                changeRange.Add(range);
                            }

                            //logger.Trace("ChangeRange : " + changeRange.Count);

                            foreach (var item in changeRange)
                            {

                                var actualPath = GetActualPath(journal, item.Entry as Win32Api.UsnEntry );

                                if (actualPath == "Unavailable")
                                {
                                    continue;
                                }

                                string relativePath;
                                try
                                {

                                    Uri drivePathUri = new Uri(drivePath.FullPath, UriKind.Absolute);
                                    Uri actualPathUri = new Uri(actualPath, UriKind.Absolute);

                                    relativePath = Uri.UnescapeDataString(drivePathUri.MakeRelativeUri(actualPathUri).ToString());

                                }
                                catch (Exception e)
                                {
                                    relativePath = "#ERROR#";
                                }

                                if (relativePath == "#ERROR#" || relativePath.StartsWith("System Volume Information"))
                                {
                                    continue;
                                }

                               var itemMin = item.Min.Truncate(TimeSpan.TicksPerMillisecond);
                                var itemMax = item.Max.Truncate(TimeSpan.TicksPerMillisecond);

                                var count = repo.Count<USNJournalSyncLog>(f =>

                                   f.Action.RelativePath == relativePath && f.DestinationMachine == Singleton.Instance.CurrentServer &&
                                    (
                                        (
                                            (f.ActionStartDate.HasValue && f.ActionStartDate <= itemMin)
                                            &&
                                            (f.ActionFinishDate.HasValue && f.ActionFinishDate >= itemMax)
                                        )

                                        ||

                                        (
                                            (
                                                ( ( f.ActionStartDate.HasValue && f.ActionStartDate >= itemMin) && f.ActionFinishDate.HasValue && f.ActionFinishDate <= itemMin )
                                                    &&
                                                (f.ActionFinishDate.HasValue && f.ActionFinishDate >= itemMax)
                                            )
                                            ||
                                            (
                                                (f.ActionStartDate.HasValue && f.ActionStartDate <= itemMin)
                                                &&
                                                ((f.ActionFinishDate.HasValue && f.ActionFinishDate <= itemMax) && f.ActionStartDate.HasValue && f.ActionStartDate >= itemMin )
                                            )
                                            ||
                                            (
                                                (f.ActionStartDate.HasValue && f.ActionStartDate >= itemMin)
                                                &&
                                                (f.ActionFinishDate.HasValue && f.ActionFinishDate <= itemMax)
                                            )
                                        )
                                    )
                                );

                                if (count > 0)
                                {
                                    //logger.Info("Count is " + count);
                                    continue;
                                }

                                var dbEntry = new RawUSNEntry();

                                PopulateFlags(dbEntry, item.Entry);

                                dbEntry.Path = actualPath;
                                dbEntry.RelativePath = relativePath;
                                dbEntry.File = item.Entry.IsFile;
                                dbEntry.Directory = item.Entry.IsFolder;
                                dbEntry.FRN = item.Entry.FileReferenceNumber;
                                dbEntry.PFRN = item.Entry.ParentFileReferenceNumber;
                                dbEntry.RecordLength = item.Entry.RecordLength;
                                dbEntry.USN = item.Entry.USN;
                                dbEntry.Mountpoint = sourceMount;

                                dbEntry.TimeStamp = item.Entry.TimeStamp.Truncate(TimeSpan.TicksPerMillisecond);
                                dbEntry.SourceInfo = item.Entry.SourceInfo.ToString();
                                dbEntry.ChangeRange = item;

                                if ( actualPath != null && actualPath != "Unavailable" && actualPath.ToLowerInvariant().StartsWith($"{journal.MountPoint.TrimEnd('\\')}\\$".ToLowerInvariant()))
                                {
                                    dbEntry.SystemFile = true;
                                }

                                if (item.RenameFrom != null)
                                {
                                    dbEntry.RenameFromPath = GetActualPath(journal, ((Win32Api.UsnEntry) item.RenameFrom));
                                    if (!string.IsNullOrWhiteSpace(dbEntry.RenameFromPath ) && dbEntry.RenameFromPath != "Unavailable")
                                    {
                                        dbEntry.RenameFromRelativePath = new Regex(Regex.Escape(drivePath.FullPath), RegexOptions.IgnoreCase).Replace(dbEntry.RenameFromPath, "", 1);
                                    }
                                }

                                entries.Add(dbEntry);
                            }

                            if (changeRange.Any())
                            {
                                repo.Add<USNChangeRange>(changeRange);
                                repo.Add<RawUSNEntry>(entries);

                                var performRollup = RollupService.PerformRollup(entries, sourceMount, Singleton.Instance.Repository);
                                logger.Info(string.Format("Adding [{2}CHANGE/{1}USN/{0}File]", performRollup.Count, entries.Count, changeRange.Count));
                                foreach (var fileAction in performRollup)
                                {
                                  //  logger.Trace("ADD: " + fileAction.RelativePath + ", USN:" + fileAction.USN);
                                }
                                repo.Add<FileAction>(performRollup);

                                //performRollup.ForEach(f=> logger.Debug("Added " + f.Id));
                            }

                            construct.CurrentJournalData = newUsnState;
                            sourceMount.CurrentUSNLocation = newUsnState.NextUsn;
                            sourceMount.Volume = construct.Volume;

                            repo.Update(sourceMount);

                        }
                        else
                        {
                            logger.Error("Error on Monitor - " + rtn.ToString());
                            throw new UsnJournalException(rtn);
                        }
                    }
                }
            }

            catch (Exception e)
            {
                logger.Error(e, "Error in USNJournalMonitor");
            }
        }
        private static string GetActualPath(NtfsUsnJournal journal, Win32Api.UsnEntry item)
        {
            string actualPath = null;

            string rawPath;
            var usnRtnCode = journal.GetPathFromFileReference(item.ParentFileReferenceNumber, out rawPath);

            if (usnRtnCode == NtfsUsnJournal.UsnJournalReturnCode.USN_JOURNAL_SUCCESS && 0 != String.Compare(rawPath, "Unavailable", StringComparison.OrdinalIgnoreCase))
            {
                actualPath = $"{journal.MountPoint.TrimEnd('\\')}{rawPath.TrimEnd('\\')}\\{item.Name}";
            }
            else
            {
                return actualPath;
            }
            if (actualPath.ToLowerInvariant().StartsWith($"{journal.MountPoint.TrimEnd('\\')}\\System Volume Information".ToLowerInvariant()))
            {
                return actualPath;
            }
            return actualPath;
        }