// Returns the directory path of a file path. This method effectively // removes the last element of the given file path, i.e. it returns a // string consisting of all characters up to but not including the last // backslash ("\") in the file path. The returned value is null if the file // path is null or if the file path denotes a root (such as "\", "C:", or // "\\server\share"). public static string GetDirectoryName(string path) { if (path == null) { return(null); } if (PathInternal.IsEffectivelyEmpty(path)) { throw new ArgumentException(SR.Arg_PathEmpty, nameof(path)); } path = PathInternal.NormalizeDirectorySeparators(path); int root = PathInternal.GetRootLength(path); int i = path.Length; if (i > root) { while (i > root && !PathInternal.IsDirectorySeparator(path[--i])) { ; } return(path.Substring(0, i)); } return(null); }
// Returns the directory path of a file path. This method effectively // removes the last element of the given file path, i.e. it returns a // string consisting of all characters up to but not including the last // backslash ("\") in the file path. The returned value is null if the file // path is null or if the file path denotes a root (such as "\", "C:", or // "\\server\share"). public static string GetDirectoryName(string path) { if (string.IsNullOrWhiteSpace(path)) { if (path == null) { return(null); } throw new ArgumentException(SR.Arg_PathEmpty, nameof(path)); } PathInternal.CheckInvalidPathChars(path); path = PathInternal.NormalizeDirectorySeparators(path); int root = PathInternal.GetRootLength(path); int i = path.Length; if (i > root) { while (i > root && !PathInternal.IsDirectorySeparator(path[--i])) { ; } return(path.Substring(0, i)); } return(null); }
// Expands the given path to a fully qualified path. public static string GetFullPath(string path) { if (path == null) { throw new ArgumentNullException(nameof(path)); } if (path.Length == 0) { throw new ArgumentException(SR.Arg_PathEmpty, nameof(path)); } if (path.Contains('\0')) { throw new ArgumentException(SR.Argument_InvalidPathChars, nameof(path)); } // Expand with current directory if necessary if (!IsPathRooted(path)) { path = Combine(Interop.Sys.GetCwd(), path); } // We would ideally use realpath to do this, but it resolves symlinks, requires that the file actually exist, // and turns it into a full path, which we only want if fullCheck is true. string collapsedString = PathInternal.RemoveRelativeSegments(path, PathInternal.GetRootLength(path)); Debug.Assert(collapsedString.Length < path.Length || collapsedString.ToString() == path, "Either we've removed characters, or the string should be unmodified from the input path."); string result = collapsedString.Length == 0 ? PathInternal.DirectorySeparatorCharAsString : collapsedString; return(result); }
internal static void SplitDirectoryFile(string path, out string directory, out string file) { directory = null; file = null; // assumes a validated full path if (path != null) { int length = path.Length; int rootLength = PathInternal.GetRootLength(path); // ignore a trailing slash if (length > rootLength && EndsInDirectorySeparator(path)) { length--; } // find the pivot index between end of string and root for (int pivot = length - 1; pivot >= rootLength; pivot--) { if (PathInternal.IsDirectorySeparator(path[pivot])) { directory = path.Substring(0, pivot); file = path.Substring(pivot + 1, length - pivot - 1); return; } } // no pivot, return just the trimmed directory directory = path.Substring(0, length); } }
private static SafeFileHandle OpenHandle(string fullPath, bool asDirectory) { string root = fullPath.Substring(0, PathInternal.GetRootLength(fullPath)); if (root == fullPath && root[1] == Path.VolumeSeparatorChar) { // intentionally not fullpath, most upstack public APIs expose this as path. throw new ArgumentException(SR.Arg_PathIsVolume, "path"); } SafeFileHandle handle = Interop.Kernel32.CreateFile( fullPath, Interop.Kernel32.GenericOperations.GENERIC_WRITE, FileShare.ReadWrite | FileShare.Delete, FileMode.Open, asDirectory ? Interop.Kernel32.FileOperations.FILE_FLAG_BACKUP_SEMANTICS : 0); if (handle.IsInvalid) { int errorCode = Marshal.GetLastWin32Error(); // NT5 oddity - when trying to open "C:\" as a File, // we usually get ERROR_PATH_NOT_FOUND from the OS. We should // probably be consistent w/ every other directory. if (!asDirectory && errorCode == Interop.Errors.ERROR_PATH_NOT_FOUND && fullPath.Equals(Directory.GetDirectoryRoot(fullPath))) { errorCode = Interop.Errors.ERROR_ACCESS_DENIED; } throw Win32Marshal.GetExceptionForWin32Error(errorCode, fullPath); } return(handle); }
// Returns the directory path of a file path. This method effectively // removes the last element of the given file path, i.e. it returns a // string consisting of all characters up to but not including the last // backslash ("\") in the file path. The returned value is null if the file // path is null or if the file path denotes a root (such as "\", "C:", or // "\\server\share"). public static string GetDirectoryName(string path) { if (path != null) { PathInternal.CheckInvalidPathChars(path); path = NormalizePath(path, fullCheck: false); int root = PathInternal.GetRootLength(path); int i = path.Length; if (i > root) { i = path.Length; if (i == root) { return(null); } while (i > root && !PathInternal.IsDirectorySeparator(path[--i])) { ; } return(path.Substring(0, i)); } } return(null); }
public static unsafe ReadOnlySpan <char> GetDirectoryNameNoChecks(ReadOnlySpan <char> path) { if (path.Length == 0) { return(ReadOnlySpan <char> .Empty); } int root = PathInternal.GetRootLength(path); int i = path.Length; fixed(char *pathPtr = &path.DangerousGetPinnableReference()) { var pathSpan = new Span <char>(pathPtr, path.Length); if (i > root) { while (i > root && !PathInternal.IsDirectorySeparator(pathSpan[--i])) { ; } return(pathSpan.Slice(0, i)); } } return(ReadOnlySpan <char> .Empty); }
internal static uint GetRootLength(StringBuffer path) { if (path.Length == 0U) { return(0U); } return(PathInternal.GetRootLength(path.CharPointer, (ulong)path.Length)); }
internal static String InternalGetDirectoryRoot(String path) { if (path == null) { return(null); } return(path.Substring(0, PathInternal.GetRootLength(path))); }
internal FileInfo(String fullPath, bool ignoreThis) { Contract.Assert(PathInternal.GetRootLength(fullPath) > 0, "fullPath must be fully qualified!"); _name = Path.GetFileName(fullPath); OriginalPath = _name; FullPath = fullPath; DisplayPath = _name; }
internal DirectoryInfo(String fullPath, bool junk) { Debug.Assert(PathInternal.GetRootLength(fullPath) > 0, "fullPath must be fully qualified!"); // Fast path when we know a DirectoryInfo exists. OriginalPath = Path.GetFileName(fullPath); FullPath = fullPath; DisplayPath = GetDisplayName(OriginalPath, FullPath); }
public static string GetPathRoot(string path) { if (path == null) { return(null); } path = NormalizePath(path, fullCheck: false); return(path.Substring(0, PathInternal.GetRootLength(path))); }
internal static bool AreRootsEqual( string first, string second, StringComparison comparisonType) { int rootLength1 = PathInternal.GetRootLength(first.AsSpan()); int rootLength2 = PathInternal.GetRootLength(second.AsSpan()); return(rootLength1 == rootLength2 && string.Compare(first, 0, second, 0, rootLength1, comparisonType) == 0); }
internal DirectoryInfo(String fullPath, bool junk) { Contract.Assert(PathInternal.GetRootLength(fullPath) > 0, "fullPath must be fully qualified!"); // Fast path when we know a DirectoryInfo exists. OriginalPath = Path.GetFileName(fullPath); FullPath = fullPath; DisplayPath = GetDisplayName(OriginalPath, FullPath); demandDir = new String[] { Directory.GetDemandDir(fullPath, true) }; }
internal unsafe static int GetRootLength(string path) { char *ptr = path; if (ptr != null) { ptr += RuntimeHelpers.OffsetToStringData / 2; } return((int)PathInternal.GetRootLength(ptr, (ulong)((long)path.Length))); }
/// <remarks> /// Unlike the string overload, this method will not normalize directory separators. /// </remarks> public static ReadOnlySpan <char> GetPathRoot(ReadOnlySpan <char> path) { if (PathInternal.IsEffectivelyEmpty(path)) { return(ReadOnlySpan <char> .Empty); } int pathRoot = PathInternal.GetRootLength(path); return(pathRoot <= 0 ? ReadOnlySpan <char> .Empty : path.Slice(0, pathRoot)); }
// Returns the root portion of the given path. The resulting string // consists of those rightmost characters of the path that constitute the // root of the path. Possible patterns for the resulting string are: An // empty string (a relative path on the current drive), "\" (an absolute // path on the current drive), "X:" (a relative path on a given drive, // where X is the drive letter), "X:\" (an absolute path on a given drive), // and "\\server\share" (a UNC path for a given server and share name). // The resulting string is null if path is null. public static string GetPathRoot(string path) { if (path == null) { return(null); } PathInternal.CheckInvalidPathChars(path); int pathRoot = PathInternal.GetRootLength(path); return(pathRoot <= 0 ? String.Empty : path.Substring(0, pathRoot)); }
// Returns the root portion of the given path. The resulting string // consists of those rightmost characters of the path that constitute the // root of the path. Possible patterns for the resulting string are: An // empty string (a relative path on the current drive), "\" (an absolute // path on the current drive), "X:" (a relative path on a given drive, // where X is the drive letter), "X:\" (an absolute path on a given drive), // and "\\server\share" (a UNC path for a given server and share name). // The resulting string is null if path is null. public static string GetPathRoot(string path) { if (path == null) { return(null); } PathInternal.CheckInvalidPathChars(path); int pathRoot = PathInternal.GetRootLength(path); // Need to return the normalized directory separator return(pathRoot <= 0 ? string.Empty : path.Substring(0, pathRoot).Replace(AltDirectorySeparatorChar, DirectorySeparatorChar)); }
public static string GetDirectoryRoot(string path) { if (path == null) { throw new ArgumentNullException(nameof(path)); } string fullPath = Path.GetFullPath(path); string root = fullPath.Substring(0, PathInternal.GetRootLength(fullPath)); return(root); }
public static String GetDirectoryRoot(String path) { if (path == null) { throw new ArgumentNullException("path"); } Contract.EndContractBlock(); String fullPath = Path.GetFullPath(path); String root = fullPath.Substring(0, PathInternal.GetRootLength(fullPath)); return(root); }
// Returns the root portion of the given path. The resulting string // consists of those rightmost characters of the path that constitute the // root of the path. Possible patterns for the resulting string are: An // empty string (a relative path on the current drive), "\" (an absolute // path on the current drive), "X:" (a relative path on a given drive, // where X is the drive letter), "X:\" (an absolute path on a given drive), // and "\\server\share" (a UNC path for a given server and share name). // The resulting string is null if path is null. If the path is empty or // only contains whitespace characters an ArgumentException gets thrown. public static string GetPathRoot(string path) { if (path == null) { return(null); } if (PathInternal.IsEffectivelyEmpty(path)) { throw new ArgumentException(SR.Arg_PathEmpty, nameof(path)); } // Need to return the normalized directory separator path = PathInternal.NormalizeDirectorySeparators(path); int pathRoot = PathInternal.GetRootLength(path); return(pathRoot <= 0 ? string.Empty : path.Substring(0, pathRoot)); }
private static int GetDirectoryNameOffset(ReadOnlySpan <char> path) { int rootLength = PathInternal.GetRootLength(path); int length = path.Length; if (length <= rootLength) { return(-1); } do { ; }while (length > rootLength && !PathInternal.IsDirectorySeparator(path[--length])); while (length > rootLength && PathInternal.IsDirectorySeparator(path[length - 1])) { --length; } return(length); }
// Returns the root portion of the given path. The resulting string // consists of those rightmost characters of the path that constitute the // root of the path. Possible patterns for the resulting string are: An // empty string (a relative path on the current drive), "\" (an absolute // path on the current drive), "X:" (a relative path on a given drive, // where X is the drive letter), "X:\" (an absolute path on a given drive), // and "\\server\share" (a UNC path for a given server and share name). // The resulting string is null if path is null. If the path is empty or // only contains whitespace characters an ArgumentException gets thrown. public static string GetPathRoot(string path) { if (path == null) { return(null); } if (string.IsNullOrWhiteSpace(path)) { throw new ArgumentException(SR.Arg_PathEmpty, nameof(path)); } PathInternal.CheckInvalidPathChars(path); // Need to return the normalized directory separator path = PathInternal.NormalizeDirectorySeparators(path); int pathRoot = PathInternal.GetRootLength(path); return(pathRoot <= 0 ? string.Empty : path.Substring(0, pathRoot)); }
// Gets the full path without argument validation private static string GetFullPathInternal(string path) { Debug.Assert(!string.IsNullOrEmpty(path)); Debug.Assert(!path.Contains('\0')); // Expand with current directory if necessary if (!IsPathRooted(path)) { path = Combine(Interop.Sys.GetCwd(), path); } // We would ideally use realpath to do this, but it resolves symlinks and requires that the file actually exist. string collapsedString = PathInternal.RemoveRelativeSegments(path, PathInternal.GetRootLength(path)); Debug.Assert(collapsedString.Length < path.Length || collapsedString.ToString() == path, "Either we've removed characters, or the string should be unmodified from the input path."); string result = collapsedString.Length == 0 ? PathInternal.DirectorySeparatorCharAsString : collapsedString; return(result); }
public static ReadOnlySpan <char> GetDirectoryNameNoChecks(ReadOnlySpan <char> path) { if (path.Length == 0) { return(ReadOnlySpan <char> .Empty); } int root = PathInternal.GetRootLength(path); int i = path.Length; if (i > root) { while (i > root && !PathInternal.IsDirectorySeparator(path[--i])) { ; } return(path.Slice(0, i)); } return(ReadOnlySpan <char> .Empty); }
private static SafeFileHandle OpenHandleToWriteAttributes(string fullPath, bool asDirectory) { if (fullPath.Length == PathInternal.GetRootLength(fullPath) && fullPath[1] == Path.VolumeSeparatorChar) { // intentionally not fullpath, most upstack public APIs expose this as path. throw new ArgumentException(SR.Arg_PathIsVolume, "path"); } int dwFlagsAndAttributes = Interop.Kernel32.FileOperations.FILE_FLAG_OPEN_REPARSE_POINT; if (asDirectory) { dwFlagsAndAttributes |= Interop.Kernel32.FileOperations.FILE_FLAG_BACKUP_SEMANTICS; } SafeFileHandle handle = Interop.Kernel32.CreateFile( fullPath, Interop.Kernel32.FileOperations.FILE_WRITE_ATTRIBUTES, FileShare.ReadWrite | FileShare.Delete, FileMode.Open, dwFlagsAndAttributes); if (handle.IsInvalid) { int errorCode = Marshal.GetLastWin32Error(); // NT5 oddity - when trying to open "C:\" as a File, // we usually get ERROR_PATH_NOT_FOUND from the OS. We should // probably be consistent w/ every other directory. if (!asDirectory && errorCode == Interop.Errors.ERROR_PATH_NOT_FOUND && fullPath.Equals(Directory.GetDirectoryRoot(fullPath))) { errorCode = Interop.Errors.ERROR_ACCESS_DENIED; } throw Win32Marshal.GetExceptionForWin32Error(errorCode, fullPath); } return(handle); }
internal static int GetDirectoryNameOffset(ReadOnlySpan <char> path) { int rootLength = PathInternal.GetRootLength(path); int end = path.Length; if (end <= rootLength) { return(-1); } while (end > rootLength && !PathInternal.IsDirectorySeparator(path[--end])) { ; } // Trim off any remaining separators (to deal with C:\foo\\bar) while (end > rootLength && PathInternal.IsDirectorySeparator(path[end - 1])) { end--; } return(end); }
public override void CreateDirectory(string fullPath) { if (PathInternal.IsDirectoryTooLong(fullPath)) { throw new PathTooLongException(SR.IO_PathTooLong); } // We can save a bunch of work if the directory we want to create already exists. This also // saves us in the case where sub paths are inaccessible (due to ERROR_ACCESS_DENIED) but the // final path is accessable and the directory already exists. For example, consider trying // to create c:\Foo\Bar\Baz, where everything already exists but ACLS prevent access to c:\Foo // and c:\Foo\Bar. In that case, this code will think it needs to create c:\Foo, and c:\Foo\Bar // and fail to due so, causing an exception to be thrown. This is not what we want. if (DirectoryExists(fullPath)) { return; } List <string> stackDir = new List <string>(); // Attempt to figure out which directories don't exist, and only // create the ones we need. Note that InternalExists may fail due // to Win32 ACL's preventing us from seeing a directory, and this // isn't threadsafe. bool somepathexists = false; int length = fullPath.Length; // We need to trim the trailing slash or the code will try to create 2 directories of the same name. if (length >= 2 && PathHelpers.EndsInDirectorySeparator(fullPath)) { length--; } int lengthRoot = PathInternal.GetRootLength(fullPath); if (length > lengthRoot) { // Special case root (fullpath = X:\\) int i = length - 1; while (i >= lengthRoot && !somepathexists) { String dir = fullPath.Substring(0, i + 1); if (!DirectoryExists(dir)) // Create only the ones missing { stackDir.Add(dir); } else { somepathexists = true; } while (i > lengthRoot && !PathInternal.IsDirectorySeparator(fullPath[i])) { i--; } i--; } } int count = stackDir.Count; // If we were passed a DirectorySecurity, convert it to a security // descriptor and set it in he call to CreateDirectory. Interop.mincore.SECURITY_ATTRIBUTES secAttrs = default(Interop.mincore.SECURITY_ATTRIBUTES); bool r = true; int firstError = 0; String errorString = fullPath; // If all the security checks succeeded create all the directories while (stackDir.Count > 0) { String name = stackDir[stackDir.Count - 1]; stackDir.RemoveAt(stackDir.Count - 1); r = Interop.mincore.CreateDirectory(name, ref secAttrs); if (!r && (firstError == 0)) { int currentError = Marshal.GetLastWin32Error(); // While we tried to avoid creating directories that don't // exist above, there are at least two cases that will // cause us to see ERROR_ALREADY_EXISTS here. InternalExists // can fail because we didn't have permission to the // directory. Secondly, another thread or process could // create the directory between the time we check and the // time we try using the directory. Thirdly, it could // fail because the target does exist, but is a file. if (currentError != Interop.mincore.Errors.ERROR_ALREADY_EXISTS) { firstError = currentError; } else { // If there's a file in this directory's place, or if we have ERROR_ACCESS_DENIED when checking if the directory already exists throw. if (File.InternalExists(name) || (!DirectoryExists(name, out currentError) && currentError == Interop.mincore.Errors.ERROR_ACCESS_DENIED)) { firstError = currentError; errorString = name; } } } } // We need this check to mask OS differences // Handle CreateDirectory("X:\\") when X: doesn't exist. Similarly for n/w paths. if ((count == 0) && !somepathexists) { String root = Directory.InternalGetDirectoryRoot(fullPath); if (!DirectoryExists(root)) { throw Win32Marshal.GetExceptionForWin32Error(Interop.mincore.Errors.ERROR_PATH_NOT_FOUND, root); } return; } // Only throw an exception if creating the exact directory we // wanted failed to work correctly. if (!r && (firstError != 0)) { throw Win32Marshal.GetExceptionForWin32Error(firstError, errorString); } }
public static void CreateDirectory(string fullPath) { // NOTE: This logic is primarily just carried forward from Win32FileSystem.CreateDirectory. int length = fullPath.Length; // We need to trim the trailing slash or the code will try to create 2 directories of the same name. if (length >= 2 && Path.EndsInDirectorySeparator(fullPath)) { length--; } // For paths that are only // or /// if (length == 2 && PathInternal.IsDirectorySeparator(fullPath[1])) { throw new IOException(SR.Format(SR.IO_CannotCreateDirectory, fullPath)); } // We can save a bunch of work if the directory we want to create already exists. if (DirectoryExists(fullPath)) { return; } // Attempt to figure out which directories don't exist, and only create the ones we need. bool somepathexists = false; Stack <string> stackDir = new Stack <string>(); int lengthRoot = PathInternal.GetRootLength(fullPath); if (length > lengthRoot) { int i = length - 1; while (i >= lengthRoot && !somepathexists) { if (!DirectoryExists(fullPath.AsSpan(0, i + 1))) // Create only the ones missing { stackDir.Push(fullPath.Substring(0, i + 1)); } else { somepathexists = true; } while (i > lengthRoot && !PathInternal.IsDirectorySeparator(fullPath[i])) { i--; } i--; } } int count = stackDir.Count; if (count == 0 && !somepathexists) { ReadOnlySpan <char> root = Path.GetPathRoot(fullPath.AsSpan()); if (!DirectoryExists(root)) { throw Interop.GetExceptionForIoErrno(Interop.Error.ENOENT.Info(), fullPath, isDirectory: true); } return; } // Create all the directories int result = 0; Interop.ErrorInfo firstError = default(Interop.ErrorInfo); string errorString = fullPath; while (stackDir.Count > 0) { string name = stackDir.Pop(); // The mkdir command uses 0777 by default (it'll be AND'd with the process umask internally). // We do the same. result = Interop.Sys.MkDir(name, (int)Interop.Sys.Permissions.Mask); if (result < 0 && firstError.Error == 0) { Interop.ErrorInfo errorInfo = Interop.Sys.GetLastErrorInfo(); // While we tried to avoid creating directories that don't // exist above, there are a few cases that can fail, e.g. // a race condition where another process or thread creates // the directory first, or there's a file at the location. if (errorInfo.Error != Interop.Error.EEXIST) { firstError = errorInfo; } else if (FileExists(name) || (!DirectoryExists(name, out errorInfo) && errorInfo.Error == Interop.Error.EACCES)) { // If there's a file in this directory's place, or if we have ERROR_ACCESS_DENIED when checking if the directory already exists throw. firstError = errorInfo; errorString = name; } } } // Only throw an exception if creating the exact directory we wanted failed to work correctly. if (result < 0 && firstError.Error != 0) { throw Interop.GetExceptionForIoErrno(firstError, errorString, isDirectory: true); } }
public static string GetFullPath(string path, string basePath) { if (path == null) { throw new ArgumentNullException(nameof(path)); } if (basePath == null) { throw new ArgumentNullException(nameof(basePath)); } if (!IsPathFullyQualified(basePath)) { throw new ArgumentException(SR.Arg_BasePathNotFullyQualified, nameof(basePath)); } if (basePath.Contains('\0') || path.Contains('\0')) { throw new ArgumentException(SR.Argument_InvalidPathChars); } if (IsPathFullyQualified(path)) { return(GetFullPath(path)); } int length = path.Length; string combinedPath = null; if ((length >= 1 && PathInternal.IsDirectorySeparator(path[0]))) { // Path is current drive rooted i.e. starts with \: // "\Foo" and "C:\Bar" => "C:\Foo" // "\Foo" and "\\?\C:\Bar" => "\\?\C:\Foo" combinedPath = Join(GetPathRoot(basePath.AsSpan()), path); } else if (length >= 2 && PathInternal.IsValidDriveChar(path[0]) && path[1] == PathInternal.VolumeSeparatorChar) { // Drive relative paths Debug.Assert(length == 2 || !PathInternal.IsDirectorySeparator(path[2])); if (StringSpanHelpers.Equals(GetVolumeName(path), GetVolumeName(basePath))) { // Matching root // "C:Foo" and "C:\Bar" => "C:\Bar\Foo" // "C:Foo" and "\\?\C:\Bar" => "\\?\C:\Bar\Foo" combinedPath = Join(basePath, path.AsSpan().Slice(2)); } else { // No matching root, root to specified drive // "D:Foo" and "C:\Bar" => "D:Foo" // "D:Foo" and "\\?\C:\Bar" => "\\?\D:\Foo" combinedPath = !PathInternal.IsDevice(basePath) ? path.Insert(2, @"\") : length == 2 ? JoinInternal(basePath.AsSpan().Slice(0, 4), path, @"\") : JoinInternal(basePath.AsSpan().Slice(0, 4), path.AsSpan().Slice(0, 2), @"\", path.AsSpan().Slice(2)); } } else { // "Simple" relative path // "Foo" and "C:\Bar" => "C:\Bar\Foo" // "Foo" and "\\?\C:\Bar" => "\\?\C:\Bar\Foo" combinedPath = JoinInternal(basePath, path); } // Device paths are normalized by definition, so passing something of this format // to GetFullPath() won't do anything by design. Additionally, GetFullPathName() in // Windows doesn't root them properly. As such we need to manually remove segments. return(PathInternal.IsDevice(combinedPath) ? RemoveRelativeSegments(combinedPath, PathInternal.GetRootLength(combinedPath)) : GetFullPath(combinedPath)); }