MegaBites-AI/Windows-powershell
0308
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4#pragma warning disable 1634, 16915 6using System.Threading;7using Dbg = System.Management.Automation;8 9namespace System.Management.Automation10{11 /// <summary>12 /// Defines a drive that exposes a provider path to the user.13 /// </summary>14 /// <remarks>15 /// A cmdlet provider may want to derive from this class to provide their16 /// own public members or to cache information related to the drive. For instance,17 /// if a drive is a connection to a remote machine and making that connection18 /// is expensive, then the provider may want keep a handle to the connection as19 /// a member of their derived <see cref="PSDriveInfo"/> class and use it when20 /// the provider is invoked.21 /// </remarks>22 public class PSDriveInfo : IComparable23 {24 /// <summary>25 /// An instance of the PSTraceSource class used for trace output26 /// using "SessionState" as the category.27 /// This is the same category as the SessionState tracer class.28 /// </summary>29 [Dbg.TraceSource(30 "PSDriveInfo",31 "The namespace navigation tracer")]32 private static readonly Dbg.PSTraceSource s_tracer =33 Dbg.PSTraceSource.GetTracer("PSDriveInfo",34 "The namespace navigation tracer");35 36 /// <summary>37 /// Gets or sets the current working directory for the drive.38 /// </summary>39 public string CurrentLocation40 {41 get42 {43 return _currentWorkingDirectory;44 }45 46 set47 {48 _currentWorkingDirectory = value;49 }50 }51 52 /// <summary>53 /// The current working directory for the virtual drive54 /// as a relative path from Root.55 /// </summary>56 private string _currentWorkingDirectory;57 58 /// <summary>59 /// Gets the name of the drive.60 /// </summary>61 public string Name62 {63 get64 {65 return _name;66 }67 }68 69 /// <summary>70 /// The name of the virtual drive.71 /// </summary>72 private string _name;73 74 /// <summary>75 /// Gets the name of the provider that root path76 /// of the drive represents.77 /// </summary>78 public ProviderInfo Provider79 {80 get81 {82 return _provider;83 }84 }85 86 /// <summary>87 /// The provider information for the provider that implements88 /// the functionality for the drive.89 /// </summary>90 private ProviderInfo _provider;91 92 /// <summary>93 /// Gets the root path of the drive.94 /// </summary>95 public string Root96 {97 get98 {99 return _root;100 }101 102 internal set103 {104 _root = value;105 }106 }107 108 /// <summary>109 /// Sets the root of the drive.110 /// </summary>111 /// <param name="path">112 /// The root path to set for the drive.113 /// </param>114 /// <remarks>115 /// This method can only be called during drive116 /// creation. A NotSupportedException if this method117 /// is called outside of drive creation.118 /// </remarks>119 /// <exception cref="ArgumentNullException">120 /// If <paramref name="path"/> is null.121 /// </exception>122 /// <exception cref="NotSupportedException">123 /// If this method gets called any other time except124 /// during drive creation.125 /// </exception>126 internal void SetRoot(string path)127 {128 if (path == null)129 {130 throw PSTraceSource.NewArgumentNullException(nameof(path));131 }132 133 if (!DriveBeingCreated)134 {135 NotSupportedException e =136 PSTraceSource.NewNotSupportedException();137 throw e;138 }139 140 _root = path;141 }142 143 /// <summary>144 /// The root of the virtual drive.145 /// </summary>146 private string _root;147 148 /// <summary>149 /// Gets or sets the description for the drive.150 /// </summary>151 public string Description { get; set; }152 153 /// <summary>154 /// When supported by provider this specifies a maximum drive size.155 /// </summary>156 public long? MaximumSize { get; internal set; }157 158 /// <summary>159 /// Gets the credential to use with the drive.160 /// </summary>161 public PSCredential Credential { get; } = PSCredential.Empty;162 163 /// <summary>164 /// Determines if the root of the drive can165 /// be modified during drive creation through166 /// the SetRoot method.167 /// </summary>168 /// <value>169 /// True if the drive is being created and the170 /// root can be modified through the SetRoot method.171 /// False otherwise.172 /// </value>173 internal bool DriveBeingCreated { get; set; }174 175 /// <summary>176 /// True if the drive was automounted by the system,177 /// false otherwise.178 /// </summary>179 /// <value></value>180 internal bool IsAutoMounted { get; set; }181 182 /// <summary>183 /// True if the drive was automounted by the system,184 /// and then manually removed by the user.185 /// </summary>186 internal bool IsAutoMountedManuallyRemoved { get; set; }187 188 /// <summary>189 /// Gets or sets the Persist Switch parameter.190 /// If this switch parameter is set then the created PSDrive191 /// would be persisted across PowerShell sessions.192 /// </summary>193 internal bool Persist { get; } = false;194 195 /// <summary>196 /// Get or sets the value indicating if the created drive is a network drive.197 /// </summary>198 internal bool IsNetworkDrive { get; set; } = false;199 200 /// <summary>201 /// Gets or sets the UNC path of the drive. This property would be populated only202 /// if the created PSDrive is targeting a network drive or else this property203 /// would be null.204 /// </summary>205 public string DisplayRoot { get; internal set; } = null;206 207 /// <summary>208 /// Gets or sets if the drive-root relative paths on this drive are separated by a209 /// colon or not.210 ///211 /// This is true for all PSDrives on all platforms, except for filesystems on212 /// non-Windows platforms.213 ///214 /// This is not a path separator in the sense of separating paths in a single215 /// string.216 ///217 /// The biggest difference in filesystem handling between PS internally, and Unix218 /// style systems is, that paths on Windows separate the drive letter from the219 /// actual path by a colon. The second difference is, that a path that starts with220 /// a \ or / on Windows is considered to be a relative path (drive-relative in221 /// that case) where a similar path on a Unix style filesystem would be222 /// root-relative, which is basically drive-relative for the filesystem, as there223 /// is only one filesystem drive.224 ///225 /// This property indicates, that a path can be checked for that drive-relativity226 /// by checking for a colon. The main reason for this can be seen in all the227 /// places that use this property, where PowerShell's code checks/splits/string228 /// manipulates paths according to the colon character. This happens in many229 /// places.230 ///231 /// The idea here was to introduce a property that allows a code to query if a232 /// PSDrive expects colon to be such a separator or not. I talked to Jim back then233 /// about the problem, and this seemed to be a reasonable solution, given that234 /// there is no other way to know for a PSDrive if paths can be qualified only in235 /// a certain windows way on all platforms, or need special treatment on platforms236 /// where colon does not exist as drive separator (regular filesystems on Unix237 /// platforms are the only exception).238 ///239 /// Globally this property can also be only true for one single PSDrive, because240 /// if there is no drive separator, there is also no drive, and because there is241 /// no drive there is no way to match against multiple such drives.242 ///243 /// Additional data:244 /// It seems that on single rooted filesystems, only the default245 /// drive of "/" needs to set this VolumeSeparatedByColon to false246 /// otherwise, creating new drives from the filesystem should actually247 /// have this set to true as all the drives will have <string>: except248 /// for "/"249 /// </summary>250 public bool VolumeSeparatedByColon { get; internal set; } = true;251 252 #region ctor253 254 /// <summary>255 /// Constructs a new instance of the PSDriveInfo using another PSDriveInfo256 /// as a template.257 /// </summary>258 /// <param name="driveInfo">259 /// An existing PSDriveInfo object that should be copied to this instance.260 /// </param>261 /// <remarks>262 /// A protected constructor that derived classes can call with an instance263 /// of this class. This allows for easy creation of derived PSDriveInfo objects264 /// which can be created in CmdletProvider's NewDrive method using the PSDriveInfo265 /// that is passed in.266 /// </remarks>267 /// <exception cref="ArgumentNullException">268 /// If <paramref name="PSDriveInfo"/> is null.269 /// </exception>270 protected PSDriveInfo(PSDriveInfo driveInfo)271 {272 if (driveInfo == null)273 {274 throw PSTraceSource.NewArgumentNullException(nameof(driveInfo));275 }276 277 _name = driveInfo.Name;278 _provider = driveInfo.Provider;279 Credential = driveInfo.Credential;280 _currentWorkingDirectory = driveInfo.CurrentLocation;281 Description = driveInfo.Description;282 this.MaximumSize = driveInfo.MaximumSize;283 DriveBeingCreated = driveInfo.DriveBeingCreated;284 _hidden = driveInfo._hidden;285 IsAutoMounted = driveInfo.IsAutoMounted;286 _root = driveInfo._root;287 Persist = driveInfo.Persist;288 this.Trace();289 }290 291 /// <summary>292 /// Constructs a drive that maps a PowerShell Path in293 /// the shell to a Cmdlet Provider.294 /// </summary>295 /// <param name="name">296 /// The name of the drive.297 /// </param>298 /// <param name="provider">299 /// The name of the provider which implements the functionality300 /// for the root path of the drive.301 /// </param>302 /// <param name="root">303 /// The root path of the drive. For example, the root of a304 /// drive in the file system can be c:\windows\system32305 /// </param>306 /// <param name="description">307 /// The description for the drive.308 /// </param>309 /// <param name="credential">310 /// The credentials under which all operations on the drive should occur.311 /// If null, the current user credential is used.312 /// </param>313 /// <throws>314 /// ArgumentNullException - if <paramref name="name"/>,315 /// <paramref name="provider"/>, or <paramref name="root"/>316 /// is null.317 /// </throws>318 public PSDriveInfo(319 string name,320 ProviderInfo provider,321 string root,322 string description,323 PSCredential credential)324 {325 // Verify the parameters326 327 if (name == null)328 {329 throw PSTraceSource.NewArgumentNullException(nameof(name));330 }331 332 if (provider == null)333 {334 throw PSTraceSource.NewArgumentNullException(nameof(provider));335 }336 337 if (root == null)338 {339 throw PSTraceSource.NewArgumentNullException(nameof(root));340 }341 342 // Copy the parameters to the local members343 344 _name = name;345 _provider = provider;346 _root = root;347 Description = description;348 349 if (credential != null)350 {351 Credential = credential;352 }353 354 // Set the current working directory to the empty355 // string since it is relative to the root.356 357 _currentWorkingDirectory = string.Empty;358 359 Dbg.Diagnostics.Assert(360 _currentWorkingDirectory != null,361 "The currentWorkingDirectory cannot be null");362 363 // Trace out the fields364 365 this.Trace();366 }367 368 /// <summary>369 /// Constructs a drive that maps a PowerShell Path in370 /// the shell to a Cmdlet Provider.371 /// </summary>372 /// <param name="name">373 /// The name of the drive.374 /// </param>375 /// <param name="provider">376 /// The name of the provider which implements the functionality377 /// for the root path of the drive.378 /// </param>379 /// <param name="root">380 /// The root path of the drive. For example, the root of a381 /// drive in the file system can be c:\windows\system32382 /// </param>383 /// <param name="description">384 /// The description for the drive.385 /// </param>386 /// <param name="credential">387 /// The credentials under which all operations on the drive should occur.388 /// If null, the current user credential is used.389 /// </param>390 /// <param name="displayRoot">391 /// The network path of the drive. This field would be populated only if PSDriveInfo392 /// is targeting the network drive or else this filed is null for local drives.393 /// </param>394 /// <throws>395 /// ArgumentNullException - if <paramref name="name"/>,396 /// <paramref name="provider"/>, or <paramref name="root"/>397 /// is null.398 /// </throws>399 public PSDriveInfo(400 string name,401 ProviderInfo provider,402 string root,403 string description,404 PSCredential credential, string displayRoot)405 : this(name, provider, root, description, credential)406 {407 DisplayRoot = displayRoot;408 }409 410 /// <summary>411 /// Constructs a drive that maps a PowerShell Path in412 /// the shell to a Cmdlet Provider.413 /// </summary>414 /// <param name="name">415 /// The name of the drive.416 /// </param>417 /// <param name="provider">418 /// The name of the provider which implements the functionality419 /// for the root path of the drive.420 /// </param>421 /// <param name="root">422 /// The root path of the drive. For example, the root of a423 /// drive in the file system can be c:\windows\system32424 /// </param>425 /// <param name="description">426 /// The description for the drive.427 /// </param>428 /// <param name="credential">429 /// The credentials under which all operations on the drive should occur.430 /// If null, the current user credential is used.431 /// </param>432 /// <param name="persist">433 /// It indicates if the created PSDrive would be434 /// persisted across PowerShell sessions.435 /// </param>436 /// <throws>437 /// ArgumentNullException - if <paramref name="name"/>,438 /// <paramref name="provider"/>, or <paramref name="root"/>439 /// is null.440 /// </throws>441 public PSDriveInfo(442 string name,443 ProviderInfo provider,444 string root,445 string description,446 PSCredential credential,447 bool persist)448 : this(name, provider, root, description, credential)449 {450 Persist = persist;451 }452 453 #endregion ctor454 455 /// <summary>456 /// Gets the name of the drive as a string.457 /// </summary>458 /// <returns>459 /// Returns a String that is that name of the drive.460 /// </returns>461 public override string ToString()462 {463 return Name;464 }465 466 /// <summary>467 /// Gets or sets the hidden property. The hidden property468 /// determines if the drive should be hidden from the user.469 /// </summary>470 /// <value>471 /// True if the drive should be hidden from the user, false472 /// otherwise.473 /// </value>474 internal bool Hidden475 {476 get477 {478 return _hidden;479 }480 481 set482 {483 _hidden = value;484 }485 }486 487 /// <summary>488 /// Determines if the drive should be hidden from the user.489 /// </summary>490 private bool _hidden;491 492 /// <summary>493 /// Sets the name of the drive to a new name.494 /// </summary>495 /// <param name="newName">496 /// The new name for the drive.497 /// </param>498 /// <remarks>499 /// This must be internal so that we allow the renaming of drives500 /// via the Core Command API but not through a reference to the501 /// drive object. More goes in to renaming a drive than just modifying502 /// the name in this class.503 /// </remarks>504 /// <exception cref="ArgumentException">505 /// If <paramref name="newName"/> is null or empty.506 /// </exception>507 internal void SetName(string newName)508 {509 if (string.IsNullOrEmpty(newName))510 {511 throw PSTraceSource.NewArgumentException(nameof(newName));512 }513 514 _name = newName;515 }516 517 /// <summary>518 /// Sets the provider of the drive to a new provider.519 /// </summary>520 /// <param name="newProvider">521 /// The new provider for the drive.522 /// </param>523 /// <remarks>524 /// This must be internal so that we allow the renaming of providers.525 /// All drives must be associated with the new provider name and can526 /// be changed using the Core Command API but not through a reference to the527 /// drive object. More goes in to renaming a provider than just modifying528 /// the provider in this class.529 /// </remarks>530 /// <exception cref="ArgumentNullException">531 /// If <paramref name="newProvider"/> is null.532 /// </exception>533 internal void SetProvider(ProviderInfo newProvider)534 {535 if (newProvider == null)536 {537 throw PSTraceSource.NewArgumentNullException(nameof(newProvider));538 }539 540 _provider = newProvider;541 }542 543 /// <summary>544 /// Traces the virtual drive.545 /// </summary>546 internal void Trace()547 {548 s_tracer.WriteLine(549 "A drive was found:");550 551 if (Name != null)552 {553 s_tracer.WriteLine(554 "\tName: {0}",555 Name);556 }557 558 if (Provider != null)559 {560 s_tracer.WriteLine(561 "\tProvider: {0}",562 Provider);563 }564 565 if (Root != null)566 {567 s_tracer.WriteLine(568 "\tRoot: {0}",569 Root);570 }571 572 if (CurrentLocation != null)573 {574 s_tracer.WriteLine(575 "\tCWD: {0}",576 CurrentLocation);577 }578 579 if (Description != null)580 {581 s_tracer.WriteLine(582 "\tDescription: {0}",583 Description);584 }585 }586 587 /// <summary>588 /// Compares this instance to the specified drive.589 /// </summary>590 /// <param name="drive">591 /// A PSDriveInfo object to compare.592 /// </param>593 /// <returns>594 /// A signed number indicating the relative values of this instance and object specified.595 /// Return Value: Less than zero Meaning: This instance is less than object.596 /// Return Value: Zero Meaning: This instance is equal to object.597 /// Return Value: Greater than zero Meaning: This instance is greater than object or object is a null reference.598 /// </returns>599 public int CompareTo(PSDriveInfo drive)600 {601#pragma warning disable 56506602 603 if (drive == null)604 {605 throw PSTraceSource.NewArgumentNullException(nameof(drive));606 }607 608 return string.Compare(Name, drive.Name, StringComparison.OrdinalIgnoreCase);609 610#pragma warning restore 56506611 }612 613 /// <summary>614 /// Compares this instance to the specified object. The object must be a PSDriveInfo.615 /// </summary>616 /// <param name="obj">617 /// An object to compare.618 /// </param>619 /// <returns>620 /// A signed number indicating the relative values of this621 /// instance and object specified.622 /// </returns>623 /// <exception cref="ArgumentException">624 /// If <paramref name="obj"/> is not a PSDriveInfo instance.625 /// </exception>626 public int CompareTo(object obj)627 {628 PSDriveInfo drive = obj as PSDriveInfo;629 630 if (drive == null)631 {632 ArgumentException e =633 PSTraceSource.NewArgumentException(634 nameof(obj),635 SessionStateStrings.OnlyAbleToComparePSDriveInfo);636 throw e;637 }638 639 return (CompareTo(drive));640 }641 642 /// <summary>643 /// Compares this instance to the specified object.644 /// </summary>645 /// <param name="obj">646 /// An object to compare.647 /// </param>648 /// <returns>649 /// True if the drive names are equal, false otherwise.650 /// </returns>651 public override bool Equals(object obj)652 {653 if (obj is PSDriveInfo)654 {655 return CompareTo(obj) == 0;656 }657 else658 {659 return false;660 }661 }662 663 /// <summary>664 /// Compares this instance to the specified object.665 /// </summary>666 /// <param name="drive">667 /// An object to compare.668 /// </param>669 /// <returns>670 /// True if the drive names are equal, false otherwise.671 /// </returns>672 public bool Equals(PSDriveInfo drive)673 {674 return CompareTo(drive) == 0;675 }676 677 /// <summary>678 /// Equality operator for the drive determines if the drives679 /// are equal by having the same name.680 /// </summary>681 /// <param name="drive1">682 /// The first object to compare to the second.683 /// </param>684 /// <param name="drive2">685 /// The second object to compare to the first.686 /// </param>687 /// <returns>688 /// True if the objects are PSDriveInfo objects and have the same name,689 /// false otherwise.690 /// </returns>691 public static bool operator ==(PSDriveInfo drive1, PSDriveInfo drive2)692 {693 object drive1Object = drive1;694 object drive2Object = drive2;695 696 if ((drive1Object == null) == (drive2Object == null))697 {698 if (drive1Object != null)699 {700 return drive1.Equals(drive2);701 }702 703 return true;704 }705 else706 {707 return false;708 }709 }710 711 /// <summary>712 /// Inequality operator for the drive determines if the drives713 /// are not equal by using the drive name.714 /// </summary>715 /// <param name="drive1">716 /// The first object to compare to the second.717 /// </param>718 /// <param name="drive2">719 /// The second object to compare to the first.720 /// </param>721 /// <returns>722 /// True if the PSDriveInfo objects do not have the same name,723 /// false otherwise.724 /// </returns>725 public static bool operator !=(PSDriveInfo drive1, PSDriveInfo drive2)726 {727 return !(drive1 == drive2);728 }729 730 /// <summary>731 /// Compares the specified drives to determine if drive1 is less than732 /// drive2.733 /// </summary>734 /// <param name="drive1">735 /// The drive to determine if it is less than the other drive.736 /// </param>737 /// <param name="drive2">738 /// The drive to compare drive1 against.739 /// </param>740 /// <returns>741 /// True if the lexical comparison of drive1's name is less than drive2's name.742 /// </returns>743 public static bool operator <(PSDriveInfo drive1, PSDriveInfo drive2)744 {745 object drive1Object = drive1;746 object drive2Object = drive2;747 748 if (drive1Object == null)749 {750 return (drive2Object != null);751 }752 else753 {754 if (drive2Object == null)755 {756 // Since drive1 is not null and drive2 is, drive1 is greater than drive2757 return false;758 }759 else760 {761 // Since drive1 and drive2 are not null use the CompareTo762 763 return drive1.CompareTo(drive2) < 0;764 }765 }766 }767 768 /// <summary>769 /// Compares the specified drives to determine if drive1 is greater than770 /// drive2.771 /// </summary>772 /// <param name="drive1">773 /// The drive to determine if it is greater than the other drive.774 /// </param>775 /// <param name="drive2">776 /// The drive to compare drive1 against.777 /// </param>778 /// <returns>779 /// True if the lexical comparison of drive1's name is greater than drive2's name.780 /// </returns>781 public static bool operator >(PSDriveInfo drive1, PSDriveInfo drive2)782 {783 object drive1Object = drive1;784 object drive2Object = drive2;785 786 if ((drive1Object == null))787 {788 // Since both drives are null, they are equal789 // Since drive1 is null it is less than drive2 which is not null790 return false;791 }792 else793 {794 if (drive2Object == null)795 {796 // Since drive1 is not null and drive2 is, drive1 is greater than drive2797 return true;798 }799 else800 {801 // Since drive1 and drive2 are not null use the CompareTo802 803 return drive1.CompareTo(drive2) > 0;804 }805 }806 }807 808 /// <summary>809 /// Gets the hash code for this instance.810 /// </summary>811 /// <returns>The result of base.GetHashCode().</returns>812 /// <!-- Override the base GetHashCode because the compiler complains813 /// if you don't when you implement operator== and operator!= -->814 public override int GetHashCode()815 {816 return base.GetHashCode();817 }818 819 private PSNoteProperty _noteProperty;820 821 internal PSNoteProperty GetNotePropertyForProviderCmdlets(string name)822 {823 if (_noteProperty == null)824 {825 Interlocked.CompareExchange(ref _noteProperty,826 new PSNoteProperty(name, this), null);827 }828 829 return _noteProperty;830 }831 }832}833 