Exemple #1
0
        public static bool IsPathRooted(ReadOnlySpan <char> path)
        {
            int length = path.Length;

            return((length >= 1 && PathInternal.IsDirectorySeparator(path[0])) ||
                   (length >= 2 && PathInternal.IsValidDriveChar(path[0]) && path[1] == PathInternal.VolumeSeparatorChar));
        }
Exemple #2
0
        /// <summary>
        /// Returns the characters to skip at the start of the path if it starts with space(s) and a drive or UNC.
        /// (examples are " C:", " \\")
        /// This is a legacy behavior of Path.GetFullPath().
        /// </summary>
        internal static int PathStartSkip(string path)
        {
            int startIndex = 0;

            while (startIndex < path.Length && path[startIndex] == ' ')
            {
                startIndex++;
            }

            if (startIndex > 0)
            {
                if (startIndex + 1 < path.Length &&
                    ((PathInternal.IsDirectorySeparator(path[startIndex]) && PathInternal.IsDirectorySeparator(path[startIndex + 1])) ||
                     (path[startIndex + 1] == ':' && PathInternal.IsValidDriveChar(path[startIndex]))))
                {
                    // Go ahead and skip spaces as we're either " C:" or " \\"
                }
                else
                {
                    // Not one of the cases we're looking for, go back to the beginning
                    startIndex = 0;
                }
            }

            return(startIndex);
        }
Exemple #3
0
 // Tests if the given path contains a root. A path is considered rooted
 // if it starts with a backslash ("\") or a valid drive letter and a colon (":").
 public static bool IsPathRooted(string path)
 {
     if (path != null)
     {
         int length = path.Length;
         if ((length >= 1 && PathInternal.IsDirectorySeparator(path[0])) ||
             (length >= 2 && PathInternal.IsValidDriveChar(path[0]) && path[1] == PathInternal.VolumeSeparatorChar))
         {
             return(true);
         }
     }
     return(false);
 }
        internal static int GetRootLength(ReadOnlySpan <char> path)
        {
            int  length = path.Length;
            int  index  = 0;
            bool flag1  = PathInternal.IsDevice(path);
            bool flag2  = flag1 && PathInternal.IsDeviceUNC(path);

            if (!flag1 | flag2 && length > 0 && PathInternal.IsDirectorySeparator(path[0]))
            {
                if (flag2 || length > 1 && PathInternal.IsDirectorySeparator(path[1]))
                {
                    index = flag2 ? 8 : 2;
                    int num = 2;
                    while (index < length && (!PathInternal.IsDirectorySeparator(path[index]) || --num > 0))
                    {
                        ++index;
                    }
                }
                else
                {
                    index = 1;
                }
            }
            else if (flag1)
            {
                index = 4;
                while (index < length && !PathInternal.IsDirectorySeparator(path[index]))
                {
                    ++index;
                }
                if (index < length && index > 4 && PathInternal.IsDirectorySeparator(path[index]))
                {
                    ++index;
                }
            }
            else if (length >= 2 && path[1] == ':' && PathInternal.IsValidDriveChar(path[0]))
            {
                index = 2;
                if (length > 2 && PathInternal.IsDirectorySeparator(path[2]))
                {
                    ++index;
                }
            }
            return(index);
        }
Exemple #5
0
        /// <summary>
        /// Returns the characters to skip at the start of the path if it starts with space(s) and a drive or directory separator.
        /// (examples are " C:", " \")
        /// This is a legacy behavior of Path.GetFullPath().
        /// </summary>
        /// <remarks>
        /// Note that this conflicts with IsPathRooted() which doesn't (and never did) such a skip.
        /// </remarks>
        internal static int PathStartSkip(string path)
        {
            int startIndex = 0;

            while (startIndex < path.Length && path[startIndex] == ' ')
            {
                startIndex++;
            }

            if (startIndex > 0 && (startIndex < path.Length && PathInternal.IsDirectorySeparator(path[startIndex])) ||
                (startIndex + 1 < path.Length && path[startIndex + 1] == ':' && PathInternal.IsValidDriveChar(path[startIndex])))
            {
                // Go ahead and skip spaces as we're either " C:" or " \"
                return(startIndex);
            }

            return(0);
        }
