diff options
| author | Michael Ryleev <gmar@google.com> | 2016-03-23 16:25:05 -0700 |
|---|---|---|
| committer | Michael Ryleev <gmar@google.com> | 2016-05-18 13:31:36 -0700 |
| commit | abebb89359d7388fee8d1ca1411e2ae435dd3210 (patch) | |
| tree | ee60961e117dd2620a234a32479fb3cf83afecc6 /trusty | |
| parent | 0321476fe2aedf9a0b960508b52681ee5f1d555e (diff) | |
| download | system_core-abebb89359d7388fee8d1ca1411e2ae435dd3210.tar.gz system_core-abebb89359d7388fee8d1ca1411e2ae435dd3210.tar.bz2 system_core-abebb89359d7388fee8d1ca1411e2ae435dd3210.zip | |
trusty: storage: add client lib for testing
Change-Id: I593aeed5f657b5de1fce47264ae31aa6e79f2a63
Diffstat (limited to 'trusty')
| -rw-r--r-- | trusty/storage/lib/Android.mk | 37 | ||||
| -rw-r--r-- | trusty/storage/lib/include/trusty/lib/storage.h | 154 | ||||
| -rw-r--r-- | trusty/storage/lib/storage.c | 311 |
3 files changed, 502 insertions, 0 deletions
diff --git a/trusty/storage/lib/Android.mk b/trusty/storage/lib/Android.mk new file mode 100644 index 000000000..7e0fc9da4 --- /dev/null +++ b/trusty/storage/lib/Android.mk @@ -0,0 +1,37 @@ +# +# Copyright (C) 2015 The Android Open-Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := libtrustystorage + +LOCAL_SRC_FILES := \ + storage.c \ + +LOCAL_CLFAGS = -fvisibility=hidden -Wall -Werror + +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include +LOCAL_C_INCLUDES := $(LOCAL_PATH)/include + +LOCAL_STATIC_LIBRARIES := \ + liblog \ + libtrusty \ + libtrustystorageinterface + +include $(BUILD_STATIC_LIBRARY) + diff --git a/trusty/storage/lib/include/trusty/lib/storage.h b/trusty/storage/lib/include/trusty/lib/storage.h new file mode 100644 index 000000000..b8ddf67d8 --- /dev/null +++ b/trusty/storage/lib/include/trusty/lib/storage.h @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <stdint.h> +#include <trusty/interface/storage.h> + +#define STORAGE_MAX_NAME_LENGTH_BYTES 159 + +__BEGIN_DECLS + +typedef uint32_t storage_session_t; +typedef uint64_t file_handle_t; +typedef uint64_t storage_off_t; + +#define STORAGE_INVALID_SESSION ((storage_session_t)-1) + +/** + * storage_ops_flags - storage related operation flags + * @STORAGE_OP_COMPLETE: forces to commit current transaction + */ +enum storage_ops_flags { + STORAGE_OP_COMPLETE = 0x1, +}; + +/** + * storage_open_session() - Opens a storage session. + * @device: device node for talking with Trusty + * @session_p: pointer to location in which to store session handle + * in case of success. + * + * Return: 0 on success, or an error code < 0 on failure. + */ +int storage_open_session(const char *device, storage_session_t *session_p, const char *port); + +/** + * storage_close_session() - Closes the session. + * @session: the session to close + */ +void storage_close_session(storage_session_t session); + +/** + * storage_open_file() - Opens a file + * @session: the storage_session_t returned from a call to storage_open_session + * @handle_p: pointer to location in which to store file handle in case of success + * @name: a null-terminated string identifier of the file to open. + * Cannot be more than STORAGE_MAX_NAME_LENGTH_BYTES in length. + * @flags: A bitmask consisting any storage_file_flag value or'ed together: + * - STORAGE_FILE_OPEN_CREATE: if this file does not exist, create it. + * - STORAGE_FILE_OPEN_CREATE_EXCLUSIVE: when specified, opening file with + * STORAGE_OPEN_FILE_CREATE flag will + * fail if the file already exists. + * Only meaningful if used in combination + * with STORAGE_FILE_OPEN_CREATE flag. + * - STORAGE_FILE_OPEN_TRUNCATE: if this file already exists, discard existing + * content and open it as a new file. No change + * in semantics if the file does not exist. + * @opflags: a combination of @storage_op_flags + * + * Return: 0 on success, or an error code < 0 on failure. + */ +int storage_open_file(storage_session_t session, file_handle_t *handle_p, + const char *name, uint32_t flags, uint32_t opflags); + +/** + * storage_close_file() - Closes a file. + * @handle: the file_handle_t retrieved from storage_open_file + */ +void storage_close_file(file_handle_t handle); + +/** + * storage_delete_file - Deletes a file. + * @session: the storage_session_t returned from a call to storage_open_session + * @name: the name of the file to delete + * @opflags: a combination of @storage_op_flags + * + * Return: 0 on success, or an error code < 0 on failure. + */ +int storage_delete_file(storage_session_t session, const char *name, + uint32_t opflags); + +/** + * storage_read() - Reads a file at a given offset. + * @handle: the file_handle_t retrieved from storage_open_file + * @off: the start offset from whence to read in the file + * @buf: the buffer in which to write the data read + * @size: the size of buf and number of bytes to read + * + * Return: the number of bytes read on success, negative error code on failure + */ +ssize_t storage_read(file_handle_t handle, + storage_off_t off, void *buf, size_t size); + +/** + * storage_write() - Writes to a file at a given offset. Grows the file if necessary. + * @handle: the file_handle_t retrieved from storage_open_file + * @off: the start offset from whence to write in the file + * @buf: the buffer containing the data to write + * @size: the size of buf and number of bytes to write + * @opflags: a combination of @storage_op_flags + * + * Return: the number of bytes written on success, negative error code on failure + */ +ssize_t storage_write(file_handle_t handle, + storage_off_t off, const void *buf, size_t size, + uint32_t opflags); + +/** + * storage_set_file_size() - Sets the size of the file. + * @handle: the file_handle_t retrieved from storage_open_file + * @off: the number of bytes to set as the new size of the file + * @opflags: a combination of @storage_op_flags + * + * Return: 0 on success, negative error code on failure. + */ +int storage_set_file_size(file_handle_t handle, storage_off_t file_size, + uint32_t opflags); + +/** + * storage_get_file_size() - Gets the size of the file. + * @session: the storage_session_t returned from a call to storage_open_session + * @handle: the file_handle_t retrieved from storage_open_file + * @size: pointer to storage_off_t in which to store the file size + * + * Return: 0 on success, negative error code on failure. + */ +int storage_get_file_size(file_handle_t handle, storage_off_t *size); + + +/** + * storage_end_transaction: End current transaction + * @session: the storage_session_t returned from a call to storage_open_session + * @complete: if true, commit current transaction, discard it otherwise + * + * Return: 0 on success, negative error code on failure. + */ +int storage_end_transaction(storage_session_t session, bool complete); + + +__END_DECLS diff --git a/trusty/storage/lib/storage.c b/trusty/storage/lib/storage.c new file mode 100644 index 000000000..8130f769a --- /dev/null +++ b/trusty/storage/lib/storage.c @@ -0,0 +1,311 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <errno.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdint.h> +#include <string.h> +#include <sys/uio.h> + +#include <trusty/tipc.h> +#include <trusty/lib/storage.h> + +#define LOG_TAG "trusty_storage_client" +#include <cutils/log.h> + +#define MAX_CHUNK_SIZE 4040 + +static inline file_handle_t make_file_handle(storage_session_t s, uint32_t fid) +{ + return ((uint64_t)s << 32) | fid; +} + +static inline storage_session_t _to_session(file_handle_t fh) +{ + return (storage_session_t)(fh >> 32); +} + +static inline uint32_t _to_handle(file_handle_t fh) +{ + return (uint32_t) fh; +} + +static inline uint32_t _to_msg_flags(uint32_t opflags) +{ + uint32_t msg_flags = 0; + + if (opflags & STORAGE_OP_COMPLETE) + msg_flags |= STORAGE_MSG_FLAG_TRANSACT_COMPLETE; + + return msg_flags; +} + +static ssize_t check_response(struct storage_msg *msg, ssize_t res) +{ + if (res < 0) + return res; + + if ((size_t)res < sizeof(*msg)) { + ALOGE("invalid msg length (%zd < %zd)\n", res, sizeof(*msg)); + return -EIO; + } + + ALOGV("cmd 0x%x: server returned %u\n", msg->cmd, msg->result); + + switch(msg->result) { + case STORAGE_NO_ERROR: + return res - sizeof(*msg); + + case STORAGE_ERR_NOT_FOUND: + return -ENOENT; + + case STORAGE_ERR_EXIST: + return -EEXIST; + + case STORAGE_ERR_NOT_VALID: + return -EINVAL; + + case STORAGE_ERR_UNIMPLEMENTED: + ALOGE("cmd 0x%x: is unhandles command\n", msg->cmd); + return -EINVAL; + + case STORAGE_ERR_ACCESS: + return -EACCES; + + case STORAGE_ERR_TRANSACT: + return -EBUSY; + + case STORAGE_ERR_GENERIC: + ALOGE("cmd 0x%x: internal server error\n", msg->cmd); + return -EIO; + + default: + ALOGE("cmd 0x%x: unhandled server response %u\n", + msg->cmd, msg->result); + } + + return -EIO; +} + +static ssize_t send_reqv(storage_session_t session, + const struct iovec *tx_iovs, uint tx_iovcnt, + const struct iovec *rx_iovs, uint rx_iovcnt) +{ + ssize_t rc; + + rc = writev(session, tx_iovs, tx_iovcnt); + if (rc < 0) { + rc = -errno; + ALOGE("failed to send request: %s\n", strerror(errno)); + return rc; + } + + rc = readv(session, rx_iovs, rx_iovcnt); + if (rc < 0) { + rc = -errno; + ALOGE("failed to recv response: %s\n", strerror(errno)); + return rc; + } + + return rc; +} + +int storage_open_session(const char *device, storage_session_t *session_p, + const char *port) +{ + int rc = tipc_connect(device, port); + if (rc < 0) + return rc; + *session_p = (storage_session_t) rc; + return 0; +} + +void storage_close_session(storage_session_t session) +{ + tipc_close(session); +} + + +int storage_open_file(storage_session_t session, file_handle_t *handle_p, const char *name, + uint32_t flags, uint32_t opflags) +{ + struct storage_msg msg = { .cmd = STORAGE_FILE_OPEN, .flags = _to_msg_flags(opflags)}; + struct storage_file_open_req req = { .flags = flags }; + struct iovec tx[3] = {{&msg, sizeof(msg)}, {&req, sizeof(req)}, {(void *)name, strlen(name)}}; + struct storage_file_open_resp rsp = { 0 }; + struct iovec rx[2] = {{&msg, sizeof(msg)}, {&rsp, sizeof(rsp)}}; + + ssize_t rc = send_reqv(session, tx, 3, rx, 2); + rc = check_response(&msg, rc); + if (rc < 0) + return rc; + + if ((size_t)rc != sizeof(rsp)) { + ALOGE("%s: invalid response length (%zd != %zd)\n", __func__, rc, sizeof(rsp)); + return -EIO; + } + + *handle_p = make_file_handle(session, rsp.handle); + return 0; +} + +void storage_close_file(file_handle_t fh) +{ + struct storage_msg msg = { .cmd = STORAGE_FILE_CLOSE }; + struct storage_file_close_req req = { .handle = _to_handle(fh)}; + struct iovec tx[2] = {{&msg, sizeof(msg)}, {&req, sizeof(req)}}; + struct iovec rx[1] = {{&msg, sizeof(msg)}}; + + ssize_t rc = send_reqv(_to_session(fh), tx, 2, rx, 1); + rc = check_response(&msg, rc); + if (rc < 0) { + ALOGE("close file failed (%d)\n", (int)rc); + } +} + +int storage_delete_file(storage_session_t session, const char *name, uint32_t opflags) +{ + struct storage_msg msg = { .cmd = STORAGE_FILE_DELETE, .flags = _to_msg_flags(opflags)}; + struct storage_file_delete_req req = { .flags = 0, }; + struct iovec tx[3] = {{&msg, sizeof(msg)}, {&req, sizeof(req)}, {(void *)name, strlen(name)}}; + struct iovec rx[1] = {{&msg, sizeof(msg)}}; + + ssize_t rc = send_reqv(session, tx, 3, rx, 1); + return check_response(&msg, rc); +} + +static int _read_chunk(file_handle_t fh, storage_off_t off, void *buf, size_t size) +{ + struct storage_msg msg = { .cmd = STORAGE_FILE_READ }; + struct storage_file_read_req req = { .handle = _to_handle(fh), .size = size, .offset = off }; + struct iovec tx[2] = {{&msg, sizeof(msg)}, {&req, sizeof(req)}}; + struct iovec rx[2] = {{&msg, sizeof(msg)}, {buf, size}}; + + ssize_t rc = send_reqv(_to_session(fh), tx, 2, rx, 2); + return check_response(&msg, rc); +} + +ssize_t storage_read(file_handle_t fh, storage_off_t off, void *buf, size_t size) +{ + int rc; + size_t bytes_read = 0; + size_t chunk = MAX_CHUNK_SIZE; + uint8_t *ptr = buf; + + while (size) { + if (chunk > size) + chunk = size; + rc = _read_chunk(fh, off, ptr, chunk); + if (rc < 0) + return rc; + if (rc == 0) + break; + off += rc; + ptr += rc; + bytes_read += rc; + size -= rc; + } + return bytes_read; +} + +static int _write_req(file_handle_t fh, storage_off_t off, + const void *buf, size_t size, uint32_t msg_flags) +{ + struct storage_msg msg = { .cmd = STORAGE_FILE_WRITE, .flags = msg_flags, }; + struct storage_file_write_req req = { .handle = _to_handle(fh), .offset = off, }; + struct iovec tx[3] = {{&msg, sizeof(msg)}, {&req, sizeof(req)}, {(void *)buf, size}}; + struct iovec rx[1] = {{&msg, sizeof(msg)}}; + + ssize_t rc = send_reqv(_to_session(fh), tx, 3, rx, 1); + rc = check_response(&msg, rc); + return rc < 0 ? rc : size; +} + +ssize_t storage_write(file_handle_t fh, storage_off_t off, + const void *buf, size_t size, uint32_t opflags) +{ + int rc; + size_t bytes_written = 0; + size_t chunk = MAX_CHUNK_SIZE; + const uint8_t *ptr = buf; + uint32_t msg_flags = _to_msg_flags(opflags & ~STORAGE_OP_COMPLETE); + + while (size) { + if (chunk >= size) { + /* last chunk in sequence */ + chunk = size; + msg_flags = _to_msg_flags(opflags); + } + rc = _write_req(fh, off, ptr, chunk, msg_flags); + if (rc < 0) + return rc; + if ((size_t)rc != chunk) { + ALOGE("got partial write (%d)\n", (int)rc); + return -EIO; + } + off += chunk; + ptr += chunk; + bytes_written += chunk; + size -= chunk; + } + return bytes_written; +} + +int storage_set_file_size(file_handle_t fh, storage_off_t file_size, uint32_t opflags) +{ + struct storage_msg msg = { .cmd = STORAGE_FILE_SET_SIZE, .flags = _to_msg_flags(opflags)}; + struct storage_file_set_size_req req = { .handle = _to_handle(fh), .size = file_size, }; + struct iovec tx[2] = {{&msg, sizeof(msg)}, {&req, sizeof(req)}}; + struct iovec rx[1] = {{&msg, sizeof(msg)}}; + + ssize_t rc = send_reqv(_to_session(fh), tx, 2, rx, 1); + return check_response(&msg, rc); +} + +int storage_get_file_size(file_handle_t fh, storage_off_t *size_p) +{ + struct storage_msg msg = { .cmd = STORAGE_FILE_GET_SIZE }; + struct storage_file_get_size_req req = { .handle = _to_handle(fh), }; + struct iovec tx[2] = {{&msg, sizeof(msg)}, {&req, sizeof(req)}}; + struct storage_file_get_size_resp rsp; + struct iovec rx[2] = {{&msg, sizeof(msg)}, {&rsp, sizeof(rsp)}}; + + ssize_t rc = send_reqv(_to_session(fh), tx, 2, rx, 2); + rc = check_response(&msg, rc); + if (rc < 0) + return rc; + + if ((size_t)rc != sizeof(rsp)) { + ALOGE("%s: invalid response length (%zd != %zd)\n", __func__, rc, sizeof(rsp)); + return -EIO; + } + + *size_p = rsp.size; + return 0; +} + +int storage_end_transaction(storage_session_t session, bool complete) +{ + struct storage_msg msg = { + .cmd = STORAGE_END_TRANSACTION, + .flags = complete ? STORAGE_MSG_FLAG_TRANSACT_COMPLETE : 0, + }; + struct iovec iov = {&msg, sizeof(msg)}; + + ssize_t rc = send_reqv(session, &iov, 1, &iov, 1); + return check_response(&msg, rc); +} |
