diff options
Diffstat (limited to 'fs/romfs/storage.c')
-rw-r--r-- | fs/romfs/storage.c | 261 |
1 files changed, 261 insertions, 0 deletions
diff --git a/fs/romfs/storage.c b/fs/romfs/storage.c new file mode 100644 index 000000000000..7e3e1e12a081 --- /dev/null +++ b/fs/romfs/storage.c | |||
@@ -0,0 +1,261 @@ | |||
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_strncmp(struct super_block *sb, unsigned long pos, | ||
71 | const char *str, size_t size) | ||
72 | { | ||
73 | u_char buf[16]; | ||
74 | size_t len, segment; | ||
75 | int ret; | ||
76 | |||
77 | /* scan the string up to 16 bytes at a time */ | ||
78 | while (size > 0) { | ||
79 | segment = min_t(size_t, size, 16); | ||
80 | ret = ROMFS_MTD_READ(sb, pos, segment, &len, buf); | ||
81 | if (ret < 0) | ||
82 | return ret; | ||
83 | if (memcmp(buf, str, len) != 0) | ||
84 | return 0; | ||
85 | size -= len; | ||
86 | pos += len; | ||
87 | str += len; | ||
88 | } | ||
89 | |||
90 | return 1; | ||
91 | } | ||
92 | #endif /* CONFIG_ROMFS_ON_MTD */ | ||
93 | |||
94 | #ifdef CONFIG_ROMFS_ON_BLOCK | ||
95 | /* | ||
96 | * read data from an romfs image on a block device | ||
97 | */ | ||
98 | static int romfs_blk_read(struct super_block *sb, unsigned long pos, | ||
99 | void *buf, size_t buflen) | ||
100 | { | ||
101 | struct buffer_head *bh; | ||
102 | unsigned long offset; | ||
103 | size_t segment; | ||
104 | |||
105 | /* copy the string up to blocksize bytes at a time */ | ||
106 | while (buflen > 0) { | ||
107 | offset = pos & (ROMBSIZE - 1); | ||
108 | segment = min_t(size_t, buflen, ROMBSIZE - offset); | ||
109 | bh = sb_bread(sb, pos >> ROMBSBITS); | ||
110 | if (!bh) | ||
111 | return -EIO; | ||
112 | memcpy(buf, bh->b_data + offset, segment); | ||
113 | brelse(bh); | ||
114 | buflen -= segment; | ||
115 | pos += segment; | ||
116 | } | ||
117 | |||
118 | return 0; | ||
119 | } | ||
120 | |||
121 | /* | ||
122 | * determine the length of a string in romfs on a block device | ||
123 | */ | ||
124 | static ssize_t romfs_blk_strnlen(struct super_block *sb, | ||
125 | unsigned long pos, size_t limit) | ||
126 | { | ||
127 | struct buffer_head *bh; | ||
128 | unsigned long offset; | ||
129 | ssize_t n = 0; | ||
130 | size_t segment; | ||
131 | u_char *buf, *p; | ||
132 | |||
133 | /* scan the string up to blocksize bytes at a time */ | ||
134 | while (limit > 0) { | ||
135 | offset = pos & (ROMBSIZE - 1); | ||
136 | segment = min_t(size_t, limit, ROMBSIZE - offset); | ||
137 | bh = sb_bread(sb, pos >> ROMBSBITS); | ||
138 | if (!bh) | ||
139 | return -EIO; | ||
140 | buf = bh->b_data + offset; | ||
141 | p = memchr(buf, 0, segment); | ||
142 | brelse(bh); | ||
143 | if (p) | ||
144 | return n + (p - buf); | ||
145 | limit -= segment; | ||
146 | pos += segment; | ||
147 | n += segment; | ||
148 | } | ||
149 | |||
150 | return n; | ||
151 | } | ||
152 | |||
153 | /* | ||
154 | * compare a string to one in a romfs image on a block device | ||
155 | * - return 1 if matched, 0 if differ, -ve if error | ||
156 | */ | ||
157 | static int romfs_blk_strncmp(struct super_block *sb, unsigned long pos, | ||
158 | const char *str, size_t size) | ||
159 | { | ||
160 | struct buffer_head *bh; | ||
161 | unsigned long offset; | ||
162 | size_t segment; | ||
163 | bool x; | ||
164 | |||
165 | /* scan the string up to 16 bytes at a time */ | ||
166 | while (size > 0) { | ||
167 | offset = pos & (ROMBSIZE - 1); | ||
168 | segment = min_t(size_t, size, ROMBSIZE - offset); | ||
169 | bh = sb_bread(sb, pos >> ROMBSBITS); | ||
170 | if (!bh) | ||
171 | return -EIO; | ||
172 | x = (memcmp(bh->b_data + offset, str, segment) != 0); | ||
173 | brelse(bh); | ||
174 | if (x) | ||
175 | return 0; | ||
176 | size -= segment; | ||
177 | pos += segment; | ||
178 | str += segment; | ||
179 | } | ||
180 | |||
181 | return 1; | ||
182 | } | ||
183 | #endif /* CONFIG_ROMFS_ON_BLOCK */ | ||
184 | |||
185 | /* | ||
186 | * read data from the romfs image | ||
187 | */ | ||
188 | int romfs_dev_read(struct super_block *sb, unsigned long pos, | ||
189 | void *buf, size_t buflen) | ||
190 | { | ||
191 | size_t limit; | ||
192 | |||
193 | limit = romfs_maxsize(sb); | ||
194 | if (pos >= limit) | ||
195 | return -EIO; | ||
196 | if (buflen > limit - pos) | ||
197 | buflen = limit - pos; | ||
198 | |||
199 | #ifdef CONFIG_ROMFS_ON_MTD | ||
200 | if (sb->s_mtd) | ||
201 | return romfs_mtd_read(sb, pos, buf, buflen); | ||
202 | #endif | ||
203 | #ifdef CONFIG_ROMFS_ON_BLOCK | ||
204 | if (sb->s_bdev) | ||
205 | return romfs_blk_read(sb, pos, buf, buflen); | ||
206 | #endif | ||
207 | return -EIO; | ||
208 | } | ||
209 | |||
210 | /* | ||
211 | * determine the length of a string in romfs | ||
212 | */ | ||
213 | ssize_t romfs_dev_strnlen(struct super_block *sb, | ||
214 | unsigned long pos, size_t maxlen) | ||
215 | { | ||
216 | size_t limit; | ||
217 | |||
218 | limit = romfs_maxsize(sb); | ||
219 | if (pos >= limit) | ||
220 | return -EIO; | ||
221 | if (maxlen > limit - pos) | ||
222 | maxlen = limit - pos; | ||
223 | |||
224 | #ifdef CONFIG_ROMFS_ON_MTD | ||
225 | if (sb->s_mtd) | ||
226 | return romfs_mtd_strnlen(sb, pos, limit); | ||
227 | #endif | ||
228 | #ifdef CONFIG_ROMFS_ON_BLOCK | ||
229 | if (sb->s_bdev) | ||
230 | return romfs_blk_strnlen(sb, pos, limit); | ||
231 | #endif | ||
232 | return -EIO; | ||
233 | } | ||
234 | |||
235 | /* | ||
236 | * compare a string to one in romfs | ||
237 | * - return 1 if matched, 0 if differ, -ve if error | ||
238 | */ | ||
239 | int romfs_dev_strncmp(struct super_block *sb, unsigned long pos, | ||
240 | const char *str, size_t size) | ||
241 | { | ||
242 | size_t limit; | ||
243 | |||
244 | limit = romfs_maxsize(sb); | ||
245 | if (pos >= limit) | ||
246 | return -EIO; | ||
247 | if (size > ROMFS_MAXFN) | ||
248 | return -ENAMETOOLONG; | ||
249 | if (size > limit - pos) | ||
250 | return -EIO; | ||
251 | |||
252 | #ifdef CONFIG_ROMFS_ON_MTD | ||
253 | if (sb->s_mtd) | ||
254 | return romfs_mtd_strncmp(sb, pos, str, size); | ||
255 | #endif | ||
256 | #ifdef CONFIG_ROMFS_ON_BLOCK | ||
257 | if (sb->s_bdev) | ||
258 | return romfs_blk_strncmp(sb, pos, str, size); | ||
259 | #endif | ||
260 | return -EIO; | ||
261 | } | ||