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