ext4fs.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  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. * This program is free software; you can redistribute it and/or modify
  22. * it under the terms of the GNU General Public License as published by
  23. * the Free Software Foundation; either version 2 of the License, or
  24. * (at your option) any later version.
  25. *
  26. * This program is distributed in the hope that it will be useful,
  27. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  28. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  29. * GNU General Public License for more details.
  30. *
  31. * You should have received a copy of the GNU General Public License
  32. * along with this program; if not, write to the Free Software
  33. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  34. */
  35. #include <common.h>
  36. #include <ext_common.h>
  37. #include <ext4fs.h>
  38. #include "ext4_common.h"
  39. int ext4fs_symlinknest;
  40. struct ext_filesystem ext_fs;
  41. struct ext_filesystem *get_fs(void)
  42. {
  43. return &ext_fs;
  44. }
  45. void ext4fs_free_node(struct ext2fs_node *node, struct ext2fs_node *currroot)
  46. {
  47. if ((node != &ext4fs_root->diropen) && (node != currroot))
  48. free(node);
  49. }
  50. /*
  51. * Taken from openmoko-kernel mailing list: By Andy green
  52. * Optimized read file API : collects and defers contiguous sector
  53. * reads into one potentially more efficient larger sequential read action
  54. */
  55. int ext4fs_read_file(struct ext2fs_node *node, int pos,
  56. unsigned int len, char *buf)
  57. {
  58. struct ext_filesystem *fs = get_fs();
  59. int i;
  60. int blockcnt;
  61. int log2blksz = fs->dev_desc->log2blksz;
  62. int log2_fs_blocksize = LOG2_BLOCK_SIZE(node->data) - log2blksz;
  63. int blocksize = (1 << (log2_fs_blocksize + log2blksz));
  64. unsigned int filesize = __le32_to_cpu(node->inode.size);
  65. int previous_block_number = -1;
  66. int delayed_start = 0;
  67. int delayed_extent = 0;
  68. int delayed_skipfirst = 0;
  69. int delayed_next = 0;
  70. char *delayed_buf = NULL;
  71. short status;
  72. /* Adjust len so it we can't read past the end of the file. */
  73. if (len > filesize)
  74. len = filesize;
  75. blockcnt = ((len + pos) + blocksize - 1) / blocksize;
  76. for (i = pos / blocksize; i < blockcnt; i++) {
  77. int blknr;
  78. int blockoff = pos % blocksize;
  79. int blockend = blocksize;
  80. int skipfirst = 0;
  81. blknr = read_allocated_block(&(node->inode), i);
  82. if (blknr < 0)
  83. return -1;
  84. blknr = blknr << log2_fs_blocksize;
  85. /* Last block. */
  86. if (i == blockcnt - 1) {
  87. blockend = (len + pos) % blocksize;
  88. /* The last portion is exactly blocksize. */
  89. if (!blockend)
  90. blockend = blocksize;
  91. }
  92. /* First block. */
  93. if (i == pos / blocksize) {
  94. skipfirst = blockoff;
  95. blockend -= skipfirst;
  96. }
  97. if (blknr) {
  98. int status;
  99. if (previous_block_number != -1) {
  100. if (delayed_next == blknr) {
  101. delayed_extent += blockend;
  102. delayed_next += blockend >> log2blksz;
  103. } else { /* spill */
  104. status = ext4fs_devread(delayed_start,
  105. delayed_skipfirst,
  106. delayed_extent,
  107. delayed_buf);
  108. if (status == 0)
  109. return -1;
  110. previous_block_number = blknr;
  111. delayed_start = blknr;
  112. delayed_extent = blockend;
  113. delayed_skipfirst = skipfirst;
  114. delayed_buf = buf;
  115. delayed_next = blknr +
  116. (blockend >> log2blksz);
  117. }
  118. } else {
  119. previous_block_number = blknr;
  120. delayed_start = blknr;
  121. delayed_extent = blockend;
  122. delayed_skipfirst = skipfirst;
  123. delayed_buf = buf;
  124. delayed_next = blknr +
  125. (blockend >> log2blksz);
  126. }
  127. } else {
  128. if (previous_block_number != -1) {
  129. /* spill */
  130. status = ext4fs_devread(delayed_start,
  131. delayed_skipfirst,
  132. delayed_extent,
  133. delayed_buf);
  134. if (status == 0)
  135. return -1;
  136. previous_block_number = -1;
  137. }
  138. memset(buf, 0, blocksize - skipfirst);
  139. }
  140. buf += blocksize - skipfirst;
  141. }
  142. if (previous_block_number != -1) {
  143. /* spill */
  144. status = ext4fs_devread(delayed_start,
  145. delayed_skipfirst, delayed_extent,
  146. delayed_buf);
  147. if (status == 0)
  148. return -1;
  149. previous_block_number = -1;
  150. }
  151. return len;
  152. }
  153. int ext4fs_ls(const char *dirname)
  154. {
  155. struct ext2fs_node *dirnode;
  156. int status;
  157. if (dirname == NULL)
  158. return 0;
  159. status = ext4fs_find_file(dirname, &ext4fs_root->diropen, &dirnode,
  160. FILETYPE_DIRECTORY);
  161. if (status != 1) {
  162. printf("** Can not find directory. **\n");
  163. return 1;
  164. }
  165. ext4fs_iterate_dir(dirnode, NULL, NULL, NULL);
  166. ext4fs_free_node(dirnode, &ext4fs_root->diropen);
  167. return 0;
  168. }
  169. int ext4fs_read(char *buf, unsigned len)
  170. {
  171. if (ext4fs_root == NULL || ext4fs_file == NULL)
  172. return 0;
  173. return ext4fs_read_file(ext4fs_file, 0, len, buf);
  174. }
  175. int ext4fs_probe(block_dev_desc_t *fs_dev_desc,
  176. disk_partition_t *fs_partition)
  177. {
  178. ext4fs_set_blk_dev(fs_dev_desc, fs_partition);
  179. if (!ext4fs_mount(fs_partition->size)) {
  180. ext4fs_close();
  181. return -1;
  182. }
  183. return 0;
  184. }
  185. int ext4_read_file(const char *filename, void *buf, int offset, int len)
  186. {
  187. int file_len;
  188. int len_read;
  189. if (offset != 0) {
  190. printf("** Cannot support non-zero offset **\n");
  191. return -1;
  192. }
  193. file_len = ext4fs_open(filename);
  194. if (file_len < 0) {
  195. printf("** File not found %s **\n", filename);
  196. return -1;
  197. }
  198. if (len == 0)
  199. len = file_len;
  200. len_read = ext4fs_read(buf, len);
  201. return len_read;
  202. }