示例#1
0
        public void ReadOnlySpanReadFail()
        {
            ReadOnlySpan <byte> span = new byte[] { 1 };

            Assert.Equal <byte>(1, MemoryMarshal.Read <byte>(span));
            Assert.True(MemoryMarshal.TryRead(span, out byte byteValue));
            Assert.Equal(1, byteValue);

            TestHelpers.AssertThrows <ArgumentOutOfRangeException, byte>(span, (_span) => MemoryMarshal.Read <short>(_span));
            Assert.False(MemoryMarshal.TryRead(span, out short shortValue));
            TestHelpers.AssertThrows <ArgumentOutOfRangeException, byte>(span, (_span) => MemoryMarshal.Read <int>(_span));
            Assert.False(MemoryMarshal.TryRead(span, out int intValue));
            TestHelpers.AssertThrows <ArgumentOutOfRangeException, byte>(span, (_span) => MemoryMarshal.Read <long>(_span));
            Assert.False(MemoryMarshal.TryRead(span, out long longValue));

            TestHelpers.AssertThrows <ArgumentOutOfRangeException, byte>(span, (_span) => MemoryMarshal.Read <ushort>(_span));
            Assert.False(MemoryMarshal.TryRead(span, out ushort ushortValue));
            TestHelpers.AssertThrows <ArgumentOutOfRangeException, byte>(span, (_span) => MemoryMarshal.Read <uint>(_span));
            Assert.False(MemoryMarshal.TryRead(span, out uint uintValue));
            TestHelpers.AssertThrows <ArgumentOutOfRangeException, byte>(span, (_span) => MemoryMarshal.Read <ulong>(_span));
            Assert.False(MemoryMarshal.TryRead(span, out ulong ulongValue));

            ReadOnlySpan <byte> largeSpan = new byte[100];

            TestHelpers.AssertThrows <ArgumentException, byte>(largeSpan, (_span) => MemoryMarshal.Read <TestHelpers.TestValueTypeWithReference>(_span));
            TestHelpers.AssertThrows <ArgumentException, byte>(largeSpan, (_span) => MemoryMarshal.TryRead(_span, out TestHelpers.TestValueTypeWithReference stringValue));
        }
    public static Guid GenerateImproved(Guid guid, DateTime nowInput)
    {
        var         newGuid   = guid;
        Span <byte> guidArray = stackalloc byte[16];

#if NETCOREAPP
        if (!newGuid.TryWriteBytes(guidArray))
#elif NETFRAMEWORK
        if (!MemoryMarshal.TryWrite(guidArray, ref newGuid))
#endif
        {
            guidArray = newGuid.ToByteArray();
        }

        var now = nowInput; // Internal use, no need for DateTimeOffset

        // Get the days and milliseconds which will be used to build the byte string
        var days      = new TimeSpan(now.Ticks - BaseDateTicksConst);
        var timeOfDay = now.TimeOfDay;

        // Convert to a byte array
        Span <byte> scratchArray = stackalloc byte[sizeof(long)] {
            0, 0, 0, 0, 0, 0, 0, 0
        };
        // Reverse the bytes to match SQL Servers ordering
        if (BitConverter.IsLittleEndian)
        {
            BinaryPrimitives.WriteInt32BigEndian(scratchArray, days.Days);
        }
        else
        {
            BinaryPrimitives.WriteInt32LittleEndian(scratchArray, days.Days);
        }
        // Copy the bytes into the guid
        scratchArray.Slice(2, 2).CopyTo(guidArray.Slice(10, 2));

        // Reverse the bytes to match SQL Servers ordering
        // Note that SQL Server is accurate to 1/300th of a millisecond so we divide by 3.333333
        if (BitConverter.IsLittleEndian)
        {
            BinaryPrimitives.WriteInt64BigEndian(scratchArray, (long)(timeOfDay.TotalMilliseconds / 3.333333));
        }
        else
        {
            BinaryPrimitives.WriteInt64LittleEndian(scratchArray, (long)(timeOfDay.TotalMilliseconds / 3.333333));
        }
        // Copy the bytes into the guid
        scratchArray.Slice(3, 4).CopyTo(guidArray.Slice(12, 4));

#if NETCOREAPP
        return(new Guid(guidArray));
#elif NETFRAMEWORK
        if (!MemoryMarshal.TryRead(guidArray, out Guid readGuid))
        {
            readGuid = new Guid(guidArray.ToArray());
        }

        return(readGuid);
#endif
    }
示例#3
0
        /// <summary>
        /// Try to read the manifest from a given file path.
        /// </summary>
        /// <param name="manifestPath">The path to the manifest file</param>
        /// <param name="graphicsApi">The graphics api used by the cache</param>
        /// <param name="hashType">The hash type of the cache</param>
        /// <param name="header">The manifest header read</param>
        /// <param name="entries">The entries read from the cache manifest</param>
        /// <returns>Return true if the manifest was read</returns>
        public static bool TryReadManifestFile(string manifestPath, CacheGraphicsApi graphicsApi, CacheHashType hashType, out CacheManifestHeader header, out HashSet <Hash128> entries)
        {
            header  = default;
            entries = new HashSet <Hash128>();

            if (File.Exists(manifestPath))
            {
                Memory <byte> rawManifest = File.ReadAllBytes(manifestPath);

                if (MemoryMarshal.TryRead(rawManifest.Span, out header))
                {
                    Memory <byte> hashTableRaw = rawManifest.Slice(Unsafe.SizeOf <CacheManifestHeader>());

                    bool isValid = header.IsValid(graphicsApi, hashType, hashTableRaw.Span);

                    if (isValid)
                    {
                        ReadOnlySpan <Hash128> hashTable = MemoryMarshal.Cast <byte, Hash128>(hashTableRaw.Span);

                        foreach (Hash128 hash in hashTable)
                        {
                            entries.Add(hash);
                        }
                    }

                    return(isValid);
                }
            }

            return(false);
        }
        public static bool TryReadUInt64LittleEndian(ReadOnlySpan <byte> source, out ulong value)
        {
            bool success = MemoryMarshal.TryRead(source, out value);

            if (!BitConverter.IsLittleEndian)
            {
                value = ReverseEndianness(value);
            }
            return(success);
        }
