예제 #1
0
        internal static unsafe void WriteAtOffset(SafeFileHandle handle, ReadOnlySpan <byte> buffer, long fileOffset)
        {
            while (!buffer.IsEmpty)
            {
                fixed(byte *bufPtr = &MemoryMarshal.GetReference(buffer))
                {
                    // The Windows implementation uses WriteFile, which ignores the offset if the handle
                    // isn't seekable.  We do the same manually with PWrite vs Write, in order to enable
                    // the function to be used by FileStream for all the same situations.
                    int bytesWritten = handle.CanSeek ?
                                       Interop.Sys.PWrite(handle, bufPtr, GetNumberOfBytesToWrite(buffer.Length), fileOffset) :
                                       Interop.Sys.Write(handle, bufPtr, GetNumberOfBytesToWrite(buffer.Length));

                    FileStreamHelpers.CheckFileCall(bytesWritten, handle.Path);
                    if (bytesWritten == buffer.Length)
                    {
                        break;
                    }

                    // The write completed successfully but for fewer bytes than requested.
                    // We need to try again for the remainder.
                    buffer      = buffer.Slice(bytesWritten);
                    fileOffset += bytesWritten;
                }
            }
        }
예제 #2
0
        internal static long GetFileLength(SafeFileHandle handle)
        {
            int result = Interop.Sys.FStat(handle, out Interop.Sys.FileStatus status);

            FileStreamHelpers.CheckFileCall(result, handle.Path);
            return(status.Size);
        }
예제 #3
0
        internal static unsafe long ReadScatterAtOffset(SafeFileHandle handle, IReadOnlyList <Memory <byte> > buffers, long fileOffset)
        {
            MemoryHandle[] handles = new MemoryHandle[buffers.Count];
            Span <Interop.Sys.IOVector> vectors = buffers.Count <= IovStackThreshold ? stackalloc Interop.Sys.IOVector[IovStackThreshold] : new Interop.Sys.IOVector[buffers.Count];

            long result;

            try
            {
                int buffersCount = buffers.Count;
                for (int i = 0; i < buffersCount; i++)
                {
                    Memory <byte> buffer       = buffers[i];
                    MemoryHandle  memoryHandle = buffer.Pin();
                    vectors[i] = new Interop.Sys.IOVector {
                        Base = (byte *)memoryHandle.Pointer, Count = (UIntPtr)buffer.Length
                    };
                    handles[i] = memoryHandle;
                }

                fixed(Interop.Sys.IOVector *pinnedVectors = &MemoryMarshal.GetReference(vectors))
                {
                    result = Interop.Sys.PReadV(handle, pinnedVectors, buffers.Count, fileOffset);
                }
            }
            finally
            {
                foreach (MemoryHandle memoryHandle in handles)
                {
                    memoryHandle.Dispose();
                }
            }

            return(FileStreamHelpers.CheckFileCall(result, handle.Path));
        }
예제 #4
0
        private static unsafe int ReadAtOffset(SafeFileHandle handle, Span <byte> buffer, long fileOffset)
        {
            fixed(byte *bufPtr = &MemoryMarshal.GetReference(buffer))
            {
                int result = Interop.Sys.PRead(handle, bufPtr, buffer.Length, fileOffset);

                FileStreamHelpers.CheckFileCall(result, path: null);
                return(result);
            }
        }
예제 #5
0
        internal static unsafe int WriteAtOffset(SafeFileHandle handle, ReadOnlySpan <byte> buffer, long fileOffset)
        {
            fixed(byte *bufPtr = &MemoryMarshal.GetReference(buffer))
            {
                int result = Interop.Sys.PWrite(handle, bufPtr, buffer.Length, fileOffset);

                FileStreamHelpers.CheckFileCall(result, handle.Path);
                return(result);
            }
        }
예제 #6
0
        internal static unsafe int ReadAtOffset(SafeFileHandle handle, Span <byte> buffer, long fileOffset)
        {
            fixed(byte *bufPtr = &MemoryMarshal.GetReference(buffer))
            {
                // The Windows implementation uses ReadFile, which ignores the offset if the handle
                // isn't seekable.  We do the same manually with PRead vs Read, in order to enable
                // the function to be used by FileStream for all the same situations.
                int result = handle.CanSeek ?
                             Interop.Sys.PRead(handle, bufPtr, buffer.Length, fileOffset) :
                             Interop.Sys.Read(handle, bufPtr, buffer.Length);

                FileStreamHelpers.CheckFileCall(result, handle.Path);
                return(result);
            }
        }
