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 34enum sync_state { 35 SS_UNUSED = -1, 36 SS_CLEAN = 0, 37 SS_DIRTY = 1, 38}; 39 40static int ssdir_fd = -1; 41static const char *ssdir_name; 42 43static enum sync_state fs_state; 44static enum sync_state dir_state; 45static enum sync_state fd_state[FD_TBL_SIZE]; 46 47static struct { 48 struct storage_file_read_resp hdr; 49 uint8_t data[MAX_READ_SIZE]; 50} read_rsp; 51 52static 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 74static 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 86static 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 94static 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 126static 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 142static 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 162int 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 208err_response: 209 if (path) 210 free(path); 211 return ipc_respond(msg, NULL, 0); 212} 213 214 215int 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 292err_response: 293 if (path) 294 free(path); 295 return ipc_respond(msg, NULL, 0); 296} 297 298int 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 333err_response: 334 return ipc_respond(msg, NULL, 0); 335} 336 337 338int 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 363err_response: 364 return ipc_respond(msg, NULL, 0); 365} 366 367 368int 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 (%zd > %zd) - 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 402err_response: 403 return ipc_respond(msg, NULL, 0); 404} 405 406 407int 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 435err_response: 436 return ipc_respond(msg, NULL, 0); 437} 438 439 440int 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 464err_response: 465 return ipc_respond(msg, NULL, 0); 466} 467 468int 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 486int 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