Normalize() static private méthode

Normalize the given path.
Normalizes via Win32 GetFullPathName(). It will also trim all "typical" whitespace at the end of the path (see s_trimEndChars). Will also trim initial spaces if the path is determined to be rooted. Note that invalid characters will be checked after the path is normalized, which could remove bad characters. (C:\|\..\a.txt -- C:\a.txt)
Thrown if the path is an illegal UNC (does not contain a full server/share) or contains illegal characters. Thrown if the path or a path segment exceeds the filesystem limits. Thrown if Windows returns ERROR_FILE_NOT_FOUND. (See Win32Marshal.GetExceptionForWin32Error) Thrown if Windows returns ERROR_PATH_NOT_FOUND. (See Win32Marshal.GetExceptionForWin32Error) Thrown if Windows returns ERROR_ACCESS_DENIED. (See Win32Marshal.GetExceptionForWin32Error) Thrown if Windows returns an error that doesn't map to the above. (See Win32Marshal.GetExceptionForWin32Error)
static private Normalize ( string path, bool checkInvalidCharacters, bool expandShortPaths ) : string
path string Path to normalize
checkInvalidCharacters bool True to check for invalid characters
expandShortPaths bool Attempt to expand short paths if true
Résultat string
Exemple #1
0
        // Returns a unique temporary file name, and creates a 0-byte file by that
        // name on disk.
        public static string GetTempFileName()
        {
            var tempPathBuilder = new ValueStringBuilder(stackalloc char[PathInternal.MaxShortPath]);

            GetTempPath(ref tempPathBuilder);

            var builder = new ValueStringBuilder(stackalloc char[PathInternal.MaxShortPath]);

            uint result = Interop.Kernel32.GetTempFileNameW(
                ref tempPathBuilder.GetPinnableReference(), "tmp", 0, ref builder.GetPinnableReference());

            tempPathBuilder.Dispose();

            if (result == 0)
            {
                throw Win32Marshal.GetExceptionForLastWin32Error();
            }

            builder.Length = builder.RawChars.IndexOf('\0');

            string path = PathHelper.Normalize(ref builder);

            builder.Dispose();
            return(path);
        }
Exemple #2
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 the path would normalize to string empty, we'll consider it empty
            if (PathInternal.IsEffectivelyEmpty(path))
            {
                throw new ArgumentException(SR.Arg_PathEmpty, nameof(path));
            }

            // Embedded null characters are the only invalid character case we trully care about.
            // This is because the nulls will signal the end of the string to Win32 and therefore have
            // unpredictable results.
            if (path.IndexOf('\0') != -1)
            {
                throw new ArgumentException(SR.Argument_InvalidPathChars, nameof(path));
            }

            if (PathInternal.IsExtended(path))
            {
                // \\?\ paths are considered normalized by definition. Windows doesn't normalize \\?\
                // paths and neither should we. Even if we wanted to GetFullPathName does not work
                // properly with device paths. If one wants to pass a \\?\ path through normalization
                // one can chop off the prefix, pass it to GetFullPath and add it again.
                return(path);
            }

            return(PathHelper.Normalize(path));
        }
