brintos

brintos / linux-shallow public Read only

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