/// <summary> /// Get directory contents. /// </summary> /// <param name="subpath"></param> /// <returns>Directory contents</returns> public IDirectoryContents GetDirectoryContents(string subpath) { // Assert enabled feature if (!options.CanBrowse) { throw new NotSupportedException(nameof(GetDirectoryContents)); } try { // Read entry. IEntry entry = FileSystem.GetEntry(subpath, token); // Directory doesn't exist if (entry == null || !entry.IsDirectory()) { return(NotFoundDirectoryContents.Singleton); } } catch (NotSupportedException) { /*GetEntry is not supported, try Browse() next*/ } // Browse IDirectoryContent entries = FileSystem.Browse(subpath, token); // if (!entries.Exists) { return(NotFoundDirectoryContents.Singleton); } // Create infos IFileInfo[] infos = new IFileInfo[entries.Count]; for (int i = 0; i < entries.Count; i++) { infos[i] = new FileInfo(FileSystem, entries[i], options, token); } // Wrap return(new DirectoryContents(infos)); }
/// <summary> /// If <see cref="IDirectoryContent.Exists"/> is false then throws <see cref="DirectoryNotFoundException"/>. /// </summary> /// <param name="browseResult"></param> /// <returns><paramref name="browseResult"/></returns> /// <exception cref="DirectoryNotFoundException">If <paramref name="browseResult"/> referes to non-existing path.</exception> public static IDirectoryContent AssertExists(this IDirectoryContent browseResult) { if (!browseResult.Exists) { throw new DirectoryNotFoundException(browseResult.Path); } return(browseResult); }
/// <summary> /// Browse a list of embedded resources. /// /// For example: /// "assembly.res1" /// "assembly.res2" /// </summary> /// <param name="path"></param> /// <param name="option">(optional) operation specific option; capability constraint, a session, security token or credential. Used for authenticating, authorizing or restricting the operation.</param> /// <returns></returns> public IDirectoryContent Browse(string path, IOption option = null) { if (path == null) { throw new ArgumentNullException(nameof(path)); } if (IsDisposed) { throw new ObjectDisposedException(GetType().FullName); } if (path == "") { return(entries ?? (entries = CreateEntries())); } return(new DirectoryNotFound(this, path)); }
/// <summary> /// Vists tree structure of filesystem. /// /// Starts at <paramref name="path"/> if provided, otherwise starts at root "". /// <paramref name="depth"/> sets maximum visit depths. /// /// "" /// ├──"" /// │ ├──"mnt" /// │ ├──"tmp" /// │ │ └──"helloworld.txt" /// │ └──"usr" /// │ └──"lex" /// └──"c:" /// └──"dir" /// └──"dir" /// /// /// Any thrown exceptions are printed into the line that produced the error. /// </summary> /// <param name="filesystem"></param> /// <param name="path"></param> /// <param name="depth">maximum visit depth</param> /// <param name="option">(optional) operation specific option; capability constraint, a session, security token or credential. Used for authenticating, authorizing or restricting the operation.</param> /// <exception cref="Exception">any exception that GetEntry or Browse can throw</exception> /// <exception cref="IOException">If Browse returns an entry whose path is not under parent entry's path</exception> public static IEnumerable <Line> VisitTree(this IFileSystem filesystem, string path = "", int depth = Int32.MaxValue, IOption option = null) { List <Line> queue = new List <Line>(); IEntry entry = filesystem.GetEntry(path, option); if (entry == null) { yield break; } queue.Add(new Line(entry, 0, 0UL)); while (queue.Count > 0) { // Next entry int lastIx = queue.Count - 1; Line line = queue[lastIx]; queue.RemoveAt(lastIx); // Children if (line.Entry.IsDirectory() && line.Level < depth) { int startIndex = queue.Count; try { // Browse IDirectoryContent content = filesystem.Browse(line.Entry.Path, option); // Assert children don't refer to the parent of the parent foreach (IEntry child in content) { if (line.Entry.Path.StartsWith(child.Path)) { throw new IOException($"{child.Path} cannot be child of {line.Entry.Path}"); } } // Bitmask when this level continues ulong levelContinuesBitMask = line.LevelContinuesBitMask | (line.Level < 64 ? 1UL << line.Level : 0UL); // Add children in reverse order foreach (IEntry child in content) { queue.Add(new Line(child, line.Level + 1, levelContinuesBitMask)); } // Sort the entries that were added if (content.Count > 1) { sorter.QuickSortInverse(ref queue, startIndex, queue.Count - 1); } // Last entry doesn't continue on its level. if (content.Count >= 1) { queue[startIndex] = queue[startIndex].NewLevelContinuesBitMask(line.LevelContinuesBitMask); } } catch (Exception e) { // Add error to be yielded along line.Error = e; } } // yield line yield return(line); } }
/// <summary>Estimate viability of operation.</summary> /// <exception cref="FileNotFoundException">If <see cref="SrcPath"/> is not found.</exception> /// <exception cref="FileSystemExceptionFileExists">If <see cref="Path"/> already exists.</exception> protected override void InnerEstimate() { PathConverter pathConverter = new PathConverter(SrcPath, Path); List <IEntry> queue = new List <IEntry>(); // Src IEntry e = SrcFileSystem.GetEntry(SrcPath, srcOption.OptionIntersection(session.Option)); // Src not found if (e == null) { // Throw if (EffectivePolicy.HasFlag(OperationPolicy.SrcThrow)) { throw new FileNotFoundException(SrcPath); } // Skip if (EffectivePolicy.HasFlag(OperationPolicy.SrcSkip)) { SetState(OperationState.Skipped); return; } // Fail anyway throw new FileNotFoundException(SrcPath); } queue.Add(e); while (queue.Count > 0) { try { // Next entry int lastIx = queue.Count - 1; IEntry entry = queue[lastIx]; queue.RemoveAt(lastIx); // Omit package mounts if (session.Policy.HasFlag(OperationPolicy.OmitMountedPackages) && entry.IsPackageMount()) { continue; } // Process directory if (entry.IsDirectory()) { // Browse children IDirectoryContent content = SrcFileSystem.Browse(entry.Path, srcOption.OptionIntersection(session.Option)); // Assert children don't refer to the parent of the parent foreach (IEntry child in content) { if (entry.Path.StartsWith(child.Path)) { throw new IOException($"{child.Path} cannot be child of {entry.Path}"); } } // Visit child for (int i = content.Count - 1; i >= 0; i--) { queue.Add(content[i]); } // Convert path string _dstPath; if (!pathConverter.ParentToChild(entry.Path, out _dstPath)) { throw new Exception("Failed to convert path"); } // Add op if (_dstPath != "") { Ops.Add(new CreateDirectory(session, FileSystem, _dstPath, Option.OptionIntersection(session.Option), OpPolicy)); } } // Process file else if (entry.IsFile()) { // Convert path string _dstPath; if (!pathConverter.ParentToChild(entry.Path, out _dstPath)) { throw new Exception("Failed to convert path"); } // Add op Ops.Add(new CopyFile(session, SrcFileSystem, entry.Path, FileSystem, _dstPath, srcOption.OptionIntersection(session.Option), Option.OptionIntersection(session.Option), OpPolicy)); } } catch (Exception error) when(SetError(error)) { } } base.InnerEstimate(); }
/// <summary>Estimate viability of operation.</summary> /// <exception cref="FileNotFoundException">If <see cref="Path"/> is not found.</exception> /// <exception cref="FileSystemExceptionFileExists">If <see cref="Path"/> already exists.</exception> protected override void InnerEstimate() { List <Delete> dirDeletes = new List <Delete>(); try { List <IEntry> queue = new List <IEntry>(); IEntry e = FileSystem.GetEntry(Path, Option.OptionIntersection(session.Option)); if (e == null) { throw new FileNotFoundException(Path); } queue.Add(e); while (queue.Count > 0) { try { // Next entry int lastIx = queue.Count - 1; IEntry entry = queue[lastIx]; queue.RemoveAt(lastIx); // Omit package mounts if (session.Policy.HasFlag(OperationPolicy.OmitMountedPackages) && entry.IsPackageMount()) { continue; } // Process directory if (entry.IsDirectory()) { // Browse children IDirectoryContent content = FileSystem.Browse(entry.Path, Option.OptionIntersection(session.Option)); // Assert children don't refer to the parent of the parent foreach (IEntry child in content) { if (entry.Path.StartsWith(child.Path)) { throw new IOException($"{child.Path} cannot be child of {entry.Path}"); } } // Visit children for (int i = content.Count - 1; i >= 0; i--) { queue.Add(content[i]); } // Add op dirDeletes.Add(new Delete(session, FileSystem, entry.Path, false)); } // Process file else if (entry.IsFile()) { // Add op Ops.Add(new Delete(session, FileSystem, entry.Path, false, Option.OptionIntersection(session.Option), OpPolicy)); } } catch (Exception error) when(SetError(error)) { } } } finally { // Add directory deletes for (int i = dirDeletes.Count - 1; i >= 0; i--) { Ops.Add(dirDeletes[i]); } } // Estimate added ops base.InnerEstimate(); }
public static void Main(string[] args) { { #region Snippet_1a IFileSystem fs = new FileSystem(@"C:\Temp\"); #endregion Snippet_1a } { #region Snippet_1b IFileSystem fs = new FileSystem(""); #endregion Snippet_1b } { IFileSystem fs = new FileSystem(""); #region Snippet_2a IDirectoryContent contents = fs.Browse("C:/Windows/"); #endregion Snippet_2a #region Snippet_2d foreach (IEntry entry in fs.Browse("C:/Windows/")) { Console.WriteLine(entry.Path); } #endregion Snippet_2d #region Snippet_2e foreach (var entry in fs.Browse("C:/Windows/").AssertExists()) { Console.WriteLine(entry.Path); } #endregion Snippet_2e { #region Snippet_2f IEntry e = FileSystem.OS.GetEntry("C:/Windows/win.ini"); Console.WriteLine(e.Path); #endregion Snippet_2f } { #region Snippet_2g IEntry e = FileSystem.OS.GetEntry("C:/Windows/win.ini").AssertExists(); #endregion Snippet_2g } #region Snippet_3a using (Stream s = fs.Open("file.txt", FileMode.Open, FileAccess.Read, FileShare.Read)) { Console.WriteLine(s.Length); } #endregion Snippet_3a #region Snippet_3b using (Stream s = fs.Open("somefile.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite)) { s.WriteByte(32); } #endregion Snippet_3b #region Snippet_5 fs.CreateDirectory("dir/"); #endregion Snippet_5 #region Snippet_6 fs.Delete("dir/", recurse: true); #endregion Snippet_6 #region Snippet_7 fs.CreateDirectory("dir/"); fs.Move("dir/", "new-name/"); #endregion Snippet_7 fs.Delete("new-name/"); } { IFileSystem fs = FileSystem.Temp; if (fs.Exists("myfile")) { fs.SetFileAttribute("myfile", FileAttributes.Normal); fs.Delete("myfile"); } fs.CreateFile("myfile", new byte[] { 1 }); #region Snippet_7f fs.SetFileAttribute("myfile", FileAttributes.ReadOnly); #endregion Snippet_7f fs.SetFileAttribute("myfile", FileAttributes.Normal); fs.Delete("myfile"); } { #region Snippet_7x1 FileSystem.OS.GetEntry("C:/Windows/win.ini"); #endregion Snippet_7x1 } { #region Snippet_8a IFileSystem fs = FileSystem.OS; #endregion Snippet_8a } { #region Snippet_8b foreach (var line in FileSystem.OS.VisitTree(depth: 2)) { Console.WriteLine(line); } #endregion Snippet_8b } { #region Snippet_8b2 FileSystem.OS.PrintTo(Console.Out, depth: 2, format: PrintTree.Format.DefaultPath); #endregion Snippet_8b2 } { #region Snippet_8c FileSystem.OS.PrintTo(Console.Out, depth: 3, format: PrintTree.Format.DefaultPath); #endregion Snippet_8c } { #region Snippet_8d FileSystem.Application.PrintTo(Console.Out); #endregion Snippet_8d } { #region Snippet_8e FileSystem.Temp.PrintTo(Console.Out, depth: 1); #endregion Snippet_8e } { // <Snippet_8f> foreach (var line in FileSystem.Temp.VisitTree(depth:2)) { Console.WriteLine(line.Entry.PhysicalPath()); } // </Snippet_8f> } { // <Snippet_8g> FileSystem.Temp.PrintTo( output: Console.Out, depth: 2, format: PrintTree.Format.Default | PrintTree.Format.PhysicalPath); // </Snippet_8g> } { // <Snippet_9a> IObserver <IEvent> observer = new Observer(); IFileSystemObserver handle = FileSystem.OS.Observe("C:/**", observer); // </Snippet_9a> } { // <Snippet_9b> using (var handle = FileSystem.Temp.Observe("*.dat", new PrintObserver())) { FileSystem.Temp.CreateFile("file.dat", new byte[] { 32, 32, 32, 32 }); FileSystem.Temp.Delete("file.dat"); Thread.Sleep(1000); } // </Snippet_9b> } { // <Snippet_9c> IObserver <IEvent> observer = new Observer(); FileSystem.OS.Observe("C:/**", observer, eventDispatcher: EventDispatcher.Instance); // </Snippet_9c> } { // <Snippet_9d> IObserver <IEvent> observer = new Observer(); FileSystem.OS.Observe("C:/**", observer, eventDispatcher: EventTaskDispatcher.Instance); // </Snippet_9d> } { #region Snippet_10a // Init object obj = new ReaderWriterLockSlim(); IFileSystemDisposable fs = new FileSystem("").AddDisposable(obj); // ... do work ... // Dispose both fs.Dispose(); #endregion Snippet_10a } { #region Snippet_10b IFileSystemDisposable fs = new FileSystem("") .AddDisposeAction(f => Console.WriteLine("Disposed")); #endregion Snippet_10b } { #region Snippet_10c FileSystem fs = new FileSystem(""); fs.Browse(""); // Postpone dispose IDisposable belateDisposeHandle = fs.BelateDispose(); // Start concurrent work Task.Run(() => { // Do work Thread.Sleep(1000); fs.GetEntry(""); // Release belate handle. Disposes here or below, depending which thread runs last. belateDisposeHandle.Dispose(); }); // Start dispose, but postpone it until belatehandle is disposed in another thread. fs.Dispose(); #endregion Snippet_10c } }