示例#5
0
        /// <summary>
        /// Load the cache manifest file and recreate it if invalid.
        /// </summary>
        private void Load()
        {
            bool isInvalid = false;

            if (!Directory.Exists(_cacheDirectory))
            {
                isInvalid = true;
            }
            else
            {
                string manifestPath = GetManifestPath();

                if (File.Exists(manifestPath))
                {
                    Memory <byte> rawManifest = File.ReadAllBytes(manifestPath);

                    if (MemoryMarshal.TryRead(rawManifest.Span, out CacheManifestHeader manifestHeader))
                    {
                        Memory <byte> hashTableRaw = rawManifest.Slice(Unsafe.SizeOf <CacheManifestHeader>());

                        isInvalid = !manifestHeader.IsValid(_version, _graphicsApi, _hashType, hashTableRaw.Span);

                        if (!isInvalid)
                        {
                            ReadOnlySpan <Hash128> hashTable = MemoryMarshal.Cast <byte, Hash128>(hashTableRaw.Span);

                            foreach (Hash128 hash in hashTable)
                            {
                                _hashTable.Add(hash);
                            }
                        }
                    }
                }
                else
                {
                    isInvalid = true;
                }
            }

            if (isInvalid)
            {
                Logger.Warning?.Print(LogClass.Gpu, $"Shader collection \"{_cacheDirectory}\" got invalidated, cache will need to be rebuilt.");

                if (Directory.Exists(_cacheDirectory))
                {
                    Directory.Delete(_cacheDirectory, true);
                }

                Directory.CreateDirectory(_cacheDirectory);

                SaveManifest();
            }

            FlushToArchive();
        }
示例#6
0
        public Guid SpanAndMemoryMarshal()
        {
            Span <byte> guidBytes = stackalloc byte[16];

            data.AsSpan().CopyTo(guidBytes);
            if (!MemoryMarshal.TryRead <Guid>(guidBytes, out var lockTokenGuid))
            {
                lockTokenGuid = new Guid(guidBytes.ToArray());
            }
            return(lockTokenGuid);
        }
示例#7
0
    private static bool tryReadAndAdvance <T>(out T val, ref ReadOnlySpan <byte> span) where T : struct
    {
        bool res = MemoryMarshal.TryRead(span, out val);

        if (res)
        {
            span = span.Slice(Unsafe.SizeOf <T>());
        }

        return(res);
    }
示例#8
0
        /// <summary>
        /// Reads a <see cref="float" /> from the beginning of a read-only span of bytes, as little endian.
        /// </summary>
        /// <param name="source">The read-only span of bytes to read.</param>
        /// <param name="value">When this method returns, the value read out of the read-only span of bytes, as little endian.</param>
        /// <returns>
        /// <see langword="true" /> if the span is large enough to contain a <see cref="float" />; otherwise, <see langword="false" />.
        /// </returns>
        /// <remarks>Reads exactly 4 bytes from the beginning of the span.</remarks>
        public static bool TryReadSingleLittleEndian(ReadOnlySpan <byte> source, out float value)
        {
            if (!BitConverter.IsLittleEndian)
            {
                bool success = MemoryMarshal.TryRead(source, out int tmp);
                value = BitConverter.Int32BitsToSingle(ReverseEndianness(tmp));
                return(success);
            }

            return(MemoryMarshal.TryRead(source, out value));
        }
示例#9
0
        public static bool TryReadDoubleLittleEndian(ReadOnlySpan <byte> source, out double value)
        {
            if (!BitConverter.IsLittleEndian)
            {
                bool success = MemoryMarshal.TryRead(source, out long tmp);
                value = BitConverter.Int64BitsToDouble(ReverseEndianness(tmp));
                return(success);
            }

            return(MemoryMarshal.TryRead(source, out value));
        }
示例#10
0
        public static bool TryReadUInt32BigEndian(ReadOnlySpan <byte> source, out uint value)
        {
            if (BitConverter.IsLittleEndian)
            {
                bool success = MemoryMarshal.TryRead(source, out uint tmp);
                value = ReverseEndianness(tmp);
                return(success);
            }

            return(MemoryMarshal.TryRead(source, out value));
        }
示例#11
0
        public static bool TryReadHalfLittleEndian(ReadOnlySpan <byte> source, out Half value)
        {
            if (!BitConverter.IsLittleEndian)
            {
                bool success = MemoryMarshal.TryRead(source, out short tmp);
                value = BitConverter.Int16BitsToHalf(ReverseEndianness(tmp));
                return(success);
            }

            return(MemoryMarshal.TryRead(source, out value));
        }
示例#12
0
文件: ByteSpan.cs 项目: 0xCM/arrows
 public static T ReadValue <T>(ReadOnlySpan <byte> src, int offset = 0)
     where T : struct
 {
     if (MemoryMarshal.TryRead(src.Slice(offset), out T value))
     {
         return(value);
     }
     else
     {
         throw new Exception();
     }
 }
