• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
buffer_read(char * buf,offset_t buf_len,char * out,offset_t off,offset_t len)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 
file_check_metadata(struct file * f)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 
file_read(struct file * f,char * buf,offset_t off,offset_t len)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 
dir_read(struct dir * d,char * buf,offset_t off,offset_t len)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 
extent_read(struct fs * fs,struct extent * e,char * buf,offset_t off,offset_t len)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 
fs_read(struct fs * fs,char * buf,offset_t start,offset_t len)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