Home | History | Annotate | Download | only in lib
      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 
     32 static inline file_handle_t make_file_handle(storage_session_t s, uint32_t fid)
     33 {
     34     return ((uint64_t)s << 32) | fid;
     35 }
     36 
     37 static inline storage_session_t _to_session(file_handle_t fh)
     38 {
     39     return (storage_session_t)(fh >> 32);
     40 }
     41 
     42 static inline uint32_t _to_handle(file_handle_t fh)
     43 {
     44     return (uint32_t) fh;
     45 }
     46 
     47 static 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 
     57 static 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 
    104 static 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 
    127 int 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 
    137 void storage_close_session(storage_session_t session)
    138 {
    139     tipc_close(session);
    140 }
    141 
    142 
    143 int 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 
    166 void 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 
    180 int 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 
    191 static 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 
    202 ssize_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 
    225 static 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 
    238 ssize_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 
    268 int 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 
    279 int 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 
    301 int 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