Exemple #6
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));
            }

            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));
        }
Exemple #7
0
        // Expands the given path to a fully qualified path.
        public static string GetFullPath(string path)
        {
            if (path == null)
            {
                throw new ArgumentNullException(nameof(path));
            }

            // Embedded null characters are the only invalid character case we want to check up front.
            // This is because the nulls will signal the end of the string to Win32 and therefore have
            // unpredictable results. Other invalid characters we give a chance to be normalized out.
            if (path.IndexOf('\0') != -1)
            {
                throw new ArgumentException(SR.Argument_InvalidPathChars, nameof(path));
            }

            if (PathInternal.IsExtended(path))
            {
                // We can't really know what is valid for all cases of extended paths.
                //
                //  - object names can include other characters as well (':', '/', etc.)
                //  - even file objects have different rules (pipe names can contain most characters)
                //
                // As such we will do no further analysis of extended paths to avoid blocking known and unknown
                // scenarios as well as minimizing compat breaks should we block now and need to unblock later.
                return(path);
            }

            bool isDevice = PathInternal.IsDevice(path);

            if (!isDevice)
            {
                // Toss out paths with colons that aren't a valid drive specifier.
                // Cannot start with a colon and can only be of the form "C:".
                // (Note that we used to explicitly check "http:" and "file:"- these are caught by this check now.)
                int startIndex = PathInternal.PathStartSkip(path);

                // Move past the colon
                startIndex += 2;

                if ((path.Length > 0 && path[0] == PathInternal.VolumeSeparatorChar) ||
                    (path.Length >= startIndex && path[startIndex - 1] == PathInternal.VolumeSeparatorChar && !PathInternal.IsValidDriveChar(path[startIndex - 2])) ||
                    (path.Length > startIndex && path.IndexOf(PathInternal.VolumeSeparatorChar, startIndex) != -1))
                {
                    throw new NotSupportedException(SR.Format(SR.Argument_PathFormatNotSupported_Path, path));
                }
            }

            // Technically this doesn't matter but we used to throw for this case
            if (PathInternal.IsEffectivelyEmpty(path))
            {
                throw new ArgumentException(SR.Arg_PathEmpty, nameof(path));
            }

            // We don't want to check invalid characters for device format- see comments for extended above
            string fullPath = PathHelper.Normalize(path, checkInvalidCharacters: !isDevice, expandShortPaths: true);

            if (!isDevice)
            {
                // Emulate FileIOPermissions checks, retained for compatibility (normal invalid characters have already been checked)
                if (PathInternal.HasWildCardCharacters(fullPath))
                {
                    throw new ArgumentException(SR.Argument_InvalidPathChars, nameof(path));
                }
            }

            return(fullPath);
        }
Exemple #8
0
        // Token: 0x0600195B RID: 6491 RVA: 0x00054644 File Offset: 0x00052844
        internal static int PathStartSkip(string path)
        {
            int num = 0;

            while (num < path.Length && path[num] == ' ')
            {
                num++;
            }
            if ((num > 0 && num < path.Length && PathInternal.IsDirectorySeparator(path[num])) || (num + 1 < path.Length && path[num + 1] == Path.VolumeSeparatorChar && PathInternal.IsValidDriveChar(path[num])))
            {
                return(num);
            }
            return(0);
        }
Exemple #9
0
 // Token: 0x0600195A RID: 6490 RVA: 0x000545C8 File Offset: 0x000527C8
 internal static bool IsPartiallyQualified(StringBuffer path)
 {
     if (path.Length < 2U)
     {
         return(true);
     }
     if (PathInternal.IsDirectorySeparator(path[0U]))
     {
         return(path[1U] != '?' && !PathInternal.IsDirectorySeparator(path[1U]));
     }
     return(path.Length < 3U || path[1U] != Path.VolumeSeparatorChar || !PathInternal.IsDirectorySeparator(path[2U]) || !PathInternal.IsValidDriveChar(path[0U]));
 }
