0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/fs.h>
0009 #include <linux/mtd/super.h>
0010 #include <linux/buffer_head.h>
0011 #include "internal.h"
0012
0013 #if !defined(CONFIG_ROMFS_ON_MTD) && !defined(CONFIG_ROMFS_ON_BLOCK)
0014 #error no ROMFS backing store interface configured
0015 #endif
0016
0017 #ifdef CONFIG_ROMFS_ON_MTD
0018 #define ROMFS_MTD_READ(sb, ...) mtd_read((sb)->s_mtd, ##__VA_ARGS__)
0019
0020
0021
0022
0023 static int romfs_mtd_read(struct super_block *sb, unsigned long pos,
0024 void *buf, size_t buflen)
0025 {
0026 size_t rlen;
0027 int ret;
0028
0029 ret = ROMFS_MTD_READ(sb, pos, buflen, &rlen, buf);
0030 return (ret < 0 || rlen != buflen) ? -EIO : 0;
0031 }
0032
0033
0034
0035
0036 static ssize_t romfs_mtd_strnlen(struct super_block *sb,
0037 unsigned long pos, size_t maxlen)
0038 {
0039 ssize_t n = 0;
0040 size_t segment;
0041 u_char buf[16], *p;
0042 size_t len;
0043 int ret;
0044
0045
0046 while (maxlen > 0) {
0047 segment = min_t(size_t, maxlen, 16);
0048 ret = ROMFS_MTD_READ(sb, pos, segment, &len, buf);
0049 if (ret < 0)
0050 return ret;
0051 p = memchr(buf, 0, len);
0052 if (p)
0053 return n + (p - buf);
0054 maxlen -= len;
0055 pos += len;
0056 n += len;
0057 }
0058
0059 return n;
0060 }
0061
0062
0063
0064
0065
0066 static int romfs_mtd_strcmp(struct super_block *sb, unsigned long pos,
0067 const char *str, size_t size)
0068 {
0069 u_char buf[17];
0070 size_t len, segment;
0071 int ret;
0072
0073
0074
0075 buf[0] = 0xff;
0076
0077 while (size > 0) {
0078 segment = min_t(size_t, size + 1, 17);
0079 ret = ROMFS_MTD_READ(sb, pos, segment, &len, buf);
0080 if (ret < 0)
0081 return ret;
0082 len--;
0083 if (memcmp(buf, str, len) != 0)
0084 return 0;
0085 buf[0] = buf[len];
0086 size -= len;
0087 pos += len;
0088 str += len;
0089 }
0090
0091
0092 if (buf[0])
0093 return 0;
0094
0095 return 1;
0096 }
0097 #endif
0098
0099 #ifdef CONFIG_ROMFS_ON_BLOCK
0100
0101
0102
0103 static int romfs_blk_read(struct super_block *sb, unsigned long pos,
0104 void *buf, size_t buflen)
0105 {
0106 struct buffer_head *bh;
0107 unsigned long offset;
0108 size_t segment;
0109
0110
0111 while (buflen > 0) {
0112 offset = pos & (ROMBSIZE - 1);
0113 segment = min_t(size_t, buflen, ROMBSIZE - offset);
0114 bh = sb_bread(sb, pos >> ROMBSBITS);
0115 if (!bh)
0116 return -EIO;
0117 memcpy(buf, bh->b_data + offset, segment);
0118 brelse(bh);
0119 buf += segment;
0120 buflen -= segment;
0121 pos += segment;
0122 }
0123
0124 return 0;
0125 }
0126
0127
0128
0129
0130 static ssize_t romfs_blk_strnlen(struct super_block *sb,
0131 unsigned long pos, size_t limit)
0132 {
0133 struct buffer_head *bh;
0134 unsigned long offset;
0135 ssize_t n = 0;
0136 size_t segment;
0137 u_char *buf, *p;
0138
0139
0140 while (limit > 0) {
0141 offset = pos & (ROMBSIZE - 1);
0142 segment = min_t(size_t, limit, ROMBSIZE - offset);
0143 bh = sb_bread(sb, pos >> ROMBSBITS);
0144 if (!bh)
0145 return -EIO;
0146 buf = bh->b_data + offset;
0147 p = memchr(buf, 0, segment);
0148 brelse(bh);
0149 if (p)
0150 return n + (p - buf);
0151 limit -= segment;
0152 pos += segment;
0153 n += segment;
0154 }
0155
0156 return n;
0157 }
0158
0159
0160
0161
0162
0163 static int romfs_blk_strcmp(struct super_block *sb, unsigned long pos,
0164 const char *str, size_t size)
0165 {
0166 struct buffer_head *bh;
0167 unsigned long offset;
0168 size_t segment;
0169 bool matched, terminated = false;
0170
0171
0172 while (size > 0) {
0173 offset = pos & (ROMBSIZE - 1);
0174 segment = min_t(size_t, size, ROMBSIZE - offset);
0175 bh = sb_bread(sb, pos >> ROMBSBITS);
0176 if (!bh)
0177 return -EIO;
0178 matched = (memcmp(bh->b_data + offset, str, segment) == 0);
0179
0180 size -= segment;
0181 pos += segment;
0182 str += segment;
0183 if (matched && size == 0 && offset + segment < ROMBSIZE) {
0184 if (!bh->b_data[offset + segment])
0185 terminated = true;
0186 else
0187 matched = false;
0188 }
0189 brelse(bh);
0190 if (!matched)
0191 return 0;
0192 }
0193
0194 if (!terminated) {
0195
0196
0197 BUG_ON((pos & (ROMBSIZE - 1)) != 0);
0198 bh = sb_bread(sb, pos >> ROMBSBITS);
0199 if (!bh)
0200 return -EIO;
0201 matched = !bh->b_data[0];
0202 brelse(bh);
0203 if (!matched)
0204 return 0;
0205 }
0206
0207 return 1;
0208 }
0209 #endif
0210
0211
0212
0213
0214 int romfs_dev_read(struct super_block *sb, unsigned long pos,
0215 void *buf, size_t buflen)
0216 {
0217 size_t limit;
0218
0219 limit = romfs_maxsize(sb);
0220 if (pos >= limit || buflen > limit - pos)
0221 return -EIO;
0222
0223 #ifdef CONFIG_ROMFS_ON_MTD
0224 if (sb->s_mtd)
0225 return romfs_mtd_read(sb, pos, buf, buflen);
0226 #endif
0227 #ifdef CONFIG_ROMFS_ON_BLOCK
0228 if (sb->s_bdev)
0229 return romfs_blk_read(sb, pos, buf, buflen);
0230 #endif
0231 return -EIO;
0232 }
0233
0234
0235
0236
0237 ssize_t romfs_dev_strnlen(struct super_block *sb,
0238 unsigned long pos, size_t maxlen)
0239 {
0240 size_t limit;
0241
0242 limit = romfs_maxsize(sb);
0243 if (pos >= limit)
0244 return -EIO;
0245 if (maxlen > limit - pos)
0246 maxlen = limit - pos;
0247
0248 #ifdef CONFIG_ROMFS_ON_MTD
0249 if (sb->s_mtd)
0250 return romfs_mtd_strnlen(sb, pos, maxlen);
0251 #endif
0252 #ifdef CONFIG_ROMFS_ON_BLOCK
0253 if (sb->s_bdev)
0254 return romfs_blk_strnlen(sb, pos, maxlen);
0255 #endif
0256 return -EIO;
0257 }
0258
0259
0260
0261
0262
0263
0264
0265 int romfs_dev_strcmp(struct super_block *sb, unsigned long pos,
0266 const char *str, size_t size)
0267 {
0268 size_t limit;
0269
0270 limit = romfs_maxsize(sb);
0271 if (pos >= limit)
0272 return -EIO;
0273 if (size > ROMFS_MAXFN)
0274 return -ENAMETOOLONG;
0275 if (size + 1 > limit - pos)
0276 return -EIO;
0277
0278 #ifdef CONFIG_ROMFS_ON_MTD
0279 if (sb->s_mtd)
0280 return romfs_mtd_strcmp(sb, pos, str, size);
0281 #endif
0282 #ifdef CONFIG_ROMFS_ON_BLOCK
0283 if (sb->s_bdev)
0284 return romfs_blk_strcmp(sb, pos, str, size);
0285 #endif
0286 return -EIO;
0287 }