示例#13
0
 public static bool TryRead(ReadOnlySpan <char> text, out PollId pollId)
 {
     try
     {
         return(MemoryMarshal.TryRead(Base58.Flickr.Decode(text), out pollId));
     }
     catch (Exception)
     {
         pollId = default;
         return(false);
     }
 }
示例#14
0
        public static bool TryReadInt64LittleEndian(ReadOnlySpan <byte> source, out long value)
        {
            if (BitConverter.IsLittleEndian)
            {
                return(MemoryMarshal.TryRead(source, out value));
            }

            bool success = MemoryMarshal.TryRead(source, out long tmp);

            value = ReverseEndianness(tmp);
            return(success);
        }
示例#15
0
 public uint ReadUInt32()
 {
     if (MemoryMarshal.TryRead(this.data.Slice(this.Position, 4), out ushort value))
     {
         this.Position += 4;
         return(value);
     }
     else
     {
         throw new InvalidOperationException();
     }
 }
示例#16
0
        public static AddrInfoSerialized Read(ReadOnlySpan <byte> buffer, out ReadOnlySpan <byte> rest)
        {
            if (!MemoryMarshal.TryRead(buffer, out AddrInfoSerializedHeader header))
            {
                rest = buffer;

                return(null);
            }

            AddrInfo4?    socketAddress  = null;
            Array4 <byte>?rawIPv4Address = null;
            string        canonicalName  = null;

            buffer = buffer[Unsafe.SizeOf <AddrInfoSerializedHeader>()..];
示例#17
0
        public unsafe void Ctor_SafeHandle_UnknownSocket_Success()
        {
            const int PF_INET       = 2;
            const int NETLINK_ROUTE = 0;
            const int SOCK_DGRAM    = 2;
            const int RTM_NEWROUTE  = 24;
            const int RTM_GETROUTE  = 26;
            const int NLM_F_REQUEST = 1;
            const int NLM_F_DUMP    = 0x300;
            const int NLMSG_ERROR   = 2;
            const int SEQ           = 42;

            int fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);

            Assert.InRange(fd, 0, int.MaxValue);
            using (Socket netlink = new Socket(new SafeSocketHandle((IntPtr)fd, ownsHandle: true)))
            {
                Assert.Equal(AddressFamily.Unknown, netlink.AddressFamily);

                netlink.Bind(new NlEndPoint(Environment.ProcessId));

                nl_request req = default;
                req.nlh.nlmsg_pid   = (uint)Environment.ProcessId;
                req.nlh.nlmsg_type  = RTM_GETROUTE; /* We wish to get routes */
                req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
                req.nlh.nlmsg_len   = sizeof(nl_request);
                req.nlh.nlmsg_seq   = SEQ;
                req.rtm.rtm_family  = PF_INET;

                netlink.Send(new ReadOnlySpan <byte>(Unsafe.AsPointer(ref req), sizeof(nl_request)));

                Assert.True(netlink.Poll(TestSettings.PassingTestTimeout, SelectMode.SelectRead));

                byte[] response  = new byte[4000];
                int    readBytes = netlink.Receive(response);
                // We should get at least header.
                Assert.True(readBytes > sizeof(nlmsghdr));

                MemoryMarshal.TryRead <nlmsghdr>(response.AsSpan(), out nlmsghdr nlh);
                Assert.Equal(SEQ, nlh.nlmsg_seq);

                if (nlh.nlmsg_type == NLMSG_ERROR)
                {
                    MemoryMarshal.TryRead <nlmsgerr>(response.AsSpan(sizeof(nlmsghdr)), out nlmsgerr err);
                    _output.WriteLine("Netlink request failed with {0}", err.error);
                }

                Assert.Equal(RTM_NEWROUTE, nlh.nlmsg_type);
            }
        }
示例#18
0
        private static bool TryReadLowerCaseUInt32(ReadOnlySpan <byte> byteValue, out uint value)
        {
            if (MemoryMarshal.TryRead(byteValue, out uint result))
            {
                if (!BitConverter.IsLittleEndian)
                {
                    result = (result & 0xffff_0000) >> 16 |
                             (result & 0x0000_ffff) << 16;
                }
                value = result | 0x0020_0020;
                return(true);
            }

            value = 0;
            return(false);
        }
