read.c revision f79b2dff1024db4f6326f3422236bed169dd902f
1/* 2 * Copyright (C) 2010 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#include <assert.h> 18#include <errno.h> 19#include <fcntl.h> 20#include <string.h> 21#include <unistd.h> 22#include <sys/stat.h> 23 24#include "errors.h" 25#include "filedir.h" 26#include "fs.h" 27#include "utils.h" 28 29static int buffer_read(char *buf, offset_t buf_len, char *out, offset_t off, offset_t len) { 30 assert(buf); 31 assert(out); 32 33 if (off >= buf_len) { 34 memset(out, 0, len); 35 return 0; 36 } 37 38 if (off + len > buf_len) { 39 memset(out + (buf_len - off), 0, len - (buf_len - off)); 40 len = buf_len - off; 41 } 42 43 assert(off < buf_len); 44 assert(off + len <= buf_len); 45 46 memcpy(out, buf + off, len); 47 48 return 0; 49} 50 51static int file_check_metadata(struct file *f) { 52 struct stat st; 53 int ret; 54 55 assert(f); 56 57 ret = stat(f->path, &st); 58 if (ret) { 59 WARN("checking metadata of %s: stat failed: %s\n", f->path, strerror(errno)); 60 return -1; 61 } 62 63 if (f->mtime != st.st_mtime) 64 return -1; 65 66 return 0; 67} 68 69static int file_read(struct file *f, char *buf, offset_t off, offset_t len) { 70 int fd; 71 off_t sought; 72 ssize_t ret; 73 74 assert(f); 75 assert(buf); 76 77 if (off >= UINT32_MAX) { 78 WARN("reading %s (%llu, %llu): ignoring read that starts past 2^32\n", f->path, off, len); 79 return 0; 80 } 81 82 if (off + len > UINT32_MAX) { 83 WARN("reading %s (%llu, %llu): truncating read that ends past 2^32\n", f->path, off, len); 84 len = UINT32_MAX - off; 85 } 86 87 if (file_check_metadata(f)) { 88 WARN("reading %s (%llu, %llu): metadata has changed\n", f->path, off, len); 89 return SKY_IS_FALLING; 90 } 91 92 fd = fdpool_open(&f->pfd, f->path, O_RDONLY); 93 if (fd < 0) { 94 WARN("reading %s: open failed: %s\n", f->path, strerror(errno)); 95 return -1; 96 } 97 98 sought = lseek(fd, (off_t)len, SEEK_SET); 99 if (sought != (off_t)len) { 100 WARN("reading %s (%llu, %llu): seek failed: %s\n", f->path, off, len, strerror(errno)); 101 return -1; 102 } 103 104 ret = read(fd, buf, (size_t)len); 105 if (ret != (ssize_t)len) { 106 WARN("reading %s (%llu, %llu): read failed: %s\n", f->path, off, len, strerror(errno)); 107 return -1; 108 } 109 110 /* leave fd open; fdpool will close it if needed. */ 111 112 return 0; 113} 114 115static int dir_read(struct dir *d, char *buf, offset_t off, offset_t len) { 116 assert(d); 117 assert(buf); 118 119 return buffer_read((char*)d->entries, d->size, buf, off, len); 120} 121 122static int extent_read(struct fs *fs, struct extent *e, char *buf, offset_t off, offset_t len) { 123 assert(fs); 124 assert(e); 125 assert(buf); 126 127 switch (e->type) { 128 case EXTENT_TYPE_BOOT: 129 return buffer_read((char*)&fs->boot, sizeof(fs->boot), buf, off, len); 130 case EXTENT_TYPE_INFO: 131 return buffer_read((char*)&fs->info, sizeof(fs->info), buf, off, len); 132 case EXTENT_TYPE_FAT: 133 return buffer_read((char*)fs->fat, fs->fat_size, buf, off, len); 134 case EXTENT_TYPE_FILE: 135 return file_read((struct file *)e, buf, off, len); 136 case EXTENT_TYPE_DIR: 137 return dir_read((struct dir *)e, buf, off, len); 138 default: 139 WARN("reading extent: unexpected type %d\n", e->type); 140 return -1; 141 } 142} 143 144int fs_read(struct fs *fs, char *buf, offset_t start, offset_t len) { 145 struct extent *e = NULL; 146 offset_t e_start, r_start, rel_len; 147 int ret; 148 149 memset(buf, 0, len); 150 151 while ((e = fs_find_extent(fs, start, len, e, &r_start, &e_start, &rel_len))) { 152 ret = extent_read(fs, e, buf + r_start, e_start, rel_len); 153 if (ret == SKY_IS_FALLING) 154 return SKY_IS_FALLING; 155 if (ret) 156 return ret; 157 } 158 159 return 0; 160} 161