]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - fs/ext4/ext4fs.c
Merge branch 'u-boot-samsung/master' into 'u-boot-arm/master'
[karo-tx-uboot.git] / fs / ext4 / ext4fs.c
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
36 #include <common.h>
37 #include <ext_common.h>
38 #include <ext4fs.h>
39 #include "ext4_common.h"
40
41 int ext4fs_symlinknest;
42 struct ext_filesystem ext_fs;
43
44 struct ext_filesystem *get_fs(void)
45 {
46         return &ext_fs;
47 }
48
49 void ext4fs_free_node(struct ext2fs_node *node, struct ext2fs_node *currroot)
50 {
51         if ((node != &ext4fs_root->diropen) && (node != currroot))
52                 free(node);
53 }
54
55 /*
56  * Taken from openmoko-kernel mailing list: By Andy green
57  * Optimized read file API : collects and defers contiguous sector
58  * reads into one potentially more efficient larger sequential read action
59  */
60 int ext4fs_read_file(struct ext2fs_node *node, int pos,
61                 unsigned int len, char *buf)
62 {
63         int i;
64         int blockcnt;
65         int log2blocksize = LOG2_EXT2_BLOCK_SIZE(node->data);
66         int blocksize = 1 << (log2blocksize + DISK_SECTOR_BITS);
67         unsigned int filesize = __le32_to_cpu(node->inode.size);
68         int previous_block_number = -1;
69         int delayed_start = 0;
70         int delayed_extent = 0;
71         int delayed_skipfirst = 0;
72         int delayed_next = 0;
73         char *delayed_buf = NULL;
74         short status;
75
76         /* Adjust len so it we can't read past the end of the file. */
77         if (len > filesize)
78                 len = filesize;
79
80         blockcnt = ((len + pos) + blocksize - 1) / blocksize;
81
82         for (i = pos / blocksize; i < blockcnt; i++) {
83                 int blknr;
84                 int blockoff = pos % blocksize;
85                 int blockend = blocksize;
86                 int skipfirst = 0;
87                 blknr = read_allocated_block(&(node->inode), i);
88                 if (blknr < 0)
89                         return -1;
90
91                 blknr = blknr << log2blocksize;
92
93                 /* Last block.  */
94                 if (i == blockcnt - 1) {
95                         blockend = (len + pos) % blocksize;
96
97                         /* The last portion is exactly blocksize. */
98                         if (!blockend)
99                                 blockend = blocksize;
100                 }
101
102                 /* First block. */
103                 if (i == pos / blocksize) {
104                         skipfirst = blockoff;
105                         blockend -= skipfirst;
106                 }
107                 if (blknr) {
108                         int status;
109
110                         if (previous_block_number != -1) {
111                                 if (delayed_next == blknr) {
112                                         delayed_extent += blockend;
113                                         delayed_next += blockend >> SECTOR_BITS;
114                                 } else {        /* spill */
115                                         status = ext4fs_devread(delayed_start,
116                                                         delayed_skipfirst,
117                                                         delayed_extent,
118                                                         delayed_buf);
119                                         if (status == 0)
120                                                 return -1;
121                                         previous_block_number = blknr;
122                                         delayed_start = blknr;
123                                         delayed_extent = blockend;
124                                         delayed_skipfirst = skipfirst;
125                                         delayed_buf = buf;
126                                         delayed_next = blknr +
127                                                 (blockend >> SECTOR_BITS);
128                                 }
129                         } else {
130                                 previous_block_number = blknr;
131                                 delayed_start = blknr;
132                                 delayed_extent = blockend;
133                                 delayed_skipfirst = skipfirst;
134                                 delayed_buf = buf;
135                                 delayed_next = blknr +
136                                         (blockend >> SECTOR_BITS);
137                         }
138                 } else {
139                         if (previous_block_number != -1) {
140                                 /* spill */
141                                 status = ext4fs_devread(delayed_start,
142                                                         delayed_skipfirst,
143                                                         delayed_extent,
144                                                         delayed_buf);
145                                 if (status == 0)
146                                         return -1;
147                                 previous_block_number = -1;
148                         }
149                         memset(buf, 0, blocksize - skipfirst);
150                 }
151                 buf += blocksize - skipfirst;
152         }
153         if (previous_block_number != -1) {
154                 /* spill */
155                 status = ext4fs_devread(delayed_start,
156                                         delayed_skipfirst, delayed_extent,
157                                         delayed_buf);
158                 if (status == 0)
159                         return -1;
160                 previous_block_number = -1;
161         }
162
163         return len;
164 }
165
166 int ext4fs_ls(const char *dirname)
167 {
168         struct ext2fs_node *dirnode;
169         int status;
170
171         if (dirname == NULL)
172                 return 0;
173
174         status = ext4fs_find_file(dirname, &ext4fs_root->diropen, &dirnode,
175                                   FILETYPE_DIRECTORY);
176         if (status != 1) {
177                 printf("** Can not find directory. **\n");
178                 return 1;
179         }
180
181         ext4fs_iterate_dir(dirnode, NULL, NULL, NULL);
182         ext4fs_free_node(dirnode, &ext4fs_root->diropen);
183
184         return 0;
185 }
186
187 int ext4fs_read(char *buf, unsigned len)
188 {
189         if (ext4fs_root == NULL || ext4fs_file == NULL)
190                 return 0;
191
192         return ext4fs_read_file(ext4fs_file, 0, len, buf);
193 }
194
195 int ext4fs_probe(block_dev_desc_t *fs_dev_desc,
196                  disk_partition_t *fs_partition)
197 {
198         ext4fs_set_blk_dev(fs_dev_desc, fs_partition);
199
200         if (!ext4fs_mount(fs_partition->size)) {
201                 ext4fs_close();
202                 return -1;
203         }
204
205         return 0;
206 }
207
208 int ext4_read_file(const char *filename, void *buf, int offset, int len)
209 {
210         int file_len;
211         int len_read;
212
213         if (offset != 0) {
214                 printf("** Cannot support non-zero offset **\n");
215                 return -1;
216         }
217
218         file_len = ext4fs_open(filename);
219         if (file_len < 0) {
220                 printf("** File not found %s **\n", filename);
221                 return -1;
222         }
223
224         if (len == 0)
225                 len = file_len;
226
227         len_read = ext4fs_read(buf, len);
228
229         return len_read;
230 }