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