ext4fs.c 5.6 KB

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