示例#19
0
        /// <summary>
        /// Try to read the manifest header from a given file path.
        /// </summary>
        /// <param name="manifestPath">The path to the manifest file</param>
        /// <param name="header">The manifest header read</param>
        /// <returns>Return true if the manifest header was read</returns>
        public static bool TryReadManifestHeader(string manifestPath, out CacheManifestHeader header)
        {
            header = default;

            if (File.Exists(manifestPath))
            {
                Memory <byte> rawManifest = File.ReadAllBytes(manifestPath);

                if (MemoryMarshal.TryRead(rawManifest.Span, out header))
                {
                    return(true);
                }
            }

            return(false);
        }
        static Guid DeterministicGuid(string src)
        {
            var byteCount = Encoding.UTF8.GetByteCount(src);
            var buffer    = ArrayPool <byte> .Shared.Rent(byteCount);

            try
            {
                var numberOfBytesWritten = Encoding.UTF8.GetBytes(src.AsSpan(), buffer);

                using var sha1CryptoServiceProvider = SHA1.Create();
                var guidBytes = sha1CryptoServiceProvider.ComputeHash(buffer, 0, numberOfBytesWritten).AsSpan().Slice(0, 16);
                if (!MemoryMarshal.TryRead <Guid>(guidBytes, out var deterministicGuid))
                {
                    deterministicGuid = new Guid(guidBytes.ToArray());
                }
                return(deterministicGuid);
            }
            finally
            {
                ArrayPool <byte> .Shared.Return(buffer, clearArray : true);
            }
        }
        /// <summary>
        /// Tries to load a <see cref="V1"/> instance from the input binary blob and returns a result.
        /// </summary>
        /// <param name="blob">The input binary blob to deserialize.</param>
        /// <param name="data">The resulting <see cref="V1"/> instance, if successful.</param>
        /// <returns>The result of the loading operation.</returns>
        private static LoadingResult TryLoadAndGetResult(ReadOnlyMemory <byte> blob, out V1 data)
        {
            data = default;

            if (blob.IsEmpty)
            {
                return(LoadingResult.EmptyBuffer);
            }

            ReadOnlySpan <byte> span = blob.Span;

            // Blob id
            if (!MemoryMarshal.TryRead(span, out Guid blobId))
            {
                return(LoadingResult.BufferTooShort);
            }

            // Validate the blob id
            if (blobId != BlobId)
            {
                return(LoadingResult.MismatchedBlobVersionId);
            }

            span = span.Slice(sizeof(Guid));

            // Effect class id
            if (!MemoryMarshal.TryRead(span, out Guid effectId))
            {
                return(LoadingResult.BufferTooShort);
            }

            span = span.Slice(sizeof(Guid));

            // Number of inputs
            if (!MemoryMarshal.TryRead(span, out int numberOfInputs))
            {
                return(LoadingResult.BufferTooShort);
            }

            // Validate the number of inputs
            if (numberOfInputs < 0)
            {
                return(LoadingResult.InvalidNumberOfInputs);
            }

            span = span.Slice(sizeof(int));

            // Effect property XML
            int lengthOfXml = span.IndexOf((byte)'\0');

            if (lengthOfXml == -1)
            {
                return(LoadingResult.InvalidPropertyXml);
            }

            string xml = Encoding.UTF8.GetString(span.Slice(0, lengthOfXml));

            span = span.Slice(lengthOfXml + 1);

            // Number of bindings
            if (!MemoryMarshal.TryRead(span, out int numberOfBindings))
            {
                return(LoadingResult.BufferTooShort);
            }

            // Validate the number of bindings
            if (numberOfBindings < 0)
            {
                return(LoadingResult.InvalidNumberOfBindings);
            }

            span = span.Slice(sizeof(int));

            D2D1PropertyBinding[] propertyBindings = new D2D1PropertyBinding[numberOfBindings];

            // Property bindings
            for (int i = 0; i < numberOfBindings; i++)
            {
                // Property name
                int lengthOfName = span.IndexOf((byte)'\0');

                if (lengthOfName == -1)
                {
                    return(LoadingResult.InvalidBindingPropertyName);
                }

                string name = Encoding.UTF8.GetString(span.Slice(0, lengthOfName));

                span = span.Slice(lengthOfName + 1);

                // Property get function
                if (!MemoryMarshal.TryRead(span, out nint getFunction))
                {
                    return(LoadingResult.BufferTooShort);
                }

                span = span.Slice(sizeof(nint));

                // Property set function
                if (!MemoryMarshal.TryRead(span, out nint setFunction))
                {
                    return(LoadingResult.BufferTooShort);
                }

                span = span.Slice(sizeof(nint));

                propertyBindings[i] = new D2D1PropertyBinding(name, (void *)getFunction, (void *)setFunction);
            }

            // Effect factory
            if (!MemoryMarshal.TryRead(span, out nint effectFactory))
            {
                return(LoadingResult.BufferTooShort);
            }

            span = span.Slice(sizeof(nint));

            // If the buffer is bigger than expected, also consider it malformed
            if (span.Length > 0)
            {
                return(LoadingResult.BufferTooLong);
            }

            data = new V1(
                effectId,
                numberOfInputs,
                xml,
                propertyBindings,
                effectFactory);

            return(LoadingResult.Success);
        }
示例#22
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);
            }
