"Das U-Boot" Source Tree
1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * (C) Copyright 2011 - 2012 Samsung Electronics
4 * EXT4 filesystem implementation in Uboot by
5 * Uma Shankar <uma.shankar@samsung.com>
6 * Manjunatha C Achar <a.manjunatha@samsung.com>
7 *
8 * ext4ls and ext4load : Based on ext2 ls and load support in Uboot.
9 * Ext4 read optimization taken from Open-Moko
10 * Qi bootloader
11 *
12 * (C) Copyright 2004
13 * esd gmbh <www.esd-electronics.com>
14 * Reinhard Arlt <reinhard.arlt@esd-electronics.com>
15 *
16 * based on code from grub2 fs/ext2.c and fs/fshelp.c by
17 * GRUB -- GRand Unified Bootloader
18 * Copyright (C) 2003, 2004 Free Software Foundation, Inc.
19 *
20 * ext4write : Based on generic ext4 protocol.
21 */
22
23#include <blk.h>
24#include <log.h>
25#include <malloc.h>
26#include <memalign.h>
27#include <part.h>
28#include <linux/stat.h>
29#include <div64.h>
30#include "ext4_common.h"
31
32static inline void ext4fs_sb_free_inodes_inc(struct ext2_sblock *sb)
33{
34 sb->free_inodes = cpu_to_le32(le32_to_cpu(sb->free_inodes) + 1);
35}
36
37static inline void ext4fs_sb_free_blocks_inc(struct ext2_sblock *sb)
38{
39 sb->free_blocks = cpu_to_le32(le32_to_cpu(sb->free_blocks) + 1);
40}
41
42static inline void ext4fs_bg_free_inodes_inc
43 (struct ext2_block_group *bg, const struct ext_filesystem *fs)
44{
45 uint32_t free_inodes = le16_to_cpu(bg->free_inodes);
46 if (fs->gdsize == 64)
47 free_inodes += le16_to_cpu(bg->free_inodes_high) << 16;
48 free_inodes++;
49
50 bg->free_inodes = cpu_to_le16(free_inodes & 0xffff);
51 if (fs->gdsize == 64)
52 bg->free_inodes_high = cpu_to_le16(free_inodes >> 16);
53}
54
55static inline void ext4fs_bg_free_blocks_inc
56 (struct ext2_block_group *bg, const struct ext_filesystem *fs)
57{
58 uint32_t free_blocks = le16_to_cpu(bg->free_blocks);
59 if (fs->gdsize == 64)
60 free_blocks += le16_to_cpu(bg->free_blocks_high) << 16;
61 free_blocks++;
62
63 bg->free_blocks = cpu_to_le16(free_blocks & 0xffff);
64 if (fs->gdsize == 64)
65 bg->free_blocks_high = cpu_to_le16(free_blocks >> 16);
66}
67
68static void ext4fs_update(void)
69{
70 short i;
71 ext4fs_update_journal();
72 struct ext_filesystem *fs = get_fs();
73 struct ext2_block_group *bgd = NULL;
74
75 /* update super block */
76 put_ext4((uint64_t)(SUPERBLOCK_SIZE),
77 (struct ext2_sblock *)fs->sb, (uint32_t)SUPERBLOCK_SIZE);
78
79 /* update block bitmaps */
80 for (i = 0; i < fs->no_blkgrp; i++) {
81 bgd = ext4fs_get_group_descriptor(fs, i);
82 bgd->bg_checksum = cpu_to_le16(ext4fs_checksum_update(i));
83 uint64_t b_bitmap_blk = ext4fs_bg_get_block_id(bgd, fs);
84 put_ext4(b_bitmap_blk * fs->blksz,
85 fs->blk_bmaps[i], fs->blksz);
86 }
87
88 /* update inode bitmaps */
89 for (i = 0; i < fs->no_blkgrp; i++) {
90 bgd = ext4fs_get_group_descriptor(fs, i);
91 uint64_t i_bitmap_blk = ext4fs_bg_get_inode_id(bgd, fs);
92 put_ext4(i_bitmap_blk * fs->blksz,
93 fs->inode_bmaps[i], fs->blksz);
94 }
95
96 /* update the block group descriptor table */
97 put_ext4((uint64_t)((uint64_t)fs->gdtable_blkno * (uint64_t)fs->blksz),
98 (struct ext2_block_group *)fs->gdtable,
99 (fs->blksz * fs->no_blk_pergdt));
100
101 ext4fs_dump_metadata();
102
103 gindex = 0;
104 gd_index = 0;
105}
106
107int ext4fs_get_bgdtable(void)
108{
109 int status;
110 struct ext_filesystem *fs = get_fs();
111 int gdsize_total = ROUND(fs->no_blkgrp * fs->gdsize, fs->blksz);
112 fs->no_blk_pergdt = gdsize_total / fs->blksz;
113
114 /* allocate memory for gdtable */
115 fs->gdtable = zalloc(gdsize_total);
116 if (!fs->gdtable)
117 return -ENOMEM;
118 /* read the group descriptor table */
119 status = ext4fs_devread((lbaint_t)fs->gdtable_blkno * fs->sect_perblk,
120 0, fs->blksz * fs->no_blk_pergdt, fs->gdtable);
121 if (status == 0)
122 goto fail;
123
124 if (ext4fs_log_gdt(fs->gdtable)) {
125 printf("Error in ext4fs_log_gdt\n");
126 return -1;
127 }
128
129 return 0;
130fail:
131 free(fs->gdtable);
132 fs->gdtable = NULL;
133
134 return -1;
135}
136
137static void delete_single_indirect_block(struct ext2_inode *inode)
138{
139 struct ext2_block_group *bgd = NULL;
140 static int prev_bg_bmap_idx = -1;
141 uint32_t blknr;
142 int remainder;
143 int bg_idx;
144 int status;
145 uint32_t blk_per_grp = le32_to_cpu(ext4fs_root->sblock.blocks_per_group);
146 struct ext_filesystem *fs = get_fs();
147 char *journal_buffer = zalloc(fs->blksz);
148 if (!journal_buffer) {
149 printf("No memory\n");
150 return;
151 }
152
153 /* deleting the single indirect block associated with inode */
154 if (inode->b.blocks.indir_block != 0) {
155 blknr = le32_to_cpu(inode->b.blocks.indir_block);
156 debug("SIPB releasing %u\n", blknr);
157 bg_idx = blknr / blk_per_grp;
158 if (fs->blksz == 1024) {
159 remainder = blknr % blk_per_grp;
160 if (!remainder)
161 bg_idx--;
162 }
163 ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], bg_idx);
164 /* get block group descriptor table */
165 bgd = ext4fs_get_group_descriptor(fs, bg_idx);
166 ext4fs_bg_free_blocks_inc(bgd, fs);
167 ext4fs_sb_free_blocks_inc(fs->sb);
168 /* journal backup */
169 if (prev_bg_bmap_idx != bg_idx) {
170 uint64_t b_bitmap_blk = ext4fs_bg_get_block_id(bgd, fs);
171 status = ext4fs_devread(
172 b_bitmap_blk * fs->sect_perblk,
173 0, fs->blksz, journal_buffer);
174 if (status == 0)
175 goto fail;
176 if (ext4fs_log_journal(journal_buffer, b_bitmap_blk))
177 goto fail;
178 prev_bg_bmap_idx = bg_idx;
179 }
180 }
181fail:
182 free(journal_buffer);
183}
184
185static void delete_double_indirect_block(struct ext2_inode *inode)
186{
187 int i;
188 short status;
189 static int prev_bg_bmap_idx = -1;
190 uint32_t blknr;
191 int remainder;
192 int bg_idx;
193 uint32_t blk_per_grp = le32_to_cpu(ext4fs_root->sblock.blocks_per_group);
194 __le32 *di_buffer = NULL;
195 void *dib_start_addr = NULL;
196 struct ext2_block_group *bgd = NULL;
197 struct ext_filesystem *fs = get_fs();
198 char *journal_buffer = zalloc(fs->blksz);
199 if (!journal_buffer) {
200 printf("No memory\n");
201 return;
202 }
203
204 if (inode->b.blocks.double_indir_block != 0) {
205 di_buffer = zalloc(fs->blksz);
206 if (!di_buffer) {
207 printf("No memory\n");
208 return;
209 }
210 dib_start_addr = di_buffer;
211 blknr = le32_to_cpu(inode->b.blocks.double_indir_block);
212 status = ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0,
213 fs->blksz, (char *)di_buffer);
214 for (i = 0; i < fs->blksz / sizeof(int); i++) {
215 if (*di_buffer == 0)
216 break;
217
218 debug("DICB releasing %u\n", *di_buffer);
219 bg_idx = le32_to_cpu(*di_buffer) / blk_per_grp;
220 if (fs->blksz == 1024) {
221 remainder = le32_to_cpu(*di_buffer) % blk_per_grp;
222 if (!remainder)
223 bg_idx--;
224 }
225 /* get block group descriptor table */
226 bgd = ext4fs_get_group_descriptor(fs, bg_idx);
227 ext4fs_reset_block_bmap(le32_to_cpu(*di_buffer),
228 fs->blk_bmaps[bg_idx], bg_idx);
229 di_buffer++;
230 ext4fs_bg_free_blocks_inc(bgd, fs);
231 ext4fs_sb_free_blocks_inc(fs->sb);
232 /* journal backup */
233 if (prev_bg_bmap_idx != bg_idx) {
234 uint64_t b_bitmap_blk =
235 ext4fs_bg_get_block_id(bgd, fs);
236 status = ext4fs_devread(b_bitmap_blk
237 * fs->sect_perblk, 0,
238 fs->blksz,
239 journal_buffer);
240 if (status == 0)
241 goto fail;
242
243 if (ext4fs_log_journal(journal_buffer,
244 b_bitmap_blk))
245 goto fail;
246 prev_bg_bmap_idx = bg_idx;
247 }
248 }
249
250 /* removing the parent double indirect block */
251 blknr = le32_to_cpu(inode->b.blocks.double_indir_block);
252 bg_idx = blknr / blk_per_grp;
253 if (fs->blksz == 1024) {
254 remainder = blknr % blk_per_grp;
255 if (!remainder)
256 bg_idx--;
257 }
258 /* get block group descriptor table */
259 bgd = ext4fs_get_group_descriptor(fs, bg_idx);
260 ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], bg_idx);
261 ext4fs_bg_free_blocks_inc(bgd, fs);
262 ext4fs_sb_free_blocks_inc(fs->sb);
263 /* journal backup */
264 if (prev_bg_bmap_idx != bg_idx) {
265 uint64_t b_bitmap_blk = ext4fs_bg_get_block_id(bgd, fs);
266 status = ext4fs_devread(b_bitmap_blk * fs->sect_perblk,
267 0, fs->blksz, journal_buffer);
268 if (status == 0)
269 goto fail;
270
271 if (ext4fs_log_journal(journal_buffer, b_bitmap_blk))
272 goto fail;
273 prev_bg_bmap_idx = bg_idx;
274 }
275 debug("DIPB releasing %d\n", blknr);
276 }
277fail:
278 free(dib_start_addr);
279 free(journal_buffer);
280}
281
282static void delete_triple_indirect_block(struct ext2_inode *inode)
283{
284 int i, j;
285 short status;
286 static int prev_bg_bmap_idx = -1;
287 uint32_t blknr;
288 int remainder;
289 int bg_idx;
290 uint32_t blk_per_grp = le32_to_cpu(ext4fs_root->sblock.blocks_per_group);
291 __le32 *tigp_buffer = NULL;
292 void *tib_start_addr = NULL;
293 __le32 *tip_buffer = NULL;
294 void *tipb_start_addr = NULL;
295 struct ext2_block_group *bgd = NULL;
296 struct ext_filesystem *fs = get_fs();
297 char *journal_buffer = zalloc(fs->blksz);
298 if (!journal_buffer) {
299 printf("No memory\n");
300 return;
301 }
302
303 if (inode->b.blocks.triple_indir_block != 0) {
304 tigp_buffer = zalloc(fs->blksz);
305 if (!tigp_buffer) {
306 printf("No memory\n");
307 return;
308 }
309 tib_start_addr = tigp_buffer;
310 blknr = le32_to_cpu(inode->b.blocks.triple_indir_block);
311 status = ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0,
312 fs->blksz, (char *)tigp_buffer);
313 for (i = 0; i < fs->blksz / sizeof(int); i++) {
314 if (*tigp_buffer == 0)
315 break;
316 debug("tigp buffer releasing %u\n", *tigp_buffer);
317
318 tip_buffer = zalloc(fs->blksz);
319 if (!tip_buffer)
320 goto fail;
321 tipb_start_addr = tip_buffer;
322 status = ext4fs_devread((lbaint_t)le32_to_cpu(*tigp_buffer) *
323 fs->sect_perblk, 0, fs->blksz,
324 (char *)tip_buffer);
325 for (j = 0; j < fs->blksz / sizeof(int); j++) {
326 if (le32_to_cpu(*tip_buffer) == 0)
327 break;
328 bg_idx = le32_to_cpu(*tip_buffer) / blk_per_grp;
329 if (fs->blksz == 1024) {
330 remainder = le32_to_cpu(*tip_buffer) % blk_per_grp;
331 if (!remainder)
332 bg_idx--;
333 }
334
335 ext4fs_reset_block_bmap(le32_to_cpu(*tip_buffer),
336 fs->blk_bmaps[bg_idx],
337 bg_idx);
338
339 tip_buffer++;
340 /* get block group descriptor table */
341 bgd = ext4fs_get_group_descriptor(fs, bg_idx);
342 ext4fs_bg_free_blocks_inc(bgd, fs);
343 ext4fs_sb_free_blocks_inc(fs->sb);
344 /* journal backup */
345 if (prev_bg_bmap_idx != bg_idx) {
346 uint64_t b_bitmap_blk =
347 ext4fs_bg_get_block_id(bgd, fs);
348 status =
349 ext4fs_devread(
350 b_bitmap_blk *
351 fs->sect_perblk, 0,
352 fs->blksz,
353 journal_buffer);
354 if (status == 0)
355 goto fail;
356
357 if (ext4fs_log_journal(journal_buffer,
358 b_bitmap_blk))
359 goto fail;
360 prev_bg_bmap_idx = bg_idx;
361 }
362 }
363 free(tipb_start_addr);
364 tipb_start_addr = NULL;
365
366 /*
367 * removing the grand parent blocks
368 * which is connected to inode
369 */
370 bg_idx = le32_to_cpu(*tigp_buffer) / blk_per_grp;
371 if (fs->blksz == 1024) {
372 remainder = le32_to_cpu(*tigp_buffer) % blk_per_grp;
373 if (!remainder)
374 bg_idx--;
375 }
376 ext4fs_reset_block_bmap(le32_to_cpu(*tigp_buffer),
377 fs->blk_bmaps[bg_idx], bg_idx);
378
379 tigp_buffer++;
380 /* get block group descriptor table */
381 bgd = ext4fs_get_group_descriptor(fs, bg_idx);
382 ext4fs_bg_free_blocks_inc(bgd, fs);
383 ext4fs_sb_free_blocks_inc(fs->sb);
384 /* journal backup */
385 if (prev_bg_bmap_idx != bg_idx) {
386 uint64_t b_bitmap_blk =
387 ext4fs_bg_get_block_id(bgd, fs);
388 memset(journal_buffer, '\0', fs->blksz);
389 status = ext4fs_devread(b_bitmap_blk *
390 fs->sect_perblk, 0,
391 fs->blksz,
392 journal_buffer);
393 if (status == 0)
394 goto fail;
395
396 if (ext4fs_log_journal(journal_buffer,
397 b_bitmap_blk))
398 goto fail;
399 prev_bg_bmap_idx = bg_idx;
400 }
401 }
402
403 /* removing the grand parent triple indirect block */
404 blknr = le32_to_cpu(inode->b.blocks.triple_indir_block);
405 bg_idx = blknr / blk_per_grp;
406 if (fs->blksz == 1024) {
407 remainder = blknr % blk_per_grp;
408 if (!remainder)
409 bg_idx--;
410 }
411 ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], bg_idx);
412 /* get block group descriptor table */
413 bgd = ext4fs_get_group_descriptor(fs, bg_idx);
414 ext4fs_bg_free_blocks_inc(bgd, fs);
415 ext4fs_sb_free_blocks_inc(fs->sb);
416 /* journal backup */
417 if (prev_bg_bmap_idx != bg_idx) {
418 uint64_t b_bitmap_blk = ext4fs_bg_get_block_id(bgd, fs);
419 status = ext4fs_devread(b_bitmap_blk * fs->sect_perblk,
420 0, fs->blksz, journal_buffer);
421 if (status == 0)
422 goto fail;
423
424 if (ext4fs_log_journal(journal_buffer, b_bitmap_blk))
425 goto fail;
426 prev_bg_bmap_idx = bg_idx;
427 }
428 debug("tigp buffer itself releasing %d\n", blknr);
429 }
430fail:
431 free(tib_start_addr);
432 free(tipb_start_addr);
433 free(journal_buffer);
434}
435
436static int ext4fs_delete_file(int inodeno)
437{
438 struct ext2_inode inode;
439 short status;
440 int i;
441 int remainder;
442 long int blknr;
443 int bg_idx;
444 int ibmap_idx;
445 char *read_buffer = NULL;
446 char *start_block_address = NULL;
447 uint32_t no_blocks;
448
449 static int prev_bg_bmap_idx = -1;
450 unsigned int inodes_per_block;
451 uint32_t blkno;
452 unsigned int blkoff;
453 uint32_t blk_per_grp = le32_to_cpu(ext4fs_root->sblock.blocks_per_group);
454 uint32_t inode_per_grp = le32_to_cpu(ext4fs_root->sblock.inodes_per_group);
455 struct ext2_inode *inode_buffer = NULL;
456 struct ext2_block_group *bgd = NULL;
457 struct ext_filesystem *fs = get_fs();
458 char *journal_buffer = zalloc(fs->blksz);
459 if (!journal_buffer)
460 return -ENOMEM;
461 status = ext4fs_read_inode(ext4fs_root, inodeno, &inode);
462 if (status == 0)
463 goto fail;
464
465 /* read the block no allocated to a file */
466 no_blocks = le32_to_cpu(inode.size) / fs->blksz;
467 if (le32_to_cpu(inode.size) % fs->blksz)
468 no_blocks++;
469
470 /*
471 * special case for symlinks whose target are small enough that
472 *it fits in struct ext2_inode.b.symlink: no block had been allocated
473 */
474 if (S_ISLNK(le16_to_cpu(inode.mode)) &&
475 le32_to_cpu(inode.size) <= sizeof(inode.b.symlink)) {
476 no_blocks = 0;
477 }
478
479 if (le32_to_cpu(inode.flags) & EXT4_EXTENTS_FL) {
480 /* FIXME delete extent index blocks, i.e. eh_depth >= 1 */
481 struct ext4_extent_header *eh =
482 (struct ext4_extent_header *)
483 inode.b.blocks.dir_blocks;
484 debug("del: dep=%d entries=%d\n", eh->eh_depth, eh->eh_entries);
485 } else {
486 delete_single_indirect_block(&inode);
487 delete_double_indirect_block(&inode);
488 delete_triple_indirect_block(&inode);
489 }
490
491 /* release data blocks */
492 for (i = 0; i < no_blocks; i++) {
493 blknr = read_allocated_block(&inode, i, NULL);
494 if (blknr == 0)
495 continue;
496 if (blknr < 0)
497 goto fail;
498 bg_idx = blknr / blk_per_grp;
499 if (fs->blksz == 1024) {
500 remainder = blknr % blk_per_grp;
501 if (!remainder)
502 bg_idx--;
503 }
504 ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx],
505 bg_idx);
506 debug("EXT4 Block releasing %ld: %d\n", blknr, bg_idx);
507
508 /* get block group descriptor table */
509 bgd = ext4fs_get_group_descriptor(fs, bg_idx);
510 ext4fs_bg_free_blocks_inc(bgd, fs);
511 ext4fs_sb_free_blocks_inc(fs->sb);
512 /* journal backup */
513 if (prev_bg_bmap_idx != bg_idx) {
514 uint64_t b_bitmap_blk = ext4fs_bg_get_block_id(bgd, fs);
515 status = ext4fs_devread(b_bitmap_blk * fs->sect_perblk,
516 0, fs->blksz,
517 journal_buffer);
518 if (status == 0)
519 goto fail;
520 if (ext4fs_log_journal(journal_buffer, b_bitmap_blk))
521 goto fail;
522 prev_bg_bmap_idx = bg_idx;
523 }
524 }
525
526 /* release inode */
527 /* from the inode no to blockno */
528 inodes_per_block = fs->blksz / fs->inodesz;
529 ibmap_idx = inodeno / inode_per_grp;
530
531 /* get the block no */
532 inodeno--;
533 /* get block group descriptor table */
534 bgd = ext4fs_get_group_descriptor(fs, ibmap_idx);
535 blkno = ext4fs_bg_get_inode_table_id(bgd, fs) +
536 (inodeno % inode_per_grp) / inodes_per_block;
537
538 /* get the offset of the inode */
539 blkoff = ((inodeno) % inodes_per_block) * fs->inodesz;
540
541 /* read the block no containing the inode */
542 read_buffer = zalloc(fs->blksz);
543 if (!read_buffer)
544 goto fail;
545 start_block_address = read_buffer;
546 status = ext4fs_devread((lbaint_t)blkno * fs->sect_perblk,
547 0, fs->blksz, read_buffer);
548 if (status == 0)
549 goto fail;
550
551 if (ext4fs_log_journal(read_buffer, blkno))
552 goto fail;
553
554 read_buffer = read_buffer + blkoff;
555 inode_buffer = (struct ext2_inode *)read_buffer;
556 memset(inode_buffer, '\0', fs->inodesz);
557
558 /* write the inode to original position in inode table */
559 if (ext4fs_put_metadata(start_block_address, blkno))
560 goto fail;
561
562 /* update the respective inode bitmaps */
563 inodeno++;
564 ext4fs_reset_inode_bmap(inodeno, fs->inode_bmaps[ibmap_idx], ibmap_idx);
565 ext4fs_bg_free_inodes_inc(bgd, fs);
566 ext4fs_sb_free_inodes_inc(fs->sb);
567 /* journal backup */
568 memset(journal_buffer, '\0', fs->blksz);
569 status = ext4fs_devread(ext4fs_bg_get_inode_id(bgd, fs) *
570 fs->sect_perblk, 0, fs->blksz, journal_buffer);
571 if (status == 0)
572 goto fail;
573 if (ext4fs_log_journal(journal_buffer, ext4fs_bg_get_inode_id(bgd, fs)))
574 goto fail;
575
576 ext4fs_update();
577 ext4fs_deinit();
578 ext4fs_reinit_global();
579
580 if (ext4fs_init() != 0) {
581 printf("error in File System init\n");
582 goto fail;
583 }
584
585 free(start_block_address);
586 free(journal_buffer);
587
588 return 0;
589fail:
590 free(start_block_address);
591 free(journal_buffer);
592
593 return -1;
594}
595
596int ext4fs_init(void)
597{
598 short status;
599 int i;
600 uint32_t real_free_blocks = 0;
601 struct ext_filesystem *fs = get_fs();
602
603 /* populate fs */
604 fs->blksz = EXT2_BLOCK_SIZE(ext4fs_root);
605 fs->sect_perblk = fs->blksz >> fs->dev_desc->log2blksz;
606
607 /* get the superblock */
608 fs->sb = zalloc(SUPERBLOCK_SIZE);
609 if (!fs->sb)
610 return -ENOMEM;
611 if (!ext4_read_superblock((char *)fs->sb))
612 goto fail;
613
614 /* init journal */
615 if (ext4fs_init_journal())
616 goto fail;
617
618 /* get total no of blockgroups */
619 fs->no_blkgrp = (uint32_t)ext4fs_div_roundup(
620 le32_to_cpu(ext4fs_root->sblock.total_blocks)
621 - le32_to_cpu(ext4fs_root->sblock.first_data_block),
622 le32_to_cpu(ext4fs_root->sblock.blocks_per_group));
623
624 /* get the block group descriptor table */
625 fs->gdtable_blkno = ((EXT2_MIN_BLOCK_SIZE == fs->blksz) + 1);
626 if (ext4fs_get_bgdtable() == -1) {
627 printf("Error in getting the block group descriptor table\n");
628 goto fail;
629 }
630
631 /* load all the available bitmap block of the partition */
632 fs->blk_bmaps = zalloc(fs->no_blkgrp * sizeof(char *));
633 if (!fs->blk_bmaps)
634 goto fail;
635 for (i = 0; i < fs->no_blkgrp; i++) {
636 fs->blk_bmaps[i] = zalloc(fs->blksz);
637 if (!fs->blk_bmaps[i])
638 goto fail;
639 }
640
641 for (i = 0; i < fs->no_blkgrp; i++) {
642 struct ext2_block_group *bgd =
643 ext4fs_get_group_descriptor(fs, i);
644 status = ext4fs_devread(ext4fs_bg_get_block_id(bgd, fs) *
645 fs->sect_perblk, 0,
646 fs->blksz, (char *)fs->blk_bmaps[i]);
647 if (status == 0)
648 goto fail;
649 }
650
651 /* load all the available inode bitmap of the partition */
652 fs->inode_bmaps = zalloc(fs->no_blkgrp * sizeof(unsigned char *));
653 if (!fs->inode_bmaps)
654 goto fail;
655 for (i = 0; i < fs->no_blkgrp; i++) {
656 fs->inode_bmaps[i] = zalloc(fs->blksz);
657 if (!fs->inode_bmaps[i])
658 goto fail;
659 }
660
661 for (i = 0; i < fs->no_blkgrp; i++) {
662 struct ext2_block_group *bgd =
663 ext4fs_get_group_descriptor(fs, i);
664 status = ext4fs_devread(ext4fs_bg_get_inode_id(bgd, fs) *
665 fs->sect_perblk,
666 0, fs->blksz,
667 (char *)fs->inode_bmaps[i]);
668 if (status == 0)
669 goto fail;
670 }
671
672 /*
673 * check filesystem consistency with free blocks of file system
674 * some time we observed that superblock freeblocks does not match
675 * with the blockgroups freeblocks when improper
676 * reboot of a linux kernel
677 */
678 for (i = 0; i < fs->no_blkgrp; i++) {
679 struct ext2_block_group *bgd =
680 ext4fs_get_group_descriptor(fs, i);
681 real_free_blocks = real_free_blocks +
682 ext4fs_bg_get_free_blocks(bgd, fs);
683 }
684 if (real_free_blocks != ext4fs_sb_get_free_blocks(fs->sb))
685 ext4fs_sb_set_free_blocks(fs->sb, real_free_blocks);
686
687 return 0;
688fail:
689 ext4fs_deinit();
690
691 return -1;
692}
693
694void ext4fs_deinit(void)
695{
696 int i;
697 struct ext2_inode inode_journal;
698 struct journal_superblock_t *jsb;
699 uint32_t blknr;
700 struct ext_filesystem *fs = get_fs();
701 uint32_t new_feature_incompat;
702
703 /* free journal */
704 char *temp_buff = zalloc(fs->blksz);
705 if (temp_buff) {
706 ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO,
707 &inode_journal);
708 blknr = read_allocated_block(&inode_journal,
709 EXT2_JOURNAL_SUPERBLOCK, NULL);
710 ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz,
711 temp_buff);
712 jsb = (struct journal_superblock_t *)temp_buff;
713 jsb->s_start = 0;
714 put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)fs->blksz),
715 (struct journal_superblock_t *)temp_buff, fs->blksz);
716 free(temp_buff);
717 }
718 ext4fs_free_journal();
719
720 /* get the superblock */
721 ext4_read_superblock((char *)fs->sb);
722 new_feature_incompat = le32_to_cpu(fs->sb->feature_incompat);
723 new_feature_incompat &= ~EXT3_FEATURE_INCOMPAT_RECOVER;
724 fs->sb->feature_incompat = cpu_to_le32(new_feature_incompat);
725 put_ext4((uint64_t)(SUPERBLOCK_SIZE),
726 (struct ext2_sblock *)fs->sb, (uint32_t)SUPERBLOCK_SIZE);
727 free(fs->sb);
728 fs->sb = NULL;
729
730 if (fs->blk_bmaps) {
731 for (i = 0; i < fs->no_blkgrp; i++) {
732 free(fs->blk_bmaps[i]);
733 fs->blk_bmaps[i] = NULL;
734 }
735 free(fs->blk_bmaps);
736 fs->blk_bmaps = NULL;
737 }
738
739 if (fs->inode_bmaps) {
740 for (i = 0; i < fs->no_blkgrp; i++) {
741 free(fs->inode_bmaps[i]);
742 fs->inode_bmaps[i] = NULL;
743 }
744 free(fs->inode_bmaps);
745 fs->inode_bmaps = NULL;
746 }
747
748 free(fs->gdtable);
749 fs->gdtable = NULL;
750 /*
751 * reinitiliazed the global inode and
752 * block bitmap first execution check variables
753 */
754 fs->first_pass_ibmap = 0;
755 fs->first_pass_bbmap = 0;
756 fs->curr_inode_no = 0;
757 fs->curr_blkno = 0;
758}
759
760/*
761 * Write data to filesystem blocks. Uses same optimization for
762 * contigous sectors as ext4fs_read_file
763 */
764static int ext4fs_write_file(struct ext2_inode *file_inode,
765 int pos, unsigned int len, const char *buf)
766{
767 int i;
768 int blockcnt;
769 uint32_t filesize = le32_to_cpu(file_inode->size);
770 struct ext_filesystem *fs = get_fs();
771 int log2blksz = fs->dev_desc->log2blksz;
772 int log2_fs_blocksize = LOG2_BLOCK_SIZE(ext4fs_root) - log2blksz;
773 int previous_block_number = -1;
774 int delayed_start = 0;
775 int delayed_extent = 0;
776 int delayed_next = 0;
777 const char *delayed_buf = NULL;
778
779 /* Adjust len so it we can't read past the end of the file. */
780 if (len > filesize)
781 len = filesize;
782
783 blockcnt = ((len + pos) + fs->blksz - 1) / fs->blksz;
784
785 for (i = pos / fs->blksz; i < blockcnt; i++) {
786 long int blknr;
787 int blockend = fs->blksz;
788 int skipfirst = 0;
789 blknr = read_allocated_block(file_inode, i, NULL);
790 if (blknr <= 0)
791 return -1;
792
793 blknr = blknr << log2_fs_blocksize;
794
795 if (blknr) {
796 if (previous_block_number != -1) {
797 if (delayed_next == blknr) {
798 delayed_extent += blockend;
799 delayed_next += blockend >> log2blksz;
800 } else { /* spill */
801 put_ext4((uint64_t)
802 ((uint64_t)delayed_start << log2blksz),
803 delayed_buf,
804 (uint32_t) delayed_extent);
805 previous_block_number = blknr;
806 delayed_start = blknr;
807 delayed_extent = blockend;
808 delayed_buf = buf;
809 delayed_next = blknr +
810 (blockend >> log2blksz);
811 }
812 } else {
813 previous_block_number = blknr;
814 delayed_start = blknr;
815 delayed_extent = blockend;
816 delayed_buf = buf;
817 delayed_next = blknr +
818 (blockend >> log2blksz);
819 }
820 } else {
821 if (previous_block_number != -1) {
822 /* spill */
823 put_ext4((uint64_t) ((uint64_t)delayed_start <<
824 log2blksz),
825 delayed_buf,
826 (uint32_t) delayed_extent);
827 previous_block_number = -1;
828 }
829 }
830 buf += fs->blksz - skipfirst;
831 }
832 if (previous_block_number != -1) {
833 /* spill */
834 put_ext4((uint64_t) ((uint64_t)delayed_start << log2blksz),
835 delayed_buf, (uint32_t) delayed_extent);
836 previous_block_number = -1;
837 }
838
839 return len;
840}
841
842int ext4fs_write(const char *fname, const char *buffer,
843 unsigned long sizebytes, int type)
844{
845 int ret = 0;
846 struct ext2_inode *file_inode = NULL;
847 struct ext2_inode *existing_file_inode = NULL;
848 unsigned char *inode_buffer = NULL;
849 int parent_inodeno;
850 int inodeno;
851 time_t timestamp = 0;
852
853 uint64_t bytes_reqd_for_file;
854 unsigned int blks_reqd_for_file;
855 unsigned int blocks_remaining;
856 int existing_file_inodeno;
857 char *temp_ptr = NULL;
858 long int itable_blkno;
859 long int parent_itable_blkno;
860 long int blkoff;
861 struct ext2_sblock *sblock = &(ext4fs_root->sblock);
862 unsigned int inodes_per_block;
863 unsigned int ibmap_idx;
864 struct ext2_block_group *bgd = NULL;
865 struct ext_filesystem *fs = get_fs();
866 ALLOC_CACHE_ALIGN_BUFFER(char, filename, 256);
867 bool store_link_in_inode = false;
868 memset(filename, 0x00, 256);
869 int missing_feat;
870
871 if (type != FILETYPE_REG && type != FILETYPE_SYMLINK)
872 return -1;
873
874 g_parent_inode = zalloc(fs->inodesz);
875 if (!g_parent_inode)
876 goto fail;
877
878 if (ext4fs_init() != 0) {
879 printf("error in File System init\n");
880 return -1;
881 }
882
883 missing_feat = le32_to_cpu(fs->sb->feature_incompat) & ~EXT4_FEATURE_INCOMPAT_SUPP;
884 if (missing_feat) {
885 log_err("Unsupported features found %08x, not writing.\n", missing_feat);
886 return -1;
887 }
888
889 missing_feat = le32_to_cpu(fs->sb->feature_ro_compat) & ~EXT4_FEATURE_RO_COMPAT_SUPP;
890 if (missing_feat) {
891 log_err("Unsupported RO compat features found %08x, not writing.\n", missing_feat);
892 return -1;
893 }
894
895 inodes_per_block = fs->blksz / fs->inodesz;
896 parent_inodeno = ext4fs_get_parent_inode_num(fname, filename, F_FILE);
897 if (parent_inodeno == -1)
898 goto fail;
899 if (ext4fs_iget(parent_inodeno, g_parent_inode))
900 goto fail;
901 /* do not mess up a directory using hash trees */
902 if (le32_to_cpu(g_parent_inode->flags) & EXT4_INDEX_FL) {
903 printf("hash tree directory\n");
904 goto fail;
905 }
906 /* check if the filename is already present in root */
907 existing_file_inodeno = ext4fs_filename_unlink(filename);
908 if (existing_file_inodeno != -1) {
909 existing_file_inode = (struct ext2_inode *)zalloc(fs->inodesz);
910 if (!existing_file_inode)
911 goto fail;
912 ret = ext4fs_iget(existing_file_inodeno, existing_file_inode);
913 if (ret) {
914 free(existing_file_inode);
915 goto fail;
916 }
917
918 ret = ext4fs_delete_file(existing_file_inodeno);
919 fs->first_pass_bbmap = 0;
920 fs->curr_blkno = 0;
921
922 fs->first_pass_ibmap = 0;
923 fs->curr_inode_no = 0;
924 if (ret)
925 goto fail;
926 }
927
928 /* calculate how many blocks required */
929 if (type == FILETYPE_SYMLINK &&
930 sizebytes <= sizeof(file_inode->b.symlink)) {
931 store_link_in_inode = true;
932 bytes_reqd_for_file = 0;
933 } else {
934 bytes_reqd_for_file = sizebytes;
935 }
936
937 blks_reqd_for_file = lldiv(bytes_reqd_for_file, fs->blksz);
938 if (do_div(bytes_reqd_for_file, fs->blksz) != 0) {
939 blks_reqd_for_file++;
940 debug("total bytes for a file %u\n", blks_reqd_for_file);
941 }
942 blocks_remaining = blks_reqd_for_file;
943 /* test for available space in partition */
944 if (le32_to_cpu(fs->sb->free_blocks) < blks_reqd_for_file) {
945 printf("Not enough space on partition !!!\n");
946 goto fail;
947 }
948
949 inodeno = ext4fs_update_parent_dentry(filename, type);
950 if (inodeno == -1)
951 goto fail;
952 /* prepare file inode */
953 inode_buffer = zalloc(fs->inodesz);
954 if (!inode_buffer)
955 goto fail;
956 file_inode = (struct ext2_inode *)inode_buffer;
957 file_inode->size = cpu_to_le32(sizebytes);
958 if (type == FILETYPE_SYMLINK) {
959 file_inode->mode = cpu_to_le16(S_IFLNK | S_IRWXU | S_IRWXG |
960 S_IRWXO);
961 if (store_link_in_inode) {
962 strncpy(file_inode->b.symlink, buffer, sizebytes);
963 sizebytes = 0;
964 }
965 } else {
966 if (existing_file_inode) {
967 file_inode->mode = existing_file_inode->mode;
968 } else {
969 file_inode->mode = cpu_to_le16(S_IFREG | S_IRWXU | S_IRGRP |
970 S_IROTH | S_IXGRP | S_IXOTH);
971 }
972 }
973 if (existing_file_inode)
974 free(existing_file_inode);
975 /* ToDo: Update correct time */
976 file_inode->mtime = cpu_to_le32(timestamp);
977 file_inode->atime = cpu_to_le32(timestamp);
978 file_inode->ctime = cpu_to_le32(timestamp);
979 file_inode->nlinks = cpu_to_le16(1);
980
981 /* Allocate data blocks */
982 ext4fs_allocate_blocks(file_inode, blocks_remaining,
983 &blks_reqd_for_file);
984 file_inode->blockcnt = cpu_to_le32((blks_reqd_for_file * fs->blksz) >>
985 LOG2_SECTOR_SIZE);
986
987 temp_ptr = zalloc(fs->blksz);
988 if (!temp_ptr)
989 goto fail;
990 ibmap_idx = inodeno / le32_to_cpu(ext4fs_root->sblock.inodes_per_group);
991 inodeno--;
992 bgd = ext4fs_get_group_descriptor(fs, ibmap_idx);
993 itable_blkno = ext4fs_bg_get_inode_table_id(bgd, fs) +
994 (inodeno % le32_to_cpu(sblock->inodes_per_group)) /
995 inodes_per_block;
996 blkoff = (inodeno % inodes_per_block) * fs->inodesz;
997 ext4fs_devread((lbaint_t)itable_blkno * fs->sect_perblk, 0, fs->blksz,
998 temp_ptr);
999 if (ext4fs_log_journal(temp_ptr, itable_blkno))
1000 goto fail;
1001
1002 memcpy(temp_ptr + blkoff, inode_buffer, fs->inodesz);
1003 if (ext4fs_put_metadata(temp_ptr, itable_blkno))
1004 goto fail;
1005 /* copy the file content into data blocks */
1006 if (ext4fs_write_file(file_inode, 0, sizebytes, buffer) == -1) {
1007 printf("Error in copying content\n");
1008 /* FIXME: Deallocate data blocks */
1009 goto fail;
1010 }
1011 ibmap_idx = parent_inodeno / le32_to_cpu(ext4fs_root->sblock.inodes_per_group);
1012 parent_inodeno--;
1013 bgd = ext4fs_get_group_descriptor(fs, ibmap_idx);
1014 parent_itable_blkno = ext4fs_bg_get_inode_table_id(bgd, fs) +
1015 (parent_inodeno %
1016 le32_to_cpu(sblock->inodes_per_group)) / inodes_per_block;
1017 blkoff = (parent_inodeno % inodes_per_block) * fs->inodesz;
1018 if (parent_itable_blkno != itable_blkno) {
1019 memset(temp_ptr, '\0', fs->blksz);
1020 ext4fs_devread((lbaint_t)parent_itable_blkno * fs->sect_perblk,
1021 0, fs->blksz, temp_ptr);
1022 if (ext4fs_log_journal(temp_ptr, parent_itable_blkno))
1023 goto fail;
1024
1025 memcpy(temp_ptr + blkoff, g_parent_inode, fs->inodesz);
1026 if (ext4fs_put_metadata(temp_ptr, parent_itable_blkno))
1027 goto fail;
1028 } else {
1029 /*
1030 * If parent and child fall in same inode table block
1031 * both should be kept in 1 buffer
1032 */
1033 memcpy(temp_ptr + blkoff, g_parent_inode, fs->inodesz);
1034 gd_index--;
1035 if (ext4fs_put_metadata(temp_ptr, itable_blkno))
1036 goto fail;
1037 }
1038 ext4fs_update();
1039 ext4fs_deinit();
1040
1041 fs->first_pass_bbmap = 0;
1042 fs->curr_blkno = 0;
1043 fs->first_pass_ibmap = 0;
1044 fs->curr_inode_no = 0;
1045 free(inode_buffer);
1046 free(g_parent_inode);
1047 free(temp_ptr);
1048 g_parent_inode = NULL;
1049
1050 return 0;
1051fail:
1052 ext4fs_deinit();
1053 free(inode_buffer);
1054 free(g_parent_inode);
1055 free(temp_ptr);
1056 g_parent_inode = NULL;
1057
1058 return -1;
1059}
1060
1061int ext4_write_file(const char *filename, void *buf, loff_t offset,
1062 loff_t len, loff_t *actwrite)
1063{
1064 int ret;
1065
1066 if (offset != 0) {
1067 printf("** Cannot support non-zero offset **\n");
1068 return -1;
1069 }
1070
1071 ret = ext4fs_write(filename, buf, len, FILETYPE_REG);
1072 if (ret) {
1073 printf("** Error ext4fs_write() **\n");
1074 goto fail;
1075 }
1076
1077 *actwrite = len;
1078
1079 return 0;
1080
1081fail:
1082 *actwrite = 0;
1083
1084 return -1;
1085}
1086
1087int ext4fs_create_link(const char *target, const char *fname)
1088{
1089 return ext4fs_write(fname, target, strlen(target), FILETYPE_SYMLINK);
1090}