IsPartiallyQualified() public static méthode

public static IsPartiallyQualified ( string path ) : bool
path string
Résultat bool
Exemple #1
0
        private static void GetFullPathName(ReadOnlySpan<char> path, ref ValueStringBuilder builder)
        {
            // If the string starts with an extended prefix we would need to remove it from the path before we call GetFullPathName as
            // it doesn't root extended paths correctly. We don't currently resolve extended paths, so we'll just assert here.
            Debug.Assert(PathInternal.IsPartiallyQualified(path) || !PathInternal.IsExtended(path));

            uint result = 0;
            while ((result = Interop.Kernel32.GetFullPathNameW(ref MemoryMarshal.GetReference(path), (uint)builder.Capacity, ref builder.GetPinnableReference(), IntPtr.Zero)) > builder.Capacity)
            {
                // Reported size is greater than the buffer size. Increase the capacity.
                builder.EnsureCapacity(checked((int)result));
            }

            if (result == 0)
            {
                // Failure, get the error and throw
                int errorCode = Marshal.GetLastWin32Error();
                if (errorCode == 0)
                    errorCode = Interop.Errors.ERROR_BAD_PATHNAME;
                throw Win32Marshal.GetExceptionForWin32Error(errorCode, path.ToString());
            }

            builder.Length = (int)result;
        }
Exemple #2
0
 public static bool IsPathFullyQualified(string path)
 {
     return(!PathInternal.IsPartiallyQualified(path));
 }
