ext4fs.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. /*
  2. * (C) Copyright 2011 - 2012 Samsung Electronics
  3. * EXT4 filesystem implementation in Uboot by
  4. * Uma Shankar <uma.shankar@samsung.com>
  5. * Manjunatha C Achar <a.manjunatha@samsung.com>
  6. *
  7. * ext4ls and ext4load : Based on ext2 ls and load support in Uboot.
  8. * Ext4 read optimization taken from Open-Moko
  9. * Qi bootloader
  10. *
  11. * (C) Copyright 2004
  12. * esd gmbh <www.esd-electronics.com>
  13. * Reinhard Arlt <reinhard.arlt@esd-electronics.com>
  14. *
  15. * based on code from grub2 fs/ext2.c and fs/fshelp.c by
  16. * GRUB -- GRand Unified Bootloader
  17. * Copyright (C) 2003, 2004 Free Software Foundation, Inc.
  18. *
  19. * ext4write : Based on generic ext4 protocol.
  20. *
  21. * SPDX-License-Identifier: GPL-2.0+
  22. */
  23. #include <common.h>
  24. #include <ext_common.h>
  25. #include <ext4fs.h>
  26. #include "ext4_common.h"
  27. int ext4fs_symlinknest;
  28. struct ext_filesystem ext_fs;
  29. struct ext_filesystem *get_fs(void)
  30. {
  31. return &ext_fs;
  32. }
  33. void ext4fs_free_node(struct ext2fs_node *node, struct ext2fs_node *currroot)
  34. {
  35. if ((node != &ext4fs_root->diropen) && (node != currroot))
  36. free(node);
  37. }
  38. /*
  39. * Taken from openmoko-kernel mailing list: By Andy green
  40. * Optimized read file API : collects and defers contiguous sector
  41. * reads into one potentially more efficient larger sequential read action
  42. */
  43. int ext4fs_read_file(struct ext2fs_node *node, int pos,
  44. unsigned int len, char *buf)
  45. {
  46. struct ext_filesystem *fs = get_fs();
  47. int i;
  48. lbaint_t blockcnt;
  49. int log2blksz = fs->dev_desc->log2blksz;
  50. int log2_fs_blocksize = LOG2_BLOCK_SIZE(node->data) - log2blksz;
  51. int blocksize = (1 << (log2_fs_blocksize + log2blksz));
  52. unsigned int filesize = __le32_to_cpu(node->inode.size);
  53. lbaint_t previous_block_number = -1;
  54. lbaint_t delayed_start = 0;
  55. lbaint_t delayed_extent = 0;
  56. lbaint_t delayed_skipfirst = 0;
  57. lbaint_t delayed_next = 0;
  58. char *delayed_buf = NULL;
  59. short status;
  60. if (le32_to_cpu(node->inode.flags) & EXT4_EXTENTS_FL) {
  61. if (ext4fs_build_extent_cache(&node->inode)) {
  62. printf("Error building extent cache!\n");
  63. len = -1;
  64. goto out_exit;
  65. }
  66. }
  67. /* Adjust len so it we can't read past the end of the file. */
  68. if (len > filesize)
  69. len = filesize;
  70. blockcnt = ((len + pos) + blocksize - 1) / blocksize;
  71. for (i = pos / blocksize; i < blockcnt; i++) {
  72. lbaint_t blknr;
  73. int blockoff = pos % blocksize;
  74. int blockend = blocksize;
  75. int skipfirst = 0;
  76. blknr = read_allocated_block(&(node->inode), i);
  77. if (blknr < 0) {
  78. len = -1;
  79. goto out_exit;
  80. }
  81. blknr = blknr << log2_fs_blocksize;
  82. /* Last block. */
  83. if (i == blockcnt - 1) {
  84. blockend = (len + pos) % blocksize;
  85. /* The last portion is exactly blocksize. */
  86. if (!blockend)
  87. blockend = blocksize;
  88. }
  89. /* First block. */
  90. if (i == pos / blocksize) {
  91. skipfirst = blockoff;
  92. blockend -= skipfirst;
  93. }
  94. if (blknr) {
  95. int status;
  96. if (previous_block_number != -1) {
  97. if (delayed_next == blknr) {
  98. delayed_extent += blockend;
  99. delayed_next += blockend >> log2blksz;
  100. } else { /* spill */
  101. status = ext4fs_devread(delayed_start,
  102. delayed_skipfirst,
  103. delayed_extent,
  104. delayed_buf);
  105. if (status == 0) {
  106. len = -1;
  107. goto out_exit;
  108. }
  109. previous_block_number = blknr;
  110. delayed_start = blknr;
  111. delayed_extent = blockend;
  112. delayed_skipfirst = skipfirst;
  113. delayed_buf = buf;
  114. delayed_next = blknr +
  115. (blockend >> log2blksz);
  116. }
  117. } else {
  118. previous_block_number = blknr;
  119. delayed_start = blknr;
  120. delayed_extent = blockend;
  121. delayed_skipfirst = skipfirst;
  122. delayed_buf = buf;
  123. delayed_next = blknr +
  124. (blockend >> log2blksz);
  125. }
  126. } else {
  127. if (previous_block_number != -1) {
  128. /* spill */
  129. status = ext4fs_devread(delayed_start,
  130. delayed_skipfirst,
  131. delayed_extent,
  132. delayed_buf);
  133. if (status == 0) {
  134. len = -1;
  135. goto out_exit;
  136. }
  137. previous_block_number = -1;
  138. }
  139. memset(buf, 0, blocksize - skipfirst);
  140. }
  141. buf += blocksize - skipfirst;
  142. }
  143. if (previous_block_number != -1) {
  144. /* spill */
  145. status = ext4fs_devread(delayed_start,
  146. delayed_skipfirst, delayed_extent,
  147. delayed_buf);
  148. if (status == 0) {
  149. len = -1;
  150. goto out_exit;
  151. }
  152. previous_block_number = -1;
  153. }
  154. out_exit:
  155. ext4fs_free_extent_cache();
  156. return len;
  157. }
  158. int ext4fs_ls(const char *dirname)
  159. {
  160. struct ext2fs_node *dirnode;
  161. int status;
  162. if (dirname == NULL)
  163. return 0;
  164. status = ext4fs_find_file(dirname, &ext4fs_root->diropen, &dirnode,
  165. FILETYPE_DIRECTORY);
  166. if (status != 1) {
  167. printf("** Can not find directory. **\n");
  168. return 1;
  169. }
  170. ext4fs_iterate_dir(dirnode, NULL, NULL, NULL);
  171. ext4fs_free_node(dirnode, &ext4fs_root->diropen);
  172. return 0;
  173. }
  174. int ext4fs_exists(const char *filename)
  175. {
  176. int file_len;
  177. file_len = ext4fs_open(filename);
  178. return file_len >= 0;
  179. }
  180. int ext4fs_read(char *buf, unsigned len)
  181. {
  182. if (ext4fs_root == NULL || ext4fs_file == NULL)
  183. return 0;
  184. return ext4fs_read_file(ext4fs_file, 0, len, buf);
  185. }
  186. int ext4fs_probe(block_dev_desc_t *fs_dev_desc,
  187. disk_partition_t *fs_partition)
  188. {
  189. ext4fs_set_blk_dev(fs_dev_desc, fs_partition);
  190. if (!ext4fs_mount(fs_partition->size)) {
  191. ext4fs_close();
  192. return -1;
  193. }
  194. return 0;
  195. }
  196. int ext4_read_file(const char *filename, void *buf, int offset, int len)
  197. {
  198. int file_len;
  199. int len_read;
  200. if (offset != 0) {
  201. printf("** Cannot support non-zero offset **\n");
  202. return -1;
  203. }
  204. file_len = ext4fs_open(filename);
  205. if (file_len < 0) {
  206. printf("** File not found %s **\n", filename);
  207. return -1;
  208. }
  209. if (len == 0)
  210. len = file_len;
  211. len_read = ext4fs_read(buf, len);
  212. return len_read;
  213. }