/// <summary> /// Checks if the caller has access to the inode /// </summary> /// <param name="path">The resource to check permissions for.</param> /// <param name="mode"></param> /// <returns>True if the requested access mode combination is available to the immediate caller. If any one requested access mode is not available, the result is false.</returns> public static bool Access(string path, AccessMode mode) { DirectoryEntry entry = PathResolver.Resolve(rootNode, ref path, PathResolutionFlags.DoNotThrowNotFoundException); if (null != entry) { return(AccessCheck.Perform(entry, mode, AccessCheckFlags.NoThrow)); } return(false); }
/// <summary> /// Deletes the named node from the filesystem. /// </summary> /// <param name="path">The path, which identifies a node.</param> public static void Delete(string path) { DirectoryEntry entry = PathResolver.Resolve(rootNode, ref path, PathResolutionFlags.DoNotThrowNotFoundException); if (null != entry) { AccessCheck.Perform(entry, AccessMode.Delete, AccessCheckFlags.None); //entry.Node.Delete(); entry.Parent.Node.Delete(entry.Node, entry); entry.Release(); } }
/// <summary> /// Creates a new node in the (virtual) filesystem. /// </summary> /// <param name="path">The path to create.</param> /// <param name="type">The type of the node to create.</param> /// <param name="settings">Settings used to initialize the node.</param> /// <param name="access">Requests the specified access modes on the created object.</param> /// <param name="share">Requests the specified sharing settings on the object.</param> /// <returns>The created filesystem object.</returns> /// <remarks> /// This function creates new nodes in the virtual filesystem. In contrast to *nix this call /// creates all node types, e.g. files, directories, devices and more. Specific types may /// require additional settings, which are specified in a settings object passed as the third /// parameter. /// </remarks> public static object Create(string path, VfsNodeType type, object settings, System.IO.FileAccess access, System.IO.FileShare share) { // Retrieve the parent directory DirectoryEntry parent = PathResolver.Resolve(rootNode, ref path, PathResolutionFlags.RetrieveParent); // Check if the caller has write access in the directory AccessCheck.Perform(parent, AccessMode.Write, AccessCheckFlags.None); // Yes, we do have write access. Create the new vfs node IVfsNode node = parent.Node.Create(path, type, settings); // FIXME: Assert(null != node); DirectoryEntry entry = DirectoryEntry.Allocate(parent, path, node); // FIXME: Fix the permissions for this call. *nix does this using its bitmasks, Win32 through its huge CreateFile API. return(node.Open(access, share)); }
/// <summary> /// /// </summary> /// <param name="path"></param> /// <param name="access"></param> /// <param name="share"></param> /// <returns></returns> public static object Open(string path, System.IO.FileAccess access, System.IO.FileShare share) { DirectoryEntry entry = PathResolver.Resolve(rootNode, ref path); /* HINT: * * 1. Do we really need to pass the FileShare flags down to the inode? * 2. Shouldn't we have some sort of lock deamon governing shared access? * * Ansers: * 1. Yes. * 2. Yes and no. A lock deamon would only work for local filesystems. For imported * ones we need to notify the server of the sharing lock anyway, so that the IVfsNode * (acting as a client to the server) is the best place to do it without giving the * lock deamon knowledge of all file sharing protocols (afp, smb, ftp, name it.) * 3. The inode may reject the file sharing requests. We do want to represent devices * and sync objects in the VFS, which means *they* need to decide if the flags are * applicable. * */ // FIXME: Perform access checks on the DirectoryEntry/IVfsNode. AccessMode modeFlags = AccessMode.Exists; switch (access) { case System.IO.FileAccess.Read: modeFlags = AccessMode.Read; break; case System.IO.FileAccess.Write: modeFlags = AccessMode.Write; break; case System.IO.FileAccess.ReadWrite: modeFlags = AccessMode.Read | AccessMode.Write; break; } AccessCheck.Perform(entry, modeFlags, AccessCheckFlags.None); return(entry.Node.Open(access, share)); }
/// <summary> /// Performs an iterative lookup of the given path starting from the root and obeying to the specified flags. /// </summary> /// <param name="path">The path to lookup. This can be a relative or absolute path. Path.DirectorySeparatorChar or Path.AltDirectorySeparatorChar are valid delimiters.</param> /// <param name="flags">The lookup flags, which control the lookup process.</param> /// <returns>The directory entry of the resolved path.</returns> /// <exception cref="System.Security.SecurityException">The caller does not have access to the path or a component. For example the caller does not have the right to traverse the path.</exception> /// <exception cref="System.IO.PathTooLongException">The path is too long to traverse. This can be the result of circular symbolic links in the path.</exception> /// <exception cref="System.IO.FileNotFoundException">The path or a component was not found. This exception can be prevented by specifying PathResolutionFlags.DoNotThrowNotFoundException.</exception> /// <exception cref="System.IO.DirectoryNotFoundException">A path component was not found. This exception can be prevented by specifying PathResolutionFlags.DoNotThrowNotFoundException.</exception> /// <remarks> /// This call may result in other exceptions not specified in the above list. Other exceptions can be thrown by IVfsNode implementations, which are visited during the traversal /// process. For example a network file system node may throw an exception, if the server is unreachable. /// </remarks> private DirectoryEntry Resolve(ref string path, PathResolutionFlags flags) { // DirectoryNode entry found by stepping through the path DirectoryEntry entry = null; // Split the given path to its components PathSplitter dirs = new PathSplitter(path); // Determine the number of path components int max = dirs.Length; // Current path component string item; // Loop index int index = 0; // Perform an access check on the root directory AccessCheck.Perform(currentDirectory, AccessMode.Traverse, AccessCheckFlags.None); // Do not resolve the last name, if we want the parent directory. if (PathResolutionFlags.RetrieveParent == (flags & PathResolutionFlags.RetrieveParent)) { path = dirs[dirs.Length - 1]; max--; } // Check if this is an absolute path? if (dirs[0].Length == 0) { // Yes, replace the current directory currentDirectory = rootDirectory; index++; } // Iterate over the remaining path components while ((currentDirectory != null) && (index < max)) { item = dirs[index]; entry = null; if (currentDirectory.Node.NodeType == VfsNodeType.SymbolicLink) { SymbolicLinkNode link = (SymbolicLinkNode)currentDirectory.Node; if (0 != depth--) { // The symlink stores a relative path, use it for a current relative lookup. string target = link.Target; // Build a new flags set for symlink lookups, as we do not want all of them. PathResolutionFlags symflags = (flags & PathResolutionFlags.SymLinkLookupSafe); entry = Resolve(ref target, symflags); } else { if (PathResolutionFlags.DoNotThrowNotFoundException != (PathResolutionFlags.DoNotThrowNotFoundException & flags)) { // FIXME: Provide a MUI resource string for the exception #if VFS_EXCEPTIONS throw new PathTooLongException(); #endif // #if !VFS_EXCEPTIONS } } } else { // Pass the lookup to the DirectoryEntry (and ultimately to the inode itself.) entry = currentDirectory.Lookup(item); // If lookup in the directory entry failed, ask the real INode to perform the lookup. if (entry == null) { IVfsNode node = currentDirectory.Node.Lookup(item); if (node != null) { entry = DirectoryEntry.Allocate(currentDirectory, item, node); } } } // Increment the path component index index++; // Check if we have a new path component? if ((entry == null) && (PathResolutionFlags.DoNotThrowNotFoundException != (PathResolutionFlags.DoNotThrowNotFoundException & flags))) { // FIXME: Move exception messages to MUI resources #if VFS_EXCEPTIONS if (index == max) { throw new FileNotFoundException(@"Failed to resolve the path.", path); } else { throw new DirectoryNotFoundException(@"Failed to resolve the path."); } #endif // #if VFS_EXCEPTIONS } // Set the current resolution directory currentDirectory = entry; // Check if the caller has traverse access to the directory AccessCheck.Perform(currentDirectory, AccessMode.Traverse, AccessCheckFlags.None); } return(currentDirectory); }