/// <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); }
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; }
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; } }
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); } } }
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; }
/// <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); } }
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); } }
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); }
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 = @"未能打开任何磁盘。"; } }
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); } }
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; } }
/// <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); } } }
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; }