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"); } }
private void PopulateFlags(RawUSNEntry dbEntry, Win32Api.UsnEntry entry) { uint value = entry.Reason & Win32Api.USN_REASON_DATA_OVERWRITE; if (0 != value) { dbEntry.DataOverwrite = true; } value = entry.Reason & Win32Api.USN_REASON_DATA_EXTEND; if (0 != value) { dbEntry.DataExtend = true; } value = entry.Reason & Win32Api.USN_REASON_DATA_TRUNCATION; if (0 != value) { dbEntry.DataTruncation = true; } value = entry.Reason & Win32Api.USN_REASON_NAMED_DATA_OVERWRITE; if (0 != value) { dbEntry.NamedDataOverwrite = true; } value = entry.Reason & Win32Api.USN_REASON_NAMED_DATA_EXTEND; if (0 != value) { dbEntry.NamedDataExtend = true; } value = entry.Reason & Win32Api.USN_REASON_NAMED_DATA_TRUNCATION; if (0 != value) { dbEntry.NamedDataTruncation = true; } value = entry.Reason & Win32Api.USN_REASON_FILE_CREATE; if (0 != value) { dbEntry.FileCreate = true; } value = entry.Reason & Win32Api.USN_REASON_FILE_DELETE; if (0 != value) { dbEntry.FileDelete = true; } value = entry.Reason & Win32Api.USN_REASON_EA_CHANGE; if (0 != value) { dbEntry.EaChange = true; } value = entry.Reason & Win32Api.USN_REASON_SECURITY_CHANGE; if (0 != value) { dbEntry.SecurityChange = true; } value = entry.Reason & Win32Api.USN_REASON_RENAME_OLD_NAME; if (0 != value) { dbEntry.RenameOldName = true; } value = entry.Reason & Win32Api.USN_REASON_RENAME_NEW_NAME; if (0 != value) { dbEntry.RenameNewName = true; } value = entry.Reason & Win32Api.USN_REASON_INDEXABLE_CHANGE; if (0 != value) { dbEntry.IndexableChange = true; } value = entry.Reason & Win32Api.USN_REASON_BASIC_INFO_CHANGE; if (0 != value) { dbEntry.BasicInfoChange = true; } value = entry.Reason & Win32Api.USN_REASON_HARD_LINK_CHANGE; if (0 != value) { dbEntry.HardLinkChange = true; } value = entry.Reason & Win32Api.USN_REASON_COMPRESSION_CHANGE; if (0 != value) { dbEntry.CompressionChange = true; } value = entry.Reason & Win32Api.USN_REASON_ENCRYPTION_CHANGE; if (0 != value) { dbEntry.EncryptionChange = true; } value = entry.Reason & Win32Api.USN_REASON_OBJECT_ID_CHANGE; if (0 != value) { dbEntry.ObjectIdChange = true; } value = entry.Reason & Win32Api.USN_REASON_REPARSE_POINT_CHANGE; if (0 != value) { dbEntry.ReparsePointChange = true; } value = entry.Reason & Win32Api.USN_REASON_STREAM_CHANGE; if (0 != value) { dbEntry.StreamChange = true; } value = entry.Reason & Win32Api.USN_REASON_CLOSE; if (0 != value) { dbEntry.Close = true; } }