Root/
1 | /* RomFS storage access routines |
2 | * |
3 | * Copyright © 2007 Red Hat, Inc. All Rights Reserved. |
4 | * Written by David Howells (dhowells@redhat.com) |
5 | * |
6 | * This program is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU General Public License |
8 | * as published by the Free Software Foundation; either version |
9 | * 2 of the License, or (at your option) any later version. |
10 | */ |
11 | |
12 | #include <linux/fs.h> |
13 | #include <linux/mtd/super.h> |
14 | #include <linux/buffer_head.h> |
15 | #include "internal.h" |
16 | |
17 | #if !defined(CONFIG_ROMFS_ON_MTD) && !defined(CONFIG_ROMFS_ON_BLOCK) |
18 | #error no ROMFS backing store interface configured |
19 | #endif |
20 | |
21 | #ifdef CONFIG_ROMFS_ON_MTD |
22 | #define ROMFS_MTD_READ(sb, ...) ((sb)->s_mtd->read((sb)->s_mtd, ##__VA_ARGS__)) |
23 | |
24 | /* |
25 | * read data from an romfs image on an MTD device |
26 | */ |
27 | static int romfs_mtd_read(struct super_block *sb, unsigned long pos, |
28 | void *buf, size_t buflen) |
29 | { |
30 | size_t rlen; |
31 | int ret; |
32 | |
33 | ret = ROMFS_MTD_READ(sb, pos, buflen, &rlen, buf); |
34 | return (ret < 0 || rlen != buflen) ? -EIO : 0; |
35 | } |
36 | |
37 | /* |
38 | * determine the length of a string in a romfs image on an MTD device |
39 | */ |
40 | static ssize_t romfs_mtd_strnlen(struct super_block *sb, |
41 | unsigned long pos, size_t maxlen) |
42 | { |
43 | ssize_t n = 0; |
44 | size_t segment; |
45 | u_char buf[16], *p; |
46 | size_t len; |
47 | int ret; |
48 | |
49 | /* scan the string up to 16 bytes at a time */ |
50 | while (maxlen > 0) { |
51 | segment = min_t(size_t, maxlen, 16); |
52 | ret = ROMFS_MTD_READ(sb, pos, segment, &len, buf); |
53 | if (ret < 0) |
54 | return ret; |
55 | p = memchr(buf, 0, len); |
56 | if (p) |
57 | return n + (p - buf); |
58 | maxlen -= len; |
59 | pos += len; |
60 | n += len; |
61 | } |
62 | |
63 | return n; |
64 | } |
65 | |
66 | /* |
67 | * compare a string to one in a romfs image on MTD |
68 | * - return 1 if matched, 0 if differ, -ve if error |
69 | */ |
70 | static int romfs_mtd_strcmp(struct super_block *sb, unsigned long pos, |
71 | const char *str, size_t size) |
72 | { |
73 | u_char buf[17]; |
74 | size_t len, segment; |
75 | int ret; |
76 | |
77 | /* scan the string up to 16 bytes at a time, and attempt to grab the |
78 | * trailing NUL whilst we're at it */ |
79 | buf[0] = 0xff; |
80 | |
81 | while (size > 0) { |
82 | segment = min_t(size_t, size + 1, 17); |
83 | ret = ROMFS_MTD_READ(sb, pos, segment, &len, buf); |
84 | if (ret < 0) |
85 | return ret; |
86 | len--; |
87 | if (memcmp(buf, str, len) != 0) |
88 | return 0; |
89 | buf[0] = buf[len]; |
90 | size -= len; |
91 | pos += len; |
92 | str += len; |
93 | } |
94 | |
95 | /* check the trailing NUL was */ |
96 | if (buf[0]) |
97 | return 0; |
98 | |
99 | return 1; |
100 | } |
101 | #endif /* CONFIG_ROMFS_ON_MTD */ |
102 | |
103 | #ifdef CONFIG_ROMFS_ON_BLOCK |
104 | /* |
105 | * read data from an romfs image on a block device |
106 | */ |
107 | static int romfs_blk_read(struct super_block *sb, unsigned long pos, |
108 | void *buf, size_t buflen) |
109 | { |
110 | struct buffer_head *bh; |
111 | unsigned long offset; |
112 | size_t segment; |
113 | |
114 | /* copy the string up to blocksize bytes at a time */ |
115 | while (buflen > 0) { |
116 | offset = pos & (ROMBSIZE - 1); |
117 | segment = min_t(size_t, buflen, ROMBSIZE - offset); |
118 | bh = sb_bread(sb, pos >> ROMBSBITS); |
119 | if (!bh) |
120 | return -EIO; |
121 | memcpy(buf, bh->b_data + offset, segment); |
122 | brelse(bh); |
123 | buf += segment; |
124 | buflen -= segment; |
125 | pos += segment; |
126 | } |
127 | |
128 | return 0; |
129 | } |
130 | |
131 | /* |
132 | * determine the length of a string in romfs on a block device |
133 | */ |
134 | static ssize_t romfs_blk_strnlen(struct super_block *sb, |
135 | unsigned long pos, size_t limit) |
136 | { |
137 | struct buffer_head *bh; |
138 | unsigned long offset; |
139 | ssize_t n = 0; |
140 | size_t segment; |
141 | u_char *buf, *p; |
142 | |
143 | /* scan the string up to blocksize bytes at a time */ |
144 | while (limit > 0) { |
145 | offset = pos & (ROMBSIZE - 1); |
146 | segment = min_t(size_t, limit, ROMBSIZE - offset); |
147 | bh = sb_bread(sb, pos >> ROMBSBITS); |
148 | if (!bh) |
149 | return -EIO; |
150 | buf = bh->b_data + offset; |
151 | p = memchr(buf, 0, segment); |
152 | brelse(bh); |
153 | if (p) |
154 | return n + (p - buf); |
155 | limit -= segment; |
156 | pos += segment; |
157 | n += segment; |
158 | } |
159 | |
160 | return n; |
161 | } |
162 | |
163 | /* |
164 | * compare a string to one in a romfs image on a block device |
165 | * - return 1 if matched, 0 if differ, -ve if error |
166 | */ |
167 | static int romfs_blk_strcmp(struct super_block *sb, unsigned long pos, |
168 | const char *str, size_t size) |
169 | { |
170 | struct buffer_head *bh; |
171 | unsigned long offset; |
172 | size_t segment; |
173 | bool matched, terminated = false; |
174 | |
175 | /* compare string up to a block at a time */ |
176 | while (size > 0) { |
177 | offset = pos & (ROMBSIZE - 1); |
178 | segment = min_t(size_t, size, ROMBSIZE - offset); |
179 | bh = sb_bread(sb, pos >> ROMBSBITS); |
180 | if (!bh) |
181 | return -EIO; |
182 | matched = (memcmp(bh->b_data + offset, str, segment) == 0); |
183 | |
184 | size -= segment; |
185 | pos += segment; |
186 | str += segment; |
187 | if (matched && size == 0 && offset + segment < ROMBSIZE) { |
188 | if (!bh->b_data[offset + segment]) |
189 | terminated = true; |
190 | else |
191 | matched = false; |
192 | } |
193 | brelse(bh); |
194 | if (!matched) |
195 | return 0; |
196 | } |
197 | |
198 | if (!terminated) { |
199 | /* the terminating NUL must be on the first byte of the next |
200 | * block */ |
201 | BUG_ON((pos & (ROMBSIZE - 1)) != 0); |
202 | bh = sb_bread(sb, pos >> ROMBSBITS); |
203 | if (!bh) |
204 | return -EIO; |
205 | matched = !bh->b_data[0]; |
206 | brelse(bh); |
207 | if (!matched) |
208 | return 0; |
209 | } |
210 | |
211 | return 1; |
212 | } |
213 | #endif /* CONFIG_ROMFS_ON_BLOCK */ |
214 | |
215 | /* |
216 | * read data from the romfs image |
217 | */ |
218 | int romfs_dev_read(struct super_block *sb, unsigned long pos, |
219 | void *buf, size_t buflen) |
220 | { |
221 | size_t limit; |
222 | |
223 | limit = romfs_maxsize(sb); |
224 | if (pos >= limit) |
225 | return -EIO; |
226 | if (buflen > limit - pos) |
227 | buflen = limit - pos; |
228 | |
229 | #ifdef CONFIG_ROMFS_ON_MTD |
230 | if (sb->s_mtd) |
231 | return romfs_mtd_read(sb, pos, buf, buflen); |
232 | #endif |
233 | #ifdef CONFIG_ROMFS_ON_BLOCK |
234 | if (sb->s_bdev) |
235 | return romfs_blk_read(sb, pos, buf, buflen); |
236 | #endif |
237 | return -EIO; |
238 | } |
239 | |
240 | /* |
241 | * determine the length of a string in romfs |
242 | */ |
243 | ssize_t romfs_dev_strnlen(struct super_block *sb, |
244 | unsigned long pos, size_t maxlen) |
245 | { |
246 | size_t limit; |
247 | |
248 | limit = romfs_maxsize(sb); |
249 | if (pos >= limit) |
250 | return -EIO; |
251 | if (maxlen > limit - pos) |
252 | maxlen = limit - pos; |
253 | |
254 | #ifdef CONFIG_ROMFS_ON_MTD |
255 | if (sb->s_mtd) |
256 | return romfs_mtd_strnlen(sb, pos, maxlen); |
257 | #endif |
258 | #ifdef CONFIG_ROMFS_ON_BLOCK |
259 | if (sb->s_bdev) |
260 | return romfs_blk_strnlen(sb, pos, maxlen); |
261 | #endif |
262 | return -EIO; |
263 | } |
264 | |
265 | /* |
266 | * compare a string to one in romfs |
267 | * - the string to be compared to, str, may not be NUL-terminated; instead the |
268 | * string is of the specified size |
269 | * - return 1 if matched, 0 if differ, -ve if error |
270 | */ |
271 | int romfs_dev_strcmp(struct super_block *sb, unsigned long pos, |
272 | const char *str, size_t size) |
273 | { |
274 | size_t limit; |
275 | |
276 | limit = romfs_maxsize(sb); |
277 | if (pos >= limit) |
278 | return -EIO; |
279 | if (size > ROMFS_MAXFN) |
280 | return -ENAMETOOLONG; |
281 | if (size + 1 > limit - pos) |
282 | return -EIO; |
283 | |
284 | #ifdef CONFIG_ROMFS_ON_MTD |
285 | if (sb->s_mtd) |
286 | return romfs_mtd_strcmp(sb, pos, str, size); |
287 | #endif |
288 | #ifdef CONFIG_ROMFS_ON_BLOCK |
289 | if (sb->s_bdev) |
290 | return romfs_blk_strcmp(sb, pos, str, size); |
291 | #endif |
292 | return -EIO; |
293 | } |
294 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9