Exemple #1
0
        // 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 unsafe string RemoveRelativeSegments(string path, int rootLength)
        {
            // ISSUE: untyped stack allocation
            ValueStringBuilder sb = new ValueStringBuilder(new Span <char>((void *)__untypedstackalloc(new IntPtr(520)), 260));

            if (PathInternal.RemoveRelativeSegments(path.AsSpan(), rootLength, ref sb))
            {
                path = sb.ToString();
            }
            sb.Dispose();
            return(path);
        }
Exemple #3
0
        // 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);
        }
Exemple #4
0
        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));
            }

            if (PathInternal.IsEffectivelyEmpty(path))
            {
                return(basePath);
            }

            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.AsSpan(1)); // Cut the separator to ensure we don't end up with two separators when joining with the root.
            }
            else if (length >= 2 && PathInternal.IsValidDriveChar(path[0]) && path[1] == PathInternal.VolumeSeparatorChar)
            {
                // Drive relative paths
                Debug.Assert(length == 2 || !PathInternal.IsDirectorySeparator(path[2]));

                if (GetVolumeName(path).EqualsOrdinal(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(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(0, 4), path, @"\")
                            : JoinInternal(basePath.AsSpan(0, 4), path.AsSpan(0, 2), @"\", path.AsSpan(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 (i.e. \\?\C:\.\tmp, \\.\C:\foo)
            // to Windows APIs won't do anything by design. Additionally, GetFullPathName() in Windows doesn't root
            // them properly. As such we need to manually remove segments and not use GetFullPath().

            return(PathInternal.IsDevice(combinedPath)
                ? PathInternal.RemoveRelativeSegments(combinedPath, PathInternal.GetRootLength(combinedPath))
                : GetFullPath(combinedPath));
        }