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