xref: /aosp_15_r20/external/okio/okio-wasifilesystem/src/wasmWasiMain/kotlin/okio/WasiFileHandle.kt (revision f9742813c14b702d71392179818a9e591da8620c)
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