示例#23
0
            internal static string GetSingleSymbolicLinkTarget(string path)
            {
                using (SafeFileHandle handle =
                           Interop.Kernel32.CreateFile(path,
                                                       0,                                                             // No file access required, this avoids file in use
                                                       FileShare.ReadWrite | FileShare.Delete,                        // Share all access
                                                       FileMode.Open,
                                                       Interop.Kernel32.FileOperations.FILE_FLAG_OPEN_REPARSE_POINT | // Open the reparse point, not its target
                                                       Interop.Kernel32.FileOperations.FILE_FLAG_BACKUP_SEMANTICS))   // Permit opening of directories
                {
                    // https://docs.microsoft.com/en-us/windows-hardware/drivers/ifs/fsctl-get-reparse-point

                    Interop.Kernel32.REPARSE_DATA_BUFFER_SYMLINK header;
                    int  sizeHeader = Marshal.SizeOf <Interop.Kernel32.REPARSE_DATA_BUFFER_SYMLINK>();
                    uint bytesRead  = 0;
                    ReadOnlySpan <byte> validBuffer;
                    int bufferSize = sizeHeader + Interop.Kernel32.MAX_PATH;

                    while (true)
                    {
                        byte[] buffer = ArrayPool <byte> .Shared.Rent(bufferSize);

                        try
                        {
                            int result = Interop.Kernel32.DeviceIoControl(handle, Interop.Kernel32.FSCTL_GET_REPARSE_POINT, inBuffer: null, cbInBuffer: 0, buffer, (uint)buffer.Length, out bytesRead, overlapped: IntPtr.Zero) ?
                                         0 : Marshal.GetLastWin32Error();

                            if (result != Interop.Errors.ERROR_SUCCESS && result != Interop.Errors.ERROR_INSUFFICIENT_BUFFER && result != Interop.Errors.ERROR_MORE_DATA)
                            {
                                throw new Win32Exception(result);
                            }

                            validBuffer = buffer.AsSpan().Slice(0, (int)bytesRead);

                            if (!MemoryMarshal.TryRead(validBuffer, out header))
                            {
                                if (result == Interop.Errors.ERROR_SUCCESS)
                                {
                                    // didn't read enough for header
                                    throw new InvalidDataException("FSCTL_GET_REPARSE_POINT did not return sufficient data");
                                }

                                // can't read header, guess at buffer length
                                buffer = new byte[buffer.Length + Interop.Kernel32.MAX_PATH];
                                continue;
                            }

                            // we only care about SubstituteName.
                            // Per https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/b41f1cbf-10df-4a47-98d4-1c52a833d913 print name is only valid for displaying to the user
                            bufferSize = sizeHeader + header.SubstituteNameOffset + header.SubstituteNameLength;
                            // bufferSize = sizeHeader + Math.Max(header.SubstituteNameOffset + header.SubstituteNameLength, header.PrintNameOffset + header.PrintNameLength);

                            if (bytesRead >= bufferSize)
                            {
                                // got entire payload with valid header.
#if NETSTANDARD2_0
                                string target = Encoding.Unicode.GetString(validBuffer.Slice(sizeHeader + header.SubstituteNameOffset, header.SubstituteNameLength).ToArray());
#elif NETCOREAPP3_1 || NET5_0
                                string target = Encoding.Unicode.GetString(validBuffer.Slice(sizeHeader + header.SubstituteNameOffset, header.SubstituteNameLength));
#else
#error Platform not supported
#endif
                                if ((header.Flags & Interop.Kernel32.SYMLINK_FLAG_RELATIVE) != 0)
                                {
                                    if (PathInternal.IsExtended(path))
                                    {
                                        var rootPath = Path.GetDirectoryName(path.Substring(4));
                                        if (rootPath != null)
                                        {
                                            target = path.Substring(0, 4) + Path.GetFullPath(Path.Combine(rootPath, target));
                                        }
                                        else
                                        {
                                            target = path.Substring(0, 4) + Path.GetFullPath(target);
                                        }
                                    }
                                    else
                                    {
                                        var rootPath = Path.GetDirectoryName(path);
                                        if (rootPath != null)
                                        {
                                            target = Path.GetFullPath(Path.Combine(rootPath, target));
                                        }
                                        else
                                        {
                                            target = Path.GetFullPath(target);
                                        }
                                    }
                                }

                                return(target);
                            }

                            if (bufferSize < buffer.Length)
                            {
                                throw new InvalidDataException($"FSCTL_GET_REPARSE_POINT did not return sufficient data ({bufferSize}) when provided buffer ({buffer.Length}).");
                            }
                        }
                        finally
                        {
                            ArrayPool <byte> .Shared.Return(buffer);
                        }
                    }
                }
            }
