internal Collection<string> GetGlobbedProviderPathsFromProviderPath(string path, bool allowNonexistingPaths, string providerId, out CmdletProvider providerInstance) { providerInstance = null; if (path == null) { throw PSTraceSource.NewArgumentNullException("path"); } CmdletProviderContext context = new CmdletProviderContext(this.sessionState.Internal.ExecutionContext); Collection<string> collection = this.GetGlobbedProviderPathsFromProviderPath(path, allowNonexistingPaths, providerId, context, out providerInstance); if (context.HasErrors()) { ErrorRecord record = context.GetAccumulatedErrorObjects()[0]; if (record != null) { throw record.Exception; } } return collection; }
internal string GetProviderPath(string path, out ProviderInfo provider) { if (path == null) { throw PSTraceSource.NewArgumentNullException("path"); } CmdletProviderContext context = new CmdletProviderContext(this.sessionState.Internal.ExecutionContext); PSDriveInfo drive = null; provider = null; string str = this.GetProviderPath(path, context, out provider, out drive); if (context.HasErrors()) { Collection<ErrorRecord> accumulatedErrorObjects = context.GetAccumulatedErrorObjects(); if ((accumulatedErrorObjects != null) && (accumulatedErrorObjects.Count > 0)) { throw accumulatedErrorObjects[0].Exception; } } return str; }
} // GetProviderPath /// <summary> /// Gets a provider specific path when given an Msh path without resolving the /// glob characters. /// </summary> /// /// <param name="path"> /// An Msh path. /// </param> /// /// <param name="provider"> /// The information of the provider that was used to resolve the path. /// </param> /// /// <returns> /// A provider specific path that the Msh path represents. /// </returns> /// /// <exception cref="ArgumentNullException"> /// If <paramref name="path"/> is null. /// </exception> /// /// <exception cref="ProviderNotFoundException"> /// If the path is a provider-qualified path for a provider that is /// not loaded into the system. /// </exception> /// /// <exception cref="DriveNotFoundException"> /// If the <paramref name="path"/> refers to a drive that could not be found. /// </exception> /// /// <exception cref="ProviderInvocationException"> /// If the provider used to build the path threw an exception. /// </exception> /// /// <exception cref="NotSupportedException"> /// If the provider that the <paramref name="path"/> represents is not a NavigationCmdletProvider /// or ContainerCmdletProvider. /// </exception> /// /// <exception cref="InvalidOperationException"> /// If the <paramref name="path"/> starts with "~" and the home location is not set for /// the provider. /// </exception> /// /// <exception cref="ProviderInvocationException"> /// If the provider specified by <paramref name="provider"/> threw an /// exception when its GetParentPath or MakePath was called while /// processing the <paramref name="path"/>. /// </exception> /// /// <exception> /// Any exception can be thrown by the provider that is called to build /// the provider path. /// </exception> /// internal string GetProviderPath(string path, out ProviderInfo provider) { if (path == null) { throw PSTraceSource.NewArgumentNullException("path"); } CmdletProviderContext context = new CmdletProviderContext(_sessionState.Internal.ExecutionContext); PSDriveInfo drive = null; provider = null; string result = GetProviderPath(path, context, out provider, out drive); if (context.HasErrors()) { Collection<ErrorRecord> errors = context.GetAccumulatedErrorObjects(); if (errors != null && errors.Count > 0) { throw errors[0].Exception; } } return result; } // GetProviderPath
} // GenerateNewPathsWithGlobLeaf /// <summary> /// Gets the child names in the specified path by using the provider /// </summary> /// /// <param name="dir"> /// The path of the directory to get the child names from. If this is an Msh Path, /// dirIsProviderPath must be false, If this is a provider-internal path, /// dirIsProviderPath must be true. /// </param> /// /// <param name="leafElement"> /// The element that we are ultimately looking for. Used to set filters on the context /// if desired. /// </param> /// /// <param name="getAllContainers"> /// Determines if the GetChildNames call should get all containers even if they don't /// match the filter. /// </param> /// /// <param name="context"> /// The context to be used for the command. The context is copied to a new context, the /// results are accumulated and then returned. /// </param> /// /// <param name="dirIsProviderPath"> /// Specifies whether the dir parameter is a provider-internal path (true) or Msh Path (false). /// </param> /// /// <param name="drive"> /// The drive to use to qualify the Msh path if dirIsProviderPath is false. /// </param> /// /// <param name="provider"> /// The provider to use to get the child names. /// </param> /// /// <param name="modifiedDirPath"> /// Returns the modified dir path. If dirIsProviderPath is true, this is the unescaped dir path. /// If dirIsProviderPath is false, this is the unescaped resolved provider path. /// </param> /// /// <returns> /// A collection of PSObjects whose BaseObject is a string that contains the name of the child. /// </returns> /// /// <exception cref="ArgumentNullException"> /// If <paramref name="dir"/> or <paramref name="drive"/> is null. /// </exception> /// /// <exception cref="ProviderNotFoundException"> /// If the path is a provider-qualified path for a provider that is /// not loaded into the system. /// </exception> /// /// <exception cref="DriveNotFoundException"> /// If the <paramref name="path"/> refers to a drive that could not be found. /// </exception> /// /// <exception cref="ProviderInvocationException"> /// If the provider used to build the path threw an exception. /// </exception> /// /// <exception cref="NotSupportedException"> /// If the provider that the <paramref name="path"/> represents is not a NavigationCmdletProvider /// or ContainerCmdletProvider. /// </exception> /// /// <exception cref="InvalidOperationException"> /// If the <paramref name="path"/> starts with "~" and the home location is not set for /// the provider. /// </exception> /// /// <exception cref="ProviderInvocationException"> /// If the provider associated with the <paramref name="path"/> threw an /// exception when its GetParentPath or MakePath was called while /// processing the <paramref name="path"/>. /// </exception> /// /// <exception cref="PipelineStoppedException"> /// If <paramref name="context"/> has been signaled for /// StopProcessing. /// </exception> /// /// <exception> /// Any exception can be thrown by the provider that is called to build /// the provider path. /// </exception> /// private Collection<PSObject> GetChildNamesInDir( string dir, string leafElement, bool getAllContainers, CmdletProviderContext context, bool dirIsProviderPath, PSDriveInfo drive, ContainerCmdletProvider provider, out string modifiedDirPath) { // See if the provider wants to convert the path and filter string convertedPath = null; string convertedFilter = null; string originalFilter = context.Filter; bool changedPathOrFilter = provider.ConvertPath(leafElement, context.Filter, ref convertedPath, ref convertedFilter, context); if (changedPathOrFilter) { if (s_tracer.IsEnabled) { s_tracer.WriteLine("Provider converted path and filter."); s_tracer.WriteLine("Original path: {0}", leafElement); s_tracer.WriteLine("Converted path: {0}", convertedPath); s_tracer.WriteLine("Original filter: {0}", context.Filter); s_tracer.WriteLine("Converted filter: {0}", convertedFilter); } leafElement = convertedPath; context.Filter = convertedFilter; } ReturnContainers returnContainers = ReturnContainers.ReturnAllContainers; if (!getAllContainers) { returnContainers = ReturnContainers.ReturnMatchingContainers; } CmdletProviderContext getChildNamesContext = new CmdletProviderContext(context); // Remove the include/exclude filters from the new context getChildNamesContext.SetFilters( new Collection<string>(), new Collection<string>(), context.Filter); try { // Use the provider to get the children string unescapedDir = null; modifiedDirPath = null; if (dirIsProviderPath) { modifiedDirPath = unescapedDir = context.SuppressWildcardExpansion ? dir : RemoveGlobEscaping(dir); } else { Dbg.Diagnostics.Assert( drive != null, "Caller should verify that drive is not null when dirIsProviderPath is false"); // If the directory is an MSH path we must resolve it before calling GetChildNames() // -- If the path is passed in by LiteralPath (context.SuppressWildcardExpansion == false), we surely should use 'dir' unchanged. // -- If the path is passed in by Path (context.SuppressWildcardExpansion == true), we still should use 'dir' unchanged, in case that the special character // in 'dir' is escaped modifiedDirPath = GetMshQualifiedPath(dir, drive); ProviderInfo providerIgnored = null; CmdletProvider providerInstanceIgnored = null; Collection<string> resolvedPaths = GetGlobbedProviderPathsFromMonadPath( modifiedDirPath, false, getChildNamesContext, out providerIgnored, out providerInstanceIgnored); // After resolving the path, we unescape the modifiedDirPath if necessary. modifiedDirPath = context.SuppressWildcardExpansion ? modifiedDirPath : RemoveGlobEscaping(modifiedDirPath); if (resolvedPaths.Count > 0) { unescapedDir = resolvedPaths[0]; } else { // If there were no results from globbing but no // exception was thrown, that means there was filtering. // So return an empty collection and let the caller deal // with it. if (changedPathOrFilter) { context.Filter = originalFilter; } return new Collection<PSObject>(); } } if (provider.HasChildItems(unescapedDir, getChildNamesContext)) { provider.GetChildNames( unescapedDir, returnContainers, getChildNamesContext); } // First check to see if there were any errors, and write them // to the real context if there are. if (getChildNamesContext.HasErrors()) { Collection<ErrorRecord> errors = getChildNamesContext.GetAccumulatedErrorObjects(); if (errors != null && errors.Count > 0) { foreach (ErrorRecord errorRecord in errors) { context.WriteError(errorRecord); } } } Collection<PSObject> childNamesObjectArray = getChildNamesContext.GetAccumulatedObjects(); if (changedPathOrFilter) { context.Filter = originalFilter; } return childNamesObjectArray; } finally { getChildNamesContext.RemoveStopReferral(); } } // GetChildNamesInDir
} //NormalizeRelativePath /// <summary> /// Normalizes the path that was passed in and returns the normalized path /// as a relative path to the basePath that was passed. /// </summary> /// /// <param name="path"> /// An MSH path to an item. The item should exist /// or the provider should write out an error. /// </param> /// /// <param name="basePath"> /// The path that the return value should be relative to. /// </param> /// /// <param name="context"> /// The context under which the command is running. /// </param> /// /// <returns> /// A normalized path that is relative to the basePath that was passed. /// </returns> /// /// <exception cref="ArgumentNullException"> /// If <paramref name="path"/> is null. /// </exception> /// /// <exception cref="NotSupportedException"> /// If the <paramref name="providerInstance"/> does not support this operation. /// </exception> /// /// <exception cref="PipelineStoppedException"> /// If the pipeline is being stopped while executing the command. /// </exception> /// /// <exception cref="ProviderInvocationException"> /// If the provider threw an exception. /// </exception> /// internal string NormalizeRelativePath( string path, string basePath, CmdletProviderContext context) { if (path == null) { throw PSTraceSource.NewArgumentNullException("path"); } CmdletProviderContext getProviderPathContext = new CmdletProviderContext(context); try { PSDriveInfo drive = null; ProviderInfo provider = null; string workingPath = Globber.GetProviderPath( path, getProviderPathContext, out provider, out drive); if (getProviderPathContext.HasErrors()) { getProviderPathContext.WriteErrorsToContext(context); return null; } if (workingPath == null || provider == null) { // Since the provider didn't write an error, and we didn't get any // results ourselves, we need to write out our own error. Exception e = PSTraceSource.NewArgumentException("path"); context.WriteError(new ErrorRecord(e, "NormalizePathNullResult", ErrorCategory.InvalidArgument, path)); return null; } if (basePath != null) { PSDriveInfo baseDrive = null; ProviderInfo baseProvider = null; Globber.GetProviderPath( basePath, getProviderPathContext, out baseProvider, out baseDrive); if (drive != null && baseDrive != null) { if (!drive.Name.Equals(baseDrive.Name, StringComparison.OrdinalIgnoreCase)) { // Make sure they are from physically different drives // Doing StartsWith from both directions covers the following cases // C:\ and C:\Temp // C:\Temp and C:\ if (!(drive.Root.StartsWith(baseDrive.Root, StringComparison.OrdinalIgnoreCase) || (baseDrive.Root.StartsWith(drive.Root, StringComparison.OrdinalIgnoreCase)))) { // In this case, no normalization is necessary return path; } } } } if (drive != null) { context.Drive = drive; // Detect if the original path was already a // provider path. This happens when a drive doesn't // have a rooted root -- such as HKEY_LOCAL_MACHINE instead of // \\HKEY_LOCAL_MACHINE if ( (GetProviderInstance(provider) is NavigationCmdletProvider) && (!String.IsNullOrEmpty(drive.Root)) && (path.StartsWith(drive.Root, StringComparison.OrdinalIgnoreCase))) { // // If the drive root doesn't end with a path separator then there is a chance the // path starts with the drive root name but doesn't actually refer to it. For example, // (see Win8 bug 922001) consider drive with root HKEY_LOCAL_MACHINE named // HKEY_LOCAL_MACHINE_foo. The path would start with the drive root but is not a provider // path. // // We will remediate this by only considering this a provider path if // 1. The drive root ends with a path separator. // OR // 2. The path starts with the drive root followed by a path separator // OR // 3. The path exactly matches the drive root. // // 1. Test for the drive root ending with a path separator. bool driveRootEndsWithPathSeparator = IsPathSeparator(drive.Root[drive.Root.Length - 1]); // 2. Test for the path starting with the drive root followed by a path separator int indexAfterDriveRoot = drive.Root.Length; bool pathStartsWithDriveRootAndPathSeparator = indexAfterDriveRoot < path.Length && IsPathSeparator(path[indexAfterDriveRoot]); // 3. Test for the drive root exactly matching the path. // Since we know the path starts with the drive root then they are equal if the lengths are equal. bool pathEqualsDriveRoot = drive.Root.Length == path.Length; if (driveRootEndsWithPathSeparator || pathStartsWithDriveRootAndPathSeparator || pathEqualsDriveRoot) { workingPath = path; } } } return NormalizeRelativePath(provider, workingPath, basePath, context); } finally { getProviderPathContext.RemoveStopReferral(); } } // NormalizeRelativePath
} // SetLocation /// <summary> /// Determines if the specified path is the current working directory /// or a parent of the current working directory. /// </summary> /// /// <param name="path"> /// A monad namespace absolute or relative path. /// </param> /// /// <param name="context"> /// The context the provider uses when performing the operation. /// </param> /// /// <returns> /// true, if the path is the current working directory or a parent of the current /// working directory. false, otherwise. /// </returns> /// /// <exception cref="ArgumentNullException"> /// If <paramref name="path"/> is null. /// </exception> /// /// <exception cref="ProviderNotFoundException"> /// If the path is a provider-qualified path for a provider that is /// not loaded into the system. /// </exception> /// /// <exception cref="DriveNotFoundException"> /// If the <paramref name="path"/> refers to a drive that could not be found. /// </exception> /// /// <exception cref="ProviderInvocationException"> /// If the provider used to build the path threw an exception. /// </exception> /// /// <exception cref="NotSupportedException"> /// If the provider that the <paramref name="path"/> represents is not a NavigationCmdletProvider /// or ContainerCmdletProvider. /// </exception> /// /// <exception cref="InvalidOperationException"> /// If the <paramref name="path"/> starts with "~" and the home location is not set for /// the provider. /// </exception> /// /// <exception cref="ProviderInvocationException"> /// If the provider specified by <paramref name="providerId"/> threw an /// exception when its GetParentPath or MakePath was called while /// processing the <paramref name="path"/>. /// </exception> /// internal bool IsCurrentLocationOrAncestor(string path, CmdletProviderContext context) { bool result = false; if (path == null) { throw PSTraceSource.NewArgumentNullException("path"); } PSDriveInfo drive = null; ProviderInfo provider = null; string providerSpecificPath = Globber.GetProviderPath( path, context, out provider, out drive); if (drive != null) { s_tracer.WriteLine("Tracing drive"); drive.Trace(); } Dbg.Diagnostics.Assert( providerSpecificPath != null, "There should always be a way to generate a provider path for a " + "given path"); if (drive != null) { context.Drive = drive; } // Check to see if the path that was specified is within the current // working drive if (drive == CurrentDrive) { // The path needs to be normalized to get rid of relative path tokens // so they don't interfere with our path comparisons below CmdletProviderContext normalizePathContext = new CmdletProviderContext(context); try { providerSpecificPath = NormalizeRelativePath(path, null, normalizePathContext); } catch (NotSupportedException) { // Since the provider does not support normalizing the path, just // use the path we currently have. } catch (LoopFlowException) { throw; } catch (PipelineStoppedException) { throw; } catch (ActionPreferenceStopException) { throw; } finally { normalizePathContext.RemoveStopReferral(); } if (normalizePathContext.HasErrors()) { normalizePathContext.ThrowFirstErrorOrDoNothing(); } s_tracer.WriteLine("Provider path = {0}", providerSpecificPath); // Get the current working directory provider specific path PSDriveInfo currentWorkingDrive = null; ProviderInfo currentDriveProvider = null; string currentWorkingPath = Globber.GetProviderPath( ".", context, out currentDriveProvider, out currentWorkingDrive); Dbg.Diagnostics.Assert( currentWorkingDrive == CurrentDrive, "The current working drive should be the CurrentDrive."); s_tracer.WriteLine( "Current working path = {0}", currentWorkingPath); // See if the path is the current working directory or a parent // of the current working directory s_tracer.WriteLine( "Comparing {0} to {1}", providerSpecificPath, currentWorkingPath); if (String.Compare(providerSpecificPath, currentWorkingPath, StringComparison.CurrentCultureIgnoreCase) == 0) { // The path is the current working directory so // return true s_tracer.WriteLine("The path is the current working directory"); result = true; } else { // Check to see if the specified path is a parent // of the current working directory string lockedDirectory = currentWorkingPath; while (lockedDirectory.Length > 0) { // We need to allow the provider to go as far up the tree // as it can even if that means it has to traverse higher // than the mount point for this drive. That is // why we are passing the empty string as the root here. lockedDirectory = GetParentPath( drive.Provider, lockedDirectory, String.Empty, context); s_tracer.WriteLine( "Comparing {0} to {1}", lockedDirectory, providerSpecificPath); if (String.Compare(lockedDirectory, providerSpecificPath, StringComparison.CurrentCultureIgnoreCase) == 0) { // The path is a parent of the current working // directory s_tracer.WriteLine( "The path is a parent of the current working directory: {0}", lockedDirectory); result = true; break; } } } } else { s_tracer.WriteLine("Drives are not the same"); } return result; } // IsCurrentLocationOrAncestor
internal void RemoveDrive(PSDriveInfo drive, bool force, string scopeID) { if (drive == null) { throw PSTraceSource.NewArgumentNullException("drive"); } CmdletProviderContext context = new CmdletProviderContext(this.ExecutionContext); this.RemoveDrive(drive, force, scopeID, context); if (context.HasErrors() && !force) { context.ThrowFirstErrorOrDoNothing(); } }
/// <summary> /// Changes the current working directory to the path specified. /// </summary> /// <param name="path"> /// The path of the new current working directory. /// </param> /// <param name="context"> /// The context the provider uses when performing the operation. /// </param> /// <param name="literalPath"> /// Indicate if the path is a literal path. /// </param> /// <returns> /// The PathInfo object representing the path of the location /// that was set. /// </returns> /// <exception cref="ArgumentNullException"> /// If <paramref name="path"/> is null. /// </exception> /// <exception cref="ArgumentException"> /// If <paramref name="path"/> does not exist, is not a container, or /// resolved to multiple containers. /// </exception> /// <exception cref="ProviderNotFoundException"> /// If <paramref name="path"/> refers to a provider that does not exist. /// </exception> /// <exception cref="DriveNotFoundException"> /// If <paramref name="path"/> refers to a drive that does not exist. /// </exception> /// <exception cref="ProviderInvocationException"> /// If the provider associated with <paramref name="path"/> threw an /// exception. /// </exception> /// <exception cref="ItemNotFoundException"> /// If the <paramref name="path"/> could not be resolved. /// </exception> internal PathInfo SetLocation(string path, CmdletProviderContext context, bool literalPath) { if (path == null) { throw PSTraceSource.NewArgumentNullException("path"); } PathInfo current = CurrentLocation; string originalPath = path; string driveName = null; ProviderInfo provider = null; string providerId = null; switch (originalPath) { case string originalPathSwitch when !literalPath && originalPathSwitch.Equals("-", StringComparison.Ordinal): if (_setLocationHistory.UndoCount <= 0) { throw new InvalidOperationException(SessionStateStrings.LocationUndoStackIsEmpty); } path = _setLocationHistory.Undo(this.CurrentLocation).Path; break; case string originalPathSwitch when !literalPath && originalPathSwitch.Equals("+", StringComparison.Ordinal): if (_setLocationHistory.RedoCount <= 0) { throw new InvalidOperationException(SessionStateStrings.LocationRedoStackIsEmpty); } path = _setLocationHistory.Redo(this.CurrentLocation).Path; break; default: var pushPathInfo = GetNewPushPathInfo(); _setLocationHistory.Push(pushPathInfo); break; } PSDriveInfo previousWorkingDrive = CurrentDrive; // First check to see if the path is a home path if (LocationGlobber.IsHomePath(path)) { path = Globber.GetHomeRelativePath(path); } if (LocationGlobber.IsProviderDirectPath(path)) { // The path is a provider-direct path so use the current // provider and its hidden drive but don't modify the path // at all. provider = CurrentLocation.Provider; CurrentDrive = provider.HiddenDrive; } else if (LocationGlobber.IsProviderQualifiedPath(path, out providerId)) { provider = GetSingleProvider(providerId); CurrentDrive = provider.HiddenDrive; } else { // See if the path is a relative or absolute // path. if (Globber.IsAbsolutePath(path, out driveName)) { // Since the path is an absolute path // we need to change the current working // drive PSDriveInfo newWorkingDrive = GetDrive(driveName); CurrentDrive = newWorkingDrive; // If the path is simply a colon-terminated drive, // not a slash-terminated path to the root of a drive, // set the path to the current working directory of that drive. string colonTerminatedVolume = CurrentDrive.Name + ':'; if (CurrentDrive.VolumeSeparatedByColon && (path.Length == colonTerminatedVolume.Length)) { path = Path.Combine(colonTerminatedVolume + Path.DirectorySeparatorChar, CurrentDrive.CurrentLocation); } // Now that the current working drive is set, // process the rest of the path as a relative path. } } if (context == null) { context = new CmdletProviderContext(this.ExecutionContext); } if (CurrentDrive != null) { context.Drive = CurrentDrive; } CmdletProvider providerInstance = null; Collection <PathInfo> workingPath = null; try { workingPath = Globber.GetGlobbedMonadPathsFromMonadPath( path, false, context, out providerInstance); } catch (LoopFlowException) { throw; } catch (PipelineStoppedException) { throw; } catch (ActionPreferenceStopException) { throw; } catch (Exception) { // Reset the drive to the previous drive and // then rethrow the error CurrentDrive = previousWorkingDrive; throw; } if (workingPath.Count == 0) { // Set the current working drive back to the previous // one in case it was changed. CurrentDrive = previousWorkingDrive; throw new ItemNotFoundException( path, "PathNotFound", SessionStateStrings.PathNotFound); } // We allow globbing the location as long as it only resolves a single container. bool foundContainer = false; bool pathIsContainer = false; bool pathIsProviderQualifiedPath = false; bool currentPathisProviderQualifiedPath = false; for (int index = 0; index < workingPath.Count; ++index) { CmdletProviderContext normalizePathContext = new CmdletProviderContext(context); PathInfo resolvedPath = workingPath[index]; string currentPath = path; try { string providerName = null; currentPathisProviderQualifiedPath = LocationGlobber.IsProviderQualifiedPath(resolvedPath.Path, out providerName); if (currentPathisProviderQualifiedPath) { // The path should be the provider-qualified path without the provider ID // or :: string providerInternalPath = LocationGlobber.RemoveProviderQualifier(resolvedPath.Path); try { currentPath = NormalizeRelativePath(GetSingleProvider(providerName), providerInternalPath, string.Empty, normalizePathContext); } catch (NotSupportedException) { // Since the provider does not support normalizing the path, just // use the path we currently have. } catch (LoopFlowException) { throw; } catch (PipelineStoppedException) { throw; } catch (ActionPreferenceStopException) { throw; } catch (Exception) { // Reset the drive to the previous drive and // then rethrow the error CurrentDrive = previousWorkingDrive; throw; } } else { try { currentPath = NormalizeRelativePath(resolvedPath.Path, CurrentDrive.Root, normalizePathContext); } catch (NotSupportedException) { // Since the provider does not support normalizing the path, just // use the path we currently have. } catch (LoopFlowException) { throw; } catch (PipelineStoppedException) { throw; } catch (ActionPreferenceStopException) { throw; } catch (Exception) { // Reset the drive to the previous drive and // then rethrow the error CurrentDrive = previousWorkingDrive; throw; } } // Now see if there was errors while normalizing the path if (normalizePathContext.HasErrors()) { // Set the current working drive back to the previous // one in case it was changed. CurrentDrive = previousWorkingDrive; normalizePathContext.ThrowFirstErrorOrDoNothing(); } } finally { normalizePathContext.RemoveStopReferral(); } bool isContainer = false; CmdletProviderContext itemContainerContext = new CmdletProviderContext(context); itemContainerContext.SuppressWildcardExpansion = true; try { isContainer = IsItemContainer( resolvedPath.Path, itemContainerContext); if (itemContainerContext.HasErrors()) { // Set the current working drive back to the previous // one in case it was changed. CurrentDrive = previousWorkingDrive; itemContainerContext.ThrowFirstErrorOrDoNothing(); } } catch (NotSupportedException) { if (currentPath.Length == 0) { // Treat this as a container because providers that only // support the ContainerCmdletProvider interface are really // containers at their root. isContainer = true; } } finally { itemContainerContext.RemoveStopReferral(); } if (isContainer) { if (foundContainer) { // The path resolved to more than one container // Set the current working drive back to the previous // one in case it was changed. CurrentDrive = previousWorkingDrive; throw PSTraceSource.NewArgumentException( "path", SessionStateStrings.PathResolvedToMultiple, originalPath); } else { // Set the path to use path = currentPath; // Mark it as a container pathIsContainer = true; // Mark whether or not it was provider-qualified pathIsProviderQualifiedPath = currentPathisProviderQualifiedPath; // Mark that we have already found one container. Finding additional // should be an error foundContainer = true; } } } if (pathIsContainer) { // Remove the root slash since it is implied that the // current working directory is relative to the root. if (!LocationGlobber.IsProviderDirectPath(path) && path.StartsWith(StringLiterals.DefaultPathSeparator) && !pathIsProviderQualifiedPath) { path = path.Substring(1); } s_tracer.WriteLine( "New working path = {0}", path); CurrentDrive.CurrentLocation = path; } else { // Set the current working drive back to the previous // one in case it was changed. CurrentDrive = previousWorkingDrive; throw new ItemNotFoundException( originalPath, "PathNotFound", SessionStateStrings.PathNotFound); } // Now make sure the current drive is set in the provider's // current working drive hashtable ProvidersCurrentWorkingDrive[CurrentDrive.Provider] = CurrentDrive; // Set the $PWD variable to the new location this.SetVariable(SpecialVariables.PWDVarPath, this.CurrentLocation, false, true, CommandOrigin.Internal); // If an action has been defined for location changes, invoke it now. if (PublicSessionState.InvokeCommand.LocationChangedAction != null) { var eventArgs = new LocationChangedEventArgs(PublicSessionState, current, CurrentLocation); PublicSessionState.InvokeCommand.LocationChangedAction.Invoke(ExecutionContext.CurrentRunspace, eventArgs); s_tracer.WriteLine("Invoked LocationChangedAction"); } return(this.CurrentLocation); }
internal bool IsCurrentLocationOrAncestor(string path, CmdletProviderContext context) { bool flag = false; if (path == null) { throw PSTraceSource.NewArgumentNullException("path"); } PSDriveInfo drive = null; ProviderInfo provider = null; string strA = this.Globber.GetProviderPath(path, context, out provider, out drive); if (drive != null) { tracer.WriteLine("Tracing drive", new object[0]); drive.Trace(); } if (drive != null) { context.Drive = drive; } if (drive == this.CurrentDrive) { CmdletProviderContext context2 = new CmdletProviderContext(context); try { strA = this.NormalizeRelativePath(path, null, context2); } catch (NotSupportedException) { } catch (LoopFlowException) { throw; } catch (PipelineStoppedException) { throw; } catch (ActionPreferenceStopException) { throw; } finally { context2.RemoveStopReferral(); } if (context2.HasErrors()) { context2.ThrowFirstErrorOrDoNothing(); } tracer.WriteLine("Provider path = {0}", new object[] { strA }); PSDriveInfo info3 = null; ProviderInfo info4 = null; string strB = this.Globber.GetProviderPath(".", context, out info4, out info3); tracer.WriteLine("Current working path = {0}", new object[] { strB }); tracer.WriteLine("Comparing {0} to {1}", new object[] { strA, strB }); if (string.Compare(strA, strB, true, Thread.CurrentThread.CurrentCulture) == 0) { tracer.WriteLine("The path is the current working directory", new object[0]); flag = true; } else { string str3 = strB; while (str3.Length > 0) { str3 = this.GetParentPath(drive.Provider, str3, string.Empty, context); tracer.WriteLine("Comparing {0} to {1}", new object[] { str3, strA }); if (string.Compare(str3, strA, true, Thread.CurrentThread.CurrentCulture) == 0) { tracer.WriteLine("The path is a parent of the current working directory: {0}", new object[] { str3 }); flag = true; break; } } } } else { tracer.WriteLine("Drives are not the same", new object[0]); } tracer.WriteLine("result = {0}", new object[] { flag }); return flag; }
internal string NormalizeRelativePath(string path, string basePath, CmdletProviderContext context) { string str2; if (path == null) { throw PSTraceSource.NewArgumentNullException("path"); } CmdletProviderContext context2 = new CmdletProviderContext(context); try { PSDriveInfo drive = null; ProviderInfo provider = null; string str = this.Globber.GetProviderPath(path, context2, out provider, out drive); if (context2.HasErrors()) { context2.WriteErrorsToContext(context); return null; } if ((str == null) || (provider == null)) { Exception exception = PSTraceSource.NewArgumentException("path"); context.WriteError(new ErrorRecord(exception, "NormalizePathNullResult", ErrorCategory.InvalidArgument, path)); return null; } if (drive != null) { context.Drive = drive; if (((this.GetProviderInstance(provider) is NavigationCmdletProvider) && !string.IsNullOrEmpty(drive.Root)) && path.StartsWith(drive.Root, StringComparison.OrdinalIgnoreCase)) { str = path; } } str2 = this.NormalizeRelativePath(provider, str, basePath, context); } finally { context2.RemoveStopReferral(); } return str2; }
internal string GetParentPath(string path, string root, CmdletProviderContext context, bool useDefaultProvider) { string str4; if (path == null) { throw PSTraceSource.NewArgumentNullException("path"); } CmdletProviderContext context2 = new CmdletProviderContext(context); try { PSDriveInfo drive = null; ProviderInfo provider = null; try { this.Globber.GetProviderPath(path, context2, out provider, out drive); } catch (System.Management.Automation.DriveNotFoundException) { if (!useDefaultProvider) { throw; } provider = this.PublicSessionState.Internal.GetSingleProvider("FileSystem"); } if (context2.HasErrors()) { context2.WriteErrorsToContext(context); return null; } if (drive != null) { context.Drive = drive; } bool isProviderQualified = false; bool isDriveQualified = false; string qualifier = null; string str2 = this.RemoveQualifier(path, out qualifier, out isProviderQualified, out isDriveQualified); string str3 = this.GetParentPath(provider, str2, root, context); if (!string.IsNullOrEmpty(qualifier) && !string.IsNullOrEmpty(str3)) { str3 = this.AddQualifier(str3, qualifier, isProviderQualified, isDriveQualified); } tracer.WriteLine("result = {0}", new object[] { str3 }); str4 = str3; } finally { context2.RemoveStopReferral(); } return str4; }
private PSDriveInfo AutomountFileSystemDrive(DriveInfo systemDriveInfo) { PSDriveInfo newDrive = null; if (!this.IsProviderLoaded(this.ExecutionContext.ProviderNames.FileSystem)) { tracer.WriteLine("The {0} provider is not loaded", new object[] { this.ExecutionContext.ProviderNames.FileSystem }); return newDrive; } try { DriveCmdletProvider driveProviderInstance = this.GetDriveProviderInstance(this.ExecutionContext.ProviderNames.FileSystem); if (driveProviderInstance == null) { return newDrive; } string name = OSHelper.IsUnix ? systemDriveInfo.Name : systemDriveInfo.Name.Substring(0, 1); string description = string.Empty; try { description = systemDriveInfo.VolumeLabel; } catch (UnauthorizedAccessException) { } PSDriveInfo drive = new PSDriveInfo(name, driveProviderInstance.ProviderInfo, systemDriveInfo.RootDirectory.FullName, description, null) { IsAutoMounted = true }; CmdletProviderContext context = new CmdletProviderContext(this.ExecutionContext); drive.DriveBeingCreated = true; newDrive = this.ValidateDriveWithProvider(driveProviderInstance, drive, context, false); drive.DriveBeingCreated = false; if ((newDrive != null) && !context.HasErrors()) { this._globalScope.NewDrive(newDrive); } } catch (LoopFlowException) { throw; } catch (PipelineStoppedException) { throw; } catch (ActionPreferenceStopException) { throw; } catch (Exception exception) { CommandProcessorBase.CheckForSevereException(exception); MshLog.LogProviderHealthEvent(this.ExecutionContext, this.ExecutionContext.ProviderNames.FileSystem, exception, Severity.Warning); } return newDrive; }
} // AutomountFileSystemDrive private PSDriveInfo AutomountFileSystemDrive(System.IO.DriveInfo systemDriveInfo) { PSDriveInfo result = null; if (!IsProviderLoaded(this.ExecutionContext.ProviderNames.FileSystem)) { s_tracer.WriteLine("The {0} provider is not loaded", this.ExecutionContext.ProviderNames.FileSystem); return null; } // Since the drive does exist, add it. try { // Get the FS provider DriveCmdletProvider driveProvider = GetDriveProviderInstance(this.ExecutionContext.ProviderNames.FileSystem); if (driveProvider != null) { // Create a new drive string systemDriveName = systemDriveInfo.Name.Substring(0, 1); string volumeLabel = String.Empty; string displayRoot = null; try { // When run in an AppContainer, we may not have access to the volume label. volumeLabel = systemDriveInfo.VolumeLabel; } catch (UnauthorizedAccessException) { } // Get the actual root path for Network type drives if (systemDriveInfo.DriveType == DriveType.Network) { try { displayRoot = Microsoft.PowerShell.Commands.FileSystemProvider .GetRootPathForNetworkDriveOrDosDevice(systemDriveInfo); } // We want to get root path of the network drive as extra information to display to the user. // It's okay we failed to get the root path for some reason. We don't want to throw exception // here as it would break the current behavior. catch (Win32Exception) { } catch (InvalidOperationException) { } } PSDriveInfo newPSDriveInfo = new PSDriveInfo( systemDriveName, driveProvider.ProviderInfo, systemDriveInfo.RootDirectory.FullName, volumeLabel, null, displayRoot); newPSDriveInfo.IsAutoMounted = true; CmdletProviderContext context = new CmdletProviderContext(this.ExecutionContext); newPSDriveInfo.DriveBeingCreated = true; // Validate the drive with the provider result = ValidateDriveWithProvider(driveProvider, newPSDriveInfo, context, false); newPSDriveInfo.DriveBeingCreated = false; if (result != null && !context.HasErrors()) { // Create the drive in the global scope. GlobalScope.NewDrive(result); } } } catch (LoopFlowException) { throw; } catch (PipelineStoppedException) { throw; } catch (ActionPreferenceStopException) { throw; } catch (Exception e) { CommandProcessorBase.CheckForSevereException(e); // Since the user isn't expecting this behavior, we don't // want to let errors find their way out. If there are any // failures we just don't mount the drive. MshLog.LogProviderHealthEvent( this.ExecutionContext, this.ExecutionContext.ProviderNames.FileSystem, e, Severity.Warning); } return result; } // AutomountFileSystemDrive
private Collection<PSObject> GetChildNamesInDir(string dir, string leafElement, bool getAllContainers, CmdletProviderContext context, bool dirIsProviderPath, PSDriveInfo drive, ContainerCmdletProvider provider, out string modifiedDirPath) { string updatedPath = null; string updatedFilter = null; Collection<PSObject> collection4; string filter = context.Filter; bool flag = provider.ConvertPath(leafElement, context.Filter, ref updatedPath, ref updatedFilter, context); if (flag) { tracer.WriteLine("Provider converted path and filter.", new object[0]); tracer.WriteLine("Original path: " + leafElement, new object[0]); tracer.WriteLine("Converted path: " + updatedPath, new object[0]); tracer.WriteLine("Original filter: " + context.Filter, new object[0]); tracer.WriteLine("Converted filter: " + updatedFilter, new object[0]); leafElement = updatedPath; context.Filter = updatedFilter; } ReturnContainers returnAllContainers = ReturnContainers.ReturnAllContainers; if (!getAllContainers) { returnAllContainers = ReturnContainers.ReturnMatchingContainers; } CmdletProviderContext context2 = new CmdletProviderContext(context); context2.SetFilters(new Collection<string>(), new Collection<string>(), context.Filter); try { string path = null; modifiedDirPath = null; if (dirIsProviderPath) { modifiedDirPath = path = context.SuppressWildcardExpansion ? dir : RemoveGlobEscaping(dir); } else { modifiedDirPath = GetMshQualifiedPath(dir, drive); ProviderInfo info = null; CmdletProvider providerInstance = null; Collection<string> collection = this.GetGlobbedProviderPathsFromMonadPath(modifiedDirPath, false, context2, out info, out providerInstance); modifiedDirPath = context.SuppressWildcardExpansion ? modifiedDirPath : RemoveGlobEscaping(modifiedDirPath); if (collection.Count > 0) { path = collection[0]; } else { if (flag) { context.Filter = filter; } return new Collection<PSObject>(); } } if (provider.HasChildItems(path, context2)) { provider.GetChildNames(path, returnAllContainers, context2); } if (context2.HasErrors()) { Collection<ErrorRecord> accumulatedErrorObjects = context2.GetAccumulatedErrorObjects(); if ((accumulatedErrorObjects != null) && (accumulatedErrorObjects.Count > 0)) { foreach (ErrorRecord record in accumulatedErrorObjects) { context.WriteError(record); } } } Collection<PSObject> accumulatedObjects = context2.GetAccumulatedObjects(); if (flag) { context.Filter = filter; } collection4 = accumulatedObjects; } finally { context2.RemoveStopReferral(); } return collection4; }
internal PathInfo SetLocation (string path, CmdletProviderContext context) { if (string.IsNullOrEmpty (path) && OSHelper.IsUnix) path = "/"; else if (path == null) { throw PSTraceSource.NewArgumentNullException ("path"); } string str = path; string driveName = null; ProviderInfo provider = null; string providerId = null; PSDriveInfo currentDrive = this.CurrentDrive; if (LocationGlobber.IsHomePath (path)) { path = this.Globber.GetHomeRelativePath (path); } if (LocationGlobber.IsProviderDirectPath (path)) { provider = this.CurrentLocation.Provider; PSDriveInfo drive = null; if (PathIntrinsics.FinDriveFromPath (path, provider, out drive)) { this.CurrentDrive = drive; } else if (LocationGlobber.IsProviderQualifiedPath (path, out providerId)) { provider = this.GetSingleProvider (providerId); if (PathIntrinsics.FinDriveFromPath (path, provider, out drive)) { this.CurrentDrive = drive; } else if (this.Globber.IsAbsolutePath(path, out driveName)) { drive = this.GetDrive(driveName); this.CurrentDrive = drive; } } } else if (LocationGlobber.IsProviderQualifiedPath (path, out providerId)) { provider = this.GetSingleProvider (providerId); PSDriveInfo drive = null; if (PathIntrinsics.FinDriveFromPath (path, provider, out drive)) { this.CurrentDrive = drive; } else if (this.Globber.IsAbsolutePath(path, out driveName)) { drive = this.GetDrive(driveName); this.CurrentDrive = drive; } } else if (this.Globber.IsAbsolutePath(path, out driveName)) { PSDriveInfo drive = this.GetDrive(driveName); this.CurrentDrive = drive; } if (context == null) { context = new CmdletProviderContext(this.ExecutionContext); } if (this.CurrentDrive != null) { context.Drive = this.CurrentDrive; } CmdletProvider providerInstance = null; Collection<PathInfo> collection = null; try { collection = this.Globber.GetGlobbedMonadPathsFromMonadPath(path, false, context, out providerInstance); } catch (LoopFlowException) { throw; } catch (PipelineStoppedException) { throw; } catch (ActionPreferenceStopException) { throw; } catch (Exception exception) { CommandProcessorBase.CheckForSevereException(exception); this.CurrentDrive = currentDrive; throw; } if (collection.Count == 0) { this.CurrentDrive = currentDrive; throw new ItemNotFoundException(path, "PathNotFound", SessionStateStrings.PathNotFound); } bool flag = false; bool flag2 = false; bool flag3 = false; bool flag4 = false; for (int i = 0; i < collection.Count; i++) { CmdletProviderContext context2 = new CmdletProviderContext(context); PathInfo info4 = collection[i]; string str4 = path; try { string str5 = null; flag4 = LocationGlobber.IsProviderQualifiedPath(info4.Path, out str5); if (flag4) { string str6 = LocationGlobber.RemoveProviderQualifier(info4.Path); try { str4 = this.NormalizeRelativePath(this.GetSingleProvider(str5), str6, string.Empty, context2); goto Label_01DF; } catch (NotSupportedException) { goto Label_01DF; } catch (LoopFlowException) { throw; } catch (PipelineStoppedException) { throw; } catch (ActionPreferenceStopException) { throw; } catch (Exception exception2) { CommandProcessorBase.CheckForSevereException(exception2); this.CurrentDrive = currentDrive; throw; } } try { str4 = this.NormalizeRelativePath(info4.Path, this.CurrentDrive.Root, context2); } catch (NotSupportedException) { } catch (LoopFlowException) { throw; } catch (PipelineStoppedException) { throw; } catch (ActionPreferenceStopException) { throw; } catch (Exception exception3) { CommandProcessorBase.CheckForSevereException(exception3); this.CurrentDrive = currentDrive; throw; } Label_01DF: if (context2.HasErrors()) { this.CurrentDrive = currentDrive; context2.ThrowFirstErrorOrDoNothing(); } } finally { context2.RemoveStopReferral(); } bool flag5 = false; CmdletProviderContext context3 = new CmdletProviderContext(context) { SuppressWildcardExpansion = true }; try { flag5 = this.IsItemContainer(info4.Path, context3); if (context3.HasErrors()) { this.CurrentDrive = currentDrive; context3.ThrowFirstErrorOrDoNothing(); } } catch (NotSupportedException) { if (str4.Length == 0) { flag5 = true; } } finally { context3.RemoveStopReferral(); } if (flag5) { if (flag) { this.CurrentDrive = currentDrive; throw PSTraceSource.NewArgumentException("path", "SessionStateStrings", "PathResolvedToMultiple", new object[] { str }); } path = str4; flag2 = true; flag3 = flag4; flag = true; } } if (flag2) { if (!OSHelper.IsUnix) { if (!LocationGlobber.IsProviderDirectPath(path)) { char ch = '\\'; if (path.StartsWith(ch.ToString(), StringComparison.CurrentCulture) && !flag3) { path = path.Substring(1); } } } tracer.WriteLine("New working path = {0}", new object[] { path }); this.CurrentDrive.CurrentLocation = path; } else { this.CurrentDrive = currentDrive; throw new ItemNotFoundException(str, "PathNotFound", SessionStateStrings.PathNotFound); } this.ProvidersCurrentWorkingDrive[this.CurrentDrive.Provider] = this.CurrentDrive; this.SetVariable(SpecialVariables.PWDVarPath, this.CurrentLocation, false, true, CommandOrigin.Internal); return this.CurrentLocation; }
} // SetLocation /// <summary> /// Changes the current working directory to the path specified /// </summary> /// /// <param name="path"> /// The path of the new current working directory /// </param> /// /// <param name="context"> /// The context the provider uses when performing the operation. /// </param> /// /// <returns> /// The PathInfo object representing the path of the location /// that was set. /// </returns> /// /// <exception cref="ArgumentNullException"> /// If <paramref name="path"/> is null. /// </exception> /// /// <exception cref="ArgumentException"> /// If <paramref name="path"/> does not exist, is not a container, or /// resolved to multiple containers. /// </exception> /// /// <exception cref="ProviderNotFoundException"> /// If <paramref name="path"/> refers to a provider that does not exist. /// </exception> /// /// <exception cref="DriveNotFoundException"> /// If <paramref name="path"/> refers to a drive that does not exist. /// </exception> /// /// <exception cref="ProviderInvocationException"> /// If the provider associated with <paramref name="path"/> threw an /// exception. /// </exception> /// /// <exception cref="ItemNotFoundException"> /// If the <paramref name="path"/> could not be resolved. /// </exception> /// internal PathInfo SetLocation(string path, CmdletProviderContext context) { if (path == null) { throw PSTraceSource.NewArgumentNullException("path"); } string originalPath = path; string driveName = null; ProviderInfo provider = null; string providerId = null; PSDriveInfo previousWorkingDrive = CurrentDrive; // First check to see if the path is a home path if (LocationGlobber.IsHomePath(path)) { path = Globber.GetHomeRelativePath(path); } if (LocationGlobber.IsProviderDirectPath(path)) { // The path is a provider-direct path so use the current // provider and its hidden drive but don't modify the path // at all. provider = CurrentLocation.Provider; CurrentDrive = provider.HiddenDrive; } else if (LocationGlobber.IsProviderQualifiedPath(path, out providerId)) { provider = GetSingleProvider(providerId); CurrentDrive = provider.HiddenDrive; } else { // See if the path is a relative or absolute // path. if (Globber.IsAbsolutePath(path, out driveName)) { // Since the path is an absolute path // we need to change the current working // drive PSDriveInfo newWorkingDrive = GetDrive(driveName); CurrentDrive = newWorkingDrive; // Now that the current working drive is set, // process the rest of the path as a relative path. } } if (context == null) { context = new CmdletProviderContext(this.ExecutionContext); } if (CurrentDrive != null) { context.Drive = CurrentDrive; } CmdletProvider providerInstance = null; Collection <PathInfo> workingPath = null; try { workingPath = Globber.GetGlobbedMonadPathsFromMonadPath( path, false, context, out providerInstance); } catch (LoopFlowException) { throw; } catch (PipelineStoppedException) { throw; } catch (ActionPreferenceStopException) { throw; } catch (Exception) // Catch-all OK, 3rd party callout { // Reset the drive to the previous drive and // then rethrow the error CurrentDrive = previousWorkingDrive; throw; } if (workingPath.Count == 0) { // Set the current working drive back to the previous // one in case it was changed. CurrentDrive = previousWorkingDrive; throw new ItemNotFoundException( path, "PathNotFound", SessionStateStrings.PathNotFound); } // We allow globbing the location as long as it only resolves a single container. bool foundContainer = false; bool pathIsContainer = false; bool pathIsProviderQualifiedPath = false; bool currentPathisProviderQualifiedPath = false; for (int index = 0; index < workingPath.Count; ++index) { CmdletProviderContext normalizePathContext = new CmdletProviderContext(context); PathInfo resolvedPath = workingPath[index]; string currentPath = path; try { string providerName = null; currentPathisProviderQualifiedPath = LocationGlobber.IsProviderQualifiedPath(resolvedPath.Path, out providerName); if (currentPathisProviderQualifiedPath) { // The path should be the provider-qualified path without the provider ID // or :: string providerInternalPath = LocationGlobber.RemoveProviderQualifier(resolvedPath.Path); try { currentPath = NormalizeRelativePath(GetSingleProvider(providerName), providerInternalPath, String.Empty, normalizePathContext); } catch (NotSupportedException) { // Since the provider does not support normalizing the path, just // use the path we currently have. } catch (LoopFlowException) { throw; } catch (PipelineStoppedException) { throw; } catch (ActionPreferenceStopException) { throw; } catch (Exception) // Catch-all OK, 3rd party callout { // Reset the drive to the previous drive and // then rethrow the error CurrentDrive = previousWorkingDrive; throw; } } else { try { currentPath = NormalizeRelativePath(resolvedPath.Path, CurrentDrive.Root, normalizePathContext); } catch (NotSupportedException) { // Since the provider does not support normalizing the path, just // use the path we currently have. } catch (LoopFlowException) { throw; } catch (PipelineStoppedException) { throw; } catch (ActionPreferenceStopException) { throw; } catch (Exception) // Catch-all OK, 3rd party callout { // Reset the drive to the previous drive and // then rethrow the error CurrentDrive = previousWorkingDrive; throw; } } // Now see if there was errors while normalizing the path if (normalizePathContext.HasErrors()) { // Set the current working drive back to the previous // one in case it was changed. CurrentDrive = previousWorkingDrive; normalizePathContext.ThrowFirstErrorOrDoNothing(); } } finally { normalizePathContext.RemoveStopReferral(); } // Check to see if the path is a container bool isContainer = false; CmdletProviderContext itemContainerContext = new CmdletProviderContext(context); itemContainerContext.SuppressWildcardExpansion = true; try { isContainer = IsItemContainer( resolvedPath.Path, itemContainerContext); if (itemContainerContext.HasErrors()) { // Set the current working drive back to the previous // one in case it was changed. CurrentDrive = previousWorkingDrive; itemContainerContext.ThrowFirstErrorOrDoNothing(); } } catch (NotSupportedException) { if (currentPath.Length == 0) { // Treat this as a container because providers that only // support the ContainerCmdletProvider interface are really // containers at their root. isContainer = true; } } finally { itemContainerContext.RemoveStopReferral(); } if (isContainer) { if (foundContainer) { // The path resolved to more than one container // Set the current working drive back to the previous // one in case it was changed. CurrentDrive = previousWorkingDrive; throw PSTraceSource.NewArgumentException( "path", SessionStateStrings.PathResolvedToMultiple, originalPath); } else { // Set the path to use path = currentPath; // Mark it as a container pathIsContainer = true; // Mark whether or not it was provider-qualified pathIsProviderQualifiedPath = currentPathisProviderQualifiedPath; // Mark that we have already found one container. Finding additional // should be an error foundContainer = true; } } } if (pathIsContainer) { // Remove the root slash since it is implied that the // current working directory is relative to the root. if (!LocationGlobber.IsProviderDirectPath(path) && path.StartsWith(StringLiterals.DefaultPathSeparatorString, StringComparison.CurrentCulture) && !pathIsProviderQualifiedPath) { path = path.Substring(1); } s_tracer.WriteLine( "New working path = {0}", path); CurrentDrive.CurrentLocation = path; } else { // Set the current working drive back to the previous // one in case it was changed. CurrentDrive = previousWorkingDrive; throw new ItemNotFoundException( originalPath, "PathNotFound", SessionStateStrings.PathNotFound); } // Now make sure the current drive is set in the provider's // current working drive hashtable ProvidersCurrentWorkingDrive[CurrentDrive.Provider] = CurrentDrive; // Set the $PWD variable to the new location this.SetVariable(SpecialVariables.PWDVarPath, this.CurrentLocation, false, true, CommandOrigin.Internal); return(this.CurrentLocation); } // SetLocation
} // SetLocation /// <summary> /// Changes the current working directory to the path specified /// </summary> /// /// <param name="path"> /// The path of the new current working directory /// </param> /// /// <param name="context"> /// The context the provider uses when performing the operation. /// </param> /// /// <returns> /// The PathInfo object representing the path of the location /// that was set. /// </returns> /// /// <exception cref="ArgumentNullException"> /// If <paramref name="path"/> is null. /// </exception> /// /// <exception cref="ArgumentException"> /// If <paramref name="path"/> does not exist, is not a container, or /// resolved to multiple containers. /// </exception> /// /// <exception cref="ProviderNotFoundException"> /// If <paramref name="path"/> refers to a provider that does not exist. /// </exception> /// /// <exception cref="DriveNotFoundException"> /// If <paramref name="path"/> refers to a drive that does not exist. /// </exception> /// /// <exception cref="ProviderInvocationException"> /// If the provider associated with <paramref name="path"/> threw an /// exception. /// </exception> /// /// <exception cref="ItemNotFoundException"> /// If the <paramref name="path"/> could not be resolved. /// </exception> /// internal PathInfo SetLocation(string path, CmdletProviderContext context) { if (path == null) { throw PSTraceSource.NewArgumentNullException("path"); } string originalPath = path; string driveName = null; ProviderInfo provider = null; string providerId = null; PSDriveInfo previousWorkingDrive = CurrentDrive; // First check to see if the path is a home path if (LocationGlobber.IsHomePath(path)) { path = Globber.GetHomeRelativePath(path); } if (LocationGlobber.IsProviderDirectPath(path)) { // The path is a provider-direct path so use the current // provider and its hidden drive but don't modify the path // at all. provider = CurrentLocation.Provider; CurrentDrive = provider.HiddenDrive; } else if (LocationGlobber.IsProviderQualifiedPath(path, out providerId)) { provider = GetSingleProvider(providerId); CurrentDrive = provider.HiddenDrive; } else { // See if the path is a relative or absolute // path. if (Globber.IsAbsolutePath(path, out driveName)) { // Since the path is an absolute path // we need to change the current working // drive PSDriveInfo newWorkingDrive = GetDrive(driveName); CurrentDrive = newWorkingDrive; // Now that the current working drive is set, // process the rest of the path as a relative path. } } if (context == null) { context = new CmdletProviderContext(this.ExecutionContext); } if (CurrentDrive != null) { context.Drive = CurrentDrive; } CmdletProvider providerInstance = null; Collection<PathInfo> workingPath = null; try { workingPath = Globber.GetGlobbedMonadPathsFromMonadPath( path, false, context, out providerInstance); } catch (LoopFlowException) { throw; } catch (PipelineStoppedException) { throw; } catch (ActionPreferenceStopException) { throw; } catch (Exception e) // Catch-all OK, 3rd party callout { CommandProcessorBase.CheckForSevereException(e); // Reset the drive to the previous drive and // then rethrow the error CurrentDrive = previousWorkingDrive; throw; } if (workingPath.Count == 0) { // Set the current working drive back to the previous // one in case it was changed. CurrentDrive = previousWorkingDrive; throw new ItemNotFoundException( path, "PathNotFound", SessionStateStrings.PathNotFound); } // We allow globbing the location as long as it only resolves a single container. bool foundContainer = false; bool pathIsContainer = false; bool pathIsProviderQualifiedPath = false; bool currentPathisProviderQualifiedPath = false; for (int index = 0; index < workingPath.Count; ++index) { CmdletProviderContext normalizePathContext = new CmdletProviderContext(context); PathInfo resolvedPath = workingPath[index]; string currentPath = path; try { string providerName = null; currentPathisProviderQualifiedPath = LocationGlobber.IsProviderQualifiedPath(resolvedPath.Path, out providerName); if (currentPathisProviderQualifiedPath) { // The path should be the provider-qualified path without the provider ID // or :: string providerInternalPath = LocationGlobber.RemoveProviderQualifier(resolvedPath.Path); try { currentPath = NormalizeRelativePath(GetSingleProvider(providerName), providerInternalPath, String.Empty, normalizePathContext); } catch (NotSupportedException) { // Since the provider does not support normalizing the path, just // use the path we currently have. } catch (LoopFlowException) { throw; } catch (PipelineStoppedException) { throw; } catch (ActionPreferenceStopException) { throw; } catch (Exception e) // Catch-all OK, 3rd party callout { CommandProcessorBase.CheckForSevereException(e); // Reset the drive to the previous drive and // then rethrow the error CurrentDrive = previousWorkingDrive; throw; } } else { try { currentPath = NormalizeRelativePath(resolvedPath.Path, CurrentDrive.Root, normalizePathContext); } catch (NotSupportedException) { // Since the provider does not support normalizing the path, just // use the path we currently have. } catch (LoopFlowException) { throw; } catch (PipelineStoppedException) { throw; } catch (ActionPreferenceStopException) { throw; } catch (Exception e) // Catch-all OK, 3rd party callout { CommandProcessorBase.CheckForSevereException(e); // Reset the drive to the previous drive and // then rethrow the error CurrentDrive = previousWorkingDrive; throw; } } // Now see if there was errors while normalizing the path if (normalizePathContext.HasErrors()) { // Set the current working drive back to the previous // one in case it was changed. CurrentDrive = previousWorkingDrive; normalizePathContext.ThrowFirstErrorOrDoNothing(); } } finally { normalizePathContext.RemoveStopReferral(); } // Check to see if the path is a container bool isContainer = false; CmdletProviderContext itemContainerContext = new CmdletProviderContext(context); itemContainerContext.SuppressWildcardExpansion = true; try { isContainer = IsItemContainer( resolvedPath.Path, itemContainerContext); if (itemContainerContext.HasErrors()) { // Set the current working drive back to the previous // one in case it was changed. CurrentDrive = previousWorkingDrive; itemContainerContext.ThrowFirstErrorOrDoNothing(); } } catch (NotSupportedException) { if (currentPath.Length == 0) { // Treat this as a container because providers that only // support the ContainerCmdletProvider interface are really // containers at their root. isContainer = true; } } finally { itemContainerContext.RemoveStopReferral(); } if (isContainer) { if (foundContainer) { // The path resolved to more than one container // Set the current working drive back to the previous // one in case it was changed. CurrentDrive = previousWorkingDrive; throw PSTraceSource.NewArgumentException( "path", SessionStateStrings.PathResolvedToMultiple, originalPath); } else { // Set the path to use path = currentPath; // Mark it as a container pathIsContainer = true; // Mark whether or not it was provider-qualified pathIsProviderQualifiedPath = currentPathisProviderQualifiedPath; // Mark that we have already found one container. Finding additional // should be an error foundContainer = true; } } } if (pathIsContainer) { // Remove the root slash since it is implied that the // current working directory is relative to the root. if (!LocationGlobber.IsProviderDirectPath(path) && path.StartsWith(StringLiterals.DefaultPathSeparatorString, StringComparison.CurrentCulture) && !pathIsProviderQualifiedPath) { path = path.Substring(1); } s_tracer.WriteLine( "New working path = {0}", path); CurrentDrive.CurrentLocation = path; } else { // Set the current working drive back to the previous // one in case it was changed. CurrentDrive = previousWorkingDrive; throw new ItemNotFoundException( originalPath, "PathNotFound", SessionStateStrings.PathNotFound); } // Now make sure the current drive is set in the provider's // current working drive hashtable ProvidersCurrentWorkingDrive[CurrentDrive.Provider] = CurrentDrive; // Set the $PWD variable to the new location this.SetVariable(SpecialVariables.PWDVarPath, this.CurrentLocation, false, true, CommandOrigin.Internal); return this.CurrentLocation; } // SetLocation
/// <summary> /// Determines if the specified path is the current working directory /// or a parent of the current working directory. /// </summary> /// <param name="path"> /// A monad namespace absolute or relative path. /// </param> /// <param name="context"> /// The context the provider uses when performing the operation. /// </param> /// <returns> /// true, if the path is the current working directory or a parent of the current /// working directory. false, otherwise. /// </returns> /// <exception cref="ArgumentNullException"> /// If <paramref name="path"/> is null. /// </exception> /// <exception cref="ProviderNotFoundException"> /// If the path is a provider-qualified path for a provider that is /// not loaded into the system. /// </exception> /// <exception cref="DriveNotFoundException"> /// If the <paramref name="path"/> refers to a drive that could not be found. /// </exception> /// <exception cref="ProviderInvocationException"> /// If the provider used to build the path threw an exception. /// </exception> /// <exception cref="NotSupportedException"> /// If the provider that the <paramref name="path"/> represents is not a NavigationCmdletProvider /// or ContainerCmdletProvider. /// </exception> /// <exception cref="InvalidOperationException"> /// If the <paramref name="path"/> starts with "~" and the home location is not set for /// the provider. /// </exception> /// <exception cref="ProviderInvocationException"> /// If the provider specified by <paramref name="providerId"/> threw an /// exception when its GetParentPath or MakePath was called while /// processing the <paramref name="path"/>. /// </exception> internal bool IsCurrentLocationOrAncestor(string path, CmdletProviderContext context) { bool result = false; if (path == null) { throw PSTraceSource.NewArgumentNullException("path"); } PSDriveInfo drive = null; ProviderInfo provider = null; string providerSpecificPath = Globber.GetProviderPath( path, context, out provider, out drive); if (drive != null) { s_tracer.WriteLine("Tracing drive"); drive.Trace(); } Dbg.Diagnostics.Assert( providerSpecificPath != null, "There should always be a way to generate a provider path for a " + "given path"); if (drive != null) { context.Drive = drive; } // Check to see if the path that was specified is within the current // working drive if (drive == CurrentDrive) { // The path needs to be normalized to get rid of relative path tokens // so they don't interfere with our path comparisons below CmdletProviderContext normalizePathContext = new CmdletProviderContext(context); try { providerSpecificPath = NormalizeRelativePath(path, null, normalizePathContext); } catch (NotSupportedException) { // Since the provider does not support normalizing the path, just // use the path we currently have. } catch (LoopFlowException) { throw; } catch (PipelineStoppedException) { throw; } catch (ActionPreferenceStopException) { throw; } finally { normalizePathContext.RemoveStopReferral(); } if (normalizePathContext.HasErrors()) { normalizePathContext.ThrowFirstErrorOrDoNothing(); } s_tracer.WriteLine("Provider path = {0}", providerSpecificPath); // Get the current working directory provider specific path PSDriveInfo currentWorkingDrive = null; ProviderInfo currentDriveProvider = null; string currentWorkingPath = Globber.GetProviderPath( ".", context, out currentDriveProvider, out currentWorkingDrive); Dbg.Diagnostics.Assert( currentWorkingDrive == CurrentDrive, "The current working drive should be the CurrentDrive."); s_tracer.WriteLine( "Current working path = {0}", currentWorkingPath); // See if the path is the current working directory or a parent // of the current working directory s_tracer.WriteLine( "Comparing {0} to {1}", providerSpecificPath, currentWorkingPath); if (String.Compare(providerSpecificPath, currentWorkingPath, StringComparison.CurrentCultureIgnoreCase) == 0) { // The path is the current working directory so // return true s_tracer.WriteLine("The path is the current working directory"); result = true; } else { // Check to see if the specified path is a parent // of the current working directory string lockedDirectory = currentWorkingPath; while (lockedDirectory.Length > 0) { // We need to allow the provider to go as far up the tree // as it can even if that means it has to traverse higher // than the mount point for this drive. That is // why we are passing the empty string as the root here. lockedDirectory = GetParentPath( drive.Provider, lockedDirectory, String.Empty, context); s_tracer.WriteLine( "Comparing {0} to {1}", lockedDirectory, providerSpecificPath); if (String.Compare(lockedDirectory, providerSpecificPath, StringComparison.CurrentCultureIgnoreCase) == 0) { // The path is a parent of the current working // directory s_tracer.WriteLine( "The path is a parent of the current working directory: {0}", lockedDirectory); result = true; break; } } } } else { s_tracer.WriteLine("Drives are not the same"); } return(result); }
/// <summary> /// Gets the path to the parent object for the given object. /// Allow to use FileSystem as the default provider when the /// given path is drive-qualified and the drive cannot be found. /// </summary> /// /// <param name="path"> /// The path to the object to get the parent path from /// </param> /// /// <param name="root"> /// The root of the drive. Namespace providers should /// return the root if GetParentPath is called for the root. /// </param> /// /// <param name="context"> /// The context which the core command is running. /// </param> /// /// <param name="useDefaultProvider"> /// Specify whether to use default provider when needed. /// </param> /// /// <returns> /// The path to the parent object /// </returns> internal string GetParentPath( string path, string root, CmdletProviderContext context, bool useDefaultProvider) { if (path == null) { throw PSTraceSource.NewArgumentNullException("path"); } CmdletProviderContext getProviderPathContext = new CmdletProviderContext(context); try { PSDriveInfo drive = null; ProviderInfo provider = null; try { Globber.GetProviderPath( path, getProviderPathContext, out provider, out drive); } catch (DriveNotFoundException) { // the path is sure to be drive_qualified and it is absolute path, otherwise the // drive would be set to the current drive and the DriveNotFoundException will not happen if (useDefaultProvider) { // the default provider is FileSystem provider = PublicSessionState.Internal.GetSingleProvider(Microsoft.PowerShell.Commands.FileSystemProvider.ProviderName); } else { throw; } } if (getProviderPathContext.HasErrors()) { getProviderPathContext.WriteErrorsToContext(context); return null; } if (drive != null) { context.Drive = drive; } bool isProviderQualified = false; bool isDriveQualified = false; string qualifier = null; string pathNoQualifier = RemoveQualifier(path, provider, out qualifier, out isProviderQualified, out isDriveQualified); string result = GetParentPath(provider, pathNoQualifier, root, context); if (!String.IsNullOrEmpty(qualifier) && !String.IsNullOrEmpty(result)) { result = AddQualifier(result, provider, qualifier, isProviderQualified, isDriveQualified); } return result; } finally { getProviderPathContext.RemoveStopReferral(); } } // GetParentPath