Exemple #10
0
 // Token: 0x06001959 RID: 6489 RVA: 0x0005454C File Offset: 0x0005274C
 internal static bool IsPartiallyQualified(string path)
 {
     if (path.Length < 2)
     {
         return(true);
     }
     if (PathInternal.IsDirectorySeparator(path[0]))
     {
         return(path[1] != '?' && !PathInternal.IsDirectorySeparator(path[1]));
     }
     return(path.Length < 3 || path[1] != Path.VolumeSeparatorChar || !PathInternal.IsDirectorySeparator(path[2]) || !PathInternal.IsValidDriveChar(path[0]));
 }
Exemple #11
0
        // Token: 0x06001941 RID: 6465 RVA: 0x00053E6C File Offset: 0x0005206C
        internal static bool HasInvalidVolumeSeparator(string path)
        {
            int num = (!AppContextSwitches.UseLegacyPathHandling && PathInternal.IsExtended(path)) ? "\\\\?\\".Length : PathInternal.PathStartSkip(path);

            return((path.Length > num && path[num] == Path.VolumeSeparatorChar) || (path.Length >= num + 2 && path[num + 1] == Path.VolumeSeparatorChar && !PathInternal.IsValidDriveChar(path[num])) || (path.Length > num + 2 && path.IndexOf(Path.VolumeSeparatorChar, num + 2) != -1));
        }
Exemple #12
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(GetFullPathInternal(path));
            }

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

            int    length = path.Length;
            string combinedPath;

            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.AsSpan()).EqualsOrdinal(GetVolumeName(basePath.AsSpan())))
                {
                    // Matching root
                    // "C:Foo" and "C:\Bar" => "C:\Bar\Foo"
                    // "C:Foo" and "\\?\C:\Bar" => "\\?\C:\Bar\Foo"
                    combinedPath = Join(basePath.AsSpan(), 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.AsSpan())
                        ? path.Insert(2, @"\")
                        : length == 2
                            ? JoinInternal(basePath.AsSpan(0, 4), path.AsSpan(), @"\".AsSpan())
                            : JoinInternal(basePath.AsSpan(0, 4), path.AsSpan(0, 2), @"\".AsSpan(), path.AsSpan(2));
                }
            }
            else
            {
                // "Simple" relative path
                // "Foo" and "C:\Bar" => "C:\Bar\Foo"
                // "Foo" and "\\?\C:\Bar" => "\\?\C:\Bar\Foo"
                combinedPath = JoinInternal(basePath.AsSpan(), path.AsSpan());
            }

            // 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.AsSpan())
                ? PathInternal.RemoveRelativeSegments(combinedPath, PathInternal.GetRootLength(combinedPath.AsSpan()))
                : GetFullPathInternal(combinedPath));
        }
        /// <summary>
        /// Normalize the path and check for bad characters or other invalid syntax.
        /// </summary>
        /// <remarks>
        /// The legacy NormalizePath
        /// </remarks>
        private static string NormalizeAndValidatePath(string path)
        {
            Debug.Assert(path != null, "path can't be null");

            // Embedded null characters are the only invalid character case we want to check up front.
            // This is because the nulls will signal the end of the string to Win32 and therefore have
            // unpredictable results. Other invalid characters we give a chance to be normalized out.
            if (path.IndexOf('\0') != -1)
            {
                throw new ArgumentException(SR.Argument_InvalidPathChars, "path");
            }

            // Toss out paths with colons that aren't a valid drive specifier.
            // Cannot start with a colon and can only be of the form "C:" or "\\?\C:".
            // (Note that we used to explicitly check "http:" and "file:"- these are caught by this check now.)
            int  startIndex = PathInternal.PathStartSkip(path);
            bool isExtended = path.Length >= PathInternal.ExtendedPathPrefix.Length + startIndex &&
                              path.IndexOf(PathInternal.ExtendedPathPrefix, startIndex, PathInternal.ExtendedPathPrefix.Length, StringComparison.Ordinal) >= 0;

            if (isExtended)
            {
                startIndex += PathInternal.ExtendedPathPrefix.Length;
            }

            // Move past the colon
            startIndex += 2;

            if ((path.Length > 0 && path[0] == VolumeSeparatorChar) ||
                (path.Length >= startIndex && path[startIndex - 1] == VolumeSeparatorChar && !PathInternal.IsValidDriveChar(path[startIndex - 2])) ||
                (path.Length > startIndex && path.IndexOf(VolumeSeparatorChar, startIndex) != -1))
            {
                throw new NotSupportedException(SR.Argument_PathFormatNotSupported);
            }

            if (isExtended)
            {
                // If the path is in extended syntax, we don't need to normalize, but we still do some basic validity checks
                if (!ValidateExtendedPath(path))
                {
                    throw new ArgumentException(SR.Arg_PathIllegal);
                }

                // \\?\GLOBALROOT gives access to devices out of the scope of the current user, we
                // don't want to allow this for security reasons.
                // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247.aspx#nt_namespaces
                if (path.StartsWith(@"\\?\globalroot", StringComparison.OrdinalIgnoreCase))
                {
                    throw new ArgumentException(SR.Arg_PathGlobalRoot);
                }


                // Look for illegal path characters.
                PathInternal.CheckInvalidPathChars(path);

                return(path);
            }
            else
            {
                // Technically this doesn't matter but we used to throw for this case
                if (String.IsNullOrWhiteSpace(path))
                {
                    throw new ArgumentException(SR.Arg_PathIllegal);
                }

                return(PathHelper.Normalize(path, checkInvalidCharacters: true, expandShortPaths: true));
            }
        }