示例#24
0
        public static ServiceBusReceivedMessage AmqpMessageToSBMessage(AmqpMessage amqpMessage, bool isPeeked = false)
        {
            Argument.AssertNotNull(amqpMessage, nameof(amqpMessage));
            AmqpAnnotatedMessage annotatedMessage;

            if ((amqpMessage.BodyType & SectionFlag.Data) != 0 && amqpMessage.DataBody != null)
            {
                annotatedMessage = new AmqpAnnotatedMessage(AmqpMessageBody.FromData(BodyMemory.FromAmqpData(amqpMessage.DataBody)));
            }
            else if ((amqpMessage.BodyType & SectionFlag.AmqpValue) != 0 && amqpMessage.ValueBody?.Value != null)
            {
                if (TryGetNetObjectFromAmqpObject(amqpMessage.ValueBody.Value, MappingType.MessageBody, out object netObject))
                {
                    annotatedMessage = new AmqpAnnotatedMessage(AmqpMessageBody.FromValue(netObject));
                }
                else
                {
                    throw new NotSupportedException(Resources.InvalidAmqpMessageValueBody.FormatForUser(amqpMessage.ValueBody.Value.GetType()));
                }
            }
            else if ((amqpMessage.BodyType & SectionFlag.AmqpSequence) != 0)
            {
                annotatedMessage = new AmqpAnnotatedMessage(
                    AmqpMessageBody.FromSequence(amqpMessage.SequenceBody.Select(s => (IList <object>)s.List).ToList()));
            }
            // default to using an empty Data section if no data
            else
            {
                annotatedMessage = new AmqpAnnotatedMessage(new AmqpMessageBody(Enumerable.Empty <ReadOnlyMemory <byte> >()));
            }
            ServiceBusReceivedMessage sbMessage = new ServiceBusReceivedMessage(annotatedMessage);

            SectionFlag sections = amqpMessage.Sections;

            if ((sections & SectionFlag.Header) != 0)
            {
                if (amqpMessage.Header.Ttl != null)
                {
                    annotatedMessage.Header.TimeToLive = TimeSpan.FromMilliseconds(amqpMessage.Header.Ttl.Value);
                }

                if (amqpMessage.Header.DeliveryCount != null)
                {
                    annotatedMessage.Header.DeliveryCount = isPeeked ? (amqpMessage.Header.DeliveryCount.Value) : (amqpMessage.Header.DeliveryCount.Value + 1);
                }
            }

            if ((sections & SectionFlag.Properties) != 0)
            {
                if (amqpMessage.Properties.MessageId != null)
                {
                    annotatedMessage.Properties.MessageId = new AmqpMessageId(amqpMessage.Properties.MessageId.ToString());
                }

                if (amqpMessage.Properties.CorrelationId != null)
                {
                    annotatedMessage.Properties.CorrelationId = new AmqpMessageId(amqpMessage.Properties.CorrelationId.ToString());
                }

                if (amqpMessage.Properties.ContentType.Value != null)
                {
                    annotatedMessage.Properties.ContentType = amqpMessage.Properties.ContentType.Value;
                }

                if (amqpMessage.Properties.Subject != null)
                {
                    annotatedMessage.Properties.Subject = amqpMessage.Properties.Subject;
                }

                if (amqpMessage.Properties.To != null)
                {
                    annotatedMessage.Properties.To = new AmqpAddress(amqpMessage.Properties.To.ToString());
                }

                if (amqpMessage.Properties.ReplyTo != null)
                {
                    annotatedMessage.Properties.ReplyTo = new AmqpAddress(amqpMessage.Properties.ReplyTo.ToString());
                }

                if (amqpMessage.Properties.GroupId != null)
                {
                    annotatedMessage.Properties.GroupId = amqpMessage.Properties.GroupId;
                }

                if (amqpMessage.Properties.ReplyToGroupId != null)
                {
                    annotatedMessage.Properties.ReplyToGroupId = amqpMessage.Properties.ReplyToGroupId;
                }
            }

            // Do application properties before message annotations, because the application properties
            // can be updated by entries from message annotation.
            if ((sections & SectionFlag.ApplicationProperties) != 0)
            {
                foreach (var pair in amqpMessage.ApplicationProperties.Map)
                {
                    if (TryGetNetObjectFromAmqpObject(pair.Value, MappingType.ApplicationProperty, out var netObject))
                    {
                        annotatedMessage.ApplicationProperties[pair.Key.ToString()] = netObject;
                    }
                }
            }

            if ((sections & SectionFlag.MessageAnnotations) != 0)
            {
                foreach (var pair in amqpMessage.MessageAnnotations.Map)
                {
                    var key = pair.Key.ToString();
                    switch (key)
                    {
                    case AmqpMessageConstants.EnqueuedTimeUtcName:
                        annotatedMessage.MessageAnnotations[AmqpMessageConstants.EnqueuedTimeUtcName] = pair.Value;
                        break;

                    case AmqpMessageConstants.ScheduledEnqueueTimeUtcName:
                        annotatedMessage.MessageAnnotations[AmqpMessageConstants.ScheduledEnqueueTimeUtcName] = pair.Value;
                        break;

                    case AmqpMessageConstants.SequenceNumberName:
                        annotatedMessage.MessageAnnotations[AmqpMessageConstants.SequenceNumberName] = pair.Value;
                        break;

                    case AmqpMessageConstants.EnqueueSequenceNumberName:
                        annotatedMessage.MessageAnnotations[AmqpMessageConstants.EnqueueSequenceNumberName] = pair.Value;
                        break;

                    case AmqpMessageConstants.LockedUntilName:
                        DateTimeOffset lockedUntil = (DateTime)pair.Value >= DateTimeOffset.MaxValue.UtcDateTime ?
                                                     DateTimeOffset.MaxValue : (DateTime)pair.Value;
                        annotatedMessage.MessageAnnotations[AmqpMessageConstants.LockedUntilName] = lockedUntil.UtcDateTime;
                        break;

                    case AmqpMessageConstants.PartitionKeyName:
                        annotatedMessage.MessageAnnotations[AmqpMessageConstants.PartitionKeyName] = pair.Value;
                        break;

                    case AmqpMessageConstants.PartitionIdName:
                        annotatedMessage.MessageAnnotations[AmqpMessageConstants.PartitionIdName] = pair.Value;
                        break;

                    case AmqpMessageConstants.ViaPartitionKeyName:
                        annotatedMessage.MessageAnnotations[AmqpMessageConstants.ViaPartitionKeyName] = pair.Value;
                        break;

                    case AmqpMessageConstants.DeadLetterSourceName:
                        annotatedMessage.MessageAnnotations[AmqpMessageConstants.DeadLetterSourceName] = pair.Value;
                        break;

                    default:
                        if (TryGetNetObjectFromAmqpObject(pair.Value, MappingType.ApplicationProperty, out var netObject))
                        {
                            annotatedMessage.MessageAnnotations[key] = netObject;
                        }
                        break;
                    }
                }
            }

            if (amqpMessage.DeliveryTag.Count == GuidSizeInBytes)
            {
                Span <byte> guidBytes = stackalloc byte[GuidSizeInBytes];
                amqpMessage.DeliveryTag.AsSpan().CopyTo(guidBytes);
                if (!MemoryMarshal.TryRead <Guid>(guidBytes, out var lockTokenGuid))
                {
                    lockTokenGuid = new Guid(guidBytes.ToArray());
                }
                sbMessage.LockTokenGuid = lockTokenGuid;
            }

            amqpMessage.Dispose();

            return(sbMessage);
        }
