root/fs/romfs/storage.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. romfs_mtd_read
  2. romfs_mtd_strnlen
  3. romfs_mtd_strcmp
  4. romfs_blk_read
  5. romfs_blk_strnlen
  6. romfs_blk_strcmp
  7. romfs_dev_read
  8. romfs_dev_strnlen
  9. romfs_dev_strcmp

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /* RomFS storage access routines
   3  *
   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 configured
  15 #endif
  16 
  17 #ifdef CONFIG_ROMFS_ON_MTD
  18 #define ROMFS_MTD_READ(sb, ...) mtd_read((sb)->s_mtd, ##__VA_ARGS__)
  19 
  20 /*
  21  * read data from an romfs image on an MTD device
  22  */
  23 static 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 device
  35  */
  36 static 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 MTD
  64  * - return 1 if matched, 0 if differ, -ve if error
  65  */
  66 static 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 the
  74          * 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_BLOCK
 100 /*
 101  * read data from an romfs image on a block device
 102  */
 103 static 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 device
 129  */
 130 static 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 device
 161  * - return 1 if matched, 0 if differ, -ve if error
 162  */
 163 static 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                         else
 187                                 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 next
 196                  * 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 image
 213  */
 214 int 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)
 221                 return -EIO;
 222         if (buflen > limit - pos)
 223                 buflen = limit - pos;
 224 
 225 #ifdef CONFIG_ROMFS_ON_MTD
 226         if (sb->s_mtd)
 227                 return romfs_mtd_read(sb, pos, buf, buflen);
 228 #endif
 229 #ifdef CONFIG_ROMFS_ON_BLOCK
 230         if (sb->s_bdev)
 231                 return romfs_blk_read(sb, pos, buf, buflen);
 232 #endif
 233         return -EIO;
 234 }
 235 
 236 /*
 237  * determine the length of a string in romfs
 238  */
 239 ssize_t romfs_dev_strnlen(struct super_block *sb,
 240                           unsigned long pos, size_t maxlen)
 241 {
 242         size_t limit;
 243 
 244         limit = romfs_maxsize(sb);
 245         if (pos >= limit)
 246                 return -EIO;
 247         if (maxlen > limit - pos)
 248                 maxlen = limit - pos;
 249 
 250 #ifdef CONFIG_ROMFS_ON_MTD
 251         if (sb->s_mtd)
 252                 return romfs_mtd_strnlen(sb, pos, maxlen);
 253 #endif
 254 #ifdef CONFIG_ROMFS_ON_BLOCK
 255         if (sb->s_bdev)
 256                 return romfs_blk_strnlen(sb, pos, maxlen);
 257 #endif
 258         return -EIO;
 259 }
 260 
 261 /*
 262  * compare a string to one in romfs
 263  * - the string to be compared to, str, may not be NUL-terminated; instead the
 264  *   string is of the specified size
 265  * - return 1 if matched, 0 if differ, -ve if error
 266  */
 267 int romfs_dev_strcmp(struct super_block *sb, unsigned long pos,
 268                      const char *str, size_t size)
 269 {
 270         size_t limit;
 271 
 272         limit = romfs_maxsize(sb);
 273         if (pos >= limit)
 274                 return -EIO;
 275         if (size > ROMFS_MAXFN)
 276                 return -ENAMETOOLONG;
 277         if (size + 1 > limit - pos)
 278                 return -EIO;
 279 
 280 #ifdef CONFIG_ROMFS_ON_MTD
 281         if (sb->s_mtd)
 282                 return romfs_mtd_strcmp(sb, pos, str, size);
 283 #endif
 284 #ifdef CONFIG_ROMFS_ON_BLOCK
 285         if (sb->s_bdev)
 286                 return romfs_blk_strcmp(sb, pos, str, size);
 287 #endif
 288         return -EIO;
 289 }

/* [<][>][^][v][top][bottom][index][help] */