{
#region Utilities
- public bool Exists(string path)
+ public virtual bool Exists(string path)
{
return Directory.Exists(path);
}
}
[Fact]
- public void PathAlreadyExistsAsFile()
- {
- string path = GetTestFilePath();
- File.Create(path).Dispose();
-
- Assert.False(Exists(IOServices.RemoveTrailingSlash(path)));
- Assert.False(Exists(IOServices.RemoveTrailingSlash(IOServices.RemoveTrailingSlash(path))));
- Assert.False(Exists(IOServices.RemoveTrailingSlash(IOServices.AddTrailingSlashIfNeeded(path))));
- }
-
- [Fact]
public void PathAlreadyExistsAsDirectory()
{
string path = GetTestFilePath();
}
[ConditionalFact(nameof(UsingNewNormalization))]
- [PlatformSpecific(TestPlatforms.Windows)] // Extended path already exists as file
- public void ExtendedPathAlreadyExistsAsFile()
- {
- string path = IOInputs.ExtendedPrefix + GetTestFilePath();
- File.Create(path).Dispose();
-
- Assert.False(Exists(IOServices.RemoveTrailingSlash(path)));
- Assert.False(Exists(IOServices.RemoveTrailingSlash(IOServices.RemoveTrailingSlash(path))));
- Assert.False(Exists(IOServices.RemoveTrailingSlash(IOServices.AddTrailingSlashIfNeeded(path))));
- }
-
- [ConditionalFact(nameof(UsingNewNormalization))]
[PlatformSpecific(TestPlatforms.Windows)] // Extended path already exists as directory
public void ExtendedPathAlreadyExistsAsDirectory()
{
Assert.False(Exists(Path.Combine(IOServices.GetNonExistentDrive(), "nonexistentsubdir")));
}
+ #endregion
+ }
+
+ public class Directory_ExistsAsFile : FileSystemTest
+ {
+ [Fact]
+ public void PathAlreadyExistsAsFile()
+ {
+ string path = GetTestFilePath();
+ File.Create(path).Dispose();
+
+ Assert.False(Directory.Exists(IOServices.RemoveTrailingSlash(path)));
+ Assert.False(Directory.Exists(IOServices.RemoveTrailingSlash(IOServices.RemoveTrailingSlash(path))));
+ Assert.False(Directory.Exists(IOServices.RemoveTrailingSlash(IOServices.AddTrailingSlashIfNeeded(path))));
+ }
+
+ [ConditionalFact(nameof(UsingNewNormalization))]
+ [PlatformSpecific(TestPlatforms.Windows)] // Extended path already exists as file
+ public void ExtendedPathAlreadyExistsAsFile()
+ {
+ string path = IOInputs.ExtendedPrefix + GetTestFilePath();
+ File.Create(path).Dispose();
+
+ Assert.False(Directory.Exists(IOServices.RemoveTrailingSlash(path)));
+ Assert.False(Directory.Exists(IOServices.RemoveTrailingSlash(IOServices.RemoveTrailingSlash(path))));
+ Assert.False(Directory.Exists(IOServices.RemoveTrailingSlash(IOServices.AddTrailingSlashIfNeeded(path))));
+ }
+
[Fact]
[PlatformSpecific(TestPlatforms.AnyUnix & ~TestPlatforms.Browser)] // Makes call to native code (libc)
public void FalseForNonRegularFile()
Assert.Equal(0, mkfifo(fileName, 0));
Assert.False(Directory.Exists(fileName));
}
-
- #endregion
}
}
{
// Checks that errors aren't thrown when calling Exists() on paths with impossible to create characters
Assert.False(Exists(invalidPath));
-
- Assert.False(Exists(".."));
- Assert.False(Exists("."));
}
[Fact]
}
[Fact]
- public void PathAlreadyExistsAsDirectory()
- {
- string path = GetTestFilePath();
- Directory.CreateDirectory(path);
-
- Assert.False(Exists(IOServices.RemoveTrailingSlash(path)));
- Assert.False(Exists(IOServices.RemoveTrailingSlash(IOServices.RemoveTrailingSlash(path))));
- Assert.False(Exists(IOServices.RemoveTrailingSlash(IOServices.AddTrailingSlashIfNeeded(path))));
- }
-
- [Fact]
public void DirectoryLongerThanMaxDirectoryAsPath_DoesntThrow()
{
Assert.All((IOInputs.GetPathsLongerThanMaxDirectory(GetTestFilePath())), (path) =>
Assert.False(Exists(component));
}
+ #endregion
+ }
+
+ public class File_ExistsAsDirectory : FileSystemTest
+ {
+ [Fact]
+ public void DotAsPathReturnsFalse()
+ {
+ Assert.False(File.Exists("."));
+ Assert.False(File.Exists(".."));
+ }
+
+ [Fact]
+ public void PathAlreadyExistsAsDirectory()
+ {
+ string path = GetTestFilePath();
+ Directory.CreateDirectory(path);
+
+ Assert.False(File.Exists(IOServices.RemoveTrailingSlash(path)));
+ Assert.False(File.Exists(IOServices.RemoveTrailingSlash(IOServices.RemoveTrailingSlash(path))));
+ Assert.False(File.Exists(IOServices.RemoveTrailingSlash(IOServices.AddTrailingSlashIfNeeded(path))));
+ }
+
[Fact]
[PlatformSpecific(TestPlatforms.AnyUnix & ~TestPlatforms.Browser)] // Uses P/Invokes
public void FalseForNonRegularFile()
Assert.Equal(0, mkfifo(fileName, 0));
Assert.True(File.Exists(fileName));
}
-
- #endregion
}
}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using Xunit;
+
+namespace System.IO.Tests
+{
+ public class PathDirectory_Exists : Directory_Exists
+ {
+ public override bool Exists(string path) => Path.Exists(path);
+
+ [Fact]
+ public void PathAlreadyExistsAsFile()
+ {
+ string path = GetTestFilePath();
+ File.Create(path).Dispose();
+
+ Assert.True(Exists(IOServices.RemoveTrailingSlash(path)));
+ Assert.True(Exists(IOServices.RemoveTrailingSlash(IOServices.RemoveTrailingSlash(path))));
+ Assert.True(Exists(IOServices.RemoveTrailingSlash(IOServices.AddTrailingSlashIfNeeded(path))));
+ }
+
+ [ConditionalFact(nameof(UsingNewNormalization))]
+ [PlatformSpecific(TestPlatforms.Windows)] // Extended path already exists as file
+ public void ExtendedPathAlreadyExistsAsFile()
+ {
+ string path = IOInputs.ExtendedPrefix + GetTestFilePath();
+ File.Create(path).Dispose();
+
+ Assert.True(Exists(IOServices.RemoveTrailingSlash(path)));
+ Assert.True(Exists(IOServices.RemoveTrailingSlash(IOServices.RemoveTrailingSlash(path))));
+ Assert.True(Exists(IOServices.RemoveTrailingSlash(IOServices.AddTrailingSlashIfNeeded(path))));
+ }
+ }
+}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using Xunit;
+
+namespace System.IO.Tests
+{
+ public class PathFile_Exists : File_Exists
+ {
+ public override bool Exists(string path) => Path.Exists(path);
+
+ [Fact]
+ public void PathAlreadyExistsAsDirectory()
+ {
+ string path = GetTestFilePath();
+ Directory.CreateDirectory(path);
+
+ Assert.True(Exists(IOServices.RemoveTrailingSlash(path)));
+ Assert.True(Exists(IOServices.RemoveTrailingSlash(IOServices.RemoveTrailingSlash(path))));
+ Assert.True(Exists(IOServices.RemoveTrailingSlash(IOServices.AddTrailingSlashIfNeeded(path))));
+ }
+
+ [Fact]
+ [PlatformSpecific(TestPlatforms.AnyUnix & ~TestPlatforms.Browser)] // Uses P/Invokes
+ public void TrueForNonRegularFile()
+ {
+ string fileName = GetTestFilePath();
+ Assert.Equal(0, mkfifo(fileName, 0));
+ Assert.True(Exists(fileName));
+ }
+ }
+}
<Compile Include="Enumeration\SymbolicLinksTests.cs" />
<Compile Include="LargeFileTests.cs" />
<Compile Include="PathInternalTests.cs" />
+ <Compile Include="Path\Exists_Directory.cs" />
+ <Compile Include="Path\Exists_File.cs" />
<Compile Include="RandomAccess\Base.cs" />
<Compile Include="RandomAccess\GetLength.cs" />
<Compile Include="RandomAccess\Read.cs" />
public static char[] GetInvalidPathChars() => new char[] { '\0' };
+ // Checks if the given path is available for use.
+ private static bool ExistsCore(string fullPath)
+ {
+ bool result = Interop.Sys.LStat(fullPath, out Interop.Sys.FileStatus fileInfo) == Interop.Errors.ERROR_SUCCESS;
+ if (PathInternal.IsDirectorySeparator(fullPath[fullPath.Length - 1]))
+ {
+ // If the path ends with trailing slash, we want to make sure it's a directory.
+ // Although Lstat returns the correct result on desktop platforms,
+ // on browser WASM, it seems to strip trailing slash, leading to false positives for files.
+ // This check prevents it from doing so.
+ result = result && (fileInfo.Mode & Interop.Sys.FileTypes.S_IFMT) == Interop.Sys.FileTypes.S_IFDIR;
+ }
+
+ return result;
+ }
+
// Expands the given path to a fully qualified path.
public static string GetFullPath(string path)
{
(char)31
};
+ private static bool ExistsCore(string fullPath)
+ {
+ Interop.Kernel32.WIN32_FILE_ATTRIBUTE_DATA data = default;
+ int errorCode = FileSystem.FillAttributeInfo(fullPath, ref data, returnErrorOnNotFound: true);
+ bool result = (errorCode == Interop.Errors.ERROR_SUCCESS) && (data.dwFileAttributes != -1);
+
+ if (PathInternal.IsDirectorySeparator(fullPath[fullPath.Length - 1]))
+ {
+ // We want to make sure that if the path ends in a trailing slash, it's truly a directory
+ // because FillAttributeInfo syscall removes any trailing slashes and may give false positives
+ // for existing files.
+ result = result && (data.dwFileAttributes & Interop.Kernel32.FileAttributes.FILE_ATTRIBUTE_DIRECTORY) != 0;
+ }
+
+ return result;
+ }
+
// Expands the given path to a fully qualified path.
public static string GetFullPath(string path)
{
}
/// <summary>
+ /// Determines whether the specified file or directory exists.
+ /// </summary>
+ /// <remarks>
+ /// Unlike <see cref="File.Exists(string?)"/> it returns true for existing, non-regular files like pipes.
+ /// If the path targets an existing link, but the target of the link does not exist, it returns true.
+ /// </remarks>
+ /// <param name="path">The path to check</param>
+ /// <returns>
+ /// <see langword="true" /> if the caller has the required permissions and <paramref name="path" /> contains
+ /// the name of an existing file or directory; otherwise, <see langword="false" />.
+ /// This method also returns <see langword="false" /> if <paramref name="path" /> is <see langword="null" />,
+ /// an invalid path, or a zero-length string. If the caller does not have sufficient permissions to read the specified path,
+ /// no exception is thrown and the method returns <see langword="false" /> regardless of the existence of <paramref name="path" />.
+ /// </returns>
+ public static bool Exists([NotNullWhen(true)] string? path)
+ {
+ if (string.IsNullOrEmpty(path))
+ {
+ return false;
+ }
+
+ string? fullPath;
+ try
+ {
+ fullPath = GetFullPath(path);
+ }
+ catch (Exception ex) when (ex is ArgumentException or IOException or UnauthorizedAccessException)
+ {
+ return false;
+ }
+
+ return ExistsCore(fullPath);
+ }
+
+ /// <summary>
/// Returns the directory portion of a file path. This method effectively
/// removes the last segment of the given file path, i.e. it returns a
/// string consisting of all characters up to but not including the last
public static string Combine(params string[] paths) { throw null; }
public static bool EndsInDirectorySeparator(System.ReadOnlySpan<char> path) { throw null; }
public static bool EndsInDirectorySeparator(string path) { throw null; }
+ public static bool Exists([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] string? path) { throw null; }
public static System.ReadOnlySpan<char> GetDirectoryName(System.ReadOnlySpan<char> path) { throw null; }
public static string? GetDirectoryName(string? path) { throw null; }
public static System.ReadOnlySpan<char> GetExtension(System.ReadOnlySpan<char> path) { throw null; }