xref: /openbmc/linux/fs/romfs/storage.c (revision b627b4ed)
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 }
262