storage.c revision 30f991f251940be3ed11566fb71139852286f68a
1/* 2 * Copyright (C) 2016 The Android Open Source Project 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 17#define LOG_TAG "trusty_storage_client" 18 19#include <errno.h> 20#include <stdarg.h> 21#include <stdbool.h> 22#include <stdint.h> 23#include <string.h> 24#include <sys/uio.h> 25 26#include <log/log.h> 27#include <trusty/tipc.h> 28#include <trusty/lib/storage.h> 29 30#define MAX_CHUNK_SIZE 4040 31 32static inline file_handle_t make_file_handle(storage_session_t s, uint32_t fid) 33{ 34 return ((uint64_t)s << 32) | fid; 35} 36 37static inline storage_session_t _to_session(file_handle_t fh) 38{ 39 return (storage_session_t)(fh >> 32); 40} 41 42static inline uint32_t _to_handle(file_handle_t fh) 43{ 44 return (uint32_t) fh; 45} 46 47static inline uint32_t _to_msg_flags(uint32_t opflags) 48{ 49 uint32_t msg_flags = 0; 50 51 if (opflags & STORAGE_OP_COMPLETE) 52 msg_flags |= STORAGE_MSG_FLAG_TRANSACT_COMPLETE; 53 54 return msg_flags; 55} 56 57static ssize_t check_response(struct storage_msg *msg, ssize_t res) 58{ 59 if (res < 0) 60 return res; 61 62 if ((size_t)res < sizeof(*msg)) { 63 ALOGE("invalid msg length (%zd < %zd)\n", res, sizeof(*msg)); 64 return -EIO; 65 } 66 67 ALOGV("cmd 0x%x: server returned %u\n", msg->cmd, msg->result); 68 69 switch(msg->result) { 70 case STORAGE_NO_ERROR: 71 return res - sizeof(*msg); 72 73 case STORAGE_ERR_NOT_FOUND: 74 return -ENOENT; 75 76 case STORAGE_ERR_EXIST: 77 return -EEXIST; 78 79 case STORAGE_ERR_NOT_VALID: 80 return -EINVAL; 81 82 case STORAGE_ERR_UNIMPLEMENTED: 83 ALOGE("cmd 0x%x: is unhandles command\n", msg->cmd); 84 return -EINVAL; 85 86 case STORAGE_ERR_ACCESS: 87 return -EACCES; 88 89 case STORAGE_ERR_TRANSACT: 90 return -EBUSY; 91 92 case STORAGE_ERR_GENERIC: 93 ALOGE("cmd 0x%x: internal server error\n", msg->cmd); 94 return -EIO; 95 96 default: 97 ALOGE("cmd 0x%x: unhandled server response %u\n", 98 msg->cmd, msg->result); 99 } 100 101 return -EIO; 102} 103 104static ssize_t send_reqv(storage_session_t session, 105 const struct iovec *tx_iovs, uint tx_iovcnt, 106 const struct iovec *rx_iovs, uint rx_iovcnt) 107{ 108 ssize_t rc; 109 110 rc = writev(session, tx_iovs, tx_iovcnt); 111 if (rc < 0) { 112 rc = -errno; 113 ALOGE("failed to send request: %s\n", strerror(errno)); 114 return rc; 115 } 116 117 rc = readv(session, rx_iovs, rx_iovcnt); 118 if (rc < 0) { 119 rc = -errno; 120 ALOGE("failed to recv response: %s\n", strerror(errno)); 121 return rc; 122 } 123 124 return rc; 125} 126 127int storage_open_session(const char *device, storage_session_t *session_p, 128 const char *port) 129{ 130 int rc = tipc_connect(device, port); 131 if (rc < 0) 132 return rc; 133 *session_p = (storage_session_t) rc; 134 return 0; 135} 136 137void storage_close_session(storage_session_t session) 138{ 139 tipc_close(session); 140} 141 142 143int storage_open_file(storage_session_t session, file_handle_t *handle_p, const char *name, 144 uint32_t flags, uint32_t opflags) 145{ 146 struct storage_msg msg = { .cmd = STORAGE_FILE_OPEN, .flags = _to_msg_flags(opflags)}; 147 struct storage_file_open_req req = { .flags = flags }; 148 struct iovec tx[3] = {{&msg, sizeof(msg)}, {&req, sizeof(req)}, {(void *)name, strlen(name)}}; 149 struct storage_file_open_resp rsp = { 0 }; 150 struct iovec rx[2] = {{&msg, sizeof(msg)}, {&rsp, sizeof(rsp)}}; 151 152 ssize_t rc = send_reqv(session, tx, 3, rx, 2); 153 rc = check_response(&msg, rc); 154 if (rc < 0) 155 return rc; 156 157 if ((size_t)rc != sizeof(rsp)) { 158 ALOGE("%s: invalid response length (%zd != %zd)\n", __func__, rc, sizeof(rsp)); 159 return -EIO; 160 } 161 162 *handle_p = make_file_handle(session, rsp.handle); 163 return 0; 164} 165 166void storage_close_file(file_handle_t fh) 167{ 168 struct storage_msg msg = { .cmd = STORAGE_FILE_CLOSE }; 169 struct storage_file_close_req req = { .handle = _to_handle(fh)}; 170 struct iovec tx[2] = {{&msg, sizeof(msg)}, {&req, sizeof(req)}}; 171 struct iovec rx[1] = {{&msg, sizeof(msg)}}; 172 173 ssize_t rc = send_reqv(_to_session(fh), tx, 2, rx, 1); 174 rc = check_response(&msg, rc); 175 if (rc < 0) { 176 ALOGE("close file failed (%d)\n", (int)rc); 177 } 178} 179 180int storage_delete_file(storage_session_t session, const char *name, uint32_t opflags) 181{ 182 struct storage_msg msg = { .cmd = STORAGE_FILE_DELETE, .flags = _to_msg_flags(opflags)}; 183 struct storage_file_delete_req req = { .flags = 0, }; 184 struct iovec tx[3] = {{&msg, sizeof(msg)}, {&req, sizeof(req)}, {(void *)name, strlen(name)}}; 185 struct iovec rx[1] = {{&msg, sizeof(msg)}}; 186 187 ssize_t rc = send_reqv(session, tx, 3, rx, 1); 188 return check_response(&msg, rc); 189} 190 191static int _read_chunk(file_handle_t fh, storage_off_t off, void *buf, size_t size) 192{ 193 struct storage_msg msg = { .cmd = STORAGE_FILE_READ }; 194 struct storage_file_read_req req = { .handle = _to_handle(fh), .size = size, .offset = off }; 195 struct iovec tx[2] = {{&msg, sizeof(msg)}, {&req, sizeof(req)}}; 196 struct iovec rx[2] = {{&msg, sizeof(msg)}, {buf, size}}; 197 198 ssize_t rc = send_reqv(_to_session(fh), tx, 2, rx, 2); 199 return check_response(&msg, rc); 200} 201 202ssize_t storage_read(file_handle_t fh, storage_off_t off, void *buf, size_t size) 203{ 204 int rc; 205 size_t bytes_read = 0; 206 size_t chunk = MAX_CHUNK_SIZE; 207 uint8_t *ptr = buf; 208 209 while (size) { 210 if (chunk > size) 211 chunk = size; 212 rc = _read_chunk(fh, off, ptr, chunk); 213 if (rc < 0) 214 return rc; 215 if (rc == 0) 216 break; 217 off += rc; 218 ptr += rc; 219 bytes_read += rc; 220 size -= rc; 221 } 222 return bytes_read; 223} 224 225static int _write_req(file_handle_t fh, storage_off_t off, 226 const void *buf, size_t size, uint32_t msg_flags) 227{ 228 struct storage_msg msg = { .cmd = STORAGE_FILE_WRITE, .flags = msg_flags, }; 229 struct storage_file_write_req req = { .handle = _to_handle(fh), .offset = off, }; 230 struct iovec tx[3] = {{&msg, sizeof(msg)}, {&req, sizeof(req)}, {(void *)buf, size}}; 231 struct iovec rx[1] = {{&msg, sizeof(msg)}}; 232 233 ssize_t rc = send_reqv(_to_session(fh), tx, 3, rx, 1); 234 rc = check_response(&msg, rc); 235 return rc < 0 ? rc : size; 236} 237 238ssize_t storage_write(file_handle_t fh, storage_off_t off, 239 const void *buf, size_t size, uint32_t opflags) 240{ 241 int rc; 242 size_t bytes_written = 0; 243 size_t chunk = MAX_CHUNK_SIZE; 244 const uint8_t *ptr = buf; 245 uint32_t msg_flags = _to_msg_flags(opflags & ~STORAGE_OP_COMPLETE); 246 247 while (size) { 248 if (chunk >= size) { 249 /* last chunk in sequence */ 250 chunk = size; 251 msg_flags = _to_msg_flags(opflags); 252 } 253 rc = _write_req(fh, off, ptr, chunk, msg_flags); 254 if (rc < 0) 255 return rc; 256 if ((size_t)rc != chunk) { 257 ALOGE("got partial write (%d)\n", (int)rc); 258 return -EIO; 259 } 260 off += chunk; 261 ptr += chunk; 262 bytes_written += chunk; 263 size -= chunk; 264 } 265 return bytes_written; 266} 267 268int storage_set_file_size(file_handle_t fh, storage_off_t file_size, uint32_t opflags) 269{ 270 struct storage_msg msg = { .cmd = STORAGE_FILE_SET_SIZE, .flags = _to_msg_flags(opflags)}; 271 struct storage_file_set_size_req req = { .handle = _to_handle(fh), .size = file_size, }; 272 struct iovec tx[2] = {{&msg, sizeof(msg)}, {&req, sizeof(req)}}; 273 struct iovec rx[1] = {{&msg, sizeof(msg)}}; 274 275 ssize_t rc = send_reqv(_to_session(fh), tx, 2, rx, 1); 276 return check_response(&msg, rc); 277} 278 279int storage_get_file_size(file_handle_t fh, storage_off_t *size_p) 280{ 281 struct storage_msg msg = { .cmd = STORAGE_FILE_GET_SIZE }; 282 struct storage_file_get_size_req req = { .handle = _to_handle(fh), }; 283 struct iovec tx[2] = {{&msg, sizeof(msg)}, {&req, sizeof(req)}}; 284 struct storage_file_get_size_resp rsp; 285 struct iovec rx[2] = {{&msg, sizeof(msg)}, {&rsp, sizeof(rsp)}}; 286 287 ssize_t rc = send_reqv(_to_session(fh), tx, 2, rx, 2); 288 rc = check_response(&msg, rc); 289 if (rc < 0) 290 return rc; 291 292 if ((size_t)rc != sizeof(rsp)) { 293 ALOGE("%s: invalid response length (%zd != %zd)\n", __func__, rc, sizeof(rsp)); 294 return -EIO; 295 } 296 297 *size_p = rsp.size; 298 return 0; 299} 300 301int storage_end_transaction(storage_session_t session, bool complete) 302{ 303 struct storage_msg msg = { 304 .cmd = STORAGE_END_TRANSACTION, 305 .flags = complete ? STORAGE_MSG_FLAG_TRANSACT_COMPLETE : 0, 306 }; 307 struct iovec iov = {&msg, sizeof(msg)}; 308 309 ssize_t rc = send_reqv(session, &iov, 1, &iov, 1); 310 return check_response(&msg, rc); 311} 312