blob: 2c123e3646652319e888c0c6a89679f523f71b3d [file] [log] [blame]
Simon Glass293d7fb2012-12-26 09:53:28 +00001/*
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 *
Wolfgang Denk1a459662013-07-08 09:37:19 +020021 * SPDX-License-Identifier: GPL-2.0+
Simon Glass293d7fb2012-12-26 09:53:28 +000022 */
23
24
25#include <common.h>
Simon Glasscf92e052015-09-02 17:24:58 -060026#include <memalign.h>
Simon Glass293d7fb2012-12-26 09:53:28 +000027#include <linux/stat.h>
28#include <div64.h>
29#include "ext4_common.h"
30
Michael Walle58a9ecb2016-09-01 11:21:40 +020031static inline void ext4fs_sb_free_inodes_inc(struct ext2_sblock *sb)
32{
33 sb->free_inodes = cpu_to_le32(le32_to_cpu(sb->free_inodes) + 1);
34}
35
36static inline void ext4fs_sb_free_blocks_inc(struct ext2_sblock *sb)
37{
38 sb->free_blocks = cpu_to_le32(le32_to_cpu(sb->free_blocks) + 1);
39}
40
41static inline void ext4fs_bg_free_inodes_inc(struct ext2_block_group *bg)
42{
43 bg->free_inodes = cpu_to_le16(le16_to_cpu(bg->free_inodes) + 1);
44}
45
46static inline void ext4fs_bg_free_blocks_inc(struct ext2_block_group *bg)
47{
48 bg->free_blocks = cpu_to_le16(le16_to_cpu(bg->free_blocks) + 1);
49}
50
Simon Glass293d7fb2012-12-26 09:53:28 +000051static void ext4fs_update(void)
52{
53 short i;
54 ext4fs_update_journal();
55 struct ext_filesystem *fs = get_fs();
Stefan Brüns688d0e72016-09-17 02:10:10 +020056 struct ext2_block_group *bgd = NULL;
Simon Glass293d7fb2012-12-26 09:53:28 +000057
58 /* update super block */
59 put_ext4((uint64_t)(SUPERBLOCK_SIZE),
60 (struct ext2_sblock *)fs->sb, (uint32_t)SUPERBLOCK_SIZE);
61
Stefan Brüns688d0e72016-09-17 02:10:10 +020062 /* update block bitmaps */
Simon Glass293d7fb2012-12-26 09:53:28 +000063 for (i = 0; i < fs->no_blkgrp; i++) {
Stefan Brüns688d0e72016-09-17 02:10:10 +020064 bgd = ext4fs_get_group_descriptor(fs, i);
65 bgd->bg_checksum = cpu_to_le16(ext4fs_checksum_update(i));
66 uint64_t b_bitmap_blk = ext4fs_bg_get_block_id(bgd, fs);
67 put_ext4(b_bitmap_blk * fs->blksz,
Simon Glass293d7fb2012-12-26 09:53:28 +000068 fs->blk_bmaps[i], fs->blksz);
69 }
70
Stefan Brüns688d0e72016-09-17 02:10:10 +020071 /* update inode bitmaps */
Simon Glass293d7fb2012-12-26 09:53:28 +000072 for (i = 0; i < fs->no_blkgrp; i++) {
Stefan Brüns688d0e72016-09-17 02:10:10 +020073 bgd = ext4fs_get_group_descriptor(fs, i);
74 uint64_t i_bitmap_blk = ext4fs_bg_get_inode_id(bgd, fs);
75 put_ext4(i_bitmap_blk * fs->blksz,
Simon Glass293d7fb2012-12-26 09:53:28 +000076 fs->inode_bmaps[i], fs->blksz);
77 }
78
79 /* update the block group descriptor table */
Ma Haijun05508702014-01-08 08:15:33 +080080 put_ext4((uint64_t)((uint64_t)fs->gdtable_blkno * (uint64_t)fs->blksz),
Simon Glass293d7fb2012-12-26 09:53:28 +000081 (struct ext2_block_group *)fs->gdtable,
82 (fs->blksz * fs->no_blk_pergdt));
83
84 ext4fs_dump_metadata();
85
86 gindex = 0;
87 gd_index = 0;
88}
89
90int ext4fs_get_bgdtable(void)
91{
92 int status;
Simon Glass293d7fb2012-12-26 09:53:28 +000093 struct ext_filesystem *fs = get_fs();
Stefan Brüns688d0e72016-09-17 02:10:10 +020094 int gdsize_total = ROUND(fs->no_blkgrp * fs->gdsize, fs->blksz);
95 fs->no_blk_pergdt = gdsize_total / fs->blksz;
Simon Glass293d7fb2012-12-26 09:53:28 +000096
97 /* allocate memory for gdtable */
Stefan Brüns688d0e72016-09-17 02:10:10 +020098 fs->gdtable = zalloc(gdsize_total);
Simon Glass293d7fb2012-12-26 09:53:28 +000099 if (!fs->gdtable)
100 return -ENOMEM;
101 /* read the group descriptor table */
Frederic Leroy04735e92013-06-26 18:11:25 +0200102 status = ext4fs_devread((lbaint_t)fs->gdtable_blkno * fs->sect_perblk,
103 0, fs->blksz * fs->no_blk_pergdt, fs->gdtable);
Simon Glass293d7fb2012-12-26 09:53:28 +0000104 if (status == 0)
105 goto fail;
106
107 if (ext4fs_log_gdt(fs->gdtable)) {
108 printf("Error in ext4fs_log_gdt\n");
109 return -1;
110 }
111
112 return 0;
113fail:
114 free(fs->gdtable);
115 fs->gdtable = NULL;
116
117 return -1;
118}
119
120static void delete_single_indirect_block(struct ext2_inode *inode)
121{
122 struct ext2_block_group *bgd = NULL;
123 static int prev_bg_bmap_idx = -1;
Michael Walle58a9ecb2016-09-01 11:21:40 +0200124 uint32_t blknr;
Simon Glass293d7fb2012-12-26 09:53:28 +0000125 int remainder;
126 int bg_idx;
127 int status;
Michael Walle58a9ecb2016-09-01 11:21:40 +0200128 uint32_t blk_per_grp = le32_to_cpu(ext4fs_root->sblock.blocks_per_group);
Simon Glass293d7fb2012-12-26 09:53:28 +0000129 struct ext_filesystem *fs = get_fs();
130 char *journal_buffer = zalloc(fs->blksz);
131 if (!journal_buffer) {
132 printf("No memory\n");
133 return;
134 }
Simon Glass293d7fb2012-12-26 09:53:28 +0000135
136 /* deleting the single indirect block associated with inode */
137 if (inode->b.blocks.indir_block != 0) {
Michael Walle58a9ecb2016-09-01 11:21:40 +0200138 blknr = le32_to_cpu(inode->b.blocks.indir_block);
139 debug("SIPB releasing %u\n", blknr);
Łukasz Majewski35dd0552014-05-06 09:36:04 +0200140 bg_idx = blknr / blk_per_grp;
141 if (fs->blksz == 1024) {
Simon Glass293d7fb2012-12-26 09:53:28 +0000142 remainder = blknr % blk_per_grp;
143 if (!remainder)
144 bg_idx--;
145 }
146 ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], bg_idx);
Stefan Brüns688d0e72016-09-17 02:10:10 +0200147 /* get block group descriptor table */
148 bgd = ext4fs_get_group_descriptor(fs, bg_idx);
149 ext4fs_bg_free_blocks_inc(bgd);
Michael Walle58a9ecb2016-09-01 11:21:40 +0200150 ext4fs_sb_free_blocks_inc(fs->sb);
Simon Glass293d7fb2012-12-26 09:53:28 +0000151 /* journal backup */
152 if (prev_bg_bmap_idx != bg_idx) {
Stefan Brüns688d0e72016-09-17 02:10:10 +0200153 uint64_t b_bitmap_blk = ext4fs_bg_get_block_id(bgd, fs);
Michael Walle58a9ecb2016-09-01 11:21:40 +0200154 status = ext4fs_devread(
Stefan Brüns688d0e72016-09-17 02:10:10 +0200155 b_bitmap_blk * fs->sect_perblk,
156 0, fs->blksz, journal_buffer);
Simon Glass293d7fb2012-12-26 09:53:28 +0000157 if (status == 0)
158 goto fail;
Stefan Brüns688d0e72016-09-17 02:10:10 +0200159 if (ext4fs_log_journal(journal_buffer, b_bitmap_blk))
Simon Glass293d7fb2012-12-26 09:53:28 +0000160 goto fail;
161 prev_bg_bmap_idx = bg_idx;
162 }
163 }
164fail:
165 free(journal_buffer);
166}
167
168static void delete_double_indirect_block(struct ext2_inode *inode)
169{
170 int i;
171 short status;
172 static int prev_bg_bmap_idx = -1;
Michael Walle58a9ecb2016-09-01 11:21:40 +0200173 uint32_t blknr;
Simon Glass293d7fb2012-12-26 09:53:28 +0000174 int remainder;
175 int bg_idx;
Michael Walle58a9ecb2016-09-01 11:21:40 +0200176 uint32_t blk_per_grp = le32_to_cpu(ext4fs_root->sblock.blocks_per_group);
177 __le32 *di_buffer = NULL;
178 void *dib_start_addr = NULL;
Simon Glass293d7fb2012-12-26 09:53:28 +0000179 struct ext2_block_group *bgd = NULL;
180 struct ext_filesystem *fs = get_fs();
181 char *journal_buffer = zalloc(fs->blksz);
182 if (!journal_buffer) {
183 printf("No memory\n");
184 return;
185 }
Simon Glass293d7fb2012-12-26 09:53:28 +0000186
187 if (inode->b.blocks.double_indir_block != 0) {
188 di_buffer = zalloc(fs->blksz);
189 if (!di_buffer) {
190 printf("No memory\n");
191 return;
192 }
Michael Walle58a9ecb2016-09-01 11:21:40 +0200193 dib_start_addr = di_buffer;
194 blknr = le32_to_cpu(inode->b.blocks.double_indir_block);
Frederic Leroy04735e92013-06-26 18:11:25 +0200195 status = ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0,
196 fs->blksz, (char *)di_buffer);
Simon Glass293d7fb2012-12-26 09:53:28 +0000197 for (i = 0; i < fs->blksz / sizeof(int); i++) {
198 if (*di_buffer == 0)
199 break;
200
201 debug("DICB releasing %u\n", *di_buffer);
Michael Walle58a9ecb2016-09-01 11:21:40 +0200202 bg_idx = le32_to_cpu(*di_buffer) / blk_per_grp;
Łukasz Majewski35dd0552014-05-06 09:36:04 +0200203 if (fs->blksz == 1024) {
Michael Walle58a9ecb2016-09-01 11:21:40 +0200204 remainder = le32_to_cpu(*di_buffer) % blk_per_grp;
Simon Glass293d7fb2012-12-26 09:53:28 +0000205 if (!remainder)
206 bg_idx--;
207 }
Stefan Brüns688d0e72016-09-17 02:10:10 +0200208 /* get block group descriptor table */
209 bgd = ext4fs_get_group_descriptor(fs, bg_idx);
Michael Walle58a9ecb2016-09-01 11:21:40 +0200210 ext4fs_reset_block_bmap(le32_to_cpu(*di_buffer),
Simon Glass293d7fb2012-12-26 09:53:28 +0000211 fs->blk_bmaps[bg_idx], bg_idx);
212 di_buffer++;
Stefan Brüns688d0e72016-09-17 02:10:10 +0200213 ext4fs_bg_free_blocks_inc(bgd);
Michael Walle58a9ecb2016-09-01 11:21:40 +0200214 ext4fs_sb_free_blocks_inc(fs->sb);
Simon Glass293d7fb2012-12-26 09:53:28 +0000215 /* journal backup */
216 if (prev_bg_bmap_idx != bg_idx) {
Stefan Brüns688d0e72016-09-17 02:10:10 +0200217 uint64_t b_bitmap_blk =
218 ext4fs_bg_get_block_id(bgd, fs);
219 status = ext4fs_devread(b_bitmap_blk
Simon Glass293d7fb2012-12-26 09:53:28 +0000220 * fs->sect_perblk, 0,
221 fs->blksz,
222 journal_buffer);
223 if (status == 0)
224 goto fail;
225
226 if (ext4fs_log_journal(journal_buffer,
Stefan Brüns688d0e72016-09-17 02:10:10 +0200227 b_bitmap_blk))
Simon Glass293d7fb2012-12-26 09:53:28 +0000228 goto fail;
229 prev_bg_bmap_idx = bg_idx;
230 }
231 }
232
233 /* removing the parent double indirect block */
Michael Walle58a9ecb2016-09-01 11:21:40 +0200234 blknr = le32_to_cpu(inode->b.blocks.double_indir_block);
Łukasz Majewski35dd0552014-05-06 09:36:04 +0200235 bg_idx = blknr / blk_per_grp;
236 if (fs->blksz == 1024) {
Simon Glass293d7fb2012-12-26 09:53:28 +0000237 remainder = blknr % blk_per_grp;
238 if (!remainder)
239 bg_idx--;
240 }
Stefan Brüns688d0e72016-09-17 02:10:10 +0200241 /* get block group descriptor table */
242 bgd = ext4fs_get_group_descriptor(fs, bg_idx);
Simon Glass293d7fb2012-12-26 09:53:28 +0000243 ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], bg_idx);
Stefan Brüns688d0e72016-09-17 02:10:10 +0200244 ext4fs_bg_free_blocks_inc(bgd);
Michael Walle58a9ecb2016-09-01 11:21:40 +0200245 ext4fs_sb_free_blocks_inc(fs->sb);
Simon Glass293d7fb2012-12-26 09:53:28 +0000246 /* journal backup */
247 if (prev_bg_bmap_idx != bg_idx) {
Stefan Brüns688d0e72016-09-17 02:10:10 +0200248 uint64_t b_bitmap_blk = ext4fs_bg_get_block_id(bgd, fs);
249 status = ext4fs_devread(b_bitmap_blk * fs->sect_perblk,
250 0, fs->blksz, journal_buffer);
Simon Glass293d7fb2012-12-26 09:53:28 +0000251 if (status == 0)
252 goto fail;
253
Stefan Brüns688d0e72016-09-17 02:10:10 +0200254 if (ext4fs_log_journal(journal_buffer, b_bitmap_blk))
Simon Glass293d7fb2012-12-26 09:53:28 +0000255 goto fail;
256 prev_bg_bmap_idx = bg_idx;
257 }
Michael Walle58a9ecb2016-09-01 11:21:40 +0200258 debug("DIPB releasing %d\n", blknr);
Simon Glass293d7fb2012-12-26 09:53:28 +0000259 }
260fail:
Michael Walle58a9ecb2016-09-01 11:21:40 +0200261 free(dib_start_addr);
Simon Glass293d7fb2012-12-26 09:53:28 +0000262 free(journal_buffer);
263}
264
265static void delete_triple_indirect_block(struct ext2_inode *inode)
266{
267 int i, j;
268 short status;
269 static int prev_bg_bmap_idx = -1;
Michael Walle58a9ecb2016-09-01 11:21:40 +0200270 uint32_t blknr;
Simon Glass293d7fb2012-12-26 09:53:28 +0000271 int remainder;
272 int bg_idx;
Michael Walle58a9ecb2016-09-01 11:21:40 +0200273 uint32_t blk_per_grp = le32_to_cpu(ext4fs_root->sblock.blocks_per_group);
274 __le32 *tigp_buffer = NULL;
275 void *tib_start_addr = NULL;
276 __le32 *tip_buffer = NULL;
277 void *tipb_start_addr = NULL;
Simon Glass293d7fb2012-12-26 09:53:28 +0000278 struct ext2_block_group *bgd = NULL;
279 struct ext_filesystem *fs = get_fs();
280 char *journal_buffer = zalloc(fs->blksz);
281 if (!journal_buffer) {
282 printf("No memory\n");
283 return;
284 }
Simon Glass293d7fb2012-12-26 09:53:28 +0000285
286 if (inode->b.blocks.triple_indir_block != 0) {
287 tigp_buffer = zalloc(fs->blksz);
288 if (!tigp_buffer) {
289 printf("No memory\n");
290 return;
291 }
Michael Walle58a9ecb2016-09-01 11:21:40 +0200292 tib_start_addr = tigp_buffer;
293 blknr = le32_to_cpu(inode->b.blocks.triple_indir_block);
Frederic Leroy04735e92013-06-26 18:11:25 +0200294 status = ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0,
295 fs->blksz, (char *)tigp_buffer);
Simon Glass293d7fb2012-12-26 09:53:28 +0000296 for (i = 0; i < fs->blksz / sizeof(int); i++) {
297 if (*tigp_buffer == 0)
298 break;
299 debug("tigp buffer releasing %u\n", *tigp_buffer);
300
301 tip_buffer = zalloc(fs->blksz);
302 if (!tip_buffer)
303 goto fail;
Michael Walle58a9ecb2016-09-01 11:21:40 +0200304 tipb_start_addr = tip_buffer;
305 status = ext4fs_devread((lbaint_t)le32_to_cpu(*tigp_buffer) *
Simon Glass293d7fb2012-12-26 09:53:28 +0000306 fs->sect_perblk, 0, fs->blksz,
307 (char *)tip_buffer);
308 for (j = 0; j < fs->blksz / sizeof(int); j++) {
Michael Walle58a9ecb2016-09-01 11:21:40 +0200309 if (le32_to_cpu(*tip_buffer) == 0)
Simon Glass293d7fb2012-12-26 09:53:28 +0000310 break;
Michael Walle58a9ecb2016-09-01 11:21:40 +0200311 bg_idx = le32_to_cpu(*tip_buffer) / blk_per_grp;
Łukasz Majewski35dd0552014-05-06 09:36:04 +0200312 if (fs->blksz == 1024) {
Michael Walle58a9ecb2016-09-01 11:21:40 +0200313 remainder = le32_to_cpu(*tip_buffer) % blk_per_grp;
Simon Glass293d7fb2012-12-26 09:53:28 +0000314 if (!remainder)
315 bg_idx--;
316 }
317
Michael Walle58a9ecb2016-09-01 11:21:40 +0200318 ext4fs_reset_block_bmap(le32_to_cpu(*tip_buffer),
Simon Glass293d7fb2012-12-26 09:53:28 +0000319 fs->blk_bmaps[bg_idx],
320 bg_idx);
321
322 tip_buffer++;
Stefan Brüns688d0e72016-09-17 02:10:10 +0200323 /* get block group descriptor table */
324 bgd = ext4fs_get_group_descriptor(fs, bg_idx);
325 ext4fs_bg_free_blocks_inc(bgd);
Michael Walle58a9ecb2016-09-01 11:21:40 +0200326 ext4fs_sb_free_blocks_inc(fs->sb);
Simon Glass293d7fb2012-12-26 09:53:28 +0000327 /* journal backup */
328 if (prev_bg_bmap_idx != bg_idx) {
Stefan Brüns688d0e72016-09-17 02:10:10 +0200329 uint64_t b_bitmap_blk =
330 ext4fs_bg_get_block_id(bgd, fs);
Simon Glass293d7fb2012-12-26 09:53:28 +0000331 status =
332 ext4fs_devread(
Stefan Brüns688d0e72016-09-17 02:10:10 +0200333 b_bitmap_blk *
Simon Glass293d7fb2012-12-26 09:53:28 +0000334 fs->sect_perblk, 0,
335 fs->blksz,
336 journal_buffer);
337 if (status == 0)
338 goto fail;
339
340 if (ext4fs_log_journal(journal_buffer,
Stefan Brüns688d0e72016-09-17 02:10:10 +0200341 b_bitmap_blk))
Simon Glass293d7fb2012-12-26 09:53:28 +0000342 goto fail;
343 prev_bg_bmap_idx = bg_idx;
344 }
345 }
346 free(tipb_start_addr);
347 tipb_start_addr = NULL;
348
349 /*
350 * removing the grand parent blocks
351 * which is connected to inode
352 */
Michael Walle58a9ecb2016-09-01 11:21:40 +0200353 bg_idx = le32_to_cpu(*tigp_buffer) / blk_per_grp;
Łukasz Majewski35dd0552014-05-06 09:36:04 +0200354 if (fs->blksz == 1024) {
Michael Walle58a9ecb2016-09-01 11:21:40 +0200355 remainder = le32_to_cpu(*tigp_buffer) % blk_per_grp;
Simon Glass293d7fb2012-12-26 09:53:28 +0000356 if (!remainder)
357 bg_idx--;
358 }
Michael Walle58a9ecb2016-09-01 11:21:40 +0200359 ext4fs_reset_block_bmap(le32_to_cpu(*tigp_buffer),
Simon Glass293d7fb2012-12-26 09:53:28 +0000360 fs->blk_bmaps[bg_idx], bg_idx);
361
362 tigp_buffer++;
Stefan Brüns688d0e72016-09-17 02:10:10 +0200363 /* get block group descriptor table */
364 bgd = ext4fs_get_group_descriptor(fs, bg_idx);
365 ext4fs_bg_free_blocks_inc(bgd);
Michael Walle58a9ecb2016-09-01 11:21:40 +0200366 ext4fs_sb_free_blocks_inc(fs->sb);
Simon Glass293d7fb2012-12-26 09:53:28 +0000367 /* journal backup */
368 if (prev_bg_bmap_idx != bg_idx) {
Stefan Brüns688d0e72016-09-17 02:10:10 +0200369 uint64_t b_bitmap_blk =
370 ext4fs_bg_get_block_id(bgd, fs);
Simon Glass293d7fb2012-12-26 09:53:28 +0000371 memset(journal_buffer, '\0', fs->blksz);
Stefan Brüns688d0e72016-09-17 02:10:10 +0200372 status = ext4fs_devread(b_bitmap_blk *
373 fs->sect_perblk, 0,
374 fs->blksz,
375 journal_buffer);
Simon Glass293d7fb2012-12-26 09:53:28 +0000376 if (status == 0)
377 goto fail;
378
379 if (ext4fs_log_journal(journal_buffer,
Stefan Brüns688d0e72016-09-17 02:10:10 +0200380 b_bitmap_blk))
Simon Glass293d7fb2012-12-26 09:53:28 +0000381 goto fail;
382 prev_bg_bmap_idx = bg_idx;
383 }
384 }
385
386 /* removing the grand parent triple indirect block */
Michael Walle58a9ecb2016-09-01 11:21:40 +0200387 blknr = le32_to_cpu(inode->b.blocks.triple_indir_block);
Łukasz Majewski35dd0552014-05-06 09:36:04 +0200388 bg_idx = blknr / blk_per_grp;
389 if (fs->blksz == 1024) {
Simon Glass293d7fb2012-12-26 09:53:28 +0000390 remainder = blknr % blk_per_grp;
391 if (!remainder)
392 bg_idx--;
393 }
394 ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], bg_idx);
Stefan Brüns688d0e72016-09-17 02:10:10 +0200395 /* get block group descriptor table */
396 bgd = ext4fs_get_group_descriptor(fs, bg_idx);
397 ext4fs_bg_free_blocks_inc(bgd);
Michael Walle58a9ecb2016-09-01 11:21:40 +0200398 ext4fs_sb_free_blocks_inc(fs->sb);
Simon Glass293d7fb2012-12-26 09:53:28 +0000399 /* journal backup */
400 if (prev_bg_bmap_idx != bg_idx) {
Stefan Brüns688d0e72016-09-17 02:10:10 +0200401 uint64_t b_bitmap_blk = ext4fs_bg_get_block_id(bgd, fs);
402 status = ext4fs_devread(b_bitmap_blk * fs->sect_perblk,
403 0, fs->blksz, journal_buffer);
Simon Glass293d7fb2012-12-26 09:53:28 +0000404 if (status == 0)
405 goto fail;
406
Stefan Brüns688d0e72016-09-17 02:10:10 +0200407 if (ext4fs_log_journal(journal_buffer, b_bitmap_blk))
Simon Glass293d7fb2012-12-26 09:53:28 +0000408 goto fail;
409 prev_bg_bmap_idx = bg_idx;
410 }
Michael Walle58a9ecb2016-09-01 11:21:40 +0200411 debug("tigp buffer itself releasing %d\n", blknr);
Simon Glass293d7fb2012-12-26 09:53:28 +0000412 }
413fail:
414 free(tib_start_addr);
415 free(tipb_start_addr);
416 free(journal_buffer);
417}
418
419static int ext4fs_delete_file(int inodeno)
420{
421 struct ext2_inode inode;
422 short status;
423 int i;
424 int remainder;
425 long int blknr;
426 int bg_idx;
427 int ibmap_idx;
428 char *read_buffer = NULL;
429 char *start_block_address = NULL;
Michael Walle58a9ecb2016-09-01 11:21:40 +0200430 uint32_t no_blocks;
Simon Glass293d7fb2012-12-26 09:53:28 +0000431
432 static int prev_bg_bmap_idx = -1;
433 unsigned int inodes_per_block;
Michael Walle58a9ecb2016-09-01 11:21:40 +0200434 uint32_t blkno;
Simon Glass293d7fb2012-12-26 09:53:28 +0000435 unsigned int blkoff;
Michael Walle58a9ecb2016-09-01 11:21:40 +0200436 uint32_t blk_per_grp = le32_to_cpu(ext4fs_root->sblock.blocks_per_group);
437 uint32_t inode_per_grp = le32_to_cpu(ext4fs_root->sblock.inodes_per_group);
Simon Glass293d7fb2012-12-26 09:53:28 +0000438 struct ext2_inode *inode_buffer = NULL;
439 struct ext2_block_group *bgd = NULL;
440 struct ext_filesystem *fs = get_fs();
441 char *journal_buffer = zalloc(fs->blksz);
442 if (!journal_buffer)
443 return -ENOMEM;
Simon Glass293d7fb2012-12-26 09:53:28 +0000444 status = ext4fs_read_inode(ext4fs_root, inodeno, &inode);
445 if (status == 0)
446 goto fail;
447
448 /* read the block no allocated to a file */
Michael Walle58a9ecb2016-09-01 11:21:40 +0200449 no_blocks = le32_to_cpu(inode.size) / fs->blksz;
450 if (le32_to_cpu(inode.size) % fs->blksz)
Simon Glass293d7fb2012-12-26 09:53:28 +0000451 no_blocks++;
452
453 if (le32_to_cpu(inode.flags) & EXT4_EXTENTS_FL) {
Stefan Brünsb779e022016-09-06 04:36:54 +0200454 /* FIXME delete extent index blocks, i.e. eh_depth >= 1 */
455 struct ext4_extent_header *eh =
456 (struct ext4_extent_header *)
457 inode.b.blocks.dir_blocks;
458 debug("del: dep=%d entries=%d\n", eh->eh_depth, eh->eh_entries);
Simon Glass293d7fb2012-12-26 09:53:28 +0000459 } else {
Simon Glass293d7fb2012-12-26 09:53:28 +0000460 delete_single_indirect_block(&inode);
461 delete_double_indirect_block(&inode);
462 delete_triple_indirect_block(&inode);
Stefan Brünsb779e022016-09-06 04:36:54 +0200463 }
Simon Glass293d7fb2012-12-26 09:53:28 +0000464
Stefan Brünsb779e022016-09-06 04:36:54 +0200465 /* release data blocks */
466 for (i = 0; i < no_blocks; i++) {
467 blknr = read_allocated_block(&inode, i);
Stefan Brünsde9e8312016-09-06 04:36:55 +0200468 if (blknr == 0)
469 continue;
470 if (blknr < 0)
471 goto fail;
Stefan Brünsb779e022016-09-06 04:36:54 +0200472 bg_idx = blknr / blk_per_grp;
473 if (fs->blksz == 1024) {
474 remainder = blknr % blk_per_grp;
475 if (!remainder)
476 bg_idx--;
477 }
478 ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx],
479 bg_idx);
480 debug("EXT4 Block releasing %ld: %d\n", blknr, bg_idx);
Simon Glass293d7fb2012-12-26 09:53:28 +0000481
Stefan Brüns688d0e72016-09-17 02:10:10 +0200482 /* get block group descriptor table */
483 bgd = ext4fs_get_group_descriptor(fs, bg_idx);
484 ext4fs_bg_free_blocks_inc(bgd);
Stefan Brünsb779e022016-09-06 04:36:54 +0200485 ext4fs_sb_free_blocks_inc(fs->sb);
486 /* journal backup */
487 if (prev_bg_bmap_idx != bg_idx) {
Stefan Brüns688d0e72016-09-17 02:10:10 +0200488 uint64_t b_bitmap_blk = ext4fs_bg_get_block_id(bgd, fs);
489 status = ext4fs_devread(b_bitmap_blk * fs->sect_perblk,
Stefan Brünsb779e022016-09-06 04:36:54 +0200490 0, fs->blksz,
491 journal_buffer);
492 if (status == 0)
493 goto fail;
Stefan Brüns688d0e72016-09-17 02:10:10 +0200494 if (ext4fs_log_journal(journal_buffer, b_bitmap_blk))
Stefan Brünsb779e022016-09-06 04:36:54 +0200495 goto fail;
496 prev_bg_bmap_idx = bg_idx;
Simon Glass293d7fb2012-12-26 09:53:28 +0000497 }
498 }
499
Stefan Brünsb779e022016-09-06 04:36:54 +0200500 /* release inode */
Simon Glass293d7fb2012-12-26 09:53:28 +0000501 /* from the inode no to blockno */
502 inodes_per_block = fs->blksz / fs->inodesz;
503 ibmap_idx = inodeno / inode_per_grp;
504
505 /* get the block no */
506 inodeno--;
Stefan Brüns688d0e72016-09-17 02:10:10 +0200507 /* get block group descriptor table */
508 bgd = ext4fs_get_group_descriptor(fs, ibmap_idx);
509 blkno = ext4fs_bg_get_inode_table_id(bgd, fs) +
Michael Walle58a9ecb2016-09-01 11:21:40 +0200510 (inodeno % inode_per_grp) / inodes_per_block;
Simon Glass293d7fb2012-12-26 09:53:28 +0000511
512 /* get the offset of the inode */
513 blkoff = ((inodeno) % inodes_per_block) * fs->inodesz;
514
515 /* read the block no containing the inode */
516 read_buffer = zalloc(fs->blksz);
517 if (!read_buffer)
518 goto fail;
519 start_block_address = read_buffer;
Frederic Leroy04735e92013-06-26 18:11:25 +0200520 status = ext4fs_devread((lbaint_t)blkno * fs->sect_perblk,
Simon Glass293d7fb2012-12-26 09:53:28 +0000521 0, fs->blksz, read_buffer);
522 if (status == 0)
523 goto fail;
524
525 if (ext4fs_log_journal(read_buffer, blkno))
526 goto fail;
527
528 read_buffer = read_buffer + blkoff;
529 inode_buffer = (struct ext2_inode *)read_buffer;
Stefan Brüns87f9fdc2016-09-06 04:36:53 +0200530 memset(inode_buffer, '\0', fs->inodesz);
Simon Glass293d7fb2012-12-26 09:53:28 +0000531
532 /* write the inode to original position in inode table */
533 if (ext4fs_put_metadata(start_block_address, blkno))
534 goto fail;
535
536 /* update the respective inode bitmaps */
537 inodeno++;
538 ext4fs_reset_inode_bmap(inodeno, fs->inode_bmaps[ibmap_idx], ibmap_idx);
Stefan Brüns688d0e72016-09-17 02:10:10 +0200539 ext4fs_bg_free_inodes_inc(bgd);
Michael Walle58a9ecb2016-09-01 11:21:40 +0200540 ext4fs_sb_free_inodes_inc(fs->sb);
Simon Glass293d7fb2012-12-26 09:53:28 +0000541 /* journal backup */
542 memset(journal_buffer, '\0', fs->blksz);
Stefan Brüns688d0e72016-09-17 02:10:10 +0200543 status = ext4fs_devread(ext4fs_bg_get_inode_id(bgd, fs) *
Simon Glass293d7fb2012-12-26 09:53:28 +0000544 fs->sect_perblk, 0, fs->blksz, journal_buffer);
545 if (status == 0)
546 goto fail;
Stefan Brüns688d0e72016-09-17 02:10:10 +0200547 if (ext4fs_log_journal(journal_buffer, ext4fs_bg_get_inode_id(bgd, fs)))
Simon Glass293d7fb2012-12-26 09:53:28 +0000548 goto fail;
549
550 ext4fs_update();
551 ext4fs_deinit();
Łukasz Majewski8b454ee2014-05-06 09:36:05 +0200552 ext4fs_reinit_global();
Simon Glass293d7fb2012-12-26 09:53:28 +0000553
554 if (ext4fs_init() != 0) {
555 printf("error in File System init\n");
556 goto fail;
557 }
558
559 free(start_block_address);
560 free(journal_buffer);
561
562 return 0;
563fail:
564 free(start_block_address);
565 free(journal_buffer);
566
567 return -1;
568}
569
570int ext4fs_init(void)
571{
572 short status;
573 int i;
Michael Walle58a9ecb2016-09-01 11:21:40 +0200574 uint32_t real_free_blocks = 0;
Simon Glass293d7fb2012-12-26 09:53:28 +0000575 struct ext_filesystem *fs = get_fs();
576
577 /* populate fs */
578 fs->blksz = EXT2_BLOCK_SIZE(ext4fs_root);
Egbert Eich50ce4c02013-05-01 01:13:19 +0000579 fs->sect_perblk = fs->blksz >> fs->dev_desc->log2blksz;
Simon Glass293d7fb2012-12-26 09:53:28 +0000580
581 /* get the superblock */
582 fs->sb = zalloc(SUPERBLOCK_SIZE);
583 if (!fs->sb)
584 return -ENOMEM;
Egbert Eich50ce4c02013-05-01 01:13:19 +0000585 if (!ext4_read_superblock((char *)fs->sb))
Simon Glass293d7fb2012-12-26 09:53:28 +0000586 goto fail;
587
588 /* init journal */
589 if (ext4fs_init_journal())
590 goto fail;
591
592 /* get total no of blockgroups */
593 fs->no_blkgrp = (uint32_t)ext4fs_div_roundup(
Michael Walle58a9ecb2016-09-01 11:21:40 +0200594 le32_to_cpu(ext4fs_root->sblock.total_blocks)
595 - le32_to_cpu(ext4fs_root->sblock.first_data_block),
596 le32_to_cpu(ext4fs_root->sblock.blocks_per_group));
Simon Glass293d7fb2012-12-26 09:53:28 +0000597
598 /* get the block group descriptor table */
599 fs->gdtable_blkno = ((EXT2_MIN_BLOCK_SIZE == fs->blksz) + 1);
600 if (ext4fs_get_bgdtable() == -1) {
601 printf("Error in getting the block group descriptor table\n");
602 goto fail;
603 }
Simon Glass293d7fb2012-12-26 09:53:28 +0000604
605 /* load all the available bitmap block of the partition */
606 fs->blk_bmaps = zalloc(fs->no_blkgrp * sizeof(char *));
607 if (!fs->blk_bmaps)
608 goto fail;
609 for (i = 0; i < fs->no_blkgrp; i++) {
610 fs->blk_bmaps[i] = zalloc(fs->blksz);
611 if (!fs->blk_bmaps[i])
612 goto fail;
613 }
614
615 for (i = 0; i < fs->no_blkgrp; i++) {
Stefan Brüns688d0e72016-09-17 02:10:10 +0200616 struct ext2_block_group *bgd =
617 ext4fs_get_group_descriptor(fs, i);
618 status = ext4fs_devread(ext4fs_bg_get_block_id(bgd, fs) *
Frederic Leroy04735e92013-06-26 18:11:25 +0200619 fs->sect_perblk, 0,
Simon Glass293d7fb2012-12-26 09:53:28 +0000620 fs->blksz, (char *)fs->blk_bmaps[i]);
621 if (status == 0)
622 goto fail;
623 }
624
625 /* load all the available inode bitmap of the partition */
626 fs->inode_bmaps = zalloc(fs->no_blkgrp * sizeof(unsigned char *));
627 if (!fs->inode_bmaps)
628 goto fail;
629 for (i = 0; i < fs->no_blkgrp; i++) {
630 fs->inode_bmaps[i] = zalloc(fs->blksz);
631 if (!fs->inode_bmaps[i])
632 goto fail;
633 }
634
635 for (i = 0; i < fs->no_blkgrp; i++) {
Stefan Brüns688d0e72016-09-17 02:10:10 +0200636 struct ext2_block_group *bgd =
637 ext4fs_get_group_descriptor(fs, i);
638 status = ext4fs_devread(ext4fs_bg_get_inode_id(bgd, fs) *
Frederic Leroy04735e92013-06-26 18:11:25 +0200639 fs->sect_perblk,
Simon Glass293d7fb2012-12-26 09:53:28 +0000640 0, fs->blksz,
641 (char *)fs->inode_bmaps[i]);
642 if (status == 0)
643 goto fail;
644 }
645
646 /*
647 * check filesystem consistency with free blocks of file system
648 * some time we observed that superblock freeblocks does not match
649 * with the blockgroups freeblocks when improper
650 * reboot of a linux kernel
651 */
Stefan Brüns688d0e72016-09-17 02:10:10 +0200652 for (i = 0; i < fs->no_blkgrp; i++) {
653 struct ext2_block_group *bgd =
654 ext4fs_get_group_descriptor(fs, i);
655 real_free_blocks = real_free_blocks +
656 ext4fs_bg_get_free_blocks(bgd, fs);
657 }
658 if (real_free_blocks != ext4fs_sb_get_free_blocks(fs->sb))
659 ext4fs_sb_set_free_blocks(fs->sb, real_free_blocks);
Simon Glass293d7fb2012-12-26 09:53:28 +0000660
661 return 0;
662fail:
663 ext4fs_deinit();
664
665 return -1;
666}
667
668void ext4fs_deinit(void)
669{
670 int i;
671 struct ext2_inode inode_journal;
672 struct journal_superblock_t *jsb;
Michael Walle58a9ecb2016-09-01 11:21:40 +0200673 uint32_t blknr;
Simon Glass293d7fb2012-12-26 09:53:28 +0000674 struct ext_filesystem *fs = get_fs();
Michael Walle58a9ecb2016-09-01 11:21:40 +0200675 uint32_t new_feature_incompat;
Simon Glass293d7fb2012-12-26 09:53:28 +0000676
677 /* free journal */
678 char *temp_buff = zalloc(fs->blksz);
679 if (temp_buff) {
680 ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO,
681 &inode_journal);
682 blknr = read_allocated_block(&inode_journal,
683 EXT2_JOURNAL_SUPERBLOCK);
Frederic Leroy04735e92013-06-26 18:11:25 +0200684 ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz,
Simon Glass293d7fb2012-12-26 09:53:28 +0000685 temp_buff);
686 jsb = (struct journal_superblock_t *)temp_buff;
Michael Walle58a9ecb2016-09-01 11:21:40 +0200687 jsb->s_start = 0;
Ma Haijun05508702014-01-08 08:15:33 +0800688 put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)fs->blksz),
Simon Glass293d7fb2012-12-26 09:53:28 +0000689 (struct journal_superblock_t *)temp_buff, fs->blksz);
690 free(temp_buff);
691 }
692 ext4fs_free_journal();
693
694 /* get the superblock */
Egbert Eich50ce4c02013-05-01 01:13:19 +0000695 ext4_read_superblock((char *)fs->sb);
Michael Walle58a9ecb2016-09-01 11:21:40 +0200696 new_feature_incompat = le32_to_cpu(fs->sb->feature_incompat);
697 new_feature_incompat &= ~EXT3_FEATURE_INCOMPAT_RECOVER;
698 fs->sb->feature_incompat = cpu_to_le32(new_feature_incompat);
Simon Glass293d7fb2012-12-26 09:53:28 +0000699 put_ext4((uint64_t)(SUPERBLOCK_SIZE),
700 (struct ext2_sblock *)fs->sb, (uint32_t)SUPERBLOCK_SIZE);
701 free(fs->sb);
702 fs->sb = NULL;
703
704 if (fs->blk_bmaps) {
705 for (i = 0; i < fs->no_blkgrp; i++) {
706 free(fs->blk_bmaps[i]);
707 fs->blk_bmaps[i] = NULL;
708 }
709 free(fs->blk_bmaps);
710 fs->blk_bmaps = NULL;
711 }
712
713 if (fs->inode_bmaps) {
714 for (i = 0; i < fs->no_blkgrp; i++) {
715 free(fs->inode_bmaps[i]);
716 fs->inode_bmaps[i] = NULL;
717 }
718 free(fs->inode_bmaps);
719 fs->inode_bmaps = NULL;
720 }
721
722
723 free(fs->gdtable);
724 fs->gdtable = NULL;
Simon Glass293d7fb2012-12-26 09:53:28 +0000725 /*
726 * reinitiliazed the global inode and
727 * block bitmap first execution check variables
728 */
729 fs->first_pass_ibmap = 0;
730 fs->first_pass_bbmap = 0;
731 fs->curr_inode_no = 0;
732 fs->curr_blkno = 0;
733}
734
Stefan Brünsde9e8312016-09-06 04:36:55 +0200735/*
736 * Write data to filesystem blocks. Uses same optimization for
737 * contigous sectors as ext4fs_read_file
738 */
Simon Glass293d7fb2012-12-26 09:53:28 +0000739static int ext4fs_write_file(struct ext2_inode *file_inode,
740 int pos, unsigned int len, char *buf)
741{
742 int i;
743 int blockcnt;
Michael Walle58a9ecb2016-09-01 11:21:40 +0200744 uint32_t filesize = le32_to_cpu(file_inode->size);
Simon Glass293d7fb2012-12-26 09:53:28 +0000745 struct ext_filesystem *fs = get_fs();
Egbert Eich50ce4c02013-05-01 01:13:19 +0000746 int log2blksz = fs->dev_desc->log2blksz;
747 int log2_fs_blocksize = LOG2_BLOCK_SIZE(ext4fs_root) - log2blksz;
Simon Glass293d7fb2012-12-26 09:53:28 +0000748 int previous_block_number = -1;
749 int delayed_start = 0;
750 int delayed_extent = 0;
751 int delayed_next = 0;
752 char *delayed_buf = NULL;
753
754 /* Adjust len so it we can't read past the end of the file. */
755 if (len > filesize)
756 len = filesize;
757
758 blockcnt = ((len + pos) + fs->blksz - 1) / fs->blksz;
759
760 for (i = pos / fs->blksz; i < blockcnt; i++) {
761 long int blknr;
762 int blockend = fs->blksz;
763 int skipfirst = 0;
764 blknr = read_allocated_block(file_inode, i);
Stefan Brünsde9e8312016-09-06 04:36:55 +0200765 if (blknr <= 0)
Simon Glass293d7fb2012-12-26 09:53:28 +0000766 return -1;
767
Egbert Eich50ce4c02013-05-01 01:13:19 +0000768 blknr = blknr << log2_fs_blocksize;
Simon Glass293d7fb2012-12-26 09:53:28 +0000769
770 if (blknr) {
771 if (previous_block_number != -1) {
772 if (delayed_next == blknr) {
773 delayed_extent += blockend;
Egbert Eich50ce4c02013-05-01 01:13:19 +0000774 delayed_next += blockend >> log2blksz;
Simon Glass293d7fb2012-12-26 09:53:28 +0000775 } else { /* spill */
Egbert Eich50ce4c02013-05-01 01:13:19 +0000776 put_ext4((uint64_t)
Ma Haijun05508702014-01-08 08:15:33 +0800777 ((uint64_t)delayed_start << log2blksz),
Simon Glass293d7fb2012-12-26 09:53:28 +0000778 delayed_buf,
779 (uint32_t) delayed_extent);
780 previous_block_number = blknr;
781 delayed_start = blknr;
782 delayed_extent = blockend;
783 delayed_buf = buf;
784 delayed_next = blknr +
Egbert Eich50ce4c02013-05-01 01:13:19 +0000785 (blockend >> log2blksz);
Simon Glass293d7fb2012-12-26 09:53:28 +0000786 }
787 } else {
788 previous_block_number = blknr;
789 delayed_start = blknr;
790 delayed_extent = blockend;
791 delayed_buf = buf;
792 delayed_next = blknr +
Egbert Eich50ce4c02013-05-01 01:13:19 +0000793 (blockend >> log2blksz);
Simon Glass293d7fb2012-12-26 09:53:28 +0000794 }
795 } else {
796 if (previous_block_number != -1) {
797 /* spill */
Ma Haijun05508702014-01-08 08:15:33 +0800798 put_ext4((uint64_t) ((uint64_t)delayed_start <<
Egbert Eich50ce4c02013-05-01 01:13:19 +0000799 log2blksz),
800 delayed_buf,
Simon Glass293d7fb2012-12-26 09:53:28 +0000801 (uint32_t) delayed_extent);
802 previous_block_number = -1;
803 }
804 memset(buf, 0, fs->blksz - skipfirst);
805 }
806 buf += fs->blksz - skipfirst;
807 }
808 if (previous_block_number != -1) {
809 /* spill */
Ma Haijun05508702014-01-08 08:15:33 +0800810 put_ext4((uint64_t) ((uint64_t)delayed_start << log2blksz),
Simon Glass293d7fb2012-12-26 09:53:28 +0000811 delayed_buf, (uint32_t) delayed_extent);
812 previous_block_number = -1;
813 }
814
815 return len;
816}
817
818int ext4fs_write(const char *fname, unsigned char *buffer,
819 unsigned long sizebytes)
820{
821 int ret = 0;
822 struct ext2_inode *file_inode = NULL;
823 unsigned char *inode_buffer = NULL;
824 int parent_inodeno;
825 int inodeno;
826 time_t timestamp = 0;
827
828 uint64_t bytes_reqd_for_file;
829 unsigned int blks_reqd_for_file;
830 unsigned int blocks_remaining;
831 int existing_file_inodeno;
832 char *temp_ptr = NULL;
833 long int itable_blkno;
834 long int parent_itable_blkno;
835 long int blkoff;
836 struct ext2_sblock *sblock = &(ext4fs_root->sblock);
837 unsigned int inodes_per_block;
838 unsigned int ibmap_idx;
Stefan Brüns688d0e72016-09-17 02:10:10 +0200839 struct ext2_block_group *bgd = NULL;
Simon Glass293d7fb2012-12-26 09:53:28 +0000840 struct ext_filesystem *fs = get_fs();
841 ALLOC_CACHE_ALIGN_BUFFER(char, filename, 256);
Jeroen Hofstee46a57072014-06-09 15:29:00 +0200842 memset(filename, 0x00, 256);
Simon Glass293d7fb2012-12-26 09:53:28 +0000843
Stefan Brüns87f9fdc2016-09-06 04:36:53 +0200844 g_parent_inode = zalloc(fs->inodesz);
Simon Glass293d7fb2012-12-26 09:53:28 +0000845 if (!g_parent_inode)
846 goto fail;
847
848 if (ext4fs_init() != 0) {
849 printf("error in File System init\n");
850 return -1;
851 }
852 inodes_per_block = fs->blksz / fs->inodesz;
853 parent_inodeno = ext4fs_get_parent_inode_num(fname, filename, F_FILE);
854 if (parent_inodeno == -1)
855 goto fail;
856 if (ext4fs_iget(parent_inodeno, g_parent_inode))
857 goto fail;
Stefan Brüns10a7a1b2016-09-06 04:36:45 +0200858 /* do not mess up a directory using hash trees */
859 if (le32_to_cpu(g_parent_inode->flags) & EXT4_INDEX_FL) {
860 printf("hash tree directory\n");
861 goto fail;
862 }
Simon Glass293d7fb2012-12-26 09:53:28 +0000863 /* check if the filename is already present in root */
Stefan Brüns76a29512016-09-06 04:36:41 +0200864 existing_file_inodeno = ext4fs_filename_unlink(filename);
Simon Glass293d7fb2012-12-26 09:53:28 +0000865 if (existing_file_inodeno != -1) {
866 ret = ext4fs_delete_file(existing_file_inodeno);
867 fs->first_pass_bbmap = 0;
868 fs->curr_blkno = 0;
869
870 fs->first_pass_ibmap = 0;
871 fs->curr_inode_no = 0;
872 if (ret)
873 goto fail;
874 }
875 /* calucalate how many blocks required */
876 bytes_reqd_for_file = sizebytes;
877 blks_reqd_for_file = lldiv(bytes_reqd_for_file, fs->blksz);
878 if (do_div(bytes_reqd_for_file, fs->blksz) != 0) {
879 blks_reqd_for_file++;
880 debug("total bytes for a file %u\n", blks_reqd_for_file);
881 }
882 blocks_remaining = blks_reqd_for_file;
883 /* test for available space in partition */
Michael Walle58a9ecb2016-09-01 11:21:40 +0200884 if (le32_to_cpu(fs->sb->free_blocks) < blks_reqd_for_file) {
Simon Glass293d7fb2012-12-26 09:53:28 +0000885 printf("Not enough space on partition !!!\n");
886 goto fail;
887 }
888
Stefan Brünsa0d767e2016-09-06 04:36:42 +0200889 inodeno = ext4fs_update_parent_dentry(filename, FILETYPE_REG);
890 if (inodeno == -1)
891 goto fail;
Simon Glass293d7fb2012-12-26 09:53:28 +0000892 /* prepare file inode */
893 inode_buffer = zalloc(fs->inodesz);
894 if (!inode_buffer)
895 goto fail;
896 file_inode = (struct ext2_inode *)inode_buffer;
Michael Walle58a9ecb2016-09-01 11:21:40 +0200897 file_inode->mode = cpu_to_le16(S_IFREG | S_IRWXU |
898 S_IRGRP | S_IROTH | S_IXGRP | S_IXOTH);
Simon Glass293d7fb2012-12-26 09:53:28 +0000899 /* ToDo: Update correct time */
Michael Walle58a9ecb2016-09-01 11:21:40 +0200900 file_inode->mtime = cpu_to_le32(timestamp);
901 file_inode->atime = cpu_to_le32(timestamp);
902 file_inode->ctime = cpu_to_le32(timestamp);
903 file_inode->nlinks = cpu_to_le16(1);
904 file_inode->size = cpu_to_le32(sizebytes);
Simon Glass293d7fb2012-12-26 09:53:28 +0000905
906 /* Allocate data blocks */
907 ext4fs_allocate_blocks(file_inode, blocks_remaining,
908 &blks_reqd_for_file);
Michael Walle58a9ecb2016-09-01 11:21:40 +0200909 file_inode->blockcnt = cpu_to_le32((blks_reqd_for_file * fs->blksz) >>
910 fs->dev_desc->log2blksz);
Simon Glass293d7fb2012-12-26 09:53:28 +0000911
912 temp_ptr = zalloc(fs->blksz);
913 if (!temp_ptr)
914 goto fail;
Michael Walle58a9ecb2016-09-01 11:21:40 +0200915 ibmap_idx = inodeno / le32_to_cpu(ext4fs_root->sblock.inodes_per_group);
Simon Glass293d7fb2012-12-26 09:53:28 +0000916 inodeno--;
Stefan Brüns688d0e72016-09-17 02:10:10 +0200917 bgd = ext4fs_get_group_descriptor(fs, ibmap_idx);
918 itable_blkno = ext4fs_bg_get_inode_table_id(bgd, fs) +
Michael Walle7f101be2016-08-29 10:46:44 +0200919 (inodeno % le32_to_cpu(sblock->inodes_per_group)) /
Simon Glass293d7fb2012-12-26 09:53:28 +0000920 inodes_per_block;
921 blkoff = (inodeno % inodes_per_block) * fs->inodesz;
Frederic Leroy04735e92013-06-26 18:11:25 +0200922 ext4fs_devread((lbaint_t)itable_blkno * fs->sect_perblk, 0, fs->blksz,
923 temp_ptr);
Simon Glass293d7fb2012-12-26 09:53:28 +0000924 if (ext4fs_log_journal(temp_ptr, itable_blkno))
925 goto fail;
926
927 memcpy(temp_ptr + blkoff, inode_buffer, fs->inodesz);
928 if (ext4fs_put_metadata(temp_ptr, itable_blkno))
929 goto fail;
930 /* copy the file content into data blocks */
931 if (ext4fs_write_file(file_inode, 0, sizebytes, (char *)buffer) == -1) {
932 printf("Error in copying content\n");
Stefan Brünsde9e8312016-09-06 04:36:55 +0200933 /* FIXME: Deallocate data blocks */
Simon Glass293d7fb2012-12-26 09:53:28 +0000934 goto fail;
935 }
Michael Walle58a9ecb2016-09-01 11:21:40 +0200936 ibmap_idx = parent_inodeno / le32_to_cpu(ext4fs_root->sblock.inodes_per_group);
Simon Glass293d7fb2012-12-26 09:53:28 +0000937 parent_inodeno--;
Stefan Brüns688d0e72016-09-17 02:10:10 +0200938 bgd = ext4fs_get_group_descriptor(fs, ibmap_idx);
939 parent_itable_blkno = ext4fs_bg_get_inode_table_id(bgd, fs) +
Simon Glass293d7fb2012-12-26 09:53:28 +0000940 (parent_inodeno %
Michael Walle7f101be2016-08-29 10:46:44 +0200941 le32_to_cpu(sblock->inodes_per_group)) / inodes_per_block;
Simon Glass293d7fb2012-12-26 09:53:28 +0000942 blkoff = (parent_inodeno % inodes_per_block) * fs->inodesz;
943 if (parent_itable_blkno != itable_blkno) {
944 memset(temp_ptr, '\0', fs->blksz);
Frederic Leroy04735e92013-06-26 18:11:25 +0200945 ext4fs_devread((lbaint_t)parent_itable_blkno * fs->sect_perblk,
Simon Glass293d7fb2012-12-26 09:53:28 +0000946 0, fs->blksz, temp_ptr);
947 if (ext4fs_log_journal(temp_ptr, parent_itable_blkno))
948 goto fail;
949
Stefan Brüns87f9fdc2016-09-06 04:36:53 +0200950 memcpy(temp_ptr + blkoff, g_parent_inode, fs->inodesz);
Simon Glass293d7fb2012-12-26 09:53:28 +0000951 if (ext4fs_put_metadata(temp_ptr, parent_itable_blkno))
952 goto fail;
Simon Glass293d7fb2012-12-26 09:53:28 +0000953 } else {
954 /*
955 * If parent and child fall in same inode table block
956 * both should be kept in 1 buffer
957 */
Stefan Brüns87f9fdc2016-09-06 04:36:53 +0200958 memcpy(temp_ptr + blkoff, g_parent_inode, fs->inodesz);
Simon Glass293d7fb2012-12-26 09:53:28 +0000959 gd_index--;
960 if (ext4fs_put_metadata(temp_ptr, itable_blkno))
961 goto fail;
Simon Glass293d7fb2012-12-26 09:53:28 +0000962 }
963 ext4fs_update();
964 ext4fs_deinit();
965
966 fs->first_pass_bbmap = 0;
967 fs->curr_blkno = 0;
968 fs->first_pass_ibmap = 0;
969 fs->curr_inode_no = 0;
970 free(inode_buffer);
971 free(g_parent_inode);
Stefan Brüns87a40b62016-09-06 04:36:51 +0200972 free(temp_ptr);
Simon Glass293d7fb2012-12-26 09:53:28 +0000973 g_parent_inode = NULL;
974
975 return 0;
976fail:
977 ext4fs_deinit();
978 free(inode_buffer);
979 free(g_parent_inode);
Stefan Brüns87a40b62016-09-06 04:36:51 +0200980 free(temp_ptr);
Simon Glass293d7fb2012-12-26 09:53:28 +0000981 g_parent_inode = NULL;
982
983 return -1;
984}
Suriyan Ramasami9f12cd02014-11-17 14:39:36 -0800985
986int ext4_write_file(const char *filename, void *buf, loff_t offset,
987 loff_t len, loff_t *actwrite)
988{
989 int ret;
990
991 if (offset != 0) {
992 printf("** Cannot support non-zero offset **\n");
993 return -1;
994 }
995
Suriyan Ramasami9f12cd02014-11-17 14:39:36 -0800996 ret = ext4fs_write(filename, buf, len);
Suriyan Ramasami9f12cd02014-11-17 14:39:36 -0800997 if (ret) {
998 printf("** Error ext4fs_write() **\n");
999 goto fail;
1000 }
Suriyan Ramasami9f12cd02014-11-17 14:39:36 -08001001
Przemyslaw Marczak22b75092015-02-17 15:31:52 +01001002 *actwrite = len;
1003
Suriyan Ramasami9f12cd02014-11-17 14:39:36 -08001004 return 0;
1005
1006fail:
Przemyslaw Marczak22b75092015-02-17 15:31:52 +01001007 *actwrite = 0;
Suriyan Ramasami9f12cd02014-11-17 14:39:36 -08001008
1009 return -1;
1010}