Home | History | Annotate | Download | only in proxy
      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 
     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 
     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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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