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