Add new RPC FS functions with useful error codes

As the interface is changed to use proper error codes, the way
parameters are passed is also updated.

Reviewed-by: Joakim Bech <joakim.bech@linaro.org>
Tested-by: Jerome Forissier <jerome.forissier@linaro.org> (HiKey)
Tested-by: Jens Wiklander <jens.wiklander@linaro.org> (QEMU)
Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
diff --git a/tee-supplicant/src/optee_msg_fs.h b/tee-supplicant/src/optee_msg_fs.h
new file mode 100644
index 0000000..6a5fcd7
--- /dev/null
+++ b/tee-supplicant/src/optee_msg_fs.h
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2016, Linaro Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __OPTEE_MSG_FS_H
+#define __OPTEE_MSG_FS_H
+
+/*
+ * Define protocol for messages with .cmd == OPTEE_MSG_RPC_CMD_FS
+ * and first parameter has the attribute OPTEE_MSG_ATTR_TYPE_VALUE_INPUT.
+ */
+
+/*
+ * Open a file
+ *
+ * [in]     param[0].u.value.a	OPTEE_MRF_OPEN
+ * [in]     param[1].u.tmem	a string holding the file name
+ * [out]    param[2].u.value.a	file descriptor of open file
+ */
+#define OPTEE_MRF_OPEN			0
+
+/*
+ * Create a file
+ *
+ * [in]     param[0].u.value.a	OPTEE_MRF_CREATE
+ * [in]     param[1].u.tmem	a string holding the file name
+ * [out]    param[2].u.value.a	file descriptor of open file
+ */
+#define OPTEE_MRF_CREATE		1
+
+/*
+ * Close a file
+ *
+ * [in]     param[0].u.value.a	OPTEE_MRF_CLOSE
+ * [in]     param[0].u.value.b	file descriptor of open file.
+ */
+#define OPTEE_MRF_CLOSE			2
+
+/*
+ * Read from a file
+ *
+ * [in]     param[0].u.value.a	OPTEE_MRF_READ
+ * [in]     param[0].u.value.b	file descriptor of open file
+ * [in]     param[0].u.value.c	offset into file
+ * [out]    param[1].u.tmem	buffer to hold returned data
+ */
+#define OPTEE_MRF_READ			3
+
+/*
+ * Write to a file
+ *
+ * [in]     param[0].u.value.a	OPTEE_MRF_WRITE
+ * [in]     param[0].u.value.b	file descriptor of open file
+ * [in]     param[0].u.value.c	offset into file
+ * [in]     param[1].u.tmem	buffer holding data to be written
+ */
+#define OPTEE_MRF_WRITE			4
+
+/*
+ * Truncate a file
+ *
+ * [in]     param[0].u.value.a	OPTEE_MRF_TRUNCATE
+ * [in]     param[0].u.value.b	file descriptor of open file
+ * [in]     param[0].u.value.c	length of file.
+ */
+#define OPTEE_MRF_TRUNCATE		5
+
+/*
+ * Remove a file
+ *
+ * [in]  param[0].u.value.a	OPTEE_MRF_REMOVE
+ * [in]  param[1].u.tmem	a string holding the file name
+ */
+#define OPTEE_MRF_REMOVE		6
+
+/*
+ * Rename a file
+ *
+ * [in]  param[0].u.value.a	OPTEE_MRF_RENAME
+ * [in]  param[0].u.value.b	true if existing target should be removed
+ * [in]  param[1].u.tmem	a string holding the old file name
+ * [in]  param[2].u.tmem	a string holding the new file name
+ */
+#define OPTEE_MRF_RENAME		7
+
+/*
+ * Opens a directory for file listing
+ *
+ * [in]  param[0].u.value.a	OPTEE_MRF_OPENDIR
+ * [in]  param[1].u.tmem	a string holding the name of the directory
+ * [out] param[2].u.value.a	handle to open directory
+ */
+#define OPTEE_MRF_OPENDIR		8
+
+/*
+ * Closes a directory handle
+ *
+ * [in]  param[0].u.value.a	OPTEE_MRF_CLOSEDIR
+ * [in]  param[0].u.value.b	handle to open directory
+ */
+#define OPTEE_MRF_CLOSEDIR		9
+
+/*
+ * Read next file name of directory
+ *
+ *
+ * [in]  param[0].u.value.a	OPTEE_MRF_READDIR
+ * [in]  param[0].u.value.b	handle to open directory
+ * [out] param[1].u.tmem	a string holding the file name
+ */
+#define OPTEE_MRF_READDIR		10
+
+/*
+ * Begins a new transaction (only valid for SQL FS)
+ *
+ * [in]  param[0].u.value.a	OPTEE_MRF_BEGIN_TRANSACTION
+ */
+#define OPTEE_MRF_BEGIN_TRANSACTION	11
+
+/*
+ * Ends a transaction (only valid for SQL FS)
+ *
+ * [in]  param[0].u.value.a	OPTEE_MRF_END_TRANSACTION
+ * [in]  param[0].u.value.b	true if rolling back to previous state
+ */
+#define OPTEE_MRF_END_TRANSACTION	12
+
+#endif /*__OPTEE_MSG_FS_H*/
diff --git a/tee-supplicant/src/sql_fs.c b/tee-supplicant/src/sql_fs.c
index b96748d..329fbe6 100644
--- a/tee-supplicant/src/sql_fs.c
+++ b/tee-supplicant/src/sql_fs.c
@@ -28,6 +28,8 @@
 #include <assert.h>
 #include <errno.h>
 #include <handle.h>
+#include <libgen.h>
+#include <optee_msg_fs.h>
 #include <sql_fs.h>
 #include <sqlfs.h>
 #include <sqlfs_internal.h>
@@ -35,9 +37,15 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/queue.h>
-#include <tee_fs.h>
-
 #include <teec_trace.h>
+#include <tee_fs.h>
+#include <tee_supplicant.h>
+
+
+#ifndef __aligned
+#define __aligned(x) __attribute__((__aligned__(x)))
+#endif
+#include <linux/tee.h>
 
 /*
  * File handles
@@ -450,74 +458,503 @@
  * used for convenience (debugging). The caller (OP-TEE) should not depend on
  * these exact values as they obviously depend on the Operating System.
  */