예제 #7
0
        internal static unsafe void WriteAtOffset(SafeFileHandle handle, ReadOnlySpan <byte> buffer, long fileOffset)
        {
            while (!buffer.IsEmpty)
            {
                fixed(byte *bufPtr = &MemoryMarshal.GetReference(buffer))
                {
                    // The Windows implementation uses WriteFile, which ignores the offset if the handle
                    // isn't seekable.  We do the same manually with PWrite vs Write, in order to enable
                    // the function to be used by FileStream for all the same situations.
                    int bytesToWrite = GetNumberOfBytesToWrite(buffer.Length);
                    int bytesWritten;

                    if (handle.SupportsRandomAccess)
                    {
                        bytesWritten = Interop.Sys.PWrite(handle, bufPtr, bytesToWrite, fileOffset);
                        if (bytesWritten == -1)
                        {
                            // We need to fallback to the non-offset version for certain file types
                            // e.g: character devices (such as /dev/tty), pipes, and sockets.
                            Interop.ErrorInfo errorInfo = Interop.Sys.GetLastErrorInfo();

                            if (errorInfo.Error == Interop.Error.ENXIO ||
                                errorInfo.Error == Interop.Error.ESPIPE)
                            {
                                handle.SupportsRandomAccess = false;
                                bytesWritten = Interop.Sys.Write(handle, bufPtr, bytesToWrite);
                            }
                        }
                    }
                    else
                    {
                        bytesWritten = Interop.Sys.Write(handle, bufPtr, bytesToWrite);
                    }

                    FileStreamHelpers.CheckFileCall(bytesWritten, handle.Path);
                    if (bytesWritten == buffer.Length)
                    {
                        break;
                    }

                    // The write completed successfully but for fewer bytes than requested.
                    // We need to try again for the remainder.
                    buffer      = buffer.Slice(bytesWritten);
                    fileOffset += bytesWritten;
                }
            }
        }
예제 #8
0
        internal static unsafe int ReadAtOffset(SafeFileHandle handle, Span <byte> buffer, long fileOffset)
        {
            fixed(byte *bufPtr = &MemoryMarshal.GetReference(buffer))
            {
                // The Windows implementation uses ReadFile, which ignores the offset if the handle
                // isn't seekable.  We do the same manually with PRead vs Read, in order to enable
                // the function to be used by FileStream for all the same situations.
                int result;

                if (handle.SupportsRandomAccess)
                {
                    // Try pread for seekable files.
                    result = Interop.Sys.PRead(handle, bufPtr, buffer.Length, fileOffset);
                    if (result == -1)
                    {
                        // We need to fallback to the non-offset version for certain file types
                        // e.g: character devices (such as /dev/tty), pipes, and sockets.
                        Interop.ErrorInfo errorInfo = Interop.Sys.GetLastErrorInfo();

                        if (errorInfo.Error == Interop.Error.ENXIO ||
                            errorInfo.Error == Interop.Error.ESPIPE)
                        {
                            handle.SupportsRandomAccess = false;
                            result = Interop.Sys.Read(handle, bufPtr, buffer.Length);
                        }
                    }
                }
                else
                {
                    result = Interop.Sys.Read(handle, bufPtr, buffer.Length);
                }

                FileStreamHelpers.CheckFileCall(result, handle.Path);
                return(result);
            }
        }
예제 #9
0
        internal static unsafe void WriteGatherAtOffset(SafeFileHandle handle, IReadOnlyList <ReadOnlyMemory <byte> > buffers, long fileOffset)
        {
            int buffersCount = buffers.Count;

            if (buffersCount == 0)
            {
                return;
            }

            var handles = new MemoryHandle[buffersCount];
            Span <Interop.Sys.IOVector> vectors = buffersCount <= IovStackThreshold ?
                                                  stackalloc Interop.Sys.IOVector[IovStackThreshold] :
                                                  new Interop.Sys.IOVector[buffersCount];

            try
            {
                int buffersOffset = 0, firstBufferOffset = 0;
                while (true)
                {
                    long totalBytesToWrite = 0;

                    for (int i = buffersOffset; i < buffersCount; i++)
                    {
                        ReadOnlyMemory <byte> buffer = buffers[i];
                        totalBytesToWrite += buffer.Length;

                        MemoryHandle memoryHandle = buffer.Pin();
                        vectors[i] = new Interop.Sys.IOVector {
                            Base = firstBufferOffset + (byte *)memoryHandle.Pointer, Count = (UIntPtr)buffer.Length
                        };
                        handles[i] = memoryHandle;

                        firstBufferOffset = 0;
                    }

                    if (totalBytesToWrite == 0)
                    {
                        break;
                    }

                    long bytesWritten;
                    fixed(Interop.Sys.IOVector *pinnedVectors = &MemoryMarshal.GetReference(vectors))
                    {
                        bytesWritten = Interop.Sys.PWriteV(handle, pinnedVectors, buffersCount, fileOffset);
                    }

                    FileStreamHelpers.CheckFileCall(bytesWritten, handle.Path);
                    if (bytesWritten == totalBytesToWrite)
                    {
                        break;
                    }

                    // The write completed successfully but for fewer bytes than requested.
                    // We need to try again for the remainder.
                    for (int i = 0; i < buffersCount; i++)
                    {
                        int n = buffers[i].Length;
                        if (n <= bytesWritten)
                        {
                            buffersOffset++;
                            bytesWritten -= n;
                            if (bytesWritten == 0)
                            {
                                break;
                            }
                        }
                        else
                        {
                            firstBufferOffset = (int)(bytesWritten - n);
                            break;
                        }
                    }
                }
            }
            finally
            {
                foreach (MemoryHandle memoryHandle in handles)
                {
                    memoryHandle.Dispose();
                }
            }
        }
예제 #10
0
 internal static unsafe void SetFileLength(SafeFileHandle handle, long length) =>
 FileStreamHelpers.CheckFileCall(Interop.Sys.FTruncate(handle, length), handle.Path);