示例#25
0
        public void SpanRead()
        {
            ulong value; // [11 22 33 44 55 66 77 88]

            if (BitConverter.IsLittleEndian)
            {
                value = 0x8877665544332211;
            }
            else
            {
                value = 0x1122334455667788;
            }
            Span <byte> span;

            unsafe
            {
                span = new Span <byte>(&value, 8);
            }

            Assert.Equal <byte>(0x11, MemoryMarshal.Read <byte>(span));
            Assert.True(MemoryMarshal.TryRead(span, out byte byteValue));
            Assert.Equal(0x11, byteValue);

            Assert.Equal <sbyte>(0x11, MemoryMarshal.Read <sbyte>(span));
            Assert.True(MemoryMarshal.TryRead(span, out byte sbyteValue));
            Assert.Equal(0x11, byteValue);

            Assert.Equal <ushort>(0x1122, ReadUInt16BigEndian(span));
            Assert.True(TryReadUInt16BigEndian(span, out ushort ushortValue));
            Assert.Equal(0x1122, ushortValue);

            Assert.Equal <ushort>(0x2211, ReadUInt16LittleEndian(span));
            Assert.True(TryReadUInt16LittleEndian(span, out ushortValue));
            Assert.Equal(0x2211, ushortValue);

            Assert.Equal <short>(0x1122, ReadInt16BigEndian(span));
            Assert.True(TryReadInt16BigEndian(span, out short shortValue));
            Assert.Equal(0x1122, shortValue);

            Assert.Equal <short>(0x2211, ReadInt16LittleEndian(span));
            Assert.True(TryReadInt16LittleEndian(span, out shortValue));
            Assert.Equal(0x2211, ushortValue);

            Assert.Equal <uint>(0x11223344, ReadUInt32BigEndian(span));
            Assert.True(TryReadUInt32BigEndian(span, out uint uintValue));
            Assert.Equal <uint>(0x11223344, uintValue);

            Assert.Equal <uint>(0x44332211, ReadUInt32LittleEndian(span));
            Assert.True(TryReadUInt32LittleEndian(span, out uintValue));
            Assert.Equal <uint>(0x44332211, uintValue);

            Assert.Equal <int>(0x11223344, ReadInt32BigEndian(span));
            Assert.True(TryReadInt32BigEndian(span, out int intValue));
            Assert.Equal <int>(0x11223344, intValue);

            Assert.Equal <int>(0x44332211, ReadInt32LittleEndian(span));
            Assert.True(TryReadInt32LittleEndian(span, out intValue));
            Assert.Equal <int>(0x44332211, intValue);

            Assert.Equal <ulong>(0x1122334455667788, ReadUInt64BigEndian(span));
            Assert.True(TryReadUInt64BigEndian(span, out ulong ulongValue));
            Assert.Equal <ulong>(0x1122334455667788, ulongValue);

            Assert.Equal <ulong>(0x8877665544332211, ReadUInt64LittleEndian(span));
            Assert.True(TryReadUInt64LittleEndian(span, out ulongValue));
            Assert.Equal <ulong>(0x8877665544332211, ulongValue);

            Assert.Equal <long>(0x1122334455667788, ReadInt64BigEndian(span));
            Assert.True(TryReadInt64BigEndian(span, out long longValue));
            Assert.Equal <long>(0x1122334455667788, longValue);

            Assert.Equal <long>(unchecked ((long)0x8877665544332211), ReadInt64LittleEndian(span));
            Assert.True(TryReadInt64LittleEndian(span, out longValue));
            Assert.Equal <long>(unchecked ((long)0x8877665544332211), longValue);

            Half expectedHalf = BitConverter.Int16BitsToHalf(0x1122);

            Assert.Equal <Half>(expectedHalf, ReadHalfBigEndian(span));
            Assert.True(TryReadHalfBigEndian(span, out Half halfValue));
            Assert.Equal <Half>(expectedHalf, halfValue);

            expectedHalf = BitConverter.Int16BitsToHalf(0x2211);
            Assert.Equal <Half>(expectedHalf, ReadHalfLittleEndian(span));
            Assert.True(TryReadHalfLittleEndian(span, out halfValue));
            Assert.Equal <Half>(expectedHalf, halfValue);

            float expectedFloat = BitConverter.Int32BitsToSingle(0x11223344);

            Assert.Equal <float>(expectedFloat, ReadSingleBigEndian(span));
            Assert.True(TryReadSingleBigEndian(span, out float floatValue));
            Assert.Equal <float>(expectedFloat, floatValue);

            expectedFloat = BitConverter.Int32BitsToSingle(0x44332211);
            Assert.Equal <float>(expectedFloat, ReadSingleLittleEndian(span));
            Assert.True(TryReadSingleLittleEndian(span, out floatValue));
            Assert.Equal <float>(expectedFloat, floatValue);

            double expectedDouble = BitConverter.Int64BitsToDouble(0x1122334455667788);

            Assert.Equal <double>(expectedDouble, ReadDoubleBigEndian(span));
            Assert.True(TryReadDoubleBigEndian(span, out double doubleValue));
            Assert.Equal <double>(expectedDouble, doubleValue);

            expectedDouble = BitConverter.Int64BitsToDouble(unchecked ((long)0x8877665544332211));
            Assert.Equal <double>(expectedDouble, ReadDoubleLittleEndian(span));
            Assert.True(TryReadDoubleLittleEndian(span, out doubleValue));
            Assert.Equal <double>(expectedDouble, doubleValue);
        }
