storage.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  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. #include <linux/fs.h>
  8. #include <linux/mtd/super.h>
  9. #include <linux/buffer_head.h>
  10. #include "internal.h"
  11. #if !defined(CONFIG_ROMFS_ON_MTD) && !defined(CONFIG_ROMFS_ON_BLOCK)
  12. #error no ROMFS backing store interface configured
  13. #endif
  14. #ifdef CONFIG_ROMFS_ON_MTD
  15. #define ROMFS_MTD_READ(sb, ...) mtd_read((sb)->s_mtd, ##__VA_ARGS__)
  16. /*
  17. * read data from an romfs image on an MTD device
  18. */
  19. static int romfs_mtd_read(struct super_block *sb, unsigned long pos,
  20. void *buf, size_t buflen)
  21. {
  22. size_t rlen;
  23. int ret;
  24. ret = ROMFS_MTD_READ(sb, pos, buflen, &rlen, buf);
  25. return (ret < 0 || rlen != buflen) ? -EIO : 0;
  26. }
  27. /*
  28. * determine the length of a string in a romfs image on an MTD device
  29. */
  30. static ssize_t romfs_mtd_strnlen(struct super_block *sb,
  31. unsigned long pos, size_t maxlen)
  32. {
  33. ssize_t n = 0;
  34. size_t segment;
  35. u_char buf[16], *p;
  36. size_t len;
  37. int ret;
  38. /* scan the string up to 16 bytes at a time */
  39. while (maxlen > 0) {
  40. segment = min_t(size_t, maxlen, 16);
  41. ret = ROMFS_MTD_READ(sb, pos, segment, &len, buf);
  42. if (ret < 0)
  43. return ret;
  44. p = memchr(buf, 0, len);
  45. if (p)
  46. return n + (p - buf);
  47. maxlen -= len;
  48. pos += len;
  49. n += len;
  50. }
  51. return n;
  52. }
  53. /*
  54. * compare a string to one in a romfs image on MTD
  55. * - return 1 if matched, 0 if differ, -ve if error
  56. */
  57. static int romfs_mtd_strcmp(struct super_block *sb, unsigned long pos,
  58. const char *str, size_t size)
  59. {
  60. u_char buf[17];
  61. size_t len, segment;
  62. int ret;
  63. /* scan the string up to 16 bytes at a time, and attempt to grab the
  64. * trailing NUL whilst we're at it */
  65. buf[0] = 0xff;
  66. while (size > 0) {
  67. segment = min_t(size_t, size + 1, 17);
  68. ret = ROMFS_MTD_READ(sb, pos, segment, &len, buf);
  69. if (ret < 0)
  70. return ret;
  71. len--;
  72. if (memcmp(buf, str, len) != 0)
  73. return 0;
  74. buf[0] = buf[len];
  75. size -= len;
  76. pos += len;
  77. str += len;
  78. }
  79. /* check the trailing NUL was */
  80. if (buf[0])
  81. return 0;
  82. return 1;
  83. }
  84. #endif /* CONFIG_ROMFS_ON_MTD */
  85. #ifdef CONFIG_ROMFS_ON_BLOCK
  86. /*
  87. * read data from an romfs image on a block device
  88. */
  89. static int romfs_blk_read(struct super_block *sb, unsigned long pos,
  90. void *buf, size_t buflen)
  91. {
  92. struct buffer_head *bh;
  93. unsigned long offset;
  94. size_t segment;
  95. /* copy the string up to blocksize bytes at a time */
  96. while (buflen > 0) {
  97. offset = pos & (ROMBSIZE - 1);
  98. segment = min_t(size_t, buflen, ROMBSIZE - offset);
  99. bh = sb_bread(sb, pos >> ROMBSBITS);
  100. if (!bh)
  101. return -EIO;
  102. memcpy(buf, bh->b_data + offset, segment);
  103. brelse(bh);
  104. buf += segment;
  105. buflen -= segment;
  106. pos += segment;
  107. }
  108. return 0;
  109. }
  110. /*
  111. * determine the length of a string in romfs on a block device
  112. */
  113. static ssize_t romfs_blk_strnlen(struct super_block *sb,
  114. unsigned long pos, size_t limit)
  115. {
  116. struct buffer_head *bh;
  117. unsigned long offset;
  118. ssize_t n = 0;
  119. size_t segment;
  120. u_char *buf, *p;
  121. /* scan the string up to blocksize bytes at a time */
  122. while (limit > 0) {
  123. offset = pos & (ROMBSIZE - 1);
  124. segment = min_t(size_t, limit, ROMBSIZE - offset);
  125. bh = sb_bread(sb, pos >> ROMBSBITS);
  126. if (!bh)
  127. return -EIO;
  128. buf = bh->b_data + offset;
  129. p = memchr(buf, 0, segment);
  130. brelse(bh);
  131. if (p)
  132. return n + (p - buf);
  133. limit -= segment;
  134. pos += segment;
  135. n += segment;
  136. }
  137. return n;
  138. }
  139. /*
  140. * compare a string to one in a romfs image on a block device
  141. * - return 1 if matched, 0 if differ, -ve if error
  142. */
  143. static int romfs_blk_strcmp(struct super_block *sb, unsigned long pos,
  144. const char *str, size_t size)
  145. {
  146. struct buffer_head *bh;
  147. unsigned long offset;
  148. size_t segment;
  149. bool matched, terminated = false;
  150. /* compare string up to a block at a time */
  151. while (size > 0) {
  152. offset = pos & (ROMBSIZE - 1);
  153. segment = min_t(size_t, size, ROMBSIZE - offset);
  154. bh = sb_bread(sb, pos >> ROMBSBITS);
  155. if (!bh)
  156. return -EIO;
  157. matched = (memcmp(bh->b_data + offset, str, segment) == 0);
  158. size -= segment;
  159. pos += segment;
  160. str += segment;
  161. if (matched && size == 0 && offset + segment < ROMBSIZE) {
  162. if (!bh->b_data[offset + segment])
  163. terminated = true;
  164. else
  165. matched = false;
  166. }
  167. brelse(bh);
  168. if (!matched)
  169. return 0;
  170. }
  171. if (!terminated) {
  172. /* the terminating NUL must be on the first byte of the next
  173. * block */
  174. BUG_ON((pos & (ROMBSIZE - 1)) != 0);
  175. bh = sb_bread(sb, pos >> ROMBSBITS);
  176. if (!bh)
  177. return -EIO;
  178. matched = !bh->b_data[0];
  179. brelse(bh);
  180. if (!matched)
  181. return 0;
  182. }
  183. return 1;
  184. }
  185. #endif /* CONFIG_ROMFS_ON_BLOCK */
  186. /*
  187. * read data from the romfs image
  188. */
  189. int romfs_dev_read(struct super_block *sb, unsigned long pos,
  190. void *buf, size_t buflen)
  191. {
  192. size_t limit;
  193. limit = romfs_maxsize(sb);
  194. if (pos >= limit || buflen > limit - pos)
  195. return -EIO;
  196. #ifdef CONFIG_ROMFS_ON_MTD
  197. if (sb->s_mtd)
  198. return romfs_mtd_read(sb, pos, buf, buflen);
  199. #endif
  200. #ifdef CONFIG_ROMFS_ON_BLOCK
  201. if (sb->s_bdev)
  202. return romfs_blk_read(sb, pos, buf, buflen);
  203. #endif
  204. return -EIO;
  205. }
  206. /*
  207. * determine the length of a string in romfs
  208. */
  209. ssize_t romfs_dev_strnlen(struct super_block *sb,
  210. unsigned long pos, size_t maxlen)
  211. {
  212. size_t limit;
  213. limit = romfs_maxsize(sb);
  214. if (pos >= limit)
  215. return -EIO;
  216. if (maxlen > limit - pos)
  217. maxlen = limit - pos;
  218. #ifdef CONFIG_ROMFS_ON_MTD
  219. if (sb->s_mtd)
  220. return romfs_mtd_strnlen(sb, pos, maxlen);
  221. #endif
  222. #ifdef CONFIG_ROMFS_ON_BLOCK
  223. if (sb->s_bdev)
  224. return romfs_blk_strnlen(sb, pos, maxlen);
  225. #endif
  226. return -EIO;
  227. }
  228. /*
  229. * compare a string to one in romfs
  230. * - the string to be compared to, str, may not be NUL-terminated; instead the
  231. * string is of the specified size
  232. * - return 1 if matched, 0 if differ, -ve if error
  233. */
  234. int romfs_dev_strcmp(struct super_block *sb, unsigned long pos,
  235. const char *str, size_t size)
  236. {
  237. size_t limit;
  238. limit = romfs_maxsize(sb);
  239. if (pos >= limit)
  240. return -EIO;
  241. if (size > ROMFS_MAXFN)
  242. return -ENAMETOOLONG;
  243. if (size + 1 > limit - pos)
  244. return -EIO;
  245. #ifdef CONFIG_ROMFS_ON_MTD
  246. if (sb->s_mtd)
  247. return romfs_mtd_strcmp(sb, pos, str, size);
  248. #endif
  249. #ifdef CONFIG_ROMFS_ON_BLOCK
  250. if (sb->s_bdev)
  251. return romfs_blk_strcmp(sb, pos, str, size);
  252. #endif
  253. return -EIO;
  254. }