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