1 /* <lambda>null2 * Copyright (C) 2023 Square, Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package okio 17 18 import kotlin.wasm.unsafe.withScopedMemoryAllocator 19 import okio.internal.ErrnoException 20 import okio.internal.fdClose 21 import okio.internal.preview1.fd 22 import okio.internal.preview1.fd_read 23 import okio.internal.preview1.size 24 import okio.internal.read 25 26 internal class FileSource( 27 private val fd: fd, 28 ) : Source { 29 private val unsafeCursor = Buffer.UnsafeCursor() 30 private var closed = false 31 32 override fun read(sink: Buffer, byteCount: Long): Long { 33 require(byteCount >= 0L) { "byteCount < 0: $byteCount" } 34 check(!closed) { "closed" } 35 val sinkInitialSize = sink.size 36 37 // Request a writable segment in `sink`. We request at least 1024 bytes, unless the request is 38 // for smaller than that, in which case we request only that many bytes. 39 val cursor = sink.readAndWriteUnsafe(unsafeCursor) 40 val addedCapacityCount = cursor.expandBuffer(minByteCount = minOf(byteCount, 1024L).toInt()) 41 42 // Now that we have a writable segment, figure out how many bytes to read. This is the smaller 43 // of the user's requested byte count, and the segment's writable capacity. 44 val attemptCount = minOf(byteCount, addedCapacityCount).toInt() 45 46 // Copy bytes from the file to the segment. 47 val bytesRead = fdRead(cursor.data!!, cursor.start, attemptCount) 48 49 // Remove new capacity that was added but not used. 50 cursor.resizeBuffer(sinkInitialSize + bytesRead) 51 cursor.close() 52 53 return when { 54 bytesRead == attemptCount -> bytesRead.toLong() 55 else -> if (bytesRead == 0) -1L else bytesRead.toLong() 56 } 57 } 58 59 private fun fdRead(data: ByteArray, offset: Int, count: Int): size { 60 withScopedMemoryAllocator { allocator -> 61 val dataPointer = allocator.allocate(count) 62 63 val iovec = allocator.allocate(8) 64 iovec.storeInt(dataPointer.address.toInt()) 65 (iovec + 4).storeInt(count) 66 67 val returnPointer = allocator.allocate(4) // `size` is u32, 4 bytes. 68 val errno = fd_read( 69 fd = fd, 70 iovs = iovec.address.toInt(), 71 iovsSize = 1, 72 returnPointer = returnPointer.address.toInt(), 73 ) 74 if (errno != 0) throw ErrnoException(errno.toShort()) 75 76 val byteCount = returnPointer.loadInt() 77 if (byteCount != -1) { 78 dataPointer.read(data, offset, byteCount) 79 } 80 81 return byteCount 82 } 83 } 84 85 override fun timeout(): Timeout = Timeout.NONE 86 87 override fun close() { 88 if (closed) return 89 closed = true 90 fdClose(fd) 91 } 92 } 93