Exemple #3
0
        private static string TryExpandShortFileName(ref StringBuffer outputBuffer, string originalPath)
        {
            // We guarantee we'll expand short names for paths that only partially exist. As such, we need to find the part of the path that actually does exist. To
            // avoid allocating like crazy we'll create only one input array and modify the contents with embedded nulls.

            Debug.Assert(!PathInternal.IsPartiallyQualified(ref outputBuffer), "should have resolved by now");

            // We'll have one of a few cases by now (the normalized path will have already:
            //
            //  1. Dos path (C:\)
            //  2. Dos UNC (\\Server\Share)
            //  3. Dos device path (\\.\C:\, \\?\C:\)
            //
            // We want to put the extended syntax on the front if it doesn't already have it, which may mean switching from \\.\.
            //
            // Note that we will never get \??\ here as GetFullPathName() does not recognize \??\ and will return it as C:\??\ (or whatever the current drive is).

            int  rootLength = PathInternal.GetRootLength(ref outputBuffer);
            bool isDevice   = PathInternal.IsDevice(ref outputBuffer);

            StringBuffer inputBuffer = new StringBuffer(0);

            try
            {
                bool isDosUnc       = false;
                int  rootDifference = 0;
                bool wasDotDevice   = false;

                // Add the extended prefix before expanding to allow growth over MAX_PATH
                if (isDevice)
                {
                    // We have one of the following (\\?\ or \\.\)
                    inputBuffer.Append(ref outputBuffer);

                    if (outputBuffer[2] == '.')
                    {
                        wasDotDevice   = true;
                        inputBuffer[2] = '?';
                    }
                }
                else
                {
                    isDosUnc       = IsDosUnc(ref outputBuffer);
                    rootDifference = GetInputBuffer(ref outputBuffer, isDosUnc, ref inputBuffer);
                }

                rootLength += rootDifference;
                int inputLength = inputBuffer.Length;

                bool success    = false;
                int  foundIndex = inputBuffer.Length - 1;

                while (!success)
                {
                    uint result = Interop.Kernel32.GetLongPathNameW(inputBuffer.UnderlyingArray, outputBuffer.UnderlyingArray, (uint)outputBuffer.Capacity);

                    // Replace any temporary null we added
                    if (inputBuffer[foundIndex] == '\0')
                    {
                        inputBuffer[foundIndex] = '\\';
                    }

                    if (result == 0)
                    {
                        // Look to see if we couldn't find the file
                        int error = Marshal.GetLastWin32Error();
                        if (error != Interop.Errors.ERROR_FILE_NOT_FOUND && error != Interop.Errors.ERROR_PATH_NOT_FOUND)
                        {
                            // Some other failure, give up
                            break;
                        }

                        // We couldn't find the path at the given index, start looking further back in the string.
                        foundIndex--;

                        for (; foundIndex > rootLength && inputBuffer[foundIndex] != '\\'; foundIndex--)
                        {
                            ;
                        }
                        if (foundIndex == rootLength)
                        {
                            // Can't trim the path back any further
                            break;
                        }
                        else
                        {
                            // Temporarily set a null in the string to get Windows to look further up the path
                            inputBuffer[foundIndex] = '\0';
                        }
                    }
                    else if (result > outputBuffer.Capacity)
                    {
                        // Not enough space. The result count for this API does not include the null terminator.
                        outputBuffer.EnsureCapacity(checked ((int)result));
                        result = Interop.Kernel32.GetLongPathNameW(inputBuffer.UnderlyingArray, outputBuffer.UnderlyingArray, (uint)outputBuffer.Capacity);
                    }
                    else
                    {
                        // Found the path
                        success             = true;
                        outputBuffer.Length = checked ((int)result);
                        if (foundIndex < inputLength - 1)
                        {
                            // It was a partial find, put the non-existent part of the path back
                            outputBuffer.Append(ref inputBuffer, foundIndex, inputBuffer.Length - foundIndex);
                        }
                    }
                }

                // Strip out the prefix and return the string
                ref StringBuffer bufferToUse = ref Choose(success, ref outputBuffer, ref inputBuffer);

                // Switch back from \\?\ to \\.\ if necessary
                if (wasDotDevice)
                {
                    bufferToUse[2] = '.';
                }

                string returnValue = null;

                int newLength = (int)(bufferToUse.Length - rootDifference);
                if (isDosUnc)
                {
                    // Need to go from \\?\UNC\ to \\?\UN\\
                    bufferToUse[PathInternal.UncExtendedPrefixLength - PathInternal.UncPrefixLength] = '\\';
                }

                // We now need to strip out any added characters at the front of the string
                if (bufferToUse.SubstringEquals(originalPath, rootDifference, newLength))
                {
                    // Use the original path to avoid allocating
                    returnValue = originalPath;
                }
                else
                {
                    returnValue = bufferToUse.Substring(rootDifference, newLength);
                }

                return(returnValue);
            }
Exemple #4
0
        internal static string TryExpandShortFileName(ref ValueStringBuilder outputBuilder, string?originalPath)
        {
            // We guarantee we'll expand short names for paths that only partially exist. As such, we need to find the part of the path that actually does exist. To
            // avoid allocating a lot we'll create only one input array and modify the contents with embedded nulls.

            Debug.Assert(!PathInternal.IsPartiallyQualified(outputBuilder.AsSpan()), "should have resolved by now");

            // We'll have one of a few cases by now (the normalized path will have already:
            //
            //  1. Dos path (C:\)
            //  2. Dos UNC (\\Server\Share)
            //  3. Dos device path (\\.\C:\, \\?\C:\)
            //
            // We want to put the extended syntax on the front if it doesn't already have it (for long path support and speed), which may mean switching from \\.\.
            //
            // Note that we will never get \??\ here as GetFullPathName() does not recognize \??\ and will return it as C:\??\ (or whatever the current drive is).

            int  rootLength = PathInternal.GetRootLength(outputBuilder.AsSpan());
            bool isDevice   = PathInternal.IsDevice(outputBuilder.AsSpan());

            // As this is a corner case we're not going to add a stackalloc here to keep the stack pressure down.
            var inputBuilder = new ValueStringBuilder();

            bool isDosUnc       = false;
            int  rootDifference = 0;
            bool wasDotDevice   = false;

            // Add the extended prefix before expanding to allow growth over MAX_PATH
            if (isDevice)
            {
                // We have one of the following (\\?\ or \\.\)
                inputBuilder.Append(outputBuilder.AsSpan());

                if (outputBuilder[2] == '.')
                {
                    wasDotDevice    = true;
                    inputBuilder[2] = '?';
                }
            }
            else
            {
                isDosUnc       = !PathInternal.IsDevice(outputBuilder.AsSpan()) && outputBuilder.Length > 1 && outputBuilder[0] == '\\' && outputBuilder[1] == '\\';
                rootDifference = PrependDevicePathChars(ref outputBuilder, isDosUnc, ref inputBuilder);
            }

            rootLength += rootDifference;
            int inputLength = inputBuilder.Length;

            bool success    = false;
            int  foundIndex = inputBuilder.Length - 1;

            while (!success)
            {
                uint result = Interop.Kernel32.GetLongPathNameW(
                    ref inputBuilder.GetPinnableReference(terminate: true), ref outputBuilder.GetPinnableReference(), (uint)outputBuilder.Capacity);

                // Replace any temporary null we added
                if (inputBuilder[foundIndex] == '\0')
                {
                    inputBuilder[foundIndex] = '\\';
                }

                if (result == 0)
                {
                    // Look to see if we couldn't find the file
                    int error = Marshal.GetLastWin32Error();
                    if (error != Interop.Errors.ERROR_FILE_NOT_FOUND && error != Interop.Errors.ERROR_PATH_NOT_FOUND)
                    {
                        // Some other failure, give up
                        break;
                    }

                    // We couldn't find the path at the given index, start looking further back in the string.
                    foundIndex--;

                    for (; foundIndex > rootLength && inputBuilder[foundIndex] != '\\'; foundIndex--)
                    {
                        ;
                    }
                    if (foundIndex == rootLength)
                    {
                        // Can't trim the path back any further
                        break;
                    }
                    else
                    {
                        // Temporarily set a null in the string to get Windows to look further up the path
                        inputBuilder[foundIndex] = '\0';
                    }
                }
                else if (result > outputBuilder.Capacity)
                {
                    // Not enough space. The result count for this API does not include the null terminator.
                    outputBuilder.EnsureCapacity(checked ((int)result));
                }
                else
                {
                    // Found the path
                    success = true;
                    outputBuilder.Length = checked ((int)result);
                    if (foundIndex < inputLength - 1)
                    {
                        // It was a partial find, put the non-existent part of the path back
                        outputBuilder.Append(inputBuilder.AsSpan(foundIndex, inputBuilder.Length - foundIndex));
                    }
                }
            }

            // If we were able to expand the path, use it, otherwise use the original full path result
            ref ValueStringBuilder builderToUse = ref (success ? ref outputBuilder : ref inputBuilder);
Exemple #5
0
        /// <summary>
        /// Gets reparse point information associated to <paramref name="linkPath"/>.
        /// </summary>
        /// <returns>The immediate link target, absolute or relative or null if the file is not a supported link.</returns>
        internal static unsafe string?GetImmediateLinkTarget(string linkPath, bool isDirectory, bool throwOnError, bool returnFullPath)
        {
            using SafeFileHandle handle = OpenSafeFileHandle(linkPath,
                                                             Interop.Kernel32.FileOperations.FILE_FLAG_BACKUP_SEMANTICS |
                                                             Interop.Kernel32.FileOperations.FILE_FLAG_OPEN_REPARSE_POINT);

            if (handle.IsInvalid)
            {
                if (!throwOnError)
                {
                    return(null);
                }

                int error = Marshal.GetLastWin32Error();
                // File not found doesn't make much sense coming from a directory.
                if (isDirectory && error == Interop.Errors.ERROR_FILE_NOT_FOUND)
                {
                    error = Interop.Errors.ERROR_PATH_NOT_FOUND;
                }

                throw Win32Marshal.GetExceptionForWin32Error(error, linkPath);
            }

            byte[] buffer = ArrayPool <byte> .Shared.Rent(Interop.Kernel32.MAXIMUM_REPARSE_DATA_BUFFER_SIZE);

            try
            {
                bool success = Interop.Kernel32.DeviceIoControl(
                    handle,
                    dwIoControlCode: Interop.Kernel32.FSCTL_GET_REPARSE_POINT,
                    lpInBuffer: IntPtr.Zero,
                    nInBufferSize: 0,
                    lpOutBuffer: buffer,
                    nOutBufferSize: Interop.Kernel32.MAXIMUM_REPARSE_DATA_BUFFER_SIZE,
                    out _,
                    IntPtr.Zero);

                if (!success)
                {
                    if (!throwOnError)
                    {
                        return(null);
                    }

                    int error = Marshal.GetLastWin32Error();
                    // The file or directory is not a reparse point.
                    if (error == Interop.Errors.ERROR_NOT_A_REPARSE_POINT)
                    {
                        return(null);
                    }

                    throw Win32Marshal.GetExceptionForWin32Error(error, linkPath);
                }

                Span <byte> bufferSpan = new(buffer);
                success = MemoryMarshal.TryRead(bufferSpan, out Interop.Kernel32.SymbolicLinkReparseBuffer rbSymlink);
                Debug.Assert(success);

                // We always use SubstituteName(Offset|Length) instead of PrintName(Offset|Length),
                // the latter is just the display name of the reparse point and it can show something completely unrelated to the target.

                if (rbSymlink.ReparseTag == Interop.Kernel32.IOReparseOptions.IO_REPARSE_TAG_SYMLINK)
                {
                    int offset = sizeof(Interop.Kernel32.SymbolicLinkReparseBuffer) + rbSymlink.SubstituteNameOffset;
                    int length = rbSymlink.SubstituteNameLength;

                    Span <char> targetPath = MemoryMarshal.Cast <byte, char>(bufferSpan.Slice(offset, length));

                    bool isRelative = (rbSymlink.Flags & Interop.Kernel32.SYMLINK_FLAG_RELATIVE) != 0;
                    if (!isRelative)
                    {
                        // Absolute target is in NT format and we need to clean it up before return it to the user.
                        if (targetPath.StartsWith(PathInternal.UncNTPathPrefix.AsSpan()))
                        {
                            // We need to prepend the Win32 equivalent of UNC NT prefix.
                            return(Path.Join(PathInternal.UncPathPrefix.AsSpan(), targetPath.Slice(PathInternal.UncNTPathPrefix.Length)));
                        }

                        return(GetTargetPathWithoutNTPrefix(targetPath));
                    }
                    else if (returnFullPath)
                    {
                        return(Path.Join(Path.GetDirectoryName(linkPath.AsSpan()), targetPath));
                    }
                    else
                    {
                        return(targetPath.ToString());
                    }
                }
                else if (rbSymlink.ReparseTag == Interop.Kernel32.IOReparseOptions.IO_REPARSE_TAG_MOUNT_POINT)
                {
                    success = MemoryMarshal.TryRead(bufferSpan, out Interop.Kernel32.MountPointReparseBuffer rbMountPoint);
                    Debug.Assert(success);

                    int offset = sizeof(Interop.Kernel32.MountPointReparseBuffer) + rbMountPoint.SubstituteNameOffset;
                    int length = rbMountPoint.SubstituteNameLength;

                    Span <char> targetPath = MemoryMarshal.Cast <byte, char>(bufferSpan.Slice(offset, length));

                    // Unlike symbolic links, mount point paths cannot be relative.
                    Debug.Assert(!PathInternal.IsPartiallyQualified(targetPath));
                    // Mount points cannot point to a remote location.
                    Debug.Assert(!targetPath.StartsWith(PathInternal.UncNTPathPrefix.AsSpan()));
                    return(GetTargetPathWithoutNTPrefix(targetPath));
                }

                return(null);
            }
            finally
            {
                ArrayPool <byte> .Shared.Return(buffer);
            }
Exemple #6
0
 public static bool IsPathFullyQualified(ReadOnlySpan <char> path)
 {
     return(!PathInternal.IsPartiallyQualified(path));
 }
Exemple #7
0
        private unsafe static string TryExpandShortFileName(StringBuffer outputBuffer, string originalPath)
        {
            // We guarantee we'll expand short names for paths that only partially exist. As such, we need to find the part of the path that actually does exist. To
            // avoid allocating like crazy we'll create only one input array and modify the contents with embedded nulls.

            Contract.Assert(!PathInternal.IsPartiallyQualified(outputBuffer), "should have resolved by now");

            using (StringBuffer inputBuffer = new StringBuffer(outputBuffer))
            {
                bool success    = false;
                uint lastIndex  = outputBuffer.Length - 1;
                uint foundIndex = lastIndex;
                uint rootLength = PathInternal.GetRootLength(outputBuffer);

                while (!success)
                {
                    uint result = Win32Native.GetLongPathNameW(inputBuffer.GetHandle(), outputBuffer.GetHandle(), outputBuffer.CharCapacity);

                    // Replace any temporary null we added
                    if (inputBuffer[foundIndex] == '\0')
                    {
                        inputBuffer[foundIndex] = '\\';
                    }

                    if (result == 0)
                    {
                        // Look to see if we couldn't find the file
                        int error = Marshal.GetLastWin32Error();
                        if (error != Win32Native.ERROR_FILE_NOT_FOUND && error != Win32Native.ERROR_PATH_NOT_FOUND)
                        {
                            // Some other failure, give up
                            break;
                        }

                        // We couldn't find the path at the given index, start looking further back in the string.
                        foundIndex--;

                        for (; foundIndex > rootLength && inputBuffer[foundIndex] != '\\'; foundIndex--)
                        {
                            ;
                        }
                        if (foundIndex == rootLength)
                        {
                            // Can't trim the path back any further
                            break;
                        }
                        else
                        {
                            // Temporarily set a null in the string to get Windows to look further up the path
                            inputBuffer[foundIndex] = '\0';
                        }
                    }
                    else if (result > outputBuffer.CharCapacity)
                    {
                        // Not enough space. The result count for this API does not include the null terminator.
                        outputBuffer.EnsureCharCapacity(result);
                    }
                    else
                    {
                        // Found the path
                        success             = true;
                        outputBuffer.Length = result;
                        if (foundIndex < lastIndex)
                        {
                            // It was a partial find, put the non-existant part of the path back
                            outputBuffer.Append(inputBuffer, foundIndex, inputBuffer.Length - foundIndex);
                        }
                    }
                }

                StringBuffer bufferToUse = success ? outputBuffer : inputBuffer;

                if (bufferToUse.SubstringEquals(originalPath))
                {
                    // Use the original path to avoid allocating
                    return(originalPath);
                }

                return(bufferToUse.ToString());
            }
        }