-int sql_fs_process(void *cmd, size_t cmd_size)
+static TEEC_Result sql_fs_process_primitive(void *cmd, size_t cmd_size)
 {
 	struct tee_fs_rpc *fsrpc = cmd;
-	int st;
 
 	if (cmd_size < sizeof(struct tee_fs_rpc))
-		return -1;
+		return TEEC_ERROR_BAD_PARAMETERS;
 
 	if (!cmd)
-		return -1;
+		return TEEC_ERROR_BAD_PARAMETERS;
 
 	switch (fsrpc->op) {
 	case TEE_FS_OPEN:
-		st = sql_fs_open(fsrpc);
+		fsrpc->res = sql_fs_open(fsrpc);
 		break;
 	case TEE_FS_CLOSE:
-		st = sql_fs_close(fsrpc);
+		fsrpc->res = sql_fs_close(fsrpc);
 		break;
 	case TEE_FS_READ:
-		st = sql_fs_read(fsrpc);
+		fsrpc->res = sql_fs_read(fsrpc);
 		break;
 	case TEE_FS_WRITE:
-		st = sql_fs_write(fsrpc);
+		fsrpc->res = sql_fs_write(fsrpc);
 		break;
 	case TEE_FS_SEEK:
-		st = sql_fs_seek(fsrpc);
+		fsrpc->res = sql_fs_seek(fsrpc);
 		break;
 	case TEE_FS_UNLINK:
-		st = sql_fs_unlink(fsrpc);
+		fsrpc->res = sql_fs_unlink(fsrpc);
 		break;
 	case TEE_FS_RENAME:
-		st = sql_fs_rename(fsrpc);
+		fsrpc->res = sql_fs_rename(fsrpc);
 		break;
 	case TEE_FS_TRUNC:
-		st = sql_fs_truncate(fsrpc);
+		fsrpc->res = sql_fs_truncate(fsrpc);
 		break;
 	case TEE_FS_MKDIR:
-		st = sql_fs_mkdir(fsrpc);
+		fsrpc->res = sql_fs_mkdir(fsrpc);
 		break;
 	case TEE_FS_OPENDIR:
-		st = sql_fs_opendir(fsrpc);
+		fsrpc->res = sql_fs_opendir(fsrpc);
 		break;
 	case TEE_FS_CLOSEDIR:
-		st = sql_fs_closedir(fsrpc);
+		fsrpc->res = sql_fs_closedir(fsrpc);
 		break;
 	case TEE_FS_READDIR:
-		st = sql_fs_readdir(fsrpc);
+		fsrpc->res = sql_fs_readdir(fsrpc);
 		break;
 	case TEE_FS_RMDIR:
-		st = sql_fs_rmdir(fsrpc);
+		fsrpc->res = sql_fs_rmdir(fsrpc);
 		break;
 	case TEE_FS_ACCESS:
-		st = sql_fs_access(fsrpc);
+		fsrpc->res = sql_fs_access(fsrpc);
 		break;
 	case TEE_FS_LINK:
-		st = -ENOTSUP;
+		fsrpc->res = -ENOTSUP;
 		break;
 	case TEE_FS_BEGIN:
-		st = sql_fs_begin();
+		fsrpc->res = sql_fs_begin();
 		break;
 	case TEE_FS_END:
-		st = sql_fs_end(fsrpc);
+		fsrpc->res = sql_fs_end(fsrpc);
 		break;
 	default:
 		EMSG("Unexpected SQL FS operation: %d", fsrpc->op);
-		return -1;
+		return TEEC_ERROR_NOT_SUPPORTED;
 	}
 
-	fsrpc->res = st;
-	return 0;
+	return TEEC_SUCCESS;
+}
+
+static TEEC_Result sql_fs_new_open(size_t num_params,
+				  struct tee_ioctl_param *params)
+{
+	struct file_state *fs;
+	char *fname;
+	int rc;
+
+	if (num_params != 3 ||
+	    (params[0].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
+			TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT ||
+	    (params[1].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
+			TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT ||
+	    (params[2].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
+			TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT)
+		return TEEC_ERROR_BAD_PARAMETERS;
+
+	fname = tee_supp_param_to_va(params + 1);
+	if (!fname)
+		return TEEC_ERROR_BAD_PARAMETERS;
+
+	fs = new_file(fname);
+	if (!fs)
+		return TEEC_ERROR_OUT_OF_MEMORY;
+
+	fs->fi.flags = O_RDWR;
+	rc = sqlfs_proc_open(db, fname, &fs->fi);
+	if (rc < 0) {
+		put_file(fs);
+		return TEEC_ERROR_ITEM_NOT_FOUND;
+	}
+
+	params[2].u.value.a = fs->fd;
+	return TEEC_SUCCESS;
+}
+
+static TEEC_Result sql_fs_new_create(size_t num_params,
+				     struct tee_ioctl_param *params)
+{
+	struct file_state *fs;
+	char *fname;
+	int rc;
+
+	if (num_params != 3 ||
+	    (params[0].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
+			TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT ||
+	    (params[1].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
+			TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT ||
+	    (params[2].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
+			TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT)
+		return TEEC_ERROR_BAD_PARAMETERS;
+
+	fname = tee_supp_param_to_va(params + 1);
+	if (!fname)
+		return TEEC_ERROR_BAD_PARAMETERS;
+
+	fs = new_file(fname);
+	if (!fs)
+		return TEEC_ERROR_OUT_OF_MEMORY;
+
+	fs->fi.flags = O_RDWR | O_CREAT | O_TRUNC;
+	rc = sqlfs_proc_open(db, fname, &fs->fi);
+	if (rc < 0) {
+		put_file(fs);
+		return TEEC_ERROR_ITEM_NOT_FOUND;
+	}
+
+	params[2].u.value.a = fs->fd;
+	return TEEC_SUCCESS;
+}
+
+static TEEC_Result sql_fs_new_close(size_t num_params,
+				    struct tee_ioctl_param *params)
+{
+	struct file_state *fs;
+
+	if (num_params != 1 ||
+	    (params[0].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
+			TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT)
+		return TEEC_ERROR_BAD_PARAMETERS;
+
+	fs = handle_lookup(&fd_db, params[0].u.value.b);
+	if (!fs)
+		return TEEC_ERROR_GENERIC;
+
+	put_file(fs);
+
+	return TEEC_SUCCESS;
+}
+
+static TEEC_Result sql_fs_new_read(size_t num_params,
+				   struct tee_ioctl_param *params)
+{
+	struct file_state *fs;
+	void *buf;
+	size_t len;
+	off_t offs;
+	int rc;
+
+	if (num_params != 2 ||
+	    (params[0].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
+			TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT ||
+	    (params[1].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
+			TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT)
+		return TEEC_ERROR_BAD_PARAMETERS;
+
+	fs = handle_lookup(&fd_db, params[0].u.value.b);
+	if (!fs)
+		return TEEC_ERROR_BAD_PARAMETERS;
+
+	offs = params[0].u.value.c;
+
+	buf = tee_supp_param_to_va(params + 1);
+	if (!buf)
+		return TEEC_ERROR_BAD_PARAMETERS;
+	len = params[1].u.memref.size;
+
+	rc = sqlfs_proc_read(db, fs->path, buf, len, offs, &fs->fi);
+	if (rc < 0)
+		return TEEC_ERROR_GENERIC;
+
+	params[1].u.memref.size = rc;
+	return TEEC_SUCCESS;
+}
+
+static TEEC_Result sql_fs_new_write(size_t num_params,
+				    struct tee_ioctl_param *params)
+{
+	struct file_state *fs;
+	void *buf;
+	size_t len;
+	off_t offs;
+	int rc;
+
+	if (num_params != 2 ||
+	    (params[0].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
+			TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT ||
+	    (params[1].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
+			TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT)
+		return TEEC_ERROR_BAD_PARAMETERS;
+
+	fs = handle_lookup(&fd_db, params[0].u.value.b);
+	if (!fs)
+		return TEEC_ERROR_BAD_PARAMETERS;
+
+	offs = params[0].u.value.c;
+
+	buf = tee_supp_param_to_va(params + 1);
+	if (!buf)
+		return TEEC_ERROR_BAD_PARAMETERS;
+	len = params[1].u.memref.size;
+
+	rc = sqlfs_proc_write(db, fs->path, buf, len, offs, &fs->fi);
+	if (rc != (int)len)
+		return TEEC_ERROR_GENERIC;
+	return TEEC_SUCCESS;
+}
+
+static TEEC_Result sql_fs_new_truncate(size_t num_params,
+				       struct tee_ioctl_param *params)
+{
+	struct file_state *fs;
+	size_t len;
+
+	if (num_params != 1 ||
+	    (params[0].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
+			TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT)
+		return TEEC_ERROR_BAD_PARAMETERS;
+
+	fs = handle_lookup(&fd_db, params[0].u.value.b);
+	if (!fs)
+		return TEEC_ERROR_BAD_PARAMETERS;
+
+	len = params[0].u.value.c;
+
+	if (sqlfs_proc_truncate(db, fs->path, len))
+		return TEEC_ERROR_GENERIC;
+
+	return TEEC_SUCCESS;
+}
+
+static void remove_dirname(const char *fname)
+{
+	char *dir = strdup(fname);
+	char *d;
+
+	if (!dir)
+		return;
+
+	d = dirname(dir);
+	sqlfs_proc_rmdir(db, d);
+	free(dir);
+}
+
+static TEEC_Result sql_fs_new_remove(size_t num_params,
+				     struct tee_ioctl_param *params)
+{
+	char *fname;
+	int rc;
+
+	if (num_params != 2 ||
+	    (params[0].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
+			TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT ||
+	    (params[1].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
+			TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT)
+		return TEEC_ERROR_BAD_PARAMETERS;
+
+	fname = tee_supp_param_to_va(params + 1);
+	if (!fname)
+		return TEEC_ERROR_BAD_PARAMETERS;
+
+	rc = sqlfs_proc_unlink(db, fname);
+	if (rc) {
+		if (rc == -ENOENT)
+			return TEEC_ERROR_ITEM_NOT_FOUND;
+		return TEEC_ERROR_GENERIC;
+	}
+	remove_dirname(fname);
+
+	return TEEC_SUCCESS;
+}
+
+static TEEC_Result sql_fs_new_rename(size_t num_params,
+				     struct tee_ioctl_param *params)
+{
+	char *old_fname;
+	char *new_fname;
+	bool overwrite;
+	int rc;
+
+	if (num_params != 3 ||
+	    (params[0].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
+			TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT ||
+	    (params[1].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
+			TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT ||
+	    (params[2].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
+			TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT)
+		return TEEC_ERROR_BAD_PARAMETERS;
+
+	overwrite = !!params[0].u.value.b;
+
+	old_fname = tee_supp_param_to_va(params + 1);
+	if (!old_fname)
+		return TEEC_ERROR_BAD_PARAMETERS;
+
+	new_fname = tee_supp_param_to_va(params + 2);
+	if (!new_fname)
+		return TEEC_ERROR_BAD_PARAMETERS;
+
+	if (!overwrite) {
+		struct stat st;
+
+		if (!sqlfs_proc_getattr(db, new_fname, &st))
+			return TEEC_ERROR_ACCESS_CONFLICT;
+	}
+
+	rc = sqlfs_proc_rename(db, old_fname, new_fname);
+	if (rc) {
+		if (rc == -EIO)
+			return TEEC_ERROR_ITEM_NOT_FOUND;
+		return TEEC_ERROR_GENERIC;
+	}
+	return TEEC_SUCCESS;
+}
+
+static TEEC_Result sql_fs_new_opendir(size_t num_params,
+				     struct tee_ioctl_param *params)
+{
+	char *fname;
+	struct dir_state *ds;
+
+	if (num_params != 3 ||
+	    (params[0].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
+			TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT ||
+	    (params[1].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
+			TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT ||
+	    (params[2].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
+			TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT)
+		return TEEC_ERROR_BAD_PARAMETERS;
+
+	fname = tee_supp_param_to_va(params + 1);
+	if (!fname)
+		return TEEC_ERROR_BAD_PARAMETERS;
+
+	ds = new_dir();
+	if (!ds)
+		return TEEC_ERROR_OUT_OF_MEMORY;
+
+	if (sqlfs_proc_readdir(db, fname, ds, fill_dir, 0, NULL)) {
+		put_dir(ds);
+		return TEEC_ERROR_ITEM_NOT_FOUND;
+	}
+
+	params[2].u.value.a = ds->handle;
+
+	return TEEC_SUCCESS;
+}
+
+static TEEC_Result sql_fs_new_closedir(size_t num_params,
+				      struct tee_ioctl_param *params)
+{
+	struct dir_state *ds;
+
+	if (num_params != 1 ||
+	    (params[0].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
+			TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT)
+		return TEEC_ERROR_BAD_PARAMETERS;
+
+	ds = handle_lookup(&dir_db, params[0].u.value.b);
+	if (!ds)
+		return TEEC_ERROR_BAD_PARAMETERS;
+
+	put_dir(ds);
+
+	return TEEC_SUCCESS;
+}
+
+static TEEC_Result sql_fs_new_readdir(size_t num_params,
+				      struct tee_ioctl_param *params)
+{
+	struct dir_state *ds;
+	struct dir_entry *de;
+	char *buf;
+	size_t len;
+	size_t fname_len;
+
+	if (num_params != 2 ||
+	    (params[0].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
+			TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT ||
+	    (params[1].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
+			TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT)
+		return TEEC_ERROR_BAD_PARAMETERS;
+
+
+	buf = tee_supp_param_to_va(params + 1);
+	if (!buf)
+		return TEEC_ERROR_BAD_PARAMETERS;
+	len = params[1].u.memref.size;
+
+	ds = handle_lookup(&dir_db, params[0].u.value.b);
+	if (!ds)
+		return TEEC_ERROR_BAD_PARAMETERS;
+
+	de = TAILQ_FIRST(&ds->dir_entries);
+	if (!de)
+		return TEEC_ERROR_ITEM_NOT_FOUND;
+
+	fname_len = strlen(de->name) + 1;
+	params[1].u.memref.size = fname_len;
+	if (fname_len > len)
+		return TEEC_ERROR_SHORT_BUFFER;
+
+	memcpy(buf, de->name, fname_len);
+	TAILQ_REMOVE(&ds->dir_entries, de, link);
+	free(de);
+
+	return TEEC_SUCCESS;
+}
+
+static TEEC_Result sql_fs_new_begin_transaction(size_t num_params,
+						struct tee_ioctl_param *params)
+{
+	if (num_params != 1 ||
+	    (params[0].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
+			TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT)
+		return TEEC_ERROR_BAD_PARAMETERS;
+
+	if (sqlfs_begin_transaction(db))
+		return TEEC_SUCCESS;
+	return TEEC_ERROR_GENERIC;
+}
+
+static TEEC_Result sql_fs_new_end_transaction(size_t num_params,
+					      struct tee_ioctl_param *params)
+{
+	if (num_params != 1 ||
+	    (params[0].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
+			TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT)
+		return TEEC_ERROR_BAD_PARAMETERS;
+
+	if (sqlfs_complete_transaction(db, !params[0].u.value.b))
+		return TEEC_SUCCESS;
+	return TEEC_ERROR_GENERIC;
+}
+
+TEEC_Result sql_fs_process(struct tee_iocl_supp_recv_arg *recv)
+{
+	struct tee_ioctl_param *param = (void *)(recv + 1);
+
+	if (recv->num_params == 1 && tee_supp_param_is_memref(param)) {
+		void *va = tee_supp_param_to_va(param);
+
+		if (!va)
+			return TEEC_ERROR_BAD_PARAMETERS;
+		return sql_fs_process_primitive(va, param->u.memref.size);
+	}
+
+	if (!tee_supp_param_is_value(param))
+		return TEEC_ERROR_BAD_PARAMETERS;
+
+	switch (param->u.value.a) {
+	case OPTEE_MRF_OPEN:
+		return sql_fs_new_open(recv->num_params, param);
+	case OPTEE_MRF_CREATE:
+		return sql_fs_new_create(recv->num_params, param);
+	case OPTEE_MRF_CLOSE:
+		return sql_fs_new_close(recv->num_params, param);
+	case OPTEE_MRF_READ:
+		return sql_fs_new_read(recv->num_params, param);
+	case OPTEE_MRF_WRITE:
+		return sql_fs_new_write(recv->num_params, param);
+	case OPTEE_MRF_TRUNCATE:
+		return sql_fs_new_truncate(recv->num_params, param);
+	case OPTEE_MRF_REMOVE:
+		return sql_fs_new_remove(recv->num_params, param);
+	case OPTEE_MRF_RENAME:
+		return sql_fs_new_rename(recv->num_params, param);
+	case OPTEE_MRF_OPENDIR:
+		return sql_fs_new_opendir(recv->num_params, param);
+	case OPTEE_MRF_CLOSEDIR:
+		return sql_fs_new_closedir(recv->num_params, param);
+	case OPTEE_MRF_READDIR:
+		return sql_fs_new_readdir(recv->num_params, param);
+	case OPTEE_MRF_BEGIN_TRANSACTION:
+		return sql_fs_new_begin_transaction(recv->num_params, param);
+	case OPTEE_MRF_END_TRANSACTION:
+		return sql_fs_new_end_transaction(recv->num_params, param);
+	default:
+		return TEEC_ERROR_BAD_PARAMETERS;
+	}
 }
diff --git a/tee-supplicant/src/sql_fs.h b/tee-supplicant/src/sql_fs.h
index d5d09a6..30ac1e3 100644
--- a/tee-supplicant/src/sql_fs.h
+++ b/tee-supplicant/src/sql_fs.h
@@ -27,26 +27,27 @@
 #ifndef SQL_FS_H
 #define SQL_FS_H
 
+#include <tee_client_api.h>
+
+struct tee_iocl_supp_recv_arg;
+
 #ifdef CFG_SQL_FS
 
 int sql_fs_init(void);
-int sql_fs_process(void *cmd, size_t cmd_size);
+TEEC_Result sql_fs_process(struct tee_iocl_supp_recv_arg *recv);
 
 #else
 
-#include <errno.h>
-
 static inline int sql_fs_init(void)
 {
 	return 0;
 }
 
-static inline int sql_fs_process(void *cmd, size_t cmd_size)
+static inline TEEC_Result sql_fs_process(struct tee_iocl_supp_recv_arg *recv)
 {
-	(void)cmd;
-	(void)cmd_size;
+	(void)recv;
 
-	return -ENOTSUP;
+	return TEEC_ERROR_NOT_SUPPORTED;
 }
 
 #endif
diff --git a/tee-supplicant/src/tee_supp_fs.c b/tee-supplicant/src/tee_supp_fs.c
index cf225b7..246c4a9 100644
--- a/tee-supplicant/src/tee_supp_fs.c
+++ b/tee-supplicant/src/tee_supp_fs.c
@@ -24,16 +24,28 @@
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  */
-#include <fcntl.h>
-#include <stdio.h>
-#include <sys/stat.h>
-#include <stdint.h>
+#include <assert.h>
 #include <dirent.h>
-#include <unistd.h>
-#include <string.h>
-#include <tee_supp_fs.h>
+#include <errno.h>
+#include <fcntl.h>
 #include <handle.h>
+#include <libgen.h>
+#include <optee_msg_fs.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <teec_trace.h>
 #include <tee_fs.h>
+#include <tee_supp_fs.h>
+#include <tee_supplicant.h>
+#include <unistd.h>
+
+#ifndef __aligned
+#define __aligned(x) __attribute__((__aligned__(x)))
+#endif
+#include <linux/tee.h>
 
 /* Path to all secure storage files. */
 #define TEE_FS_SUBPATH "/data"
@@ -187,10 +199,10 @@
 static int tee_fs_mkdir(struct tee_fs_rpc *fsrpc)
 {
 	char abs_dirname[PATH_MAX];
-	char *dirname = (char *)(fsrpc + 1);
+	char *dname = (char *)(fsrpc + 1);
 	mode_t mode;
 	int ret = -1; /* Same as mkir on error */
-	size_t filesize = tee_fs_get_absolute_filename(dirname, abs_dirname,
+	size_t filesize = tee_fs_get_absolute_filename(dname, abs_dirname,
 						       sizeof(abs_dirname));
 
 	if (filesize) {
@@ -204,10 +216,10 @@
 static int tee_fs_opendir(struct tee_fs_rpc *fsrpc)
 {
 	char abs_dirname[PATH_MAX];
-	char *dirname = (char *)(fsrpc + 1);
+	char *dname = (char *)(fsrpc + 1);
 	DIR *dir;
 	int handle = -1;
-	size_t filesize = tee_fs_get_absolute_filename(dirname, abs_dirname,
+	size_t filesize = tee_fs_get_absolute_filename(dname, abs_dirname,
 						       sizeof(abs_dirname));
 	if (!filesize)
 		goto exit;
@@ -232,7 +244,7 @@
 
 static int tee_fs_readdir(struct tee_fs_rpc *fsrpc)
 {
-	char *dirname = (char *)(fsrpc + 1);
+	char *dname = (char *)(fsrpc + 1);
 	DIR *dir = handle_lookup(&dir_handle_db, fsrpc->arg);
 	struct dirent *dirent;
 	size_t len;
@@ -251,7 +263,7 @@
 		return -1;
 
 	len++;
-	memcpy(dirname, dirent->d_name, len);
+	memcpy(dname, dirent->d_name, len);
 	fsrpc->len = len;
 
 	return 0;
@@ -260,9 +272,9 @@
 static int tee_fs_rmdir(struct tee_fs_rpc *fsrpc)
 {
 	char abs_dirname[PATH_MAX];
-	char *dirname = (char *)(fsrpc + 1);
+	char *dname = (char *)(fsrpc + 1);
 	int ret = -1; /* Corresponds to the error value for rmdir */
-	size_t filesize = tee_fs_get_absolute_filename(dirname, abs_dirname,
+	size_t filesize = tee_fs_get_absolute_filename(dname, abs_dirname,
 						       sizeof(abs_dirname));
 
 	if (filesize)
@@ -298,67 +310,549 @@
 	return 0;
 }
 
-int tee_supp_fs_process(void *cmd, size_t cmd_size)
+static TEEC_Result tee_supp_fs_process_primitive(void *cmd, size_t cmd_size)
 {
 	struct tee_fs_rpc *fsrpc = cmd;
-	int ret = -1;
 
 	if (cmd_size < sizeof(struct tee_fs_rpc))
-		return ret;
+		return TEEC_ERROR_BAD_PARAMETERS;
 
-	if (cmd == NULL)
-		return ret;
+	if (!cmd)
+		return TEEC_ERROR_BAD_PARAMETERS;
 
 	switch (fsrpc->op) {
 	case TEE_FS_OPEN:
-		ret = tee_fs_open(fsrpc);
+		fsrpc->res = tee_fs_open(fsrpc);
 		break;
 	case TEE_FS_CLOSE:
-		ret = tee_fs_close(fsrpc);
+		fsrpc->res = tee_fs_close(fsrpc);
 		break;
 	case TEE_FS_READ:
-		ret = tee_fs_read(fsrpc);
+		fsrpc->res = tee_fs_read(fsrpc);
 		break;
 	case TEE_FS_WRITE:
-		ret = tee_fs_write(fsrpc);
+		fsrpc->res = tee_fs_write(fsrpc);
 		break;
 	case TEE_FS_SEEK:
-		ret = tee_fs_seek(fsrpc);
+		fsrpc->res = tee_fs_seek(fsrpc);
 		break;
 	case TEE_FS_UNLINK:
-		ret = tee_fs_unlink(fsrpc);
+		fsrpc->res = tee_fs_unlink(fsrpc);
 		break;
 	case TEE_FS_RENAME:
-		ret = tee_fs_rename(fsrpc);
+		fsrpc->res = tee_fs_rename(fsrpc);
 		break;
 	case TEE_FS_TRUNC:
-		ret = tee_fs_truncate(fsrpc);
+		fsrpc->res = tee_fs_truncate(fsrpc);
 		break;
 	case TEE_FS_MKDIR:
-		ret = tee_fs_mkdir(fsrpc);
+		fsrpc->res = tee_fs_mkdir(fsrpc);
 		break;
 	case TEE_FS_OPENDIR:
-		ret = tee_fs_opendir(fsrpc);
+		fsrpc->res = tee_fs_opendir(fsrpc);
 		break;
 	case TEE_FS_CLOSEDIR:
-		ret = tee_fs_closedir(fsrpc);
+		fsrpc->res = tee_fs_closedir(fsrpc);
 		break;
 	case TEE_FS_READDIR:
-		ret = tee_fs_readdir(fsrpc);
+		fsrpc->res = tee_fs_readdir(fsrpc);
 		break;
 	case TEE_FS_RMDIR:
-		ret = tee_fs_rmdir(fsrpc);
+		fsrpc->res = tee_fs_rmdir(fsrpc);
 		break;
 	case TEE_FS_ACCESS:
-		ret = tee_fs_access(fsrpc);
+		fsrpc->res = tee_fs_access(fsrpc);
 		break;
 	case TEE_FS_LINK:
-		ret = tee_fs_link(fsrpc);
-	default:
+		fsrpc->res = tee_fs_link(fsrpc);
 		break;
+	default:
+		EMSG("Unexpected REE FS operation: %d", fsrpc->op);
+		return TEEC_ERROR_NOT_SUPPORTED;
 	}
 
-	fsrpc->res = ret;
+	return TEEC_SUCCESS;
+}
 
-	return ret;
+static int open_wrapper(const char *fname, int flags)
+{
+	int fd;
+
+	while (true) {
+		fd = open(fname, flags);
+		if (fd >= 0 || errno != EINTR)
+			return fd;
+	}
+}
+
+static TEEC_Result ree_fs_new_open(size_t num_params,
+				   struct tee_ioctl_param *params)
+{
+	char abs_filename[PATH_MAX];
+	char *fname;
+	int fd;
+
+	if (num_params != 3 ||
+	    (params[0].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
+			TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT ||
+	    (params[1].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
+			TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT ||
+	    (params[2].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
+			TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT)
+		return TEEC_ERROR_BAD_PARAMETERS;
+
+	fname = tee_supp_param_to_va(params + 1);
+	if (!fname)
+		return TEEC_ERROR_BAD_PARAMETERS;
+
+	if (!tee_fs_get_absolute_filename(fname, abs_filename,
+					  sizeof(abs_filename)))
+		return TEEC_ERROR_BAD_PARAMETERS;
+
+	fd = open_wrapper(abs_filename, O_RDWR);
+	if (fd < 0)
+		return TEEC_ERROR_ITEM_NOT_FOUND;
+
+	params[2].u.value.a = fd;
+	return TEEC_SUCCESS;
+}
+
+static TEEC_Result ree_fs_new_create(size_t num_params,
+				     struct tee_ioctl_param *params)
+{
+	char abs_filename[PATH_MAX];
+	char abs_dir[PATH_MAX];
+	char *fname;
+	char *d;
+	int fd;
+	const int flags = O_RDWR | O_CREAT | O_TRUNC;
+
+	if (num_params != 3 ||
+	    (params[0].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
+			TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT ||
+	    (params[1].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
+			TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT ||
+	    (params[2].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
+			TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT)
+		return TEEC_ERROR_BAD_PARAMETERS;
+
+	fname = tee_supp_param_to_va(params + 1);
+	if (!fname)
+		return TEEC_ERROR_BAD_PARAMETERS;
+
+	if (!tee_fs_get_absolute_filename(fname, abs_filename,
+					  sizeof(abs_filename)))
+		return TEEC_ERROR_BAD_PARAMETERS;
+
+	fd = open_wrapper(abs_filename, flags);
+	if (fd >= 0)
+		goto out;
+	if (errno != ENOENT)
+		return TEEC_ERROR_GENERIC;
+
+	/* Directory for file missing, try make to it */
+	strncpy(abs_dir, abs_filename, sizeof(abs_dir));
+	abs_dir[sizeof(abs_dir) - 1] = '\0';
+	d = dirname(abs_dir);
+	if (!mkdir(d, S_IRUSR | S_IWUSR | S_IXUSR)) {
+		fd = open_wrapper(abs_filename, flags);
+		if (fd >= 0)
+			goto out;
+		/*
+		 * The directory was made but the file could still not be
+		 * created.
+		 */
+		rmdir(d);
+		return TEEC_ERROR_GENERIC;
+	}
+	if (errno != ENOENT)
+		return TEEC_ERROR_GENERIC;
+
+	/* Parent directory for file missing, try to make it */
+	d = dirname(d);
+	if (mkdir(d, S_IRUSR | S_IWUSR | S_IXUSR))
+		return TEEC_ERROR_GENERIC;
+
+	/* Try to make directory for file again */
+	strncpy(abs_dir, abs_filename, sizeof(abs_dir));
+	abs_dir[sizeof(abs_dir) - 1] = '\0';
+	d = dirname(abs_dir);
+	if (mkdir(d, S_IRUSR | S_IWUSR | S_IXUSR)) {
+		d = dirname(d);
+		rmdir(d);
+		return TEEC_ERROR_GENERIC;
+	}
+
+	fd = open_wrapper(abs_filename, flags);
+	if (fd < 0) {
+		rmdir(d);
+		d = dirname(d);
+		rmdir(d);
+		return TEEC_ERROR_GENERIC;
+	}
+
+out:
+	params[2].u.value.a = fd;
+	return TEEC_SUCCESS;
+}
+
+static TEEC_Result ree_fs_new_close(size_t num_params,
+				    struct tee_ioctl_param *params)
+{
+	int fd;
+
+	if (num_params != 1 ||
+	    (params[0].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
+			TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT)
+		return TEEC_ERROR_BAD_PARAMETERS;
+
+	fd = params[0].u.value.b;
+	while (close(fd)) {
+		if (errno != EINTR)
+			return TEEC_ERROR_GENERIC;
+	}
+	return TEEC_SUCCESS;
+}
+
+static TEEC_Result ree_fs_new_read(size_t num_params,
+				   struct tee_ioctl_param *params)
+{
+	uint8_t *buf;
+	size_t len;
+	off_t offs;
+	int fd;
+	ssize_t r;
+	size_t s;
+
+	if (num_params != 2 ||
+	    (params[0].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
+			TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT ||
+	    (params[1].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
+			TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT)
+		return TEEC_ERROR_BAD_PARAMETERS;
+
+	fd = params[0].u.value.b;
+	offs = params[0].u.value.c;
+
+	buf = tee_supp_param_to_va(params + 1);
+	if (!buf)
+		return TEEC_ERROR_BAD_PARAMETERS;
+	len = params[1].u.memref.size;
+
+	s = 0;
+	r = -1;
+	while (r && len) {
+		r = pread(fd, buf, len, offs);
+		if (r < 0) {
+			if (errno == EINTR)
+				continue;
+			return TEEC_ERROR_GENERIC;
+		}
+		assert((size_t)r <= len);
+		buf += r;
+		len -= r;
+		offs += r;
+		s += r;
+	}
+
+	params[1].u.memref.size = s;
+	return TEEC_SUCCESS;
+}
+
+static TEEC_Result ree_fs_new_write(size_t num_params,
+				    struct tee_ioctl_param *params)
+{
+	uint8_t *buf;
+	size_t len;
+	off_t offs;
+	int fd;
+	ssize_t r;
+
+	if (num_params != 2 ||
+	    (params[0].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
+			TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT ||
+	    (params[1].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
+			TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT)
+		return TEEC_ERROR_BAD_PARAMETERS;
+
+	fd = params[0].u.value.b;
+	offs = params[0].u.value.c;
+
+	buf = tee_supp_param_to_va(params + 1);
+	if (!buf)
+		return TEEC_ERROR_BAD_PARAMETERS;
+	len = params[1].u.memref.size;
+
+	while (len) {
+		r = pwrite(fd, buf, len, offs);
+		if (r < 0) {
+			if (errno == EINTR)
+				continue;
+			return TEEC_ERROR_GENERIC;
+		}
+		assert((size_t)r <= len);
+		buf += r;
+		len -= r;
+		offs += r;
+	}
+
+	return TEEC_SUCCESS;
+}
+
+static TEEC_Result ree_fs_new_truncate(size_t num_params,
+				       struct tee_ioctl_param *params)
+{
+	size_t len;
+	int fd;
+
+	if (num_params != 1 ||
+	    (params[0].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
+			TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT)
+		return TEEC_ERROR_BAD_PARAMETERS;
+
+	fd = params[0].u.value.b;
+	len = params[0].u.value.c;
+
+	while (ftruncate(fd, len)) {
+		if (errno != EINTR)
+			return TEEC_ERROR_GENERIC;
+	}
+
+	return TEEC_SUCCESS;
+}
+
+static TEEC_Result ree_fs_new_remove(size_t num_params,
+				     struct tee_ioctl_param *params)
+{
+	char abs_filename[PATH_MAX];
+	char *fname;
+	char *d;
+
+	if (num_params != 2 ||
+	    (params[0].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
+			TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT ||
+	    (params[1].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
+			TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT)
+		return TEEC_ERROR_BAD_PARAMETERS;
+
+	fname = tee_supp_param_to_va(params + 1);
+	if (!fname)
+		return TEEC_ERROR_BAD_PARAMETERS;
+
+	if (!tee_fs_get_absolute_filename(fname, abs_filename,
+					  sizeof(abs_filename)))
+		return TEEC_ERROR_BAD_PARAMETERS;
+
+	if (unlink(abs_filename)) {
+		if (errno == ENOENT)
+			return TEEC_ERROR_ITEM_NOT_FOUND;
+		return TEEC_ERROR_GENERIC;
+	}
+
+	/* If a file is removed, maybe the directory can be removed to? */
+	d = dirname(abs_filename);
+	if (!rmdir(d)) {
+		/*
+		 * If the directory was removed, maybe the parent directory
+		 * can be removed too?
+		 */
+		d = dirname(d);
+		rmdir(d);
+	}
+
+	return TEEC_SUCCESS;
+}
+
+static TEEC_Result ree_fs_new_rename(size_t num_params,
+				     struct tee_ioctl_param *params)
+{
+	char old_abs_filename[PATH_MAX];
+	char new_abs_filename[PATH_MAX];
+	char *old_fname;
+	char *new_fname;
+	bool overwrite;
+
+	if (num_params != 3 ||
+	    (params[0].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
+			TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT ||
+	    (params[1].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
+			TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT ||
+	    (params[2].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
+			TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT)
+		return TEEC_ERROR_BAD_PARAMETERS;
+
+	overwrite = !!params[0].u.value.b;
+
+	old_fname = tee_supp_param_to_va(params + 1);
+	if (!old_fname)
+		return TEEC_ERROR_BAD_PARAMETERS;
+
+	new_fname = tee_supp_param_to_va(params + 2);
+	if (!new_fname)
+		return TEEC_ERROR_BAD_PARAMETERS;
+
+	if (!tee_fs_get_absolute_filename(old_fname, old_abs_filename,
+					  sizeof(old_abs_filename)))
+		return TEEC_ERROR_BAD_PARAMETERS;
+
+	if (!tee_fs_get_absolute_filename(new_fname, new_abs_filename,
+					  sizeof(new_abs_filename)))
+		return TEEC_ERROR_BAD_PARAMETERS;
+
+	if (!overwrite) {
+		struct stat st;
+
+		if (!stat(new_abs_filename, &st))
+			return TEEC_ERROR_ACCESS_CONFLICT;
+	}
+	if (rename(old_abs_filename, new_abs_filename)) {
+		if (errno == ENOENT)
+			return TEEC_ERROR_ITEM_NOT_FOUND;
+	}
+	return TEEC_SUCCESS;
+}
+
+static TEEC_Result ree_fs_new_opendir(size_t num_params,
+				      struct tee_ioctl_param *params)
+{
+	char abs_filename[PATH_MAX];
+	char *fname;
+	DIR *dir;
+	int handle;
+
+	if (num_params != 3 ||
+	    (params[0].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
+			TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT ||
+	    (params[1].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
+			TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT ||
+	    (params[2].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
+			TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT)
+		return TEEC_ERROR_BAD_PARAMETERS;
+
+	fname = tee_supp_param_to_va(params + 1);
+	if (!fname)
+		return TEEC_ERROR_BAD_PARAMETERS;
+
+	if (!tee_fs_get_absolute_filename(fname, abs_filename,
+					  sizeof(abs_filename)))
+		return TEEC_ERROR_BAD_PARAMETERS;
+
+	dir = opendir(abs_filename);
+	if (!dir)
+		return TEEC_ERROR_ITEM_NOT_FOUND;
+
+	handle = handle_get(&dir_handle_db, dir);
+	if (handle < 0) {
+		closedir(dir);
+		return TEEC_ERROR_OUT_OF_MEMORY;
+	}
+
+	params[2].u.value.a = handle;
+	return TEEC_SUCCESS;
+}
+
+static TEEC_Result ree_fs_new_closedir(size_t num_params,
+				       struct tee_ioctl_param *params)
+{
+	DIR *dir;
+
+	if (num_params != 1 ||
+	    (params[0].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
+			TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT)
+		return TEEC_ERROR_BAD_PARAMETERS;
+
+	dir = handle_put(&dir_handle_db, params[0].u.value.b);
+	if (!dir)
+		return TEEC_ERROR_BAD_PARAMETERS;
+
+	closedir(dir);
+
+	return TEEC_SUCCESS;
+}
+
+static TEEC_Result ree_fs_new_readdir(size_t num_params,
+				      struct tee_ioctl_param *params)
+{
+	DIR *dir;
+	struct dirent *dirent;
+	char *buf;
+	size_t len;
+	size_t fname_len;
+
+	if (num_params != 2 ||
+	    (params[0].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
+			TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT ||
+	    (params[1].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
+			TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT)
+		return TEEC_ERROR_BAD_PARAMETERS;
+
+
+	buf = tee_supp_param_to_va(params + 1);
+	if (!buf)
+		return TEEC_ERROR_BAD_PARAMETERS;
+	len = params[1].u.memref.size;
+
+	dir = handle_lookup(&dir_handle_db, params[0].u.value.b);
+	if (!dir)
+		return TEEC_ERROR_BAD_PARAMETERS;
+
+	while (true) {
+		dirent = readdir(dir);
+		if (!dirent)
+			return TEEC_ERROR_ITEM_NOT_FOUND;
+		if (dirent->d_name[0] != '.')
+			break;
+	}
+
+	fname_len = strlen(dirent->d_name) + 1;
+	params[1].u.memref.size = fname_len;
+	if (fname_len > len)
+		return TEEC_ERROR_SHORT_BUFFER;
+
+	memcpy(buf, dirent->d_name, fname_len);
+
+	return TEEC_SUCCESS;
+}
+
+TEEC_Result tee_supp_fs_process(struct tee_iocl_supp_recv_arg *recv)
+{
+	struct tee_ioctl_param *param = (void *)(recv + 1);
+
+	if (recv->num_params == 1 && tee_supp_param_is_memref(param)) {
+		void *va = tee_supp_param_to_va(param);
+
+		if (!va)
+			return TEEC_ERROR_BAD_PARAMETERS;
+		return tee_supp_fs_process_primitive(va, param->u.memref.size);
+	}
+
+	if (!tee_supp_param_is_value(param))
+		return TEEC_ERROR_BAD_PARAMETERS;
+
+	switch (param->u.value.a) {
+	case OPTEE_MRF_OPEN:
+		return ree_fs_new_open(recv->num_params, param);
+	case OPTEE_MRF_CREATE:
+		return ree_fs_new_create(recv->num_params, param);
+	case OPTEE_MRF_CLOSE:
+		return ree_fs_new_close(recv->num_params, param);
+	case OPTEE_MRF_READ:
+		return ree_fs_new_read(recv->num_params, param);
+	case OPTEE_MRF_WRITE:
+		return ree_fs_new_write(recv->num_params, param);
+	case OPTEE_MRF_TRUNCATE:
+		return ree_fs_new_truncate(recv->num_params, param);
+	case OPTEE_MRF_REMOVE:
+		return ree_fs_new_remove(recv->num_params, param);
+	case OPTEE_MRF_RENAME:
+		return ree_fs_new_rename(recv->num_params, param);
+	case OPTEE_MRF_OPENDIR:
+		return ree_fs_new_opendir(recv->num_params, param);
+	case OPTEE_MRF_CLOSEDIR:
+		return ree_fs_new_closedir(recv->num_params, param);
+	case OPTEE_MRF_READDIR:
+		return ree_fs_new_readdir(recv->num_params, param);
+	default:
+		return TEEC_ERROR_BAD_PARAMETERS;
+	}
 }
diff --git a/tee-supplicant/src/tee_supp_fs.h b/tee-supplicant/src/tee_supp_fs.h
index 3d14a98..3342b7e 100644
--- a/tee-supplicant/src/tee_supp_fs.h
+++ b/tee-supplicant/src/tee_supp_fs.h
@@ -27,10 +27,11 @@
 #ifndef TEE_SUPP_FS_H
 #define TEE_SUPP_FS_H
 
-#include <stddef.h>
+#include <tee_client_api.h>
 
 int tee_supp_fs_init(void);
 
-int tee_supp_fs_process(void *cmd, size_t cmd_size);
+struct tee_iocl_supp_recv_arg;
+TEEC_Result tee_supp_fs_process(struct tee_iocl_supp_recv_arg *recv);
 
 #endif
diff --git a/tee-supplicant/src/tee_supplicant.c b/tee-supplicant/src/tee_supplicant.c
index 0892bd7..52a33b1 100644
--- a/tee-supplicant/src/tee_supplicant.c
+++ b/tee-supplicant/src/tee_supplicant.c
@@ -26,34 +26,36 @@
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  */
+
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
-#include <stdint.h>
 #include <inttypes.h>
+#include <rpmb.h>
+#include <sql_fs.h>
 #include <stdbool.h>
+#include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/mman.h>
 #include <sys/ioctl.h>
-#include <unistd.h>
-
-#include <teec_trace.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <tee_client_api.h>
 #include <teec_ta_load.h>
 #include <tee_supp_fs.h>
+#include <teec_trace.h>
+#include <tee_supplicant.h>
+#include <unistd.h>
 
 #ifndef __aligned
 #define __aligned(x) __attribute__((__aligned__(x)))
 #endif
 #include <linux/tee.h>
 
-#include <rpmb.h>
-#include <sql_fs.h>
-#define RPC_NUM_PARAMS	2
+#define RPC_NUM_PARAMS	3
 
 #define RPC_BUF_SIZE	(sizeof(struct tee_iocl_supp_send_arg) + \
 			 RPC_NUM_PARAMS * sizeof(struct tee_ioctl_param))
@@ -105,6 +107,16 @@
 	}
 }
 
+static struct tee_shm *find_tshm(int id)
+{
+	struct tee_shm *tshm;
+
+	tshm = shm_head;
+	while (tshm && tshm->id != id)
+		tshm = tshm->next;
+	return tshm;
+}
+
 /* Get parameter allocated by secure world */
 static int get_param(union tee_rpc_invoke *request, const uint32_t idx,
 		     TEEC_SharedMemory *shm)
@@ -127,9 +139,7 @@
 
 	memset(shm, 0, sizeof(*shm));
 
-	tshm = shm_head;
-	while (tshm && tshm->id != params[idx].u.memref.shm_id)
-		tshm = tshm->next;
+	tshm = find_tshm(params[idx].u.memref.shm_id);
 	if (!tshm) {
 		/*
 		 * It doesn't make sense to query required size of an
@@ -161,37 +171,12 @@
 
 static void process_fs(union tee_rpc_invoke *request)
 {
-	TEEC_SharedMemory shm;
-
-	if (request->recv.num_params != 1 || get_param(request, 0, &shm)) {
-		request->send.ret = TEEC_ERROR_BAD_PARAMETERS;
-		return;
-	}
-
-	if (tee_supp_fs_process(shm.buffer, shm.size) < 0) {
-		request->send.ret = TEEC_ERROR_BAD_PARAMETERS;
-		return;
-	}
-
-	request->send.ret = TEEC_SUCCESS;
+	request->send.ret = tee_supp_fs_process(&request->recv);
 }
 
-
 static void process_sql_fs(union tee_rpc_invoke *request)
 {
-	TEEC_SharedMemory shm;
-
-	if (request->recv.num_params != 1 || get_param(request, 0, &shm)) {
-		request->send.ret = TEEC_ERROR_BAD_PARAMETERS;
-		return;
-	}
-
-	if (sql_fs_process(shm.buffer, shm.size) < 0) {
-		request->send.ret = TEEC_ERROR_BAD_PARAMETERS;
-		return;
-	}
-
-	request->send.ret = TEEC_SUCCESS;
+	request->send.ret = sql_fs_process(&request->recv);
 }
 
 static void load_ta(union tee_rpc_invoke *request)
@@ -485,3 +470,50 @@
 	}
 	return 0;
 }
+
+bool tee_supp_param_is_memref(struct tee_ioctl_param *param)
+{
+	switch (param->attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) {
+	case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT:
+	case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
+	case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
+		return true;
+	default:
+		return false;
+	}
+}
+
+bool tee_supp_param_is_value(struct tee_ioctl_param *param)
+{
+	switch (param->attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) {
+	case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT:
+	case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT:
+	case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT:
+		return true;
+	default:
+		return false;
+	}
+}
+
+void *tee_supp_param_to_va(struct tee_ioctl_param *param)
+{
+	struct tee_shm *tshm;
+	size_t end_offs;
+
+	if (!tee_supp_param_is_memref(param))
+		return NULL;
+
+	end_offs = param->u.memref.size + param->u.memref.shm_offs;
+	if (end_offs < param->u.memref.size ||
+	    end_offs < param->u.memref.shm_offs)
+		return NULL;
+
+	tshm = find_tshm(param->u.memref.shm_id);
+	if (!tshm)
+		return NULL;
+
+	if (end_offs > tshm->size)
+		return NULL;
+
+	return (uint8_t *)tshm->p + param->u.memref.shm_offs;
+}
diff --git a/tee-supplicant/src/tee_supplicant.h b/tee-supplicant/src/tee_supplicant.h
new file mode 100644
index 0000000..a21f0a3
--- /dev/null
+++ b/tee-supplicant/src/tee_supplicant.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2016, Linaro Limited
+ * Copyright (c) 2014, STMicroelectronics International N.V.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef TEE_SUPPLICANT_H
+#define TEE_SUPPLICANT_H
+
+#include <stdbool.h>
+
+struct tee_ioctl_param;
+
+bool tee_supp_param_is_memref(struct tee_ioctl_param *param);
+bool tee_supp_param_is_value(struct tee_ioctl_param *param);
+void *tee_supp_param_to_va(struct tee_ioctl_param *param);
+
+#endif /*TEE_SUPPLICANT_H*/