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