Exemple #3
0
        // Returns a unique temporary file name, and creates a 0-byte file by that
        // name on disk.
        public static string GetTempFileName()
        {
            Span <char>        initialTempPathBuffer = stackalloc char[PathInternal.MaxShortPath];
            ValueStringBuilder tempPathBuilder       = new ValueStringBuilder(initialTempPathBuffer);

            GetTempPath(ref tempPathBuilder);

            Span <char> initialBuffer = stackalloc char[PathInternal.MaxShortPath];
            var         builder       = new ValueStringBuilder(initialBuffer);

            uint result = 0;

            while ((result = Interop.Kernel32.GetTempFileNameW(
                        ref tempPathBuilder.GetPinnableReference(), "tmp", 0, ref builder.GetPinnableReference())) > builder.Capacity)
            {
                // Reported size is greater than the buffer size. Increase the capacity.
                builder.EnsureCapacity(checked ((int)result));
            }

            tempPathBuilder.Dispose();

            if (result == 0)
            {
                throw Win32Marshal.GetExceptionForLastWin32Error();
            }

            builder.Length = (int)result;

            string path = PathHelper.Normalize(ref builder);

            builder.Dispose();
            return(path);
        }
        private static unsafe string CreateTempSubdirectoryCore(string?prefix)
        {
            ValueStringBuilder builder = new ValueStringBuilder(stackalloc char[PathInternal.MaxShortPath]);

            Path.GetTempPath(ref builder);

            // ensure the base TEMP directory exists
            CreateDirectory(PathHelper.Normalize(ref builder));

            builder.Append(prefix);

            const int RandomFileNameLength  = 12; // 12 == 8 + 1 (for period) + 3
            int       initialTempPathLength = builder.Length;

            builder.EnsureCapacity(initialTempPathLength + RandomFileNameLength);

            // For generating random file names
            // 8 random bytes provides 12 chars in our encoding for the 8.3 name.
            const int RandomKeyLength = 8;
            byte *    pKey            = stackalloc byte[RandomKeyLength];

            // to avoid an infinite loop, only try as many as GetTempFileNameW will create
            const int MaxAttempts = ushort.MaxValue;
            int       attempts    = 0;

            while (attempts < MaxAttempts)
            {
                // simulate a call to Path.GetRandomFileName() without allocating an intermediate string
                Interop.GetRandomBytes(pKey, RandomKeyLength);
                Path.Populate83FileNameFromRandomBytes(pKey, RandomKeyLength, builder.RawChars.Slice(builder.Length, RandomFileNameLength));
                builder.Length += RandomFileNameLength;

                string path = PathHelper.Normalize(ref builder);

                bool directoryCreated = Interop.Kernel32.CreateDirectory(path, null);
                if (!directoryCreated)
                {
                    // in the off-chance that the directory already exists, try again
                    int error = Marshal.GetLastPInvokeError();
                    if (error == Interop.Errors.ERROR_ALREADY_EXISTS)
                    {
                        builder.Length = initialTempPathLength;
                        attempts++;
                        continue;
                    }

                    throw Win32Marshal.GetExceptionForWin32Error(error, path);
                }

                builder.Dispose();
                return(path);
            }

            throw new IOException(SR.IO_MaxAttemptsReached);
        }
Exemple #5
0
        public static string GetTempPath()
        {
            var builder = new ValueStringBuilder(stackalloc char[PathInternal.MaxShortPath]);

            GetTempPath(ref builder);

            string path = PathHelper.Normalize(ref builder);

            builder.Dispose();
            return(path);
        }
Exemple #6
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
            {
                // 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, fullCheck, expandShortPaths));
            }
        }
Exemple #7
0
        // Gets the full path without argument validation
        private static string GetFullPathInternal(string path)
        {
            Debug.Assert(!string.IsNullOrEmpty(path));
            Debug.Assert(!path.Contains('\0'));

            if (PathInternal.IsExtended(path.AsSpan()))
            {
                // \\?\ paths are considered normalized by definition. Windows doesn't normalize \\?\
                // paths and neither should we. Even if we wanted to GetFullPathName does not work
                // properly with device paths. If one wants to pass a \\?\ path through normalization
                // one can chop off the prefix, pass it to GetFullPath and add it again.
                return(path);
            }

            return(PathHelper.Normalize(path));
        }
Exemple #8
0
        private static string NormalizeStandardPath(string path, bool fullCheck, bool expandShortPaths)
        {
            // Technically this doesn't matter, but we used to throw for this case
            if (String.IsNullOrWhiteSpace(path))
            {
                throw new ArgumentException(SR.Arg_PathIllegal);
            }

            PathHelper helper    = new PathHelper();
            string     returnVal = helper.Normalize(path, fullCheck, expandShortPaths);

            if (String.Equals(returnVal, path, StringComparison.Ordinal))
            {
                returnVal = path;
            }
            return(returnVal);
        }
Exemple #9
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 #10
0
        private static string NormalizeStandardPath(string path, bool fullCheck, bool expandShortPaths)
        {
            // Technically this doesn't matter, but we used to throw for this case
            if (String.IsNullOrWhiteSpace(path))
                throw new ArgumentException(SR.Arg_PathIllegal);

            PathHelper helper = new PathHelper();
            string returnVal = helper.Normalize(path, fullCheck, expandShortPaths);

            if (String.Equals(returnVal, path, StringComparison.Ordinal))
            {
                returnVal = path;
            }
            return returnVal;
        }
        /// <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));
            }
        }