Exemple #14
0
        private static string NormalizePath(string path, bool fullCheck = true, bool expandShortPaths = true)
        {
            Debug.Assert(path != null, "path can't be null");

            bool isExtended = PathInternal.IsExtended(path);

            if (fullCheck)
            {
                // Embedded null characters are the only invalid character case we want to check up front.
                // This is because the nulls will signal the end of the string to Win32 and therefore have
                // unpredictable results. Other invalid characters we give a chance to be normalized out.
                if (path.IndexOf('\0') != -1)
                {
                    throw new ArgumentException(SR.Argument_InvalidPathChars, "path");
                }

                // Toss out paths with colons that aren't a valid drive specifier.
                // Cannot start with a colon and can only be of the form "C:" or "\\?\C:".
                // (Note that we used to explicitly check "http:" and "file:"- these are caught by this check now.)
                int startIndex = PathInternal.PathStartSkip(path) + 2;
                if (isExtended)
                {
                    startIndex += PathInternal.ExtendedPathPrefix.Length;
                }

                if ((path.Length > 0 && path[0] == VolumeSeparatorChar) ||
                    (path.Length >= startIndex && path[startIndex - 1] == VolumeSeparatorChar && !PathInternal.IsValidDriveChar(path[startIndex - 2])) ||
                    (path.Length > startIndex && path.IndexOf(VolumeSeparatorChar, startIndex) != -1))
                {
                    throw new NotSupportedException(SR.Argument_PathFormatNotSupported);
                }
            }

            if (isExtended)
            {
                return(NormalizeExtendedPath(path, fullCheck));
            }
            else
            {
                return(NormalizeStandardPath(path, fullCheck, expandShortPaths));
            }
        }
 internal static bool IsPartiallyQualified(ReadOnlySpan <char> path)
 {
     if (path.Length < 2)
     {
         return(true);
     }
     return(PathInternal.IsDirectorySeparator(path[0]) ? path[1] != '?' && !PathInternal.IsDirectorySeparator(path[1]) : path.Length < 3 || path[1] != ':' || !PathInternal.IsDirectorySeparator(path[2]) || !PathInternal.IsValidDriveChar(path[0]));
 }