• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <errno.h>
17 #include <fcntl.h>
18 #include <inttypes.h>
19 #include <stdbool.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <sys/stat.h>
23 #include <sys/syscall.h>
24 #include <sys/types.h>
25 #include <unistd.h>
26 
27 #include "log.h"
28 #include "ipc.h"
29 #include "storage.h"
30 
31 #define FD_TBL_SIZE 64
32 #define MAX_READ_SIZE 4096
33 
34 enum sync_state {
35     SS_UNUSED = -1,
36     SS_CLEAN =  0,
37     SS_DIRTY =  1,
38 };
39 
40 static int ssdir_fd = -1;
41 static const char *ssdir_name;
42 
43 static enum sync_state fs_state;
44 static enum sync_state dir_state;
45 static enum sync_state fd_state[FD_TBL_SIZE];
46 
47 static struct {
48    struct storage_file_read_resp hdr;
49    uint8_t data[MAX_READ_SIZE];
50 }  read_rsp;
51 
insert_fd(int open_flags,int fd)52 static uint32_t insert_fd(int open_flags, int fd)
53 {
54     uint32_t handle = fd;
55 
56     if (open_flags & O_CREAT) {
57         dir_state = SS_DIRTY;
58     }
59 
60     if (handle < FD_TBL_SIZE) {
61             fd_state[fd] = SS_CLEAN; /* fd clean */
62             if (open_flags & O_TRUNC) {
63                 fd_state[fd] = SS_DIRTY;  /* set fd dirty */
64             }
65     } else {
66             ALOGW("%s: untracked fd %u\n", __func__, fd);
67             if (open_flags & (O_TRUNC | O_CREAT)) {
68                 fs_state = SS_DIRTY;
69             }
70     }
71     return handle;
72 }
73 
lookup_fd(uint32_t handle,bool dirty)74 static int lookup_fd(uint32_t handle, bool dirty)
75 {
76     if (dirty) {
77         if (handle < FD_TBL_SIZE) {
78             fd_state[handle] = SS_DIRTY;
79         } else {
80             fs_state = SS_DIRTY;
81         }
82     }
83     return handle;
84 }
85 
remove_fd(uint32_t handle)86 static int remove_fd(uint32_t handle)
87 {
88     if (handle < FD_TBL_SIZE) {
89         fd_state[handle] = SS_UNUSED; /* set to uninstalled */
90     }
91     return handle;
92 }
93 
translate_errno(int error)94 static enum storage_err translate_errno(int error)
95 {
96     enum storage_err result;
97     switch (error) {
98     case 0:
99         result = STORAGE_NO_ERROR;
100         break;
101     case EBADF:
102     case EINVAL:
103     case ENOTDIR:
104     case EISDIR:
105     case ENAMETOOLONG:
106         result = STORAGE_ERR_NOT_VALID;
107         break;
108     case ENOENT:
109         result = STORAGE_ERR_NOT_FOUND;
110         break;
111     case EEXIST:
112         result = STORAGE_ERR_EXIST;
113         break;
114     case EPERM:
115     case EACCES:
116         result = STORAGE_ERR_ACCESS;
117         break;
118     default:
119         result = STORAGE_ERR_GENERIC;
120         break;
121     }
122 
123     return result;
124 }
125 
write_with_retry(int fd,const void * buf_,size_t size,off_t offset)126 static ssize_t write_with_retry(int fd, const void *buf_, size_t size, off_t offset)
127 {
128     ssize_t rc;
129     const uint8_t *buf = buf_;
130 
131     while (size > 0) {
132         rc = TEMP_FAILURE_RETRY(pwrite(fd, buf, size, offset));
133         if (rc < 0)
134             return rc;
135         size -= rc;
136         buf += rc;
137         offset += rc;
138     }
139     return 0;
140 }
141 
read_with_retry(int fd,void * buf_,size_t size,off_t offset)142 static ssize_t read_with_retry(int fd, void *buf_, size_t size, off_t offset)
143 {
144     ssize_t rc;
145     size_t  rcnt = 0;
146     uint8_t *buf = buf_;
147 
148     while (size > 0) {
149         rc = TEMP_FAILURE_RETRY(pread(fd, buf, size, offset));
150         if (rc < 0)
151             return rc;
152         if (rc == 0)
153             break;
154         size -= rc;
155         buf += rc;
156         offset += rc;
157         rcnt += rc;
158     }
159     return rcnt;
160 }
161 
storage_file_delete(struct storage_msg * msg,const void * r,size_t req_len)162 int storage_file_delete(struct storage_msg *msg,
163                         const void *r, size_t req_len)
164 {
165     char *path = NULL;
166     const struct storage_file_delete_req *req = r;
167 
168     if (req_len < sizeof(*req)) {
169         ALOGE("%s: invalid request length (%zd < %zd)\n",
170               __func__, req_len, sizeof(*req));
171         msg->result = STORAGE_ERR_NOT_VALID;
172         goto err_response;
173     }
174 
175     size_t fname_len = strlen(req->name);
176     if (fname_len != req_len - sizeof(*req)) {
177         ALOGE("%s: invalid filename length (%zd != %zd)\n",
178               __func__, fname_len, req_len - sizeof(*req));
179         msg->result = STORAGE_ERR_NOT_VALID;
180         goto err_response;
181     }
182 
183     int rc = asprintf(&path, "%s/%s", ssdir_name, req->name);
184     if (rc < 0) {
185         ALOGE("%s: asprintf failed\n", __func__);
186         msg->result = STORAGE_ERR_GENERIC;
187         goto err_response;
188     }
189 
190     dir_state = SS_DIRTY;
191     rc = unlink(path);
192     if (rc < 0) {
193         rc = errno;
194         if (errno == ENOENT) {
195             ALOGV("%s: error (%d) unlinking file '%s'\n",
196                   __func__, rc, path);
197         } else {
198             ALOGE("%s: error (%d) unlinking file '%s'\n",
199                   __func__, rc, path);
200         }
201         msg->result = translate_errno(rc);
202         goto err_response;
203     }
204 
205     ALOGV("%s: \"%s\"\n", __func__, path);
206     msg->result = STORAGE_NO_ERROR;
207 
208 err_response:
209     if (path)
210         free(path);
211     return ipc_respond(msg, NULL, 0);
212 }
213 
214 
storage_file_open(struct storage_msg * msg,const void * r,size_t req_len)215 int storage_file_open(struct storage_msg *msg,
216                       const void *r, size_t req_len)
217 {
218     char *path = NULL;
219     const struct storage_file_open_req *req = r;
220     struct storage_file_open_resp resp = {0};
221 
222     if (req_len < sizeof(*req)) {
223         ALOGE("%s: invalid request length (%zd < %zd)\n",
224                __func__, req_len, sizeof(*req));
225         msg->result = STORAGE_ERR_NOT_VALID;
226         goto err_response;
227     }
228 
229     size_t fname_len = strlen(req->name);
230     if (fname_len != req_len - sizeof(*req)) {
231         ALOGE("%s: invalid filename length (%zd != %zd)\n",
232               __func__, fname_len, req_len - sizeof(*req));
233         msg->result = STORAGE_ERR_NOT_VALID;
234         goto err_response;
235     }
236 
237     int rc = asprintf(&path, "%s/%s", ssdir_name, req->name);
238     if (rc < 0) {
239         ALOGE("%s: asprintf failed\n", __func__);
240         msg->result = STORAGE_ERR_GENERIC;
241         goto err_response;
242     }
243 
244     int open_flags = O_RDWR;
245 
246     if (req->flags & STORAGE_FILE_OPEN_TRUNCATE)
247         open_flags |= O_TRUNC;
248 
249     if (req->flags & STORAGE_FILE_OPEN_CREATE) {
250         /* open or create */
251         if (req->flags & STORAGE_FILE_OPEN_CREATE_EXCLUSIVE) {
252             /* create exclusive */
253             open_flags |= O_CREAT | O_EXCL;
254             rc = TEMP_FAILURE_RETRY(open(path, open_flags, S_IRUSR | S_IWUSR));
255         } else {
256             /* try open first */
257             rc = TEMP_FAILURE_RETRY(open(path, open_flags, S_IRUSR | S_IWUSR));
258             if (rc == -1 && errno == ENOENT) {
259                 /* then try open with O_CREATE */
260                 open_flags |= O_CREAT;
261                 rc = TEMP_FAILURE_RETRY(open(path, open_flags, S_IRUSR | S_IWUSR));
262             }
263 
264         }
265     } else {
266         /* open an existing file */
267         rc = TEMP_FAILURE_RETRY(open(path, open_flags, S_IRUSR | S_IWUSR));
268     }
269 
270     if (rc < 0) {
271         rc = errno;
272         if (errno == EEXIST || errno == ENOENT) {
273             ALOGV("%s: failed to open file \"%s\": %s\n",
274                   __func__, path, strerror(errno));
275         } else {
276             ALOGE("%s: failed to open file \"%s\": %s\n",
277                   __func__, path, strerror(errno));
278         }
279         msg->result = translate_errno(rc);
280         goto err_response;
281     }
282     free(path);
283 
284     /* at this point rc contains storage file fd */
285     msg->result = STORAGE_NO_ERROR;
286     resp.handle = insert_fd(open_flags, rc);
287     ALOGV("%s: \"%s\": fd = %u: handle = %d\n",
288           __func__, path, rc, resp.handle);
289 
290     return ipc_respond(msg, &resp, sizeof(resp));
291 
292 err_response:
293     if (path)
294         free(path);
295     return ipc_respond(msg, NULL, 0);
296 }
297 
storage_file_close(struct storage_msg * msg,const void * r,size_t req_len)298 int storage_file_close(struct storage_msg *msg,
299                        const void *r, size_t req_len)
300 {
301     const struct storage_file_close_req *req = r;
302 
303     if (req_len != sizeof(*req)) {
304         ALOGE("%s: invalid request length (%zd != %zd)\n",
305               __func__, req_len, sizeof(*req));
306         msg->result = STORAGE_ERR_NOT_VALID;
307         goto err_response;
308     }
309 
310     int fd = remove_fd(req->handle);
311     ALOGV("%s: handle = %u: fd = %u\n", __func__, req->handle, fd);
312 
313     int rc = fsync(fd);
314     if (rc < 0) {
315         rc = errno;
316         ALOGE("%s: fsync failed for fd=%u: %s\n",
317               __func__, fd, strerror(errno));
318         msg->result = translate_errno(rc);
319         goto err_response;
320     }
321 
322     rc = close(fd);
323     if (rc < 0) {
324         rc = errno;
325         ALOGE("%s: close failed for fd=%u: %s\n",
326               __func__, fd, strerror(errno));
327         msg->result = translate_errno(rc);
328         goto err_response;
329     }
330 
331     msg->result = STORAGE_NO_ERROR;
332 
333 err_response:
334     return ipc_respond(msg, NULL, 0);
335 }
336 
337 
storage_file_write(struct storage_msg * msg,const void * r,size_t req_len)338 int storage_file_write(struct storage_msg *msg,
339                        const void *r, size_t req_len)
340 {
341     int rc;
342     const struct storage_file_write_req *req = r;
343 
344     if (req_len < sizeof(*req)) {
345         ALOGE("%s: invalid request length (%zd < %zd)\n",
346               __func__, req_len, sizeof(*req));
347         msg->result = STORAGE_ERR_NOT_VALID;
348         goto err_response;
349     }
350 
351     int fd = lookup_fd(req->handle, true);
352     if (write_with_retry(fd, &req->data[0], req_len - sizeof(*req),
353                          req->offset) < 0) {
354         rc = errno;
355         ALOGW("%s: error writing file (fd=%d): %s\n",
356               __func__, fd, strerror(errno));
357         msg->result = translate_errno(rc);
358         goto err_response;
359     }
360 
361     msg->result = STORAGE_NO_ERROR;
362 
363 err_response:
364     return ipc_respond(msg, NULL, 0);
365 }
366 
367 
storage_file_read(struct storage_msg * msg,const void * r,size_t req_len)368 int storage_file_read(struct storage_msg *msg,
369                       const void *r, size_t req_len)
370 {
371     int rc;
372     const struct storage_file_read_req *req = r;
373 
374     if (req_len != sizeof(*req)) {
375         ALOGE("%s: invalid request length (%zd != %zd)\n",
376               __func__, req_len, sizeof(*req));
377         msg->result = STORAGE_ERR_NOT_VALID;
378         goto err_response;
379     }
380 
381     if (req->size > MAX_READ_SIZE) {
382         ALOGW("%s: request is too large (%u > %d) - refusing\n",
383               __func__, req->size, MAX_READ_SIZE);
384         msg->result = STORAGE_ERR_NOT_VALID;
385         goto err_response;
386     }
387 
388     int fd = lookup_fd(req->handle, false);
389     ssize_t read_res = read_with_retry(fd, read_rsp.hdr.data, req->size,
390                                        (off_t)req->offset);
391     if (read_res < 0) {
392         rc = errno;
393         ALOGW("%s: error reading file (fd=%d): %s\n",
394               __func__, fd, strerror(errno));
395         msg->result = translate_errno(rc);
396         goto err_response;
397     }
398 
399     msg->result = STORAGE_NO_ERROR;
400     return ipc_respond(msg, &read_rsp, read_res + sizeof(read_rsp.hdr));
401 
402 err_response:
403     return ipc_respond(msg, NULL, 0);
404 }
405 
406 
storage_file_get_size(struct storage_msg * msg,const void * r,size_t req_len)407 int storage_file_get_size(struct storage_msg *msg,
408                           const void *r, size_t req_len)
409 {
410     const struct storage_file_get_size_req *req = r;
411     struct storage_file_get_size_resp resp = {0};
412 
413     if (req_len != sizeof(*req)) {
414         ALOGE("%s: invalid request length (%zd != %zd)\n",
415               __func__, req_len, sizeof(*req));
416         msg->result = STORAGE_ERR_NOT_VALID;
417         goto err_response;
418     }
419 
420     struct stat stat;
421     int fd = lookup_fd(req->handle, false);
422     int rc = fstat(fd, &stat);
423     if (rc < 0) {
424         rc = errno;
425         ALOGE("%s: error stat'ing file (fd=%d): %s\n",
426               __func__, fd, strerror(errno));
427         msg->result = translate_errno(rc);
428         goto err_response;
429     }
430 
431     resp.size = stat.st_size;
432     msg->result = STORAGE_NO_ERROR;
433     return ipc_respond(msg, &resp, sizeof(resp));
434 
435 err_response:
436     return ipc_respond(msg, NULL, 0);
437 }
438 
439 
storage_file_set_size(struct storage_msg * msg,const void * r,size_t req_len)440 int storage_file_set_size(struct storage_msg *msg,
441                           const void *r, size_t req_len)
442 {
443     const struct storage_file_set_size_req *req = r;
444 
445     if (req_len != sizeof(*req)) {
446         ALOGE("%s: invalid request length (%zd != %zd)\n",
447               __func__, req_len, sizeof(*req));
448         msg->result = STORAGE_ERR_NOT_VALID;
449         goto err_response;
450     }
451 
452     int fd = lookup_fd(req->handle, true);
453     int rc = TEMP_FAILURE_RETRY(ftruncate(fd, req->size));
454     if (rc < 0) {
455         rc = errno;
456         ALOGE("%s: error truncating file (fd=%d): %s\n",
457               __func__, fd, strerror(errno));
458         msg->result = translate_errno(rc);
459         goto err_response;
460     }
461 
462     msg->result = STORAGE_NO_ERROR;
463 
464 err_response:
465     return ipc_respond(msg, NULL, 0);
466 }
467 
storage_init(const char * dirname)468 int storage_init(const char *dirname)
469 {
470     fs_state = SS_CLEAN;
471     dir_state = SS_CLEAN;
472     for (uint i = 0; i < FD_TBL_SIZE; i++) {
473         fd_state[i] = SS_UNUSED;  /* uninstalled */
474     }
475 
476     ssdir_fd = open(dirname, O_RDONLY);
477     if (ssdir_fd < 0) {
478         ALOGE("failed to open ss root dir \"%s\": %s\n",
479                dirname, strerror(errno));
480         return -1;
481     }
482     ssdir_name = dirname;
483     return 0;
484 }
485 
storage_sync_checkpoint(void)486 int storage_sync_checkpoint(void)
487 {
488     int rc;
489 
490     /* sync fd table and reset it to clean state first */
491     for (uint fd = 0; fd < FD_TBL_SIZE; fd++) {
492          if (fd_state[fd] == SS_DIRTY) {
493              if (fs_state == SS_CLEAN) {
494                  /* need to sync individual fd */
495                  rc = fsync(fd);
496                  if (rc < 0) {
497                      ALOGE("fsync for fd=%d failed: %s\n", fd, strerror(errno));
498                      return rc;
499                  }
500              }
501              fd_state[fd] = SS_CLEAN; /* set to clean */
502          }
503     }
504 
505     /* check if we need to sync the directory */
506     if (dir_state == SS_DIRTY) {
507         if (fs_state == SS_CLEAN) {
508             rc = fsync(ssdir_fd);
509             if (rc < 0) {
510                 ALOGE("fsync for ssdir failed: %s\n", strerror(errno));
511                 return rc;
512             }
513         }
514         dir_state = SS_CLEAN;  /* set to clean */
515     }
516 
517     /* check if we need to sync the whole fs */
518     if (fs_state == SS_DIRTY) {
519         rc = syscall(SYS_syncfs, ssdir_fd);
520         if (rc < 0) {
521             ALOGE("syncfs failed: %s\n", strerror(errno));
522             return rc;
523         }
524         fs_state = SS_CLEAN;
525     }
526 
527     return 0;
528 }
529 
530