wip
[tripe-android] / jni.scala
CommitLineData
8eabb4ff
MW
1/* -*-java-*-
2 *
3 * Declarations of C functions
4 *
5 * (c) 2018 Straylight/Edgeware
6 */
7
8/*----- Licensing notice --------------------------------------------------*
9 *
10 * This file is part of the Trivial IP Encryption (TrIPE) Android app.
11 *
12 * TrIPE is free software: you can redistribute it and/or modify it under
13 * the terms of the GNU General Public License as published by the Free
14 * Software Foundation; either version 3 of the License, or (at your
15 * option) any later version.
16 *
17 * TrIPE is distributed in the hope that it will be useful, but WITHOUT
18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with TrIPE. If not, see <https://www.gnu.org/licenses/>.
24 */
25
26package uk.org.distorted.tripe; package object jni {
27
28/*----- Imports -----------------------------------------------------------*/
29
30import java.io.{Closeable, File};
31import java.util.Date;
32import Magic._;
33
34/*----- Main code ---------------------------------------------------------*/
35
36/* Import the native code library. */
37System.loadLibrary("toy");
38
39/* Exception indicating that a wrapped native object has been clobbered. */
40class NativeObjectTypeException(msg: String) extends RuntimeException(msg);
41type Wrapper = Array[Byte];
42
43case class ErrorEntry(val tag: String, val err: Int);
44@native def errtab: Array[ErrorEntry];
45@native def strerror(err: Int): CString;
46
47@native def hashsz(hash: String): Int;
48 /* Return the output hash size for the named HASH function, or -1. */
49
50/* Flags for `close'. */
51val CF_CLOSERD = 1;
52val CF_CLOSEWR = 2;
53val CF_CLOSEMASK = CF_CLOSERD | CF_CLOSEWR;
54
55/* Flags for `lock'. */
56val LKF_EXCL = 1;
57val LKF_WAIT = 2;
58
59/* Flags for `stat'. */
60val S_IFMT = 0xf000;
61val S_IFIFO = 0x1000;
62val S_IFCHR = 0x2000;
63val S_IFDIR = 0x4000;
64val S_IFBLK = 0x6000;
65val S_IFREG = 0x8000;
66val S_IFLNK = 0xa000;
67val S_IFSOCK = 0xc000;
68
69object FileType extends Enumeration {
70 val FIFO, CHR, DIR, BLK, REG, LNK, SOCK, UNK = Value;
71}
72import FileType.{Value => _, _};
73
74class FileInfo private[this](val devMajor: Int, val devMinor: Int,
75 val ino: Long, val mode: Int, val nlink: Int,
76 val uid: Int, val gid: Int,
77 _rdevMinor: Int, _rdevMajor: Int,
78 val size: Long,
79 val blksize: Int, val blocks: Long,
80 val atime: Date, val mtime: Date,
81 val ctime: Date) {
82 def this(devMajor: Int, devMinor: Int, ino: Long,
83 mode: Int, nlink: Int, uid: Int, gid: Int,
84 rdevMinor: Int, rdevMajor: Int,
85 size: Long, blksize: Int, blocks: Long,
86 atime: Long, mtime: Long, ctime: Long) {
87 this(devMajor, devMinor, ino, mode, nlink, uid, gid,
88 rdevMajor, rdevMinor, size, blksize, blocks,
89 new Date(atime), new Date(mtime), new Date(ctime));
90 }
91 def perms: Int = mode&0xfff;
92 def ftype: FileType.Value = (mode&S_IFMT) match {
93 case S_IFIFO => FIFO
94 case S_IFCHR => CHR
95 case S_IFDIR => DIR
96 case S_IFBLK => BLK
97 case S_IFREG => REG
98 case S_IFLNK => LNK
99 case S_IFSOCK => SOCK
100 case _ => UNK
101 }
102 def isfifo: Boolean = ftype == FIFO
103 def ischr: Boolean = ftype == CHR
104 def isdir: Boolean = ftype == DIR
105 def isblk: Boolean = ftype == BLK
106 def isreg: Boolean = ftype == REG
107 def islnk: Boolean = ftype == LNK
108 def issock: Boolean = ftype == SOCK
109 def isdev: Boolean = ischr || isblk;
110 private[this] def mustBeDevice() {
111 if (!isdev) throw new IllegalArgumentException("Object is not a device");
112 }
113 def rdevMajor: Int = { mustBeDevice(); _rdevMajor }
114 def rdevMinor: Int = { mustBeDevice(); _rdevMinor }
115}
116@native protected def unlink(path: CString);
117def unlink(path: String) { unlink(path.toCString); }
118def unlink(file: File) { unlink(file.getPath); }
119@native protected def rmdir(path: CString);
120def rmdir(path: String) { rmdir(path.toCString); }
121def rmdir(file: File) { rmdir(file.getPath); }
122@native protected def mkdir(path: CString, mode: Int);
123def mkdir(path: String, mode: Int) { mkdir(path.toCString, mode); }
124def mkdir(path: String) { mkdir(path, 0x1ff); }
125def mkdir(file: File, mode: Int) { mkdir(file.getPath, mode); }
126def mkdir(file: File) { mkdir(file.getPath); }
127@native protected def mkfile(path: CString, mode: Int);
128def mkfile(path: String, mode: Int) { mkfile(path.toCString, mode); }
129def mkfile(path: String) { mkfile(path, 0x1b6); }
130def mkfile(file: File, mode: Int) { mkfile(file.getPath, mode); }
131def mkfile(file: File) { mkfile(file.getPath); }
132@native protected def rename(from: CString, to: CString);
133def rename(from: String, to: String)
134 { rename(from.toCString, to.toCString); }
135def rename(from: File, to: File)
136 { rename(from.getPath, to.getPath); }
137@native protected def stat(path: CString): FileInfo;
138def stat(path: String): FileInfo = stat(path.toCString);
139def stat(file: File): FileInfo = stat(file.getPath);
140@native protected def lstat(path: CString): FileInfo;
141def lstat(path: String): FileInfo = lstat(path.toCString);
142def lstat(file: File): FileInfo = lstat(file.getPath);
143
144@native protected def opendir(path: CString): Wrapper;
145@native protected def readdir(path: CString, dir: Wrapper): CString;
146@native protected def closedir(path: CString, dir: Wrapper);
147
148abstract class BaseDirIterator[T](cpath: CString)
149 extends LookaheadIterator[T] with Closeable {
150 def this(path: String) { this(path.toCString); }
151 def this(dir: File) { this(dir.getPath); }
152 override def close() { closedir(cpath, dir); }
153 override protected def finalize() { super.finalize(); close(); }
154 private[this] val dir = opendir(cpath);
155 protected def mangle(file: String): T;
156 override protected def fetch(): Option[T] = readdir(cpath, dir) match {
157 case null => None
158 case f => f.toJString match {
159 case "." | ".." => fetch()
160 case jf => Some(mangle(jf))
161 }
162 }
163}
164
165class DirIterator(val path: String) extends BaseDirIterator[String](path) {
166 def this(dir: File) { this(dir.getPath); }
167 override protected def mangle(file: String): String = file;
168}
169def listDir(path: String): List[String] = {
170 val iter = new DirIterator(path);
171 try { iter.toList }
172 finally { iter.close(); }
173}
174def listDir(dir: File): List[String] = listDir(dir.getPath);
175
176class DirFilesIterator private[this](val dir: File, cpath: CString)
177 extends BaseDirIterator[File](cpath) {
178 def this(dir: File) { this(dir, dir.getPath.toCString); }
179 def this(path: String) { this(new File(path), path.toCString); }
180 override protected def mangle(file: String): File = new File(dir, file);
181}
182def listDirFiles(path: String): List[File] = {
183 val iter = new DirFilesIterator(path);
184 try { iter.toList }
185 finally { iter.close(); }
186}
187def listDirFiles(dir: File): List[File] = listDirFiles(dir.getPath);
188
189@native protected def lock(path: CString, flags: Int): Wrapper;
190@native protected def unlock(lock: Wrapper);
191class FileLock(path: String, flags: Int) extends Closeable {
192 def this(file: File, flags: Int) { this(file.getPath, flags); }
193 def this(path: String) { this(path, LKF_EXCL); }
194 def this(file: File) { this(file.getPath, LKF_EXCL); }
195 private[this] val lk = lock(path.toCString, flags);
196 override def close() { unlock(lk); }
197 override protected def finalize() { super.finalize(); close(); }
198}
199def withLock[T](path: String, flags: Int)(body: => T): T = {
200 val lk = new FileLock(path, flags);
201 try { body; } finally { lk.close(); }
202}
203def withLock[T](file: File, flags: Int)(body: => T): T =
204 withLock(file.getPath, flags) { body }
205def withLock[T](path: String)(body: => T): T =
206 withLock(path, LKF_EXCL) { body }
207def withLock[T](file: File)(body: => T): T =
208 withLock(file.getPath, LKF_EXCL) { body }
209
210@native protected def connect(path: CString): Wrapper;
211@native def send(conn: Wrapper, buf: CString,
212 start: Int, len: Int);
213@native def recv(conn: Wrapper, buf: CString,
214 start: Int, len: Int): Int;
215@native def close(conn: Wrapper, how: Int);
216class Connection(path: String) extends Closeable {
217 def this(file: File) { this(file.getPath); }
218 private[this] val conn = connect(path.toCString);
219 override def close() { jni.close(conn, CF_CLOSEMASK); }
220 override protected def finalize() { super.finalize(); close(); }
221 class InputStream private[Connection] extends java.io.InputStream {
222 override def read(): Int = {
223 val buf = new Array[Byte](1);
224 val n = read(buf, 0, 1);
225 if (n < 0) -1 else buf(0)&0xff;
226 }
227 override def read(buf: Array[Byte]): Int =
228 read(buf, 0, buf.length);
229 override def read(buf: Array[Byte], start: Int, len: Int) =
230 recv(conn, buf, start, len);
231 override def close() { jni.close(conn, CF_CLOSERD); }
232 }
233 lazy val input = new InputStream;
234 class OutputStream private[Connection] extends java.io.OutputStream {
235 override def write(b: Int) { write(Array[Byte](b.toByte), 0, 1); }
236 override def write(buf: Array[Byte]) { write(buf, 0, buf.length); }
237 override def write(buf: Array[Byte], start: Int, len: Int)
238 { send(conn, buf, start, len); }
239 override def close() { jni.close(conn, CF_CLOSEWR); }
240 }
241 lazy val output = new OutputStream;
242}
243
244/*----- That's all, folks -------------------------------------------------*/
245
246}