示例#26
0
        public void ReadOnlySpanRead()
        {
            Assert.True(BitConverter.IsLittleEndian);

            ulong value = 0x8877665544332211; // [11 22 33 44 55 66 77 88]
            ReadOnlySpan <byte> span;

            unsafe
            {
                span = new ReadOnlySpan <byte>(&value, 8);
            }

            Assert.Equal <byte>(0x11, MemoryMarshal.Read <byte>(span));
            Assert.True(MemoryMarshal.TryRead(span, out byte byteValue));
            Assert.Equal(0x11, byteValue);

            Assert.Equal <sbyte>(0x11, MemoryMarshal.Read <sbyte>(span));
            Assert.True(MemoryMarshal.TryRead(span, out byte sbyteValue));
            Assert.Equal(0x11, byteValue);

            Assert.Equal <ushort>(0x1122, ReadUInt16BigEndian(span));
            Assert.True(TryReadUInt16BigEndian(span, out ushort ushortValue));
            Assert.Equal(0x1122, ushortValue);

            Assert.Equal <ushort>(0x2211, ReadUInt16LittleEndian(span));
            Assert.True(TryReadUInt16LittleEndian(span, out ushortValue));
            Assert.Equal(0x2211, ushortValue);

            Assert.Equal <short>(0x1122, ReadInt16BigEndian(span));
            Assert.True(TryReadInt16BigEndian(span, out short shortValue));
            Assert.Equal(0x1122, shortValue);

            Assert.Equal <short>(0x2211, ReadInt16LittleEndian(span));
            Assert.True(TryReadInt16LittleEndian(span, out shortValue));
            Assert.Equal(0x2211, ushortValue);

            Assert.Equal <uint>(0x11223344, ReadUInt32BigEndian(span));
            Assert.True(TryReadUInt32BigEndian(span, out uint uintValue));
            Assert.Equal <uint>(0x11223344, uintValue);

            Assert.Equal <uint>(0x44332211, ReadUInt32LittleEndian(span));
            Assert.True(TryReadUInt32LittleEndian(span, out uintValue));
            Assert.Equal <uint>(0x44332211, uintValue);

            Assert.Equal <int>(0x11223344, ReadInt32BigEndian(span));
            Assert.True(TryReadInt32BigEndian(span, out int intValue));
            Assert.Equal <int>(0x11223344, intValue);

            Assert.Equal <int>(0x44332211, ReadInt32LittleEndian(span));
            Assert.True(TryReadInt32LittleEndian(span, out intValue));
            Assert.Equal <int>(0x44332211, intValue);

            Assert.Equal <ulong>(0x1122334455667788, ReadUInt64BigEndian(span));
            Assert.True(TryReadUInt64BigEndian(span, out ulong ulongValue));
            Assert.Equal <ulong>(0x1122334455667788, ulongValue);

            Assert.Equal <ulong>(0x8877665544332211, ReadUInt64LittleEndian(span));
            Assert.True(TryReadUInt64LittleEndian(span, out ulongValue));
            Assert.Equal <ulong>(0x8877665544332211, ulongValue);

            Assert.Equal <long>(0x1122334455667788, ReadInt64BigEndian(span));
            Assert.True(TryReadInt64BigEndian(span, out long longValue));
            Assert.Equal <long>(0x1122334455667788, longValue);

            Assert.Equal <long>(unchecked ((long)0x8877665544332211), ReadInt64LittleEndian(span));
            Assert.True(TryReadInt64LittleEndian(span, out longValue));
            Assert.Equal <long>(unchecked ((long)0x8877665544332211), longValue);
        }
 public static bool TryReadInt64(this ReadOnlySpan <byte> source, out Int64 value)
 => MemoryMarshal.TryRead(source, out value);
 public static bool TryReadGuid(this ReadOnlySpan <byte> source, out Guid value)
 => MemoryMarshal.TryRead(source, out value);
示例#29
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.REPARSE_DATA_BUFFER rdb);
                Debug.Assert(success);

                // Only symbolic links are supported at the moment.
                if ((rdb.ReparseTag & Interop.Kernel32.IOReparseOptions.IO_REPARSE_TAG_SYMLINK) == 0)
                {
                    return(null);
                }

                // We use PrintName instead of SubstitutneName given that we don't want to return a NT path when the link wasn't created with such NT path.
                // Unlike SubstituteName and GetFinalPathNameByHandle(), PrintName doesn't start with a prefix.
                // Another nuance is that SubstituteName does not contain redundant path segments while PrintName does.
                // PrintName can ONLY return a NT path if the link was created explicitly targeting a file/folder in such way. e.g: mklink /D linkName \??\C:\path\to\target.
                int printNameNameOffset = sizeof(Interop.Kernel32.REPARSE_DATA_BUFFER) + rdb.ReparseBufferSymbolicLink.PrintNameOffset;
                int printNameNameLength = rdb.ReparseBufferSymbolicLink.PrintNameLength;

                Span <char> targetPath = MemoryMarshal.Cast <byte, char>(bufferSpan.Slice(printNameNameOffset, printNameNameLength));
                Debug.Assert((rdb.ReparseBufferSymbolicLink.Flags & Interop.Kernel32.SYMLINK_FLAG_RELATIVE) == 0 || !PathInternal.IsExtended(targetPath));

                if (returnFullPath && (rdb.ReparseBufferSymbolicLink.Flags & Interop.Kernel32.SYMLINK_FLAG_RELATIVE) != 0)
                {
                    // Target path is relative and is for ResolveLinkTarget(), we need to append the link directory.
                    return(Path.Join(Path.GetDirectoryName(linkPath.AsSpan()), targetPath));
                }

                return(targetPath.ToString());
            }
            finally
            {
                ArrayPool <byte> .Shared.Return(buffer);
            }
        }
 public static bool TryRead <T>(this ReadOnlySpan <byte> source, out T value) where T : struct
 => MemoryMarshal.TryRead <T>(source, out value);