private static void ProcessListFast(FSScan scan, Area area, List <FlatFSEntry> results, string rootFolder, System.Threading.CountdownEvent ce, System.Collections.Concurrent.ConcurrentBag <Entry> e2, int start, int end, Entry parentEntry = null, bool ignoreFiles = false) { int rflen = rootFolder.Length; if (rootFolder[rflen - 2] == ':') { rflen--; } rflen++; for (int i = start; i < end; i++) { var r = results[i]; if (r.Length == -1) { bool ignoreDirectory = false; bool ignoreContents = false; bool hide = false; string slashedSubdirectory = r.FullName.Substring(rflen); if (slashedSubdirectory == ".versionr/") { if (parentEntry == null) { if (r.ChildCount != 0) { throw new Exception(); } continue; } } CheckDirectoryIgnores(area, slashedSubdirectory, ref ignoreDirectory, ref ignoreContents, ref hide); if (hide) { i += r.ChildCount; continue; } var parent = new Entry(area, parentEntry, slashedSubdirectory, r.FullName, parentEntry == null ? slashedSubdirectory : r.FullName.Substring(parentEntry.FullName.Length), r.FileTime, 0, ignoreDirectory, (FileAttributes)r.Attributes); if (parent.IsSymlink) { i += r.ChildCount; continue; } e2.Add(parent); if (ignoreDirectory) { // have to find child files and mark them specifically as ignored int next = r.ChildCount + i + 1; for (int x = i + 1; x < next; x++) { if (results[x].Length != -1) { var f = results[x]; string fn = f.FullName.Substring(rflen); var ignoredFile = new Entry(area, parent, fn, f.FullName, f.FullName.Substring(parent.FullName.Length), f.FileTime, f.Length, true, (FileAttributes)f.Attributes); e2.Add(ignoredFile); } else { x += results[x].ChildCount; } } i += r.ChildCount; } else { int s = i + 1; int e = i + 1 + r.ChildCount; if (r.ChildCount > 16) { ce.AddCount(); System.Threading.Tasks.Task.Factory.StartNew(() => { ProcessListFast(scan, area, results, rootFolder, ce, e2, s, e, parent, ignoreContents); ce.Signal(); }); } else { ProcessListFast(scan, area, results, rootFolder, ce, e2, s, e, parent, ignoreContents); } i += r.ChildCount; } } else { if (!ignoreFiles) { string fn = r.FullName.Substring(rflen); string fnI = fn.ToLowerInvariant(); bool ignored = CheckFileIgnores(area, fn, fnI, scan.FRIncludes, scan.FRIgnores, scan.ExtIncludes, scan.ExtIgnores); e2.Add(new Entry(area, parentEntry, fn, r.FullName, parentEntry == null ? fn : r.FullName.Substring(parentEntry.FullName.Length), r.FileTime, r.Length, ignored, (FileAttributes)r.Attributes)); } } } }
private static List <Entry> GetEntryList(Area area, DirectoryInfo root, DirectoryInfo adminFolder) { System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); sw.Restart(); try { Func <string, List <FlatFSEntry> > nativeGenerator = null; if (!Utilities.MultiArchPInvoke.IsRunningOnMono) { if (GetFSFast == null) { var asm = System.Reflection.Assembly.LoadFrom(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + "/x64/VersionrCore.Win32.dll"); GetFSFast = asm.GetType("Versionr.Win32.FileSystem").GetMethod("EnumerateFileSystem").CreateDelegate(typeof(Func <string, List <FlatFSEntry> >)) as Func <string, List <FlatFSEntry> >; } nativeGenerator = GetFSFast; } else { nativeGenerator = PosixFS.GetFlatEntries; } List <FlatFSEntry> flatEntries = null; if (!Utilities.MultiArchPInvoke.IsRunningOnMono) { } if (nativeGenerator != null) { string fn = root.FullName.Replace('\\', '/'); if (fn[fn.Length - 1] != '/') { fn += '/'; } System.Net.Sockets.Socket socket = new System.Net.Sockets.Socket(System.Net.Sockets.SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp); if (flatEntries == null) { Printer.PrintDiagnostics("#q#Using native file scanner...##"); sw.Restart(); flatEntries = nativeGenerator(fn); if (area.GetLocalPath(fn) != "") { flatEntries.Insert(0, new FlatFSEntry() { Attributes = (int)root.Attributes, ChildCount = flatEntries.Count, Length = -1, FileTime = root.LastWriteTimeUtc.Ticks, FullName = fn }); } sw.Restart(); } } if (flatEntries != null) { FSScan scan = new FSScan(); scan.FRIgnores = area?.Directives?.Ignore?.RegexFilePatterns; scan.FRIncludes = area?.Directives?.Include?.RegexFilePatterns; scan.ExtIgnores = area?.Directives?.Ignore?.Extensions; scan.ExtIncludes = area?.Directives?.Include?.Extensions; List <Entry> e2 = new List <Entry>(flatEntries.Count); System.Collections.Concurrent.ConcurrentBag <Entry> entries2 = new System.Collections.Concurrent.ConcurrentBag <Entry>(); System.Threading.CountdownEvent ce2 = new System.Threading.CountdownEvent(1); ProcessListFast(scan, area, flatEntries, area.RootDirectory.FullName, ce2, entries2, 0, flatEntries.Count, null); ce2.Signal(); ce2.Wait(); var ea = entries2.ToArray(); e2.Capacity = ea.Length; e2.AddRange(ea); return(e2); } } catch (System.Exception e) { // try again with the slow mode Printer.PrintDiagnostics("#q#Couldn't use fast scanners {0}##", e); } Printer.PrintDiagnostics("#q#Using fallback file scanner...##"); sw.Restart(); System.Collections.Concurrent.ConcurrentBag <Entry> entries = new System.Collections.Concurrent.ConcurrentBag <Entry>(); System.Threading.CountdownEvent ce = new System.Threading.CountdownEvent(1); PopulateList(entries, ce, area, null, root, area.GetLocalPath(root.FullName), adminFolder, false); ce.Signal(); ce.Wait(); Entry[] entryArray = entries.ToArray(); Array.Sort(entryArray, (Entry x, Entry y) => { return(string.CompareOrdinal(x.CanonicalName, y.CanonicalName)); }); return(entryArray.ToList()); }