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