diff --git a/src/Microsoft.PowerShell.Security/security/Utils.cs b/src/Microsoft.PowerShell.Security/security/Utils.cs index 4bf0ce1a88..4104c3ce36 100644 --- a/src/Microsoft.PowerShell.Security/security/Utils.cs +++ b/src/Microsoft.PowerShell.Security/security/Utils.cs @@ -204,7 +204,7 @@ namespace Microsoft.PowerShell string path) { string resolvedProviderPath = cmdlet.SessionState.Path.GetUnresolvedProviderPathFromPSPath(path); - if (Utils.FileExists(resolvedProviderPath)) + if (File.Exists(resolvedProviderPath)) { return resolvedProviderPath; } diff --git a/src/System.Management.Automation/engine/CommandSearcher.cs b/src/System.Management.Automation/engine/CommandSearcher.cs index 182804a853..ca953739f3 100644 --- a/src/System.Management.Automation/engine/CommandSearcher.cs +++ b/src/System.Management.Automation/engine/CommandSearcher.cs @@ -578,7 +578,7 @@ namespace System.Management.Automation do // false loop { - if (!Utils.FileExists(path)) + if (!File.Exists(path)) { CommandDiscovery.discoveryTracer.TraceError("The path does not exist: {0}", path); break; diff --git a/src/System.Management.Automation/engine/Modules/AnalysisCache.cs b/src/System.Management.Automation/engine/Modules/AnalysisCache.cs index 654cd20be2..f3a196cd2b 100644 --- a/src/System.Management.Automation/engine/Modules/AnalysisCache.cs +++ b/src/System.Management.Automation/engine/Modules/AnalysisCache.cs @@ -691,10 +691,9 @@ namespace System.Management.Automation var keys = Entries.Keys; foreach (var key in keys) { - if (!Utils.FileExists(key)) + if (!File.Exists(key)) { - ModuleCacheEntry unused; - removedSomething |= Entries.TryRemove(key, out unused); + removedSomething |= Entries.TryRemove(key, out ModuleCacheEntry _); } } @@ -731,7 +730,7 @@ namespace System.Management.Automation try { - if (Utils.FileExists(filename)) + if (File.Exists(filename)) { var fileLastWriteTime = new FileInfo(filename).LastWriteTime; if (fileLastWriteTime > this.LastReadTime) @@ -1028,7 +1027,7 @@ namespace System.Management.Automation { try { - if (Utils.FileExists(s_cacheStoreLocation)) + if (File.Exists(s_cacheStoreLocation)) { return Deserialize(s_cacheStoreLocation); } diff --git a/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs b/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs index 219f9c9f19..ece7795ebd 100644 --- a/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs +++ b/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs @@ -312,7 +312,7 @@ namespace Microsoft.PowerShell.Commands { qualifiedPath = Path.Combine(qualifiedPath, fileBaseName); } - else if (Utils.DirectoryExists(qualifiedPath)) + else if (Directory.Exists(qualifiedPath)) { // if it points to a directory, add the basename back onto the path... qualifiedPath = Path.Combine(qualifiedPath, Path.GetFileName(fileBaseName)); @@ -921,10 +921,9 @@ namespace Microsoft.PowerShell.Commands foreach (string resolvedModulePath in modulePathCollection) { string moduleName = Path.GetFileName(resolvedModulePath); - bool isDirectory = Utils.DirectoryExists(resolvedModulePath); // If the given path is a valid module file, we will load the specific file - if (!isDirectory && ModuleIntrinsics.IsPowerShellModuleExtension(Path.GetExtension(moduleName))) + if (!Directory.Exists(resolvedModulePath) && ModuleIntrinsics.IsPowerShellModuleExtension(Path.GetExtension(moduleName))) { PSModuleInfo module = CreateModuleInfoForGetModule(resolvedModulePath, refresh); if (module != null) @@ -1593,7 +1592,7 @@ namespace Microsoft.PowerShell.Commands return loadedModule; } // remove the module if force is specified (and if module is already loaded) - else if (Utils.FileExists(rootedPath)) + else if (File.Exists(rootedPath)) { RemoveModule(loadedModule); } @@ -4360,7 +4359,7 @@ namespace Microsoft.PowerShell.Commands // which we can't really do b/c the file doesn't exist. fixedFileName = psHome + "\\" + Path.GetFileName(s); } - else if (verifyFilesExist && !Utils.FileExists(fixedFileName)) + else if (verifyFilesExist && !File.Exists(fixedFileName)) { string message = StringUtil.Format(SessionStateStrings.PathNotFound, fixedFileName); throw new FileNotFoundException(message, fixedFileName); @@ -5084,7 +5083,7 @@ namespace Microsoft.PowerShell.Commands else // reimport the module + return alreadyLoadedModule (alreadyLoadedModule = no need to proceed with regular import) { // If the module has already been loaded, then while loading it the second time, we should load it with the DefaultCommandPrefix specified in the module manifest. (If there is no Prefix from command line) - if (string.IsNullOrEmpty(prefix) && Utils.FileExists(alreadyLoadedModule.Path)) + if (string.IsNullOrEmpty(prefix) && File.Exists(alreadyLoadedModule.Path)) { string defaultPrefix = GetDefaultPrefix(alreadyLoadedModule); if (!string.IsNullOrEmpty(defaultPrefix)) @@ -5260,7 +5259,7 @@ namespace Microsoft.PowerShell.Commands found = true; return module; } - else if (Utils.FileExists(fileName)) + else if (File.Exists(fileName)) { moduleFileFound = true; // Win8: 325243 - Added the version check so that we do not unload modules with the same name but different version @@ -5410,7 +5409,7 @@ namespace Microsoft.PowerShell.Commands { Dbg.Assert(fileName != null, "Filename argument to LoadModule() shouldn't be null"); - if (!Utils.FileExists(fileName)) + if (!File.Exists(fileName)) { found = false; moduleFileFound = false; diff --git a/src/System.Management.Automation/engine/SessionStateDriveAPIs.cs b/src/System.Management.Automation/engine/SessionStateDriveAPIs.cs index 5d010b1942..7e513a360c 100644 --- a/src/System.Management.Automation/engine/SessionStateDriveAPIs.cs +++ b/src/System.Management.Automation/engine/SessionStateDriveAPIs.cs @@ -963,25 +963,9 @@ namespace System.Management.Automation if (systemDriveInfo.DriveType == DriveType.NoRootDirectory) { - try - { - // Checking for the presence of mounted drive locally using Utils.DirectoryExists API as - // the calls to this API is faster than normal Directory.Exist API. - bool validDrive = Utils.DirectoryExists(drive.Root); - if (!validDrive) - { - result = true; - } - } - // We don't want to have automounting cause an exception. We - // rather it just fail silently as it wasn't a result of an - // explicit request by the user anyway. - // Following the same pattern as the Calling API. - catch (IOException) - { - } - catch (UnauthorizedAccessException) + if (!Directory.Exists(drive.Root)) { + result = true; } } } diff --git a/src/System.Management.Automation/engine/Utils.cs b/src/System.Management.Automation/engine/Utils.cs index 5d43d2b6af..eb228a77c4 100644 --- a/src/System.Management.Automation/engine/Utils.cs +++ b/src/System.Management.Automation/engine/Utils.cs @@ -908,61 +908,6 @@ namespace System.Management.Automation #endif } - internal static bool ItemExists(string path) - { - try - { - return ItemExists(path, out bool _); - } - catch - { - } - - return false; - } - - internal static bool ItemExists(string path, out bool isDirectory) - { - isDirectory = false; - - if (String.IsNullOrEmpty(path)) - { - return false; - } - - if (IsReservedDeviceName(path)) - { - return false; - } - - try - { - // Use 'File.GetAttributes()' because we want to get access exceptions. - FileAttributes attributes = File.GetAttributes(path); - isDirectory = attributes.HasFlag(FileAttributes.Directory); - - return (int)attributes != -1; - } - catch (IOException) - { - return false; - } - } - - internal static bool FileExists(string path) - { - bool itemExists = ItemExists(path, out bool isDirectory); - - return (itemExists && (!isDirectory)); - } - - internal static bool DirectoryExists(string path) - { - bool itemExists = ItemExists(path, out bool isDirectory); - - return (itemExists && isDirectory); - } - internal static void NativeEnumerateDirectory(string directory, out List directories, out List files) { IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1); diff --git a/src/System.Management.Automation/help/UpdatableHelpSystem.cs b/src/System.Management.Automation/help/UpdatableHelpSystem.cs index 7327fe0153..f9e87c97c9 100644 --- a/src/System.Management.Automation/help/UpdatableHelpSystem.cs +++ b/src/System.Management.Automation/help/UpdatableHelpSystem.cs @@ -1627,32 +1627,33 @@ namespace System.Management.Automation.Help /// internal static string GetFilePath(string path) { + FileInfo item = new FileInfo(path); + + // We use 'FileInfo.Attributes' (not 'FileInfo.Exist') + // because we want to get exceptions + // like UnauthorizedAccessException or IOException. + if ((int)item.Attributes != -1) + { + return path; + } #if UNIX // On Linux, file paths are case sensitive. // The user does not have control over the files (HelpInfo.xml, .zip, and cab) that are generated by the Publishing team. // The logic below is to support updating help content via sourcepath parameter for case insensitive files. - FileInfo item = new FileInfo(path); - string directoryPath = item.Directory.FullName; + var dirInfo = item.Directory; string fileName = item.Name; // Prerequisite: The directory in the given path must exist and it is case sensitive. - if (Utils.DirectoryExists(directoryPath)) + if (dirInfo.Exists) { // Get the list of files in the directory. - string[] fileList = Directory.GetFiles(directoryPath); - foreach (string filePath in fileList) + FileInfo[] fileList = dirInfo.GetFiles(searchPattern: fileName, new System.IO.EnumerationOptions { MatchCasing = MatchCasing.CaseInsensitive }); + + if (fileList.Length > 0) { - if (filePath.EndsWith(fileName, StringComparison.OrdinalIgnoreCase)) - { - return filePath; - } + return fileList[0].FullName; } } -#else - if (Utils.FileExists(path)) - { - return path; - } #endif return null; } diff --git a/src/System.Management.Automation/namespaces/FileSystemProvider.cs b/src/System.Management.Automation/namespaces/FileSystemProvider.cs index c559c1f4c8..8e6a4b3b6a 100644 --- a/src/System.Management.Automation/namespaces/FileSystemProvider.cs +++ b/src/System.Management.Automation/namespaces/FileSystemProvider.cs @@ -100,29 +100,45 @@ namespace Microsoft.PowerShell.Commands } // NormalizePath /// - /// Checks if the item exist at the specified path. if it exists then creates + /// Checks if the item exist at the specified path. if it exists then creates /// appropriate directoryinfo or fileinfo object. /// /// - /// refers to the item for which we are checking for existence and creating filesysteminfo object. + /// Refers to the item for which we are checking for existence and creating filesysteminfo object. /// /// - /// return true if path points to a directory else returns false. + /// Return true if path points to a directory else returns false. /// - /// - private static FileSystemInfo GetFileSystemInfo(string path, ref bool isContainer) + /// FileInfo or DirectoryInfo object. + /// + /// The path is null. + /// + /// + /// I/O error occurs. + /// + /// + /// An I/O error or a specific type of security error. + /// + private static FileSystemInfo GetFileSystemInfo(string path, out bool isContainer) { - isContainer = false; + // We use 'FileInfo.Attributes' (not 'FileInfo.Exist') + // because we want to get exceptions + // like UnauthorizedAccessException or IOException. + FileSystemInfo fsinfo = new FileInfo(path); + var attr = fsinfo.Attributes; + var exists = (int)attr != -1; + isContainer = exists && attr.HasFlag(FileAttributes.Directory); - if (Utils.FileExists(path)) + if (exists) { - return new FileInfo(path); - } - - if (Utils.DirectoryExists(path)) - { - isContainer = true; - return new DirectoryInfo(path); + if (isContainer) + { + return new DirectoryInfo(path); + } + else + { + return fsinfo; + } } return null; @@ -445,18 +461,7 @@ namespace Microsoft.PowerShell.Commands if (driveIsFixed) { // Since the drive is fixed, ensure the root is valid. - try - { - validDrive = Utils.DirectoryExists(drive.Root); - } - catch (IOException) - { - // Ignore, the network path may not be found. - } - catch (UnauthorizedAccessException) - { - // Ignore, we may be running in an AppContainer - } + validDrive = Directory.Exists(drive.Root); } if (validDrive) @@ -1494,11 +1499,12 @@ namespace Microsoft.PowerShell.Commands path = NormalizePath(path); - if (Utils.ItemExists(path, out bool isDirectory)) + var fsinfo = GetFileSystemInfo(path, out bool isDirectory); + + if (fsinfo != null) { if (isDirectory) { - DirectoryInfo directory = new DirectoryInfo(path); InodeTracker tracker = null; if (recurse) @@ -1506,18 +1512,15 @@ namespace Microsoft.PowerShell.Commands GetChildDynamicParameters fspDynamicParam = DynamicParameters as GetChildDynamicParameters; if (fspDynamicParam != null && fspDynamicParam.FollowSymlink) { - tracker = new InodeTracker(directory.FullName); + tracker = new InodeTracker(fsinfo.FullName); } } // Enumerate the directory - Dir(directory, recurse, depth, nameOnly, returnContainers, tracker); + Dir((DirectoryInfo)fsinfo, recurse, depth, nameOnly, returnContainers, tracker); } else { - // Maybe the path is a file name so try a FileInfo instead - FileInfo fileInfo = new FileInfo(path); - FlagsExpression evaluator = null; FlagsExpression switchEvaluator = null; GetChildDynamicParameters fspDynamicParam = DynamicParameters as GetChildDynamicParameters; @@ -1534,16 +1537,16 @@ namespace Microsoft.PowerShell.Commands if (evaluator != null) { - attributeFilter = evaluator.Evaluate(fileInfo.Attributes); // expressions + attributeFilter = evaluator.Evaluate(fsinfo.Attributes); // expressions filterHidden = evaluator.ExistsInExpression(FileAttributes.Hidden); } if (switchEvaluator != null) { - switchAttributeFilter = switchEvaluator.Evaluate(fileInfo.Attributes); // switch parameters + switchAttributeFilter = switchEvaluator.Evaluate(fsinfo.Attributes); // switch parameters switchFilterHidden = switchEvaluator.ExistsInExpression(FileAttributes.Hidden); } - bool hidden = (fileInfo.Attributes & FileAttributes.Hidden) != 0; + bool hidden = (fsinfo.Attributes & FileAttributes.Hidden) != 0; // if "Hidden" is explicitly specified anywhere in the attribute filter, then override // default hidden attribute filter. @@ -1553,12 +1556,12 @@ namespace Microsoft.PowerShell.Commands if (nameOnly) { WriteItemObject( - fileInfo.Name, - fileInfo.FullName, + fsinfo.Name, + fsinfo.FullName, false); } else - WriteItemObject(fileInfo, path, false); + WriteItemObject(fsinfo, path, false); } } } @@ -2156,9 +2159,13 @@ namespace Microsoft.PowerShell.Commands // non-existing targets on either Windows or Linux. try { - exists = Utils.ItemExists(strTargetPath, out isDirectory); + exists = GetFileSystemInfo(strTargetPath, out isDirectory) != null; + + // Pretend the target exists if we're making a symbolic link. if (itemType == ItemType.SymbolicLink) - exists = true; // pretend the target exists if we're making a symbolic link + { + exists = true; + } } catch (Exception e) { @@ -2189,7 +2196,7 @@ namespace Microsoft.PowerShell.Commands try { - symLinkExists = Utils.ItemExists(path, out isSymLinkDirectory); + symLinkExists = GetFileSystemInfo(path, out isSymLinkDirectory) != null; } catch (Exception e) { @@ -2318,7 +2325,7 @@ namespace Microsoft.PowerShell.Commands try { - exists = Utils.ItemExists(strTargetPath, out isDirectory); + exists = GetFileSystemInfo(strTargetPath, out isDirectory) != null; } catch (Exception e) { @@ -2341,12 +2348,11 @@ namespace Microsoft.PowerShell.Commands } bool isPathDirectory = false; - - bool pathExists = false; + FileSystemInfo pathDirInfo; try { - pathExists = Utils.ItemExists(path, out isPathDirectory); + pathDirInfo = GetFileSystemInfo(path, out isPathDirectory); } catch (Exception e) { @@ -2354,7 +2360,7 @@ namespace Microsoft.PowerShell.Commands return; } - DirectoryInfo pathDirInfo = new DirectoryInfo(path); + bool pathExists = pathDirInfo != null; if (pathExists) { @@ -2367,7 +2373,7 @@ namespace Microsoft.PowerShell.Commands } //Junctions cannot have files - if (DirectoryInfoHasChildItems(pathDirInfo)) + if (DirectoryInfoHasChildItems((DirectoryInfo)pathDirInfo)) { string message = StringUtil.Format(FileSystemProviderStrings.DirectoryNotEmpty, path); WriteError(new ErrorRecord(new IOException(message), "DirectoryNotEmpty", ErrorCategory.WriteError, path)); @@ -2397,6 +2403,7 @@ namespace Microsoft.PowerShell.Commands else { CreateDirectory(path, false); + pathDirInfo = new DirectoryInfo(path); } try @@ -2730,8 +2737,7 @@ namespace Microsoft.PowerShell.Commands } #endif - bool iscontainer = false; - FileSystemInfo fsinfo = GetFileSystemInfo(path, ref iscontainer); + FileSystemInfo fsinfo = GetFileSystemInfo(path, out bool iscontainer); if (fsinfo == null) { String error = StringUtil.Format(FileSystemProviderStrings.ItemDoesNotExist, path); @@ -3187,7 +3193,8 @@ namespace Microsoft.PowerShell.Commands try { - result = Utils.ItemExists(path, out bool _); + var fsinfo = GetFileSystemInfo(path, out bool _); + result = fsinfo != null; FileSystemItemProviderDynamicParameters itemExistsDynamicParameters = DynamicParameters as FileSystemItemProviderDynamicParameters; @@ -3195,7 +3202,7 @@ namespace Microsoft.PowerShell.Commands // If the items see if we need to check the age of the file... if (result && itemExistsDynamicParameters != null) { - DateTime lastWriteTime = File.GetLastWriteTime(path); + DateTime lastWriteTime = fsinfo.LastWriteTime; if (itemExistsDynamicParameters.OlderThan.HasValue) { @@ -3492,8 +3499,6 @@ namespace Microsoft.PowerShell.Commands if (op["Items"] != null) { - bool destinationPathIsFile = Utils.FileExists(destinationPath); - PSObject obj = (PSObject)op["Items"]; ArrayList itemsList = (ArrayList)obj.BaseObject; foreach (PSObject item in itemsList) @@ -3505,7 +3510,7 @@ namespace Microsoft.PowerShell.Commands if (isContainer) { - if (destinationPathIsFile) + if (File.Exists(destinationPath)) { Exception e = new IOException(String.Format( CultureInfo.InvariantCulture, @@ -3866,7 +3871,7 @@ namespace Microsoft.PowerShell.Commands CreateDirectory(destination, false); // If failed to create directory - if (!Utils.DirectoryExists(destination)) + if (!Directory.Exists(destination)) { return; } @@ -4935,11 +4940,11 @@ namespace Microsoft.PowerShell.Commands } #if UNIX - // We don't use the Directory class for Unix because the path + // We don't use the Directory.EnumerateFiles() for Unix because the path // may contain additional globbing patterns such as '[ab]' // which Directory.EnumerateFiles() processes, giving undesireable // results in this context. - if (!Utils.ItemExists(result)) + if (!File.Exists(result) && !Directory.Exists(result)) { String error = StringUtil.Format(FileSystemProviderStrings.ItemDoesNotExist, path); Exception e = new IOException(error); @@ -5401,8 +5406,7 @@ namespace Microsoft.PowerShell.Commands { currentPath = MakePath(currentPath, childName); - Boolean isContainer = false; - FileSystemInfo fsinfo = GetFileSystemInfo(currentPath, ref isContainer); + var fsinfo = GetFileSystemInfo(currentPath, out bool _); // Clean up the child name to proper casing and short-path // expansion if required. Also verify that .NET hasn't over-normalized @@ -5425,8 +5429,7 @@ namespace Microsoft.PowerShell.Commands else { // We couldn't find the item - if ((!isContainer) && - (tokenizedPathStack.Count == 0)) + if (tokenizedPathStack.Count == 0) { throw PSTraceSource.NewArgumentException("path", FileSystemProviderStrings.ItemDoesNotExist, currentPath); } @@ -5573,7 +5576,7 @@ namespace Microsoft.PowerShell.Commands path = NormalizePath(path); - return Utils.DirectoryExists(path); + return Directory.Exists(path); } #region MoveItem @@ -5988,20 +5991,7 @@ namespace Microsoft.PowerShell.Commands try { - FileSystemInfo fileSystemObject = null;// Get the directory object - - if (Utils.ItemExists(path, out bool isDirectory)) - { - if (isDirectory) - { - fileSystemObject = new DirectoryInfo(path); - } - else - { - // Maybe the path is a file name so try a FileInfo instead - fileSystemObject = new FileInfo(path); - } - } + var fileSystemObject = GetFileSystemInfo(path, out bool isDirectory); if (fileSystemObject == null) { @@ -6143,28 +6133,14 @@ namespace Microsoft.PowerShell.Commands path = NormalizePath(path); PSObject results = new PSObject(); - PSObject fileSystemInfoShell = null; - bool isContainer = false; - // Create a PSObject with either a DirectoryInfo or FileInfo object - // at its core. + var fsinfo = GetFileSystemInfo(path, out bool isDirectory); - if (Utils.ItemExists(path, out bool isDirectory)) + // Create a PSObject with either a DirectoryInfo or FileInfo object at its core. + if (fsinfo != null) { - if (isDirectory) - { - isContainer = true; - fileSystemInfoShell = PSObject.AsPSObject(new DirectoryInfo(path)); - } - else - { - // Maybe the path is a file name so try a FileInfo instead - fileSystemInfoShell = PSObject.AsPSObject(new FileInfo(path)); - } - } + PSObject fileSystemInfoShell = PSObject.AsPSObject(fsinfo); - if (fileSystemInfoShell != null) - { bool propertySet = false; foreach (PSMemberInfo property in propertyToSet.Properties) @@ -6174,7 +6150,7 @@ namespace Microsoft.PowerShell.Commands // Get the confirmation text string action = null; - if (isContainer) + if (isDirectory) { action = FileSystemProviderStrings.SetPropertyActionDirectory; } diff --git a/src/System.Management.Automation/utils/ClrFacade.cs b/src/System.Management.Automation/utils/ClrFacade.cs index fdb9bc10ab..144844c3b4 100644 --- a/src/System.Management.Automation/utils/ClrFacade.cs +++ b/src/System.Management.Automation/utils/ClrFacade.cs @@ -137,7 +137,7 @@ namespace System.Management.Automation internal static SecurityZone GetFileSecurityZone(string filePath) { Diagnostics.Assert(Path.IsPathRooted(filePath), "Caller makes sure the path is rooted."); - Diagnostics.Assert(Utils.FileExists(filePath), "Caller makes sure the file exists."); + Diagnostics.Assert(File.Exists(filePath), "Caller makes sure the file exists."); return MapSecurityZone(filePath); }