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