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.Pointer 19 import kotlin.wasm.unsafe.withScopedMemoryAllocator 20 import okio.internal.ErrnoException 21 import okio.internal.fdClose 22 import okio.internal.preview1.fd 23 import okio.internal.preview1.fd_filestat_get 24 import okio.internal.preview1.fd_filestat_set_size 25 import okio.internal.preview1.fd_pread 26 import okio.internal.preview1.fd_pwrite 27 import okio.internal.preview1.fd_sync 28 import okio.internal.read 29 import okio.internal.write 30 31 internal class WasiFileHandle( 32 private val fd: fd, 33 readWrite: Boolean, 34 ) : FileHandle(readWrite) { 35 override fun protectedSize(): Long { 36 withScopedMemoryAllocator { allocator -> 37 val returnPointer: Pointer = allocator.allocate(64) // filestat is 64 bytes. 38 val errno = fd_filestat_get(fd, returnPointer.address.toInt()) 39 if (errno != 0) throw ErrnoException(errno.toShort()) 40 41 return (returnPointer + 32).loadLong() 42 } 43 } 44 45 override fun protectedRead( 46 fileOffset: Long, 47 array: ByteArray, 48 arrayOffset: Int, 49 byteCount: Int, 50 ): Int { 51 withScopedMemoryAllocator { allocator -> 52 val dataPointer = allocator.allocate(byteCount) 53 54 val iovec = allocator.allocate(8) 55 iovec.storeInt(dataPointer.address.toInt()) 56 (iovec + 4).storeInt(byteCount) 57 58 val returnPointer = allocator.allocate(4) // `size` is u32, 4 bytes. 59 val errno = fd_pread( 60 fd = fd, 61 iovs = iovec.address.toInt(), 62 iovsSize = 1, 63 offset = fileOffset, 64 returnPointer = returnPointer.address.toInt(), 65 ) 66 if (errno != 0) throw ErrnoException(errno.toShort()) 67 68 val readByteCount = returnPointer.loadInt() 69 if (byteCount != -1) { 70 dataPointer.read(array, arrayOffset, readByteCount) 71 } 72 73 if (readByteCount == 0) return -1 74 return readByteCount 75 } 76 } 77 78 override fun protectedWrite( 79 fileOffset: Long, 80 array: ByteArray, 81 arrayOffset: Int, 82 byteCount: Int, 83 ) { 84 withScopedMemoryAllocator { allocator -> 85 val dataPointer = allocator.write(array, arrayOffset, byteCount) 86 87 val iovec = allocator.allocate(8) 88 iovec.storeInt(dataPointer.address.toInt()) 89 (iovec + 4).storeInt(byteCount) 90 91 val returnPointer = allocator.allocate(4) // `size` is u32, 4 bytes. 92 val errno = fd_pwrite( 93 fd = fd, 94 iovs = iovec.address.toInt(), 95 iovsSize = 1, 96 offset = fileOffset, 97 returnPointer = returnPointer.address.toInt(), 98 ) 99 if (errno != 0) throw ErrnoException(errno.toShort()) 100 101 val writtenByteCount = returnPointer.loadInt() 102 if (writtenByteCount != byteCount) { 103 throw IOException("expected $byteCount but was $writtenByteCount") 104 } 105 } 106 } 107 108 override fun protectedFlush() { 109 val errno = fd_sync(fd) 110 if (errno != 0) throw ErrnoException(errno.toShort()) 111 } 112 113 override fun protectedResize(size: Long) { 114 val errno = fd_filestat_set_size(fd, size) 115 if (errno != 0) throw ErrnoException(errno.toShort()) 116 } 117 118 override fun protectedClose() { 119 fdClose(fd) 120 } 121 } 122