xref: /OK3568_Linux_fs/u-boot/fs/ext4/ext4_common.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 load support in Uboot.
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  * (C) Copyright 2004
10*4882a593Smuzhiyun  * esd gmbh <www.esd-electronics.com>
11*4882a593Smuzhiyun  * Reinhard Arlt <reinhard.arlt@esd-electronics.com>
12*4882a593Smuzhiyun  *
13*4882a593Smuzhiyun  * based on code from grub2 fs/ext2.c and fs/fshelp.c by
14*4882a593Smuzhiyun  * GRUB  --  GRand Unified Bootloader
15*4882a593Smuzhiyun  * Copyright (C) 2003, 2004  Free Software Foundation, Inc.
16*4882a593Smuzhiyun  *
17*4882a593Smuzhiyun  * ext4write : Based on generic ext4 protocol.
18*4882a593Smuzhiyun  *
19*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0+
20*4882a593Smuzhiyun  */
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun #include <common.h>
23*4882a593Smuzhiyun #include <ext_common.h>
24*4882a593Smuzhiyun #include <ext4fs.h>
25*4882a593Smuzhiyun #include <inttypes.h>
26*4882a593Smuzhiyun #include <malloc.h>
27*4882a593Smuzhiyun #include <memalign.h>
28*4882a593Smuzhiyun #include <stddef.h>
29*4882a593Smuzhiyun #include <linux/stat.h>
30*4882a593Smuzhiyun #include <linux/time.h>
31*4882a593Smuzhiyun #include <asm/byteorder.h>
32*4882a593Smuzhiyun #include "ext4_common.h"
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun struct ext2_data *ext4fs_root;
35*4882a593Smuzhiyun struct ext2fs_node *ext4fs_file;
36*4882a593Smuzhiyun __le32 *ext4fs_indir1_block;
37*4882a593Smuzhiyun int ext4fs_indir1_size;
38*4882a593Smuzhiyun int ext4fs_indir1_blkno = -1;
39*4882a593Smuzhiyun __le32 *ext4fs_indir2_block;
40*4882a593Smuzhiyun int ext4fs_indir2_size;
41*4882a593Smuzhiyun int ext4fs_indir2_blkno = -1;
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun __le32 *ext4fs_indir3_block;
44*4882a593Smuzhiyun int ext4fs_indir3_size;
45*4882a593Smuzhiyun int ext4fs_indir3_blkno = -1;
46*4882a593Smuzhiyun struct ext2_inode *g_parent_inode;
47*4882a593Smuzhiyun static int symlinknest;
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun #if defined(CONFIG_EXT4_WRITE)
ext4fs_get_group_descriptor(const struct ext_filesystem * fs,uint32_t bg_idx)50*4882a593Smuzhiyun struct ext2_block_group *ext4fs_get_group_descriptor
51*4882a593Smuzhiyun 	(const struct ext_filesystem *fs, uint32_t bg_idx)
52*4882a593Smuzhiyun {
53*4882a593Smuzhiyun 	return (struct ext2_block_group *)(fs->gdtable + (bg_idx * fs->gdsize));
54*4882a593Smuzhiyun }
55*4882a593Smuzhiyun 
ext4fs_sb_free_inodes_dec(struct ext2_sblock * sb)56*4882a593Smuzhiyun static inline void ext4fs_sb_free_inodes_dec(struct ext2_sblock *sb)
57*4882a593Smuzhiyun {
58*4882a593Smuzhiyun 	sb->free_inodes = cpu_to_le32(le32_to_cpu(sb->free_inodes) - 1);
59*4882a593Smuzhiyun }
60*4882a593Smuzhiyun 
ext4fs_sb_free_blocks_dec(struct ext2_sblock * sb)61*4882a593Smuzhiyun static inline void ext4fs_sb_free_blocks_dec(struct ext2_sblock *sb)
62*4882a593Smuzhiyun {
63*4882a593Smuzhiyun 	uint64_t free_blocks = le32_to_cpu(sb->free_blocks);
64*4882a593Smuzhiyun 	free_blocks += (uint64_t)le32_to_cpu(sb->free_blocks_high) << 32;
65*4882a593Smuzhiyun 	free_blocks--;
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun 	sb->free_blocks = cpu_to_le32(free_blocks & 0xffffffff);
68*4882a593Smuzhiyun 	sb->free_blocks_high = cpu_to_le16(free_blocks >> 32);
69*4882a593Smuzhiyun }
70*4882a593Smuzhiyun 
ext4fs_bg_free_inodes_dec(struct ext2_block_group * bg,const struct ext_filesystem * fs)71*4882a593Smuzhiyun static inline void ext4fs_bg_free_inodes_dec
72*4882a593Smuzhiyun 	(struct ext2_block_group *bg, const struct ext_filesystem *fs)
73*4882a593Smuzhiyun {
74*4882a593Smuzhiyun 	uint32_t free_inodes = le16_to_cpu(bg->free_inodes);
75*4882a593Smuzhiyun 	if (fs->gdsize == 64)
76*4882a593Smuzhiyun 		free_inodes += le16_to_cpu(bg->free_inodes_high) << 16;
77*4882a593Smuzhiyun 	free_inodes--;
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun 	bg->free_inodes = cpu_to_le16(free_inodes & 0xffff);
80*4882a593Smuzhiyun 	if (fs->gdsize == 64)
81*4882a593Smuzhiyun 		bg->free_inodes_high = cpu_to_le16(free_inodes >> 16);
82*4882a593Smuzhiyun }
83*4882a593Smuzhiyun 
ext4fs_bg_free_blocks_dec(struct ext2_block_group * bg,const struct ext_filesystem * fs)84*4882a593Smuzhiyun static inline void ext4fs_bg_free_blocks_dec
85*4882a593Smuzhiyun 	(struct ext2_block_group *bg, const struct ext_filesystem *fs)
86*4882a593Smuzhiyun {
87*4882a593Smuzhiyun 	uint32_t free_blocks = le16_to_cpu(bg->free_blocks);
88*4882a593Smuzhiyun 	if (fs->gdsize == 64)
89*4882a593Smuzhiyun 		free_blocks += le16_to_cpu(bg->free_blocks_high) << 16;
90*4882a593Smuzhiyun 	free_blocks--;
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun 	bg->free_blocks = cpu_to_le16(free_blocks & 0xffff);
93*4882a593Smuzhiyun 	if (fs->gdsize == 64)
94*4882a593Smuzhiyun 		bg->free_blocks_high = cpu_to_le16(free_blocks >> 16);
95*4882a593Smuzhiyun }
96*4882a593Smuzhiyun 
ext4fs_bg_itable_unused_dec(struct ext2_block_group * bg,const struct ext_filesystem * fs)97*4882a593Smuzhiyun static inline void ext4fs_bg_itable_unused_dec
98*4882a593Smuzhiyun 	(struct ext2_block_group *bg, const struct ext_filesystem *fs)
99*4882a593Smuzhiyun {
100*4882a593Smuzhiyun 	uint32_t free_inodes = le16_to_cpu(bg->bg_itable_unused);
101*4882a593Smuzhiyun 	if (fs->gdsize == 64)
102*4882a593Smuzhiyun 		free_inodes += le16_to_cpu(bg->bg_itable_unused_high) << 16;
103*4882a593Smuzhiyun 	free_inodes--;
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun 	bg->bg_itable_unused = cpu_to_le16(free_inodes & 0xffff);
106*4882a593Smuzhiyun 	if (fs->gdsize == 64)
107*4882a593Smuzhiyun 		bg->bg_itable_unused_high = cpu_to_le16(free_inodes >> 16);
108*4882a593Smuzhiyun }
109*4882a593Smuzhiyun 
ext4fs_sb_get_free_blocks(const struct ext2_sblock * sb)110*4882a593Smuzhiyun uint64_t ext4fs_sb_get_free_blocks(const struct ext2_sblock *sb)
111*4882a593Smuzhiyun {
112*4882a593Smuzhiyun 	uint64_t free_blocks = le32_to_cpu(sb->free_blocks);
113*4882a593Smuzhiyun 	free_blocks += (uint64_t)le32_to_cpu(sb->free_blocks_high) << 32;
114*4882a593Smuzhiyun 	return free_blocks;
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun 
ext4fs_sb_set_free_blocks(struct ext2_sblock * sb,uint64_t free_blocks)117*4882a593Smuzhiyun void ext4fs_sb_set_free_blocks(struct ext2_sblock *sb, uint64_t free_blocks)
118*4882a593Smuzhiyun {
119*4882a593Smuzhiyun 	sb->free_blocks = cpu_to_le32(free_blocks & 0xffffffff);
120*4882a593Smuzhiyun 	sb->free_blocks_high = cpu_to_le16(free_blocks >> 32);
121*4882a593Smuzhiyun }
122*4882a593Smuzhiyun 
ext4fs_bg_get_free_blocks(const struct ext2_block_group * bg,const struct ext_filesystem * fs)123*4882a593Smuzhiyun uint32_t ext4fs_bg_get_free_blocks(const struct ext2_block_group *bg,
124*4882a593Smuzhiyun 				   const struct ext_filesystem *fs)
125*4882a593Smuzhiyun {
126*4882a593Smuzhiyun 	uint32_t free_blocks = le16_to_cpu(bg->free_blocks);
127*4882a593Smuzhiyun 	if (fs->gdsize == 64)
128*4882a593Smuzhiyun 		free_blocks += le16_to_cpu(bg->free_blocks_high) << 16;
129*4882a593Smuzhiyun 	return free_blocks;
130*4882a593Smuzhiyun }
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun static inline
ext4fs_bg_get_free_inodes(const struct ext2_block_group * bg,const struct ext_filesystem * fs)133*4882a593Smuzhiyun uint32_t ext4fs_bg_get_free_inodes(const struct ext2_block_group *bg,
134*4882a593Smuzhiyun 				   const struct ext_filesystem *fs)
135*4882a593Smuzhiyun {
136*4882a593Smuzhiyun 	uint32_t free_inodes = le16_to_cpu(bg->free_inodes);
137*4882a593Smuzhiyun 	if (fs->gdsize == 64)
138*4882a593Smuzhiyun 		free_inodes += le16_to_cpu(bg->free_inodes_high) << 16;
139*4882a593Smuzhiyun 	return free_inodes;
140*4882a593Smuzhiyun }
141*4882a593Smuzhiyun 
ext4fs_bg_get_flags(const struct ext2_block_group * bg)142*4882a593Smuzhiyun static inline uint16_t ext4fs_bg_get_flags(const struct ext2_block_group *bg)
143*4882a593Smuzhiyun {
144*4882a593Smuzhiyun 	return le16_to_cpu(bg->bg_flags);
145*4882a593Smuzhiyun }
146*4882a593Smuzhiyun 
ext4fs_bg_set_flags(struct ext2_block_group * bg,uint16_t flags)147*4882a593Smuzhiyun static inline void ext4fs_bg_set_flags(struct ext2_block_group *bg,
148*4882a593Smuzhiyun 				       uint16_t flags)
149*4882a593Smuzhiyun {
150*4882a593Smuzhiyun 	bg->bg_flags = cpu_to_le16(flags);
151*4882a593Smuzhiyun }
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun /* Block number of the block bitmap */
ext4fs_bg_get_block_id(const struct ext2_block_group * bg,const struct ext_filesystem * fs)154*4882a593Smuzhiyun uint64_t ext4fs_bg_get_block_id(const struct ext2_block_group *bg,
155*4882a593Smuzhiyun 				const struct ext_filesystem *fs)
156*4882a593Smuzhiyun {
157*4882a593Smuzhiyun 	uint64_t block_nr = le32_to_cpu(bg->block_id);
158*4882a593Smuzhiyun 	if (fs->gdsize == 64)
159*4882a593Smuzhiyun 		block_nr += (uint64_t)le32_to_cpu(bg->block_id_high) << 32;
160*4882a593Smuzhiyun 	return block_nr;
161*4882a593Smuzhiyun }
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun /* Block number of the inode bitmap */
ext4fs_bg_get_inode_id(const struct ext2_block_group * bg,const struct ext_filesystem * fs)164*4882a593Smuzhiyun uint64_t ext4fs_bg_get_inode_id(const struct ext2_block_group *bg,
165*4882a593Smuzhiyun 				const struct ext_filesystem *fs)
166*4882a593Smuzhiyun {
167*4882a593Smuzhiyun 	uint64_t block_nr = le32_to_cpu(bg->inode_id);
168*4882a593Smuzhiyun 	if (fs->gdsize == 64)
169*4882a593Smuzhiyun 		block_nr += (uint64_t)le32_to_cpu(bg->inode_id_high) << 32;
170*4882a593Smuzhiyun 	return block_nr;
171*4882a593Smuzhiyun }
172*4882a593Smuzhiyun #endif
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun /* Block number of the inode table */
ext4fs_bg_get_inode_table_id(const struct ext2_block_group * bg,const struct ext_filesystem * fs)175*4882a593Smuzhiyun uint64_t ext4fs_bg_get_inode_table_id(const struct ext2_block_group *bg,
176*4882a593Smuzhiyun 				      const struct ext_filesystem *fs)
177*4882a593Smuzhiyun {
178*4882a593Smuzhiyun 	uint64_t block_nr = le32_to_cpu(bg->inode_table_id);
179*4882a593Smuzhiyun 	if (fs->gdsize == 64)
180*4882a593Smuzhiyun 		block_nr +=
181*4882a593Smuzhiyun 			(uint64_t)le32_to_cpu(bg->inode_table_id_high) << 32;
182*4882a593Smuzhiyun 	return block_nr;
183*4882a593Smuzhiyun }
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun #if defined(CONFIG_EXT4_WRITE)
ext4fs_div_roundup(uint32_t size,uint32_t n)186*4882a593Smuzhiyun uint32_t ext4fs_div_roundup(uint32_t size, uint32_t n)
187*4882a593Smuzhiyun {
188*4882a593Smuzhiyun 	uint32_t res = size / n;
189*4882a593Smuzhiyun 	if (res * n != size)
190*4882a593Smuzhiyun 		res++;
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun 	return res;
193*4882a593Smuzhiyun }
194*4882a593Smuzhiyun 
put_ext4(uint64_t off,void * buf,uint32_t size)195*4882a593Smuzhiyun void put_ext4(uint64_t off, void *buf, uint32_t size)
196*4882a593Smuzhiyun {
197*4882a593Smuzhiyun 	uint64_t startblock;
198*4882a593Smuzhiyun 	uint64_t remainder;
199*4882a593Smuzhiyun 	unsigned char *temp_ptr = NULL;
200*4882a593Smuzhiyun 	struct ext_filesystem *fs = get_fs();
201*4882a593Smuzhiyun 	int log2blksz = fs->dev_desc->log2blksz;
202*4882a593Smuzhiyun 	ALLOC_CACHE_ALIGN_BUFFER(unsigned char, sec_buf, fs->dev_desc->blksz);
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun 	startblock = off >> log2blksz;
205*4882a593Smuzhiyun 	startblock += part_offset;
206*4882a593Smuzhiyun 	remainder = off & (uint64_t)(fs->dev_desc->blksz - 1);
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun 	if (fs->dev_desc == NULL)
209*4882a593Smuzhiyun 		return;
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun 	if ((startblock + (size >> log2blksz)) >
212*4882a593Smuzhiyun 	    (part_offset + fs->total_sect)) {
213*4882a593Smuzhiyun 		printf("part_offset is " LBAFU "\n", part_offset);
214*4882a593Smuzhiyun 		printf("total_sector is %" PRIu64 "\n", fs->total_sect);
215*4882a593Smuzhiyun 		printf("error: overflow occurs\n");
216*4882a593Smuzhiyun 		return;
217*4882a593Smuzhiyun 	}
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun 	if (remainder) {
220*4882a593Smuzhiyun 		blk_dread(fs->dev_desc, startblock, 1, sec_buf);
221*4882a593Smuzhiyun 		temp_ptr = sec_buf;
222*4882a593Smuzhiyun 		memcpy((temp_ptr + remainder), (unsigned char *)buf, size);
223*4882a593Smuzhiyun 		blk_dwrite(fs->dev_desc, startblock, 1, sec_buf);
224*4882a593Smuzhiyun 	} else {
225*4882a593Smuzhiyun 		if (size >> log2blksz != 0) {
226*4882a593Smuzhiyun 			blk_dwrite(fs->dev_desc, startblock, size >> log2blksz,
227*4882a593Smuzhiyun 				   (unsigned long *)buf);
228*4882a593Smuzhiyun 		} else {
229*4882a593Smuzhiyun 			blk_dread(fs->dev_desc, startblock, 1, sec_buf);
230*4882a593Smuzhiyun 			temp_ptr = sec_buf;
231*4882a593Smuzhiyun 			memcpy(temp_ptr, buf, size);
232*4882a593Smuzhiyun 			blk_dwrite(fs->dev_desc, startblock, 1,
233*4882a593Smuzhiyun 				   (unsigned long *)sec_buf);
234*4882a593Smuzhiyun 		}
235*4882a593Smuzhiyun 	}
236*4882a593Smuzhiyun }
237*4882a593Smuzhiyun 
_get_new_inode_no(unsigned char * buffer)238*4882a593Smuzhiyun static int _get_new_inode_no(unsigned char *buffer)
239*4882a593Smuzhiyun {
240*4882a593Smuzhiyun 	struct ext_filesystem *fs = get_fs();
241*4882a593Smuzhiyun 	unsigned char input;
242*4882a593Smuzhiyun 	int operand, status;
243*4882a593Smuzhiyun 	int count = 1;
244*4882a593Smuzhiyun 	int j = 0;
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 	/* get the blocksize of the filesystem */
247*4882a593Smuzhiyun 	unsigned char *ptr = buffer;
248*4882a593Smuzhiyun 	while (*ptr == 255) {
249*4882a593Smuzhiyun 		ptr++;
250*4882a593Smuzhiyun 		count += 8;
251*4882a593Smuzhiyun 		if (count > le32_to_cpu(ext4fs_root->sblock.inodes_per_group))
252*4882a593Smuzhiyun 			return -1;
253*4882a593Smuzhiyun 	}
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 	for (j = 0; j < fs->blksz; j++) {
256*4882a593Smuzhiyun 		input = *ptr;
257*4882a593Smuzhiyun 		int i = 0;
258*4882a593Smuzhiyun 		while (i <= 7) {
259*4882a593Smuzhiyun 			operand = 1 << i;
260*4882a593Smuzhiyun 			status = input & operand;
261*4882a593Smuzhiyun 			if (status) {
262*4882a593Smuzhiyun 				i++;
263*4882a593Smuzhiyun 				count++;
264*4882a593Smuzhiyun 			} else {
265*4882a593Smuzhiyun 				*ptr |= operand;
266*4882a593Smuzhiyun 				return count;
267*4882a593Smuzhiyun 			}
268*4882a593Smuzhiyun 		}
269*4882a593Smuzhiyun 		ptr = ptr + 1;
270*4882a593Smuzhiyun 	}
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun 	return -1;
273*4882a593Smuzhiyun }
274*4882a593Smuzhiyun 
_get_new_blk_no(unsigned char * buffer)275*4882a593Smuzhiyun static int _get_new_blk_no(unsigned char *buffer)
276*4882a593Smuzhiyun {
277*4882a593Smuzhiyun 	int operand;
278*4882a593Smuzhiyun 	int count = 0;
279*4882a593Smuzhiyun 	int i;
280*4882a593Smuzhiyun 	unsigned char *ptr = buffer;
281*4882a593Smuzhiyun 	struct ext_filesystem *fs = get_fs();
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun 	while (*ptr == 255) {
284*4882a593Smuzhiyun 		ptr++;
285*4882a593Smuzhiyun 		count += 8;
286*4882a593Smuzhiyun 		if (count == (fs->blksz * 8))
287*4882a593Smuzhiyun 			return -1;
288*4882a593Smuzhiyun 	}
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun 	if (fs->blksz == 1024)
291*4882a593Smuzhiyun 		count += 1;
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun 	for (i = 0; i <= 7; i++) {
294*4882a593Smuzhiyun 		operand = 1 << i;
295*4882a593Smuzhiyun 		if (*ptr & operand) {
296*4882a593Smuzhiyun 			count++;
297*4882a593Smuzhiyun 		} else {
298*4882a593Smuzhiyun 			*ptr |= operand;
299*4882a593Smuzhiyun 			return count;
300*4882a593Smuzhiyun 		}
301*4882a593Smuzhiyun 	}
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun 	return -1;
304*4882a593Smuzhiyun }
305*4882a593Smuzhiyun 
ext4fs_set_block_bmap(long int blockno,unsigned char * buffer,int index)306*4882a593Smuzhiyun int ext4fs_set_block_bmap(long int blockno, unsigned char *buffer, int index)
307*4882a593Smuzhiyun {
308*4882a593Smuzhiyun 	int i, remainder, status;
309*4882a593Smuzhiyun 	unsigned char *ptr = buffer;
310*4882a593Smuzhiyun 	unsigned char operand;
311*4882a593Smuzhiyun 	i = blockno / 8;
312*4882a593Smuzhiyun 	remainder = blockno % 8;
313*4882a593Smuzhiyun 	int blocksize = EXT2_BLOCK_SIZE(ext4fs_root);
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun 	i = i - (index * blocksize);
316*4882a593Smuzhiyun 	if (blocksize != 1024) {
317*4882a593Smuzhiyun 		ptr = ptr + i;
318*4882a593Smuzhiyun 		operand = 1 << remainder;
319*4882a593Smuzhiyun 		status = *ptr & operand;
320*4882a593Smuzhiyun 		if (status)
321*4882a593Smuzhiyun 			return -1;
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun 		*ptr = *ptr | operand;
324*4882a593Smuzhiyun 		return 0;
325*4882a593Smuzhiyun 	} else {
326*4882a593Smuzhiyun 		if (remainder == 0) {
327*4882a593Smuzhiyun 			ptr = ptr + i - 1;
328*4882a593Smuzhiyun 			operand = (1 << 7);
329*4882a593Smuzhiyun 		} else {
330*4882a593Smuzhiyun 			ptr = ptr + i;
331*4882a593Smuzhiyun 			operand = (1 << (remainder - 1));
332*4882a593Smuzhiyun 		}
333*4882a593Smuzhiyun 		status = *ptr & operand;
334*4882a593Smuzhiyun 		if (status)
335*4882a593Smuzhiyun 			return -1;
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun 		*ptr = *ptr | operand;
338*4882a593Smuzhiyun 		return 0;
339*4882a593Smuzhiyun 	}
340*4882a593Smuzhiyun }
341*4882a593Smuzhiyun 
ext4fs_reset_block_bmap(long int blockno,unsigned char * buffer,int index)342*4882a593Smuzhiyun void ext4fs_reset_block_bmap(long int blockno, unsigned char *buffer, int index)
343*4882a593Smuzhiyun {
344*4882a593Smuzhiyun 	int i, remainder, status;
345*4882a593Smuzhiyun 	unsigned char *ptr = buffer;
346*4882a593Smuzhiyun 	unsigned char operand;
347*4882a593Smuzhiyun 	i = blockno / 8;
348*4882a593Smuzhiyun 	remainder = blockno % 8;
349*4882a593Smuzhiyun 	int blocksize = EXT2_BLOCK_SIZE(ext4fs_root);
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun 	i = i - (index * blocksize);
352*4882a593Smuzhiyun 	if (blocksize != 1024) {
353*4882a593Smuzhiyun 		ptr = ptr + i;
354*4882a593Smuzhiyun 		operand = (1 << remainder);
355*4882a593Smuzhiyun 		status = *ptr & operand;
356*4882a593Smuzhiyun 		if (status)
357*4882a593Smuzhiyun 			*ptr = *ptr & ~(operand);
358*4882a593Smuzhiyun 	} else {
359*4882a593Smuzhiyun 		if (remainder == 0) {
360*4882a593Smuzhiyun 			ptr = ptr + i - 1;
361*4882a593Smuzhiyun 			operand = (1 << 7);
362*4882a593Smuzhiyun 		} else {
363*4882a593Smuzhiyun 			ptr = ptr + i;
364*4882a593Smuzhiyun 			operand = (1 << (remainder - 1));
365*4882a593Smuzhiyun 		}
366*4882a593Smuzhiyun 		status = *ptr & operand;
367*4882a593Smuzhiyun 		if (status)
368*4882a593Smuzhiyun 			*ptr = *ptr & ~(operand);
369*4882a593Smuzhiyun 	}
370*4882a593Smuzhiyun }
371*4882a593Smuzhiyun 
ext4fs_set_inode_bmap(int inode_no,unsigned char * buffer,int index)372*4882a593Smuzhiyun int ext4fs_set_inode_bmap(int inode_no, unsigned char *buffer, int index)
373*4882a593Smuzhiyun {
374*4882a593Smuzhiyun 	int i, remainder, status;
375*4882a593Smuzhiyun 	unsigned char *ptr = buffer;
376*4882a593Smuzhiyun 	unsigned char operand;
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun 	inode_no -= (index * le32_to_cpu(ext4fs_root->sblock.inodes_per_group));
379*4882a593Smuzhiyun 	i = inode_no / 8;
380*4882a593Smuzhiyun 	remainder = inode_no % 8;
381*4882a593Smuzhiyun 	if (remainder == 0) {
382*4882a593Smuzhiyun 		ptr = ptr + i - 1;
383*4882a593Smuzhiyun 		operand = (1 << 7);
384*4882a593Smuzhiyun 	} else {
385*4882a593Smuzhiyun 		ptr = ptr + i;
386*4882a593Smuzhiyun 		operand = (1 << (remainder - 1));
387*4882a593Smuzhiyun 	}
388*4882a593Smuzhiyun 	status = *ptr & operand;
389*4882a593Smuzhiyun 	if (status)
390*4882a593Smuzhiyun 		return -1;
391*4882a593Smuzhiyun 
392*4882a593Smuzhiyun 	*ptr = *ptr | operand;
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun 	return 0;
395*4882a593Smuzhiyun }
396*4882a593Smuzhiyun 
ext4fs_reset_inode_bmap(int inode_no,unsigned char * buffer,int index)397*4882a593Smuzhiyun void ext4fs_reset_inode_bmap(int inode_no, unsigned char *buffer, int index)
398*4882a593Smuzhiyun {
399*4882a593Smuzhiyun 	int i, remainder, status;
400*4882a593Smuzhiyun 	unsigned char *ptr = buffer;
401*4882a593Smuzhiyun 	unsigned char operand;
402*4882a593Smuzhiyun 
403*4882a593Smuzhiyun 	inode_no -= (index * le32_to_cpu(ext4fs_root->sblock.inodes_per_group));
404*4882a593Smuzhiyun 	i = inode_no / 8;
405*4882a593Smuzhiyun 	remainder = inode_no % 8;
406*4882a593Smuzhiyun 	if (remainder == 0) {
407*4882a593Smuzhiyun 		ptr = ptr + i - 1;
408*4882a593Smuzhiyun 		operand = (1 << 7);
409*4882a593Smuzhiyun 	} else {
410*4882a593Smuzhiyun 		ptr = ptr + i;
411*4882a593Smuzhiyun 		operand = (1 << (remainder - 1));
412*4882a593Smuzhiyun 	}
413*4882a593Smuzhiyun 	status = *ptr & operand;
414*4882a593Smuzhiyun 	if (status)
415*4882a593Smuzhiyun 		*ptr = *ptr & ~(operand);
416*4882a593Smuzhiyun }
417*4882a593Smuzhiyun 
ext4fs_checksum_update(uint32_t i)418*4882a593Smuzhiyun uint16_t ext4fs_checksum_update(uint32_t i)
419*4882a593Smuzhiyun {
420*4882a593Smuzhiyun 	struct ext2_block_group *desc;
421*4882a593Smuzhiyun 	struct ext_filesystem *fs = get_fs();
422*4882a593Smuzhiyun 	uint16_t crc = 0;
423*4882a593Smuzhiyun 	__le32 le32_i = cpu_to_le32(i);
424*4882a593Smuzhiyun 
425*4882a593Smuzhiyun 	desc = ext4fs_get_group_descriptor(fs, i);
426*4882a593Smuzhiyun 	if (le32_to_cpu(fs->sb->feature_ro_compat) & EXT4_FEATURE_RO_COMPAT_GDT_CSUM) {
427*4882a593Smuzhiyun 		int offset = offsetof(struct ext2_block_group, bg_checksum);
428*4882a593Smuzhiyun 
429*4882a593Smuzhiyun 		crc = ext2fs_crc16(~0, fs->sb->unique_id,
430*4882a593Smuzhiyun 				   sizeof(fs->sb->unique_id));
431*4882a593Smuzhiyun 		crc = ext2fs_crc16(crc, &le32_i, sizeof(le32_i));
432*4882a593Smuzhiyun 		crc = ext2fs_crc16(crc, desc, offset);
433*4882a593Smuzhiyun 		offset += sizeof(desc->bg_checksum);	/* skip checksum */
434*4882a593Smuzhiyun 		assert(offset == sizeof(*desc));
435*4882a593Smuzhiyun 		if (offset < fs->gdsize) {
436*4882a593Smuzhiyun 			crc = ext2fs_crc16(crc, (__u8 *)desc + offset,
437*4882a593Smuzhiyun 					   fs->gdsize - offset);
438*4882a593Smuzhiyun 		}
439*4882a593Smuzhiyun 	}
440*4882a593Smuzhiyun 
441*4882a593Smuzhiyun 	return crc;
442*4882a593Smuzhiyun }
443*4882a593Smuzhiyun 
check_void_in_dentry(struct ext2_dirent * dir,char * filename)444*4882a593Smuzhiyun static int check_void_in_dentry(struct ext2_dirent *dir, char *filename)
445*4882a593Smuzhiyun {
446*4882a593Smuzhiyun 	int dentry_length;
447*4882a593Smuzhiyun 	int sizeof_void_space;
448*4882a593Smuzhiyun 	int new_entry_byte_reqd;
449*4882a593Smuzhiyun 	short padding_factor = 0;
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun 	if (dir->namelen % 4 != 0)
452*4882a593Smuzhiyun 		padding_factor = 4 - (dir->namelen % 4);
453*4882a593Smuzhiyun 
454*4882a593Smuzhiyun 	dentry_length = sizeof(struct ext2_dirent) +
455*4882a593Smuzhiyun 			dir->namelen + padding_factor;
456*4882a593Smuzhiyun 	sizeof_void_space = le16_to_cpu(dir->direntlen) - dentry_length;
457*4882a593Smuzhiyun 	if (sizeof_void_space == 0)
458*4882a593Smuzhiyun 		return 0;
459*4882a593Smuzhiyun 
460*4882a593Smuzhiyun 	padding_factor = 0;
461*4882a593Smuzhiyun 	if (strlen(filename) % 4 != 0)
462*4882a593Smuzhiyun 		padding_factor = 4 - (strlen(filename) % 4);
463*4882a593Smuzhiyun 
464*4882a593Smuzhiyun 	new_entry_byte_reqd = strlen(filename) +
465*4882a593Smuzhiyun 	    sizeof(struct ext2_dirent) + padding_factor;
466*4882a593Smuzhiyun 	if (sizeof_void_space >= new_entry_byte_reqd) {
467*4882a593Smuzhiyun 		dir->direntlen = cpu_to_le16(dentry_length);
468*4882a593Smuzhiyun 		return sizeof_void_space;
469*4882a593Smuzhiyun 	}
470*4882a593Smuzhiyun 
471*4882a593Smuzhiyun 	return 0;
472*4882a593Smuzhiyun }
473*4882a593Smuzhiyun 
ext4fs_update_parent_dentry(char * filename,int file_type)474*4882a593Smuzhiyun int ext4fs_update_parent_dentry(char *filename, int file_type)
475*4882a593Smuzhiyun {
476*4882a593Smuzhiyun 	unsigned int *zero_buffer = NULL;
477*4882a593Smuzhiyun 	char *root_first_block_buffer = NULL;
478*4882a593Smuzhiyun 	int blk_idx;
479*4882a593Smuzhiyun 	long int first_block_no_of_root = 0;
480*4882a593Smuzhiyun 	int totalbytes = 0;
481*4882a593Smuzhiyun 	unsigned int new_entry_byte_reqd;
482*4882a593Smuzhiyun 	int sizeof_void_space = 0;
483*4882a593Smuzhiyun 	int templength = 0;
484*4882a593Smuzhiyun 	int inodeno = -1;
485*4882a593Smuzhiyun 	int status;
486*4882a593Smuzhiyun 	struct ext_filesystem *fs = get_fs();
487*4882a593Smuzhiyun 	/* directory entry */
488*4882a593Smuzhiyun 	struct ext2_dirent *dir;
489*4882a593Smuzhiyun 	char *temp_dir = NULL;
490*4882a593Smuzhiyun 	uint32_t new_blk_no;
491*4882a593Smuzhiyun 	uint32_t new_size;
492*4882a593Smuzhiyun 	uint32_t new_blockcnt;
493*4882a593Smuzhiyun 	uint32_t directory_blocks;
494*4882a593Smuzhiyun 
495*4882a593Smuzhiyun 	zero_buffer = zalloc(fs->blksz);
496*4882a593Smuzhiyun 	if (!zero_buffer) {
497*4882a593Smuzhiyun 		printf("No Memory\n");
498*4882a593Smuzhiyun 		return -1;
499*4882a593Smuzhiyun 	}
500*4882a593Smuzhiyun 	root_first_block_buffer = zalloc(fs->blksz);
501*4882a593Smuzhiyun 	if (!root_first_block_buffer) {
502*4882a593Smuzhiyun 		free(zero_buffer);
503*4882a593Smuzhiyun 		printf("No Memory\n");
504*4882a593Smuzhiyun 		return -1;
505*4882a593Smuzhiyun 	}
506*4882a593Smuzhiyun 	new_entry_byte_reqd = ROUND(strlen(filename) +
507*4882a593Smuzhiyun 				    sizeof(struct ext2_dirent), 4);
508*4882a593Smuzhiyun restart:
509*4882a593Smuzhiyun 	directory_blocks = le32_to_cpu(g_parent_inode->size) >>
510*4882a593Smuzhiyun 		LOG2_BLOCK_SIZE(ext4fs_root);
511*4882a593Smuzhiyun 	blk_idx = directory_blocks - 1;
512*4882a593Smuzhiyun 
513*4882a593Smuzhiyun restart_read:
514*4882a593Smuzhiyun 	/* read the block no allocated to a file */
515*4882a593Smuzhiyun 	first_block_no_of_root = read_allocated_block(g_parent_inode, blk_idx);
516*4882a593Smuzhiyun 	if (first_block_no_of_root <= 0)
517*4882a593Smuzhiyun 		goto fail;
518*4882a593Smuzhiyun 
519*4882a593Smuzhiyun 	status = ext4fs_devread((lbaint_t)first_block_no_of_root
520*4882a593Smuzhiyun 				* fs->sect_perblk,
521*4882a593Smuzhiyun 				0, fs->blksz, root_first_block_buffer);
522*4882a593Smuzhiyun 	if (status == 0)
523*4882a593Smuzhiyun 		goto fail;
524*4882a593Smuzhiyun 
525*4882a593Smuzhiyun 	if (ext4fs_log_journal(root_first_block_buffer, first_block_no_of_root))
526*4882a593Smuzhiyun 		goto fail;
527*4882a593Smuzhiyun 	dir = (struct ext2_dirent *)root_first_block_buffer;
528*4882a593Smuzhiyun 	totalbytes = 0;
529*4882a593Smuzhiyun 
530*4882a593Smuzhiyun 	while (le16_to_cpu(dir->direntlen) > 0) {
531*4882a593Smuzhiyun 		unsigned short used_len = ROUND(dir->namelen +
532*4882a593Smuzhiyun 		    sizeof(struct ext2_dirent), 4);
533*4882a593Smuzhiyun 
534*4882a593Smuzhiyun 		/* last entry of block */
535*4882a593Smuzhiyun 		if (fs->blksz - totalbytes == le16_to_cpu(dir->direntlen)) {
536*4882a593Smuzhiyun 
537*4882a593Smuzhiyun 			/* check if new entry fits */
538*4882a593Smuzhiyun 			if ((used_len + new_entry_byte_reqd) <=
539*4882a593Smuzhiyun 			    le16_to_cpu(dir->direntlen)) {
540*4882a593Smuzhiyun 				dir->direntlen = cpu_to_le16(used_len);
541*4882a593Smuzhiyun 				break;
542*4882a593Smuzhiyun 			} else {
543*4882a593Smuzhiyun 				if (blk_idx > 0) {
544*4882a593Smuzhiyun 					printf("Block full, trying previous\n");
545*4882a593Smuzhiyun 					blk_idx--;
546*4882a593Smuzhiyun 					goto restart_read;
547*4882a593Smuzhiyun 				}
548*4882a593Smuzhiyun 				printf("All blocks full: Allocate new\n");
549*4882a593Smuzhiyun 
550*4882a593Smuzhiyun 				if (le32_to_cpu(g_parent_inode->flags) &
551*4882a593Smuzhiyun 						EXT4_EXTENTS_FL) {
552*4882a593Smuzhiyun 					printf("Directory uses extents\n");
553*4882a593Smuzhiyun 					goto fail;
554*4882a593Smuzhiyun 				}
555*4882a593Smuzhiyun 				if (directory_blocks >= INDIRECT_BLOCKS) {
556*4882a593Smuzhiyun 					printf("Directory exceeds limit\n");
557*4882a593Smuzhiyun 					goto fail;
558*4882a593Smuzhiyun 				}
559*4882a593Smuzhiyun 				new_blk_no = ext4fs_get_new_blk_no();
560*4882a593Smuzhiyun 				if (new_blk_no == -1) {
561*4882a593Smuzhiyun 					printf("no block left to assign\n");
562*4882a593Smuzhiyun 					goto fail;
563*4882a593Smuzhiyun 				}
564*4882a593Smuzhiyun 				put_ext4((uint64_t)new_blk_no * fs->blksz, zero_buffer, fs->blksz);
565*4882a593Smuzhiyun 				g_parent_inode->b.blocks.
566*4882a593Smuzhiyun 					dir_blocks[directory_blocks] =
567*4882a593Smuzhiyun 					cpu_to_le32(new_blk_no);
568*4882a593Smuzhiyun 
569*4882a593Smuzhiyun 				new_size = le32_to_cpu(g_parent_inode->size);
570*4882a593Smuzhiyun 				new_size += fs->blksz;
571*4882a593Smuzhiyun 				g_parent_inode->size = cpu_to_le32(new_size);
572*4882a593Smuzhiyun 
573*4882a593Smuzhiyun 				new_blockcnt = le32_to_cpu(g_parent_inode->blockcnt);
574*4882a593Smuzhiyun 				new_blockcnt += fs->sect_perblk;
575*4882a593Smuzhiyun 				g_parent_inode->blockcnt = cpu_to_le32(new_blockcnt);
576*4882a593Smuzhiyun 
577*4882a593Smuzhiyun 				if (ext4fs_put_metadata
578*4882a593Smuzhiyun 				    (root_first_block_buffer,
579*4882a593Smuzhiyun 				     first_block_no_of_root))
580*4882a593Smuzhiyun 					goto fail;
581*4882a593Smuzhiyun 				goto restart;
582*4882a593Smuzhiyun 			}
583*4882a593Smuzhiyun 		}
584*4882a593Smuzhiyun 
585*4882a593Smuzhiyun 		templength = le16_to_cpu(dir->direntlen);
586*4882a593Smuzhiyun 		totalbytes = totalbytes + templength;
587*4882a593Smuzhiyun 		sizeof_void_space = check_void_in_dentry(dir, filename);
588*4882a593Smuzhiyun 		if (sizeof_void_space)
589*4882a593Smuzhiyun 			break;
590*4882a593Smuzhiyun 
591*4882a593Smuzhiyun 		dir = (struct ext2_dirent *)((char *)dir + templength);
592*4882a593Smuzhiyun 	}
593*4882a593Smuzhiyun 
594*4882a593Smuzhiyun 	/* make a pointer ready for creating next directory entry */
595*4882a593Smuzhiyun 	templength = le16_to_cpu(dir->direntlen);
596*4882a593Smuzhiyun 	totalbytes = totalbytes + templength;
597*4882a593Smuzhiyun 	dir = (struct ext2_dirent *)((char *)dir + templength);
598*4882a593Smuzhiyun 
599*4882a593Smuzhiyun 	/* get the next available inode number */
600*4882a593Smuzhiyun 	inodeno = ext4fs_get_new_inode_no();
601*4882a593Smuzhiyun 	if (inodeno == -1) {
602*4882a593Smuzhiyun 		printf("no inode left to assign\n");
603*4882a593Smuzhiyun 		goto fail;
604*4882a593Smuzhiyun 	}
605*4882a593Smuzhiyun 	dir->inode = cpu_to_le32(inodeno);
606*4882a593Smuzhiyun 	if (sizeof_void_space)
607*4882a593Smuzhiyun 		dir->direntlen = cpu_to_le16(sizeof_void_space);
608*4882a593Smuzhiyun 	else
609*4882a593Smuzhiyun 		dir->direntlen = cpu_to_le16(fs->blksz - totalbytes);
610*4882a593Smuzhiyun 
611*4882a593Smuzhiyun 	dir->namelen = strlen(filename);
612*4882a593Smuzhiyun 	dir->filetype = FILETYPE_REG;	/* regular file */
613*4882a593Smuzhiyun 	temp_dir = (char *)dir;
614*4882a593Smuzhiyun 	temp_dir = temp_dir + sizeof(struct ext2_dirent);
615*4882a593Smuzhiyun 	memcpy(temp_dir, filename, strlen(filename));
616*4882a593Smuzhiyun 
617*4882a593Smuzhiyun 	/* update or write  the 1st block of root inode */
618*4882a593Smuzhiyun 	if (ext4fs_put_metadata(root_first_block_buffer,
619*4882a593Smuzhiyun 				first_block_no_of_root))
620*4882a593Smuzhiyun 		goto fail;
621*4882a593Smuzhiyun 
622*4882a593Smuzhiyun fail:
623*4882a593Smuzhiyun 	free(zero_buffer);
624*4882a593Smuzhiyun 	free(root_first_block_buffer);
625*4882a593Smuzhiyun 
626*4882a593Smuzhiyun 	return inodeno;
627*4882a593Smuzhiyun }
628*4882a593Smuzhiyun 
search_dir(struct ext2_inode * parent_inode,char * dirname)629*4882a593Smuzhiyun static int search_dir(struct ext2_inode *parent_inode, char *dirname)
630*4882a593Smuzhiyun {
631*4882a593Smuzhiyun 	int status;
632*4882a593Smuzhiyun 	int inodeno = 0;
633*4882a593Smuzhiyun 	int offset;
634*4882a593Smuzhiyun 	int blk_idx;
635*4882a593Smuzhiyun 	long int blknr;
636*4882a593Smuzhiyun 	char *block_buffer = NULL;
637*4882a593Smuzhiyun 	struct ext2_dirent *dir = NULL;
638*4882a593Smuzhiyun 	struct ext_filesystem *fs = get_fs();
639*4882a593Smuzhiyun 	uint32_t directory_blocks;
640*4882a593Smuzhiyun 	char *direntname;
641*4882a593Smuzhiyun 
642*4882a593Smuzhiyun 	directory_blocks = le32_to_cpu(parent_inode->size) >>
643*4882a593Smuzhiyun 		LOG2_BLOCK_SIZE(ext4fs_root);
644*4882a593Smuzhiyun 
645*4882a593Smuzhiyun 	block_buffer = zalloc(fs->blksz);
646*4882a593Smuzhiyun 	if (!block_buffer)
647*4882a593Smuzhiyun 		goto fail;
648*4882a593Smuzhiyun 
649*4882a593Smuzhiyun 	/* get the block no allocated to a file */
650*4882a593Smuzhiyun 	for (blk_idx = 0; blk_idx < directory_blocks; blk_idx++) {
651*4882a593Smuzhiyun 		blknr = read_allocated_block(parent_inode, blk_idx);
652*4882a593Smuzhiyun 		if (blknr <= 0)
653*4882a593Smuzhiyun 			goto fail;
654*4882a593Smuzhiyun 
655*4882a593Smuzhiyun 		/* read the directory block */
656*4882a593Smuzhiyun 		status = ext4fs_devread((lbaint_t)blknr * fs->sect_perblk,
657*4882a593Smuzhiyun 					0, fs->blksz, (char *)block_buffer);
658*4882a593Smuzhiyun 		if (status == 0)
659*4882a593Smuzhiyun 			goto fail;
660*4882a593Smuzhiyun 
661*4882a593Smuzhiyun 		offset = 0;
662*4882a593Smuzhiyun 		do {
663*4882a593Smuzhiyun 			if (offset & 3) {
664*4882a593Smuzhiyun 				printf("Badly aligned ext2_dirent\n");
665*4882a593Smuzhiyun 				break;
666*4882a593Smuzhiyun 			}
667*4882a593Smuzhiyun 
668*4882a593Smuzhiyun 			dir = (struct ext2_dirent *)(block_buffer + offset);
669*4882a593Smuzhiyun 			direntname = (char*)(dir) + sizeof(struct ext2_dirent);
670*4882a593Smuzhiyun 
671*4882a593Smuzhiyun 			int direntlen = le16_to_cpu(dir->direntlen);
672*4882a593Smuzhiyun 			if (direntlen < sizeof(struct ext2_dirent))
673*4882a593Smuzhiyun 				break;
674*4882a593Smuzhiyun 
675*4882a593Smuzhiyun 			if (dir->inode && (strlen(dirname) == dir->namelen) &&
676*4882a593Smuzhiyun 			    (strncmp(dirname, direntname, dir->namelen) == 0)) {
677*4882a593Smuzhiyun 				inodeno = le32_to_cpu(dir->inode);
678*4882a593Smuzhiyun 				break;
679*4882a593Smuzhiyun 			}
680*4882a593Smuzhiyun 
681*4882a593Smuzhiyun 			offset += direntlen;
682*4882a593Smuzhiyun 
683*4882a593Smuzhiyun 		} while (offset < fs->blksz);
684*4882a593Smuzhiyun 
685*4882a593Smuzhiyun 		if (inodeno > 0) {
686*4882a593Smuzhiyun 			free(block_buffer);
687*4882a593Smuzhiyun 			return inodeno;
688*4882a593Smuzhiyun 		}
689*4882a593Smuzhiyun 	}
690*4882a593Smuzhiyun 
691*4882a593Smuzhiyun fail:
692*4882a593Smuzhiyun 	free(block_buffer);
693*4882a593Smuzhiyun 
694*4882a593Smuzhiyun 	return -1;
695*4882a593Smuzhiyun }
696*4882a593Smuzhiyun 
find_dir_depth(char * dirname)697*4882a593Smuzhiyun static int find_dir_depth(char *dirname)
698*4882a593Smuzhiyun {
699*4882a593Smuzhiyun 	char *token = strtok(dirname, "/");
700*4882a593Smuzhiyun 	int count = 0;
701*4882a593Smuzhiyun 	while (token != NULL) {
702*4882a593Smuzhiyun 		token = strtok(NULL, "/");
703*4882a593Smuzhiyun 		count++;
704*4882a593Smuzhiyun 	}
705*4882a593Smuzhiyun 	return count + 1 + 1;
706*4882a593Smuzhiyun 	/*
707*4882a593Smuzhiyun 	 * for example  for string /home/temp
708*4882a593Smuzhiyun 	 * depth=home(1)+temp(1)+1 extra for NULL;
709*4882a593Smuzhiyun 	 * so count is 4;
710*4882a593Smuzhiyun 	 */
711*4882a593Smuzhiyun }
712*4882a593Smuzhiyun 
parse_path(char ** arr,char * dirname)713*4882a593Smuzhiyun static int parse_path(char **arr, char *dirname)
714*4882a593Smuzhiyun {
715*4882a593Smuzhiyun 	char *token = strtok(dirname, "/");
716*4882a593Smuzhiyun 	int i = 0;
717*4882a593Smuzhiyun 
718*4882a593Smuzhiyun 	/* add root */
719*4882a593Smuzhiyun 	arr[i] = zalloc(strlen("/") + 1);
720*4882a593Smuzhiyun 	if (!arr[i])
721*4882a593Smuzhiyun 		return -ENOMEM;
722*4882a593Smuzhiyun 	memcpy(arr[i++], "/", strlen("/"));
723*4882a593Smuzhiyun 
724*4882a593Smuzhiyun 	/* add each path entry after root */
725*4882a593Smuzhiyun 	while (token != NULL) {
726*4882a593Smuzhiyun 		arr[i] = zalloc(strlen(token) + 1);
727*4882a593Smuzhiyun 		if (!arr[i])
728*4882a593Smuzhiyun 			return -ENOMEM;
729*4882a593Smuzhiyun 		memcpy(arr[i++], token, strlen(token));
730*4882a593Smuzhiyun 		token = strtok(NULL, "/");
731*4882a593Smuzhiyun 	}
732*4882a593Smuzhiyun 	arr[i] = NULL;
733*4882a593Smuzhiyun 
734*4882a593Smuzhiyun 	return 0;
735*4882a593Smuzhiyun }
736*4882a593Smuzhiyun 
ext4fs_iget(int inode_no,struct ext2_inode * inode)737*4882a593Smuzhiyun int ext4fs_iget(int inode_no, struct ext2_inode *inode)
738*4882a593Smuzhiyun {
739*4882a593Smuzhiyun 	if (ext4fs_read_inode(ext4fs_root, inode_no, inode) == 0)
740*4882a593Smuzhiyun 		return -1;
741*4882a593Smuzhiyun 
742*4882a593Smuzhiyun 	return 0;
743*4882a593Smuzhiyun }
744*4882a593Smuzhiyun 
745*4882a593Smuzhiyun /*
746*4882a593Smuzhiyun  * Function: ext4fs_get_parent_inode_num
747*4882a593Smuzhiyun  * Return Value: inode Number of the parent directory of  file/Directory to be
748*4882a593Smuzhiyun  * created
749*4882a593Smuzhiyun  * dirname : Input parmater, input path name of the file/directory to be created
750*4882a593Smuzhiyun  * dname : Output parameter, to be filled with the name of the directory
751*4882a593Smuzhiyun  * extracted from dirname
752*4882a593Smuzhiyun  */
ext4fs_get_parent_inode_num(const char * dirname,char * dname,int flags)753*4882a593Smuzhiyun int ext4fs_get_parent_inode_num(const char *dirname, char *dname, int flags)
754*4882a593Smuzhiyun {
755*4882a593Smuzhiyun 	int i;
756*4882a593Smuzhiyun 	int depth = 0;
757*4882a593Smuzhiyun 	int matched_inode_no;
758*4882a593Smuzhiyun 	int result_inode_no = -1;
759*4882a593Smuzhiyun 	char **ptr = NULL;
760*4882a593Smuzhiyun 	char *depth_dirname = NULL;
761*4882a593Smuzhiyun 	char *parse_dirname = NULL;
762*4882a593Smuzhiyun 	struct ext2_inode *parent_inode = NULL;
763*4882a593Smuzhiyun 	struct ext2_inode *first_inode = NULL;
764*4882a593Smuzhiyun 	struct ext2_inode temp_inode;
765*4882a593Smuzhiyun 
766*4882a593Smuzhiyun 	if (*dirname != '/') {
767*4882a593Smuzhiyun 		printf("Please supply Absolute path\n");
768*4882a593Smuzhiyun 		return -1;
769*4882a593Smuzhiyun 	}
770*4882a593Smuzhiyun 
771*4882a593Smuzhiyun 	/* TODO: input validation make equivalent to linux */
772*4882a593Smuzhiyun 	depth_dirname = zalloc(strlen(dirname) + 1);
773*4882a593Smuzhiyun 	if (!depth_dirname)
774*4882a593Smuzhiyun 		return -ENOMEM;
775*4882a593Smuzhiyun 
776*4882a593Smuzhiyun 	memcpy(depth_dirname, dirname, strlen(dirname));
777*4882a593Smuzhiyun 	depth = find_dir_depth(depth_dirname);
778*4882a593Smuzhiyun 	parse_dirname = zalloc(strlen(dirname) + 1);
779*4882a593Smuzhiyun 	if (!parse_dirname)
780*4882a593Smuzhiyun 		goto fail;
781*4882a593Smuzhiyun 	memcpy(parse_dirname, dirname, strlen(dirname));
782*4882a593Smuzhiyun 
783*4882a593Smuzhiyun 	/* allocate memory for each directory level */
784*4882a593Smuzhiyun 	ptr = zalloc((depth) * sizeof(char *));
785*4882a593Smuzhiyun 	if (!ptr)
786*4882a593Smuzhiyun 		goto fail;
787*4882a593Smuzhiyun 	if (parse_path(ptr, parse_dirname))
788*4882a593Smuzhiyun 		goto fail;
789*4882a593Smuzhiyun 	parent_inode = zalloc(sizeof(struct ext2_inode));
790*4882a593Smuzhiyun 	if (!parent_inode)
791*4882a593Smuzhiyun 		goto fail;
792*4882a593Smuzhiyun 	first_inode = zalloc(sizeof(struct ext2_inode));
793*4882a593Smuzhiyun 	if (!first_inode)
794*4882a593Smuzhiyun 		goto fail;
795*4882a593Smuzhiyun 	memcpy(parent_inode, ext4fs_root->inode, sizeof(struct ext2_inode));
796*4882a593Smuzhiyun 	memcpy(first_inode, parent_inode, sizeof(struct ext2_inode));
797*4882a593Smuzhiyun 	if (flags & F_FILE)
798*4882a593Smuzhiyun 		result_inode_no = EXT2_ROOT_INO;
799*4882a593Smuzhiyun 	for (i = 1; i < depth; i++) {
800*4882a593Smuzhiyun 		matched_inode_no = search_dir(parent_inode, ptr[i]);
801*4882a593Smuzhiyun 		if (matched_inode_no == -1) {
802*4882a593Smuzhiyun 			if (ptr[i + 1] == NULL && i == 1) {
803*4882a593Smuzhiyun 				result_inode_no = EXT2_ROOT_INO;
804*4882a593Smuzhiyun 				goto end;
805*4882a593Smuzhiyun 			} else {
806*4882a593Smuzhiyun 				if (ptr[i + 1] == NULL)
807*4882a593Smuzhiyun 					break;
808*4882a593Smuzhiyun 				printf("Invalid path\n");
809*4882a593Smuzhiyun 				result_inode_no = -1;
810*4882a593Smuzhiyun 				goto fail;
811*4882a593Smuzhiyun 			}
812*4882a593Smuzhiyun 		} else {
813*4882a593Smuzhiyun 			if (ptr[i + 1] != NULL) {
814*4882a593Smuzhiyun 				memset(parent_inode, '\0',
815*4882a593Smuzhiyun 				       sizeof(struct ext2_inode));
816*4882a593Smuzhiyun 				if (ext4fs_iget(matched_inode_no,
817*4882a593Smuzhiyun 						parent_inode)) {
818*4882a593Smuzhiyun 					result_inode_no = -1;
819*4882a593Smuzhiyun 					goto fail;
820*4882a593Smuzhiyun 				}
821*4882a593Smuzhiyun 				result_inode_no = matched_inode_no;
822*4882a593Smuzhiyun 			} else {
823*4882a593Smuzhiyun 				break;
824*4882a593Smuzhiyun 			}
825*4882a593Smuzhiyun 		}
826*4882a593Smuzhiyun 	}
827*4882a593Smuzhiyun 
828*4882a593Smuzhiyun end:
829*4882a593Smuzhiyun 	if (i == 1)
830*4882a593Smuzhiyun 		matched_inode_no = search_dir(first_inode, ptr[i]);
831*4882a593Smuzhiyun 	else
832*4882a593Smuzhiyun 		matched_inode_no = search_dir(parent_inode, ptr[i]);
833*4882a593Smuzhiyun 
834*4882a593Smuzhiyun 	if (matched_inode_no != -1) {
835*4882a593Smuzhiyun 		ext4fs_iget(matched_inode_no, &temp_inode);
836*4882a593Smuzhiyun 		if (le16_to_cpu(temp_inode.mode) & S_IFDIR) {
837*4882a593Smuzhiyun 			printf("It is a Directory\n");
838*4882a593Smuzhiyun 			result_inode_no = -1;
839*4882a593Smuzhiyun 			goto fail;
840*4882a593Smuzhiyun 		}
841*4882a593Smuzhiyun 	}
842*4882a593Smuzhiyun 
843*4882a593Smuzhiyun 	if (strlen(ptr[i]) > 256) {
844*4882a593Smuzhiyun 		result_inode_no = -1;
845*4882a593Smuzhiyun 		goto fail;
846*4882a593Smuzhiyun 	}
847*4882a593Smuzhiyun 	memcpy(dname, ptr[i], strlen(ptr[i]));
848*4882a593Smuzhiyun 
849*4882a593Smuzhiyun fail:
850*4882a593Smuzhiyun 	free(depth_dirname);
851*4882a593Smuzhiyun 	free(parse_dirname);
852*4882a593Smuzhiyun 	for (i = 0; i < depth; i++) {
853*4882a593Smuzhiyun 		if (!ptr[i])
854*4882a593Smuzhiyun 			break;
855*4882a593Smuzhiyun 		free(ptr[i]);
856*4882a593Smuzhiyun 	}
857*4882a593Smuzhiyun 	free(ptr);
858*4882a593Smuzhiyun 	free(parent_inode);
859*4882a593Smuzhiyun 	free(first_inode);
860*4882a593Smuzhiyun 
861*4882a593Smuzhiyun 	return result_inode_no;
862*4882a593Smuzhiyun }
863*4882a593Smuzhiyun 
unlink_filename(char * filename,unsigned int blknr)864*4882a593Smuzhiyun static int unlink_filename(char *filename, unsigned int blknr)
865*4882a593Smuzhiyun {
866*4882a593Smuzhiyun 	int status;
867*4882a593Smuzhiyun 	int inodeno = 0;
868*4882a593Smuzhiyun 	int offset;
869*4882a593Smuzhiyun 	char *block_buffer = NULL;
870*4882a593Smuzhiyun 	struct ext2_dirent *dir = NULL;
871*4882a593Smuzhiyun 	struct ext2_dirent *previous_dir;
872*4882a593Smuzhiyun 	struct ext_filesystem *fs = get_fs();
873*4882a593Smuzhiyun 	int ret = -1;
874*4882a593Smuzhiyun 	char *direntname;
875*4882a593Smuzhiyun 
876*4882a593Smuzhiyun 	block_buffer = zalloc(fs->blksz);
877*4882a593Smuzhiyun 	if (!block_buffer)
878*4882a593Smuzhiyun 		return -ENOMEM;
879*4882a593Smuzhiyun 
880*4882a593Smuzhiyun 	/* read the directory block */
881*4882a593Smuzhiyun 	status = ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0,
882*4882a593Smuzhiyun 				fs->blksz, block_buffer);
883*4882a593Smuzhiyun 	if (status == 0)
884*4882a593Smuzhiyun 		goto fail;
885*4882a593Smuzhiyun 
886*4882a593Smuzhiyun 	offset = 0;
887*4882a593Smuzhiyun 	do {
888*4882a593Smuzhiyun 		if (offset & 3) {
889*4882a593Smuzhiyun 			printf("Badly aligned ext2_dirent\n");
890*4882a593Smuzhiyun 			break;
891*4882a593Smuzhiyun 		}
892*4882a593Smuzhiyun 
893*4882a593Smuzhiyun 		previous_dir = dir;
894*4882a593Smuzhiyun 		dir = (struct ext2_dirent *)(block_buffer + offset);
895*4882a593Smuzhiyun 		direntname = (char *)(dir) + sizeof(struct ext2_dirent);
896*4882a593Smuzhiyun 
897*4882a593Smuzhiyun 		int direntlen = le16_to_cpu(dir->direntlen);
898*4882a593Smuzhiyun 		if (direntlen < sizeof(struct ext2_dirent))
899*4882a593Smuzhiyun 			break;
900*4882a593Smuzhiyun 
901*4882a593Smuzhiyun 		if (dir->inode && (strlen(filename) == dir->namelen) &&
902*4882a593Smuzhiyun 		    (strncmp(direntname, filename, dir->namelen) == 0)) {
903*4882a593Smuzhiyun 			inodeno = le32_to_cpu(dir->inode);
904*4882a593Smuzhiyun 			break;
905*4882a593Smuzhiyun 		}
906*4882a593Smuzhiyun 
907*4882a593Smuzhiyun 		offset += direntlen;
908*4882a593Smuzhiyun 
909*4882a593Smuzhiyun 	} while (offset < fs->blksz);
910*4882a593Smuzhiyun 
911*4882a593Smuzhiyun 	if (inodeno > 0) {
912*4882a593Smuzhiyun 		printf("file found, deleting\n");
913*4882a593Smuzhiyun 		if (ext4fs_log_journal(block_buffer, blknr))
914*4882a593Smuzhiyun 			goto fail;
915*4882a593Smuzhiyun 
916*4882a593Smuzhiyun 		if (previous_dir) {
917*4882a593Smuzhiyun 			/* merge dir entry with predecessor */
918*4882a593Smuzhiyun 			uint16_t new_len;
919*4882a593Smuzhiyun 			new_len = le16_to_cpu(previous_dir->direntlen);
920*4882a593Smuzhiyun 			new_len += le16_to_cpu(dir->direntlen);
921*4882a593Smuzhiyun 			previous_dir->direntlen = cpu_to_le16(new_len);
922*4882a593Smuzhiyun 		} else {
923*4882a593Smuzhiyun 			/* invalidate dir entry */
924*4882a593Smuzhiyun 			dir->inode = 0;
925*4882a593Smuzhiyun 		}
926*4882a593Smuzhiyun 		if (ext4fs_put_metadata(block_buffer, blknr))
927*4882a593Smuzhiyun 			goto fail;
928*4882a593Smuzhiyun 		ret = inodeno;
929*4882a593Smuzhiyun 	}
930*4882a593Smuzhiyun fail:
931*4882a593Smuzhiyun 	free(block_buffer);
932*4882a593Smuzhiyun 
933*4882a593Smuzhiyun 	return ret;
934*4882a593Smuzhiyun }
935*4882a593Smuzhiyun 
ext4fs_filename_unlink(char * filename)936*4882a593Smuzhiyun int ext4fs_filename_unlink(char *filename)
937*4882a593Smuzhiyun {
938*4882a593Smuzhiyun 	int blk_idx;
939*4882a593Smuzhiyun 	long int blknr = -1;
940*4882a593Smuzhiyun 	int inodeno = -1;
941*4882a593Smuzhiyun 	uint32_t directory_blocks;
942*4882a593Smuzhiyun 
943*4882a593Smuzhiyun 	directory_blocks = le32_to_cpu(g_parent_inode->size) >>
944*4882a593Smuzhiyun 		LOG2_BLOCK_SIZE(ext4fs_root);
945*4882a593Smuzhiyun 
946*4882a593Smuzhiyun 	/* read the block no allocated to a file */
947*4882a593Smuzhiyun 	for (blk_idx = 0; blk_idx < directory_blocks; blk_idx++) {
948*4882a593Smuzhiyun 		blknr = read_allocated_block(g_parent_inode, blk_idx);
949*4882a593Smuzhiyun 		if (blknr <= 0)
950*4882a593Smuzhiyun 			break;
951*4882a593Smuzhiyun 		inodeno = unlink_filename(filename, blknr);
952*4882a593Smuzhiyun 		if (inodeno != -1)
953*4882a593Smuzhiyun 			return inodeno;
954*4882a593Smuzhiyun 	}
955*4882a593Smuzhiyun 
956*4882a593Smuzhiyun 	return -1;
957*4882a593Smuzhiyun }
958*4882a593Smuzhiyun 
ext4fs_get_new_blk_no(void)959*4882a593Smuzhiyun uint32_t ext4fs_get_new_blk_no(void)
960*4882a593Smuzhiyun {
961*4882a593Smuzhiyun 	short i;
962*4882a593Smuzhiyun 	short status;
963*4882a593Smuzhiyun 	int remainder;
964*4882a593Smuzhiyun 	unsigned int bg_idx;
965*4882a593Smuzhiyun 	static int prev_bg_bitmap_index = -1;
966*4882a593Smuzhiyun 	unsigned int blk_per_grp = le32_to_cpu(ext4fs_root->sblock.blocks_per_group);
967*4882a593Smuzhiyun 	struct ext_filesystem *fs = get_fs();
968*4882a593Smuzhiyun 	char *journal_buffer = zalloc(fs->blksz);
969*4882a593Smuzhiyun 	char *zero_buffer = zalloc(fs->blksz);
970*4882a593Smuzhiyun 	if (!journal_buffer || !zero_buffer)
971*4882a593Smuzhiyun 		goto fail;
972*4882a593Smuzhiyun 
973*4882a593Smuzhiyun 	if (fs->first_pass_bbmap == 0) {
974*4882a593Smuzhiyun 		for (i = 0; i < fs->no_blkgrp; i++) {
975*4882a593Smuzhiyun 			struct ext2_block_group *bgd = NULL;
976*4882a593Smuzhiyun 			bgd = ext4fs_get_group_descriptor(fs, i);
977*4882a593Smuzhiyun 			if (ext4fs_bg_get_free_blocks(bgd, fs)) {
978*4882a593Smuzhiyun 				uint16_t bg_flags = ext4fs_bg_get_flags(bgd);
979*4882a593Smuzhiyun 				uint64_t b_bitmap_blk =
980*4882a593Smuzhiyun 					ext4fs_bg_get_block_id(bgd, fs);
981*4882a593Smuzhiyun 				if (bg_flags & EXT4_BG_BLOCK_UNINIT) {
982*4882a593Smuzhiyun 					memcpy(fs->blk_bmaps[i], zero_buffer,
983*4882a593Smuzhiyun 					       fs->blksz);
984*4882a593Smuzhiyun 					put_ext4(b_bitmap_blk * fs->blksz,
985*4882a593Smuzhiyun 						 fs->blk_bmaps[i], fs->blksz);
986*4882a593Smuzhiyun 					bg_flags &= ~EXT4_BG_BLOCK_UNINIT;
987*4882a593Smuzhiyun 					ext4fs_bg_set_flags(bgd, bg_flags);
988*4882a593Smuzhiyun 				}
989*4882a593Smuzhiyun 				fs->curr_blkno =
990*4882a593Smuzhiyun 				    _get_new_blk_no(fs->blk_bmaps[i]);
991*4882a593Smuzhiyun 				if (fs->curr_blkno == -1)
992*4882a593Smuzhiyun 					/* block bitmap is completely filled */
993*4882a593Smuzhiyun 					continue;
994*4882a593Smuzhiyun 				fs->curr_blkno = fs->curr_blkno +
995*4882a593Smuzhiyun 						(i * fs->blksz * 8);
996*4882a593Smuzhiyun 				fs->first_pass_bbmap++;
997*4882a593Smuzhiyun 				ext4fs_bg_free_blocks_dec(bgd, fs);
998*4882a593Smuzhiyun 				ext4fs_sb_free_blocks_dec(fs->sb);
999*4882a593Smuzhiyun 				status = ext4fs_devread(b_bitmap_blk *
1000*4882a593Smuzhiyun 							fs->sect_perblk,
1001*4882a593Smuzhiyun 							0, fs->blksz,
1002*4882a593Smuzhiyun 							journal_buffer);
1003*4882a593Smuzhiyun 				if (status == 0)
1004*4882a593Smuzhiyun 					goto fail;
1005*4882a593Smuzhiyun 				if (ext4fs_log_journal(journal_buffer,
1006*4882a593Smuzhiyun 						       b_bitmap_blk))
1007*4882a593Smuzhiyun 					goto fail;
1008*4882a593Smuzhiyun 				goto success;
1009*4882a593Smuzhiyun 			} else {
1010*4882a593Smuzhiyun 				debug("no space left on block group %d\n", i);
1011*4882a593Smuzhiyun 			}
1012*4882a593Smuzhiyun 		}
1013*4882a593Smuzhiyun 
1014*4882a593Smuzhiyun 		goto fail;
1015*4882a593Smuzhiyun 	} else {
1016*4882a593Smuzhiyun 		fs->curr_blkno++;
1017*4882a593Smuzhiyun restart:
1018*4882a593Smuzhiyun 		/* get the blockbitmap index respective to blockno */
1019*4882a593Smuzhiyun 		bg_idx = fs->curr_blkno / blk_per_grp;
1020*4882a593Smuzhiyun 		if (fs->blksz == 1024) {
1021*4882a593Smuzhiyun 			remainder = fs->curr_blkno % blk_per_grp;
1022*4882a593Smuzhiyun 			if (!remainder)
1023*4882a593Smuzhiyun 				bg_idx--;
1024*4882a593Smuzhiyun 		}
1025*4882a593Smuzhiyun 
1026*4882a593Smuzhiyun 		/*
1027*4882a593Smuzhiyun 		 * To skip completely filled block group bitmaps
1028*4882a593Smuzhiyun 		 * Optimize the block allocation
1029*4882a593Smuzhiyun 		 */
1030*4882a593Smuzhiyun 		if (bg_idx >= fs->no_blkgrp)
1031*4882a593Smuzhiyun 			goto fail;
1032*4882a593Smuzhiyun 
1033*4882a593Smuzhiyun 		struct ext2_block_group *bgd = NULL;
1034*4882a593Smuzhiyun 		bgd = ext4fs_get_group_descriptor(fs, bg_idx);
1035*4882a593Smuzhiyun 		if (ext4fs_bg_get_free_blocks(bgd, fs) == 0) {
1036*4882a593Smuzhiyun 			debug("block group %u is full. Skipping\n", bg_idx);
1037*4882a593Smuzhiyun 			fs->curr_blkno = (bg_idx + 1) * blk_per_grp;
1038*4882a593Smuzhiyun 			if (fs->blksz == 1024)
1039*4882a593Smuzhiyun 				fs->curr_blkno += 1;
1040*4882a593Smuzhiyun 			goto restart;
1041*4882a593Smuzhiyun 		}
1042*4882a593Smuzhiyun 
1043*4882a593Smuzhiyun 		uint16_t bg_flags = ext4fs_bg_get_flags(bgd);
1044*4882a593Smuzhiyun 		uint64_t b_bitmap_blk = ext4fs_bg_get_block_id(bgd, fs);
1045*4882a593Smuzhiyun 		if (bg_flags & EXT4_BG_BLOCK_UNINIT) {
1046*4882a593Smuzhiyun 			memcpy(fs->blk_bmaps[bg_idx], zero_buffer, fs->blksz);
1047*4882a593Smuzhiyun 			put_ext4(b_bitmap_blk * fs->blksz,
1048*4882a593Smuzhiyun 				 zero_buffer, fs->blksz);
1049*4882a593Smuzhiyun 			bg_flags &= ~EXT4_BG_BLOCK_UNINIT;
1050*4882a593Smuzhiyun 			ext4fs_bg_set_flags(bgd, bg_flags);
1051*4882a593Smuzhiyun 		}
1052*4882a593Smuzhiyun 
1053*4882a593Smuzhiyun 		if (ext4fs_set_block_bmap(fs->curr_blkno, fs->blk_bmaps[bg_idx],
1054*4882a593Smuzhiyun 				   bg_idx) != 0) {
1055*4882a593Smuzhiyun 			debug("going for restart for the block no %ld %u\n",
1056*4882a593Smuzhiyun 			      fs->curr_blkno, bg_idx);
1057*4882a593Smuzhiyun 			fs->curr_blkno++;
1058*4882a593Smuzhiyun 			goto restart;
1059*4882a593Smuzhiyun 		}
1060*4882a593Smuzhiyun 
1061*4882a593Smuzhiyun 		/* journal backup */
1062*4882a593Smuzhiyun 		if (prev_bg_bitmap_index != bg_idx) {
1063*4882a593Smuzhiyun 			status = ext4fs_devread(b_bitmap_blk * fs->sect_perblk,
1064*4882a593Smuzhiyun 						0, fs->blksz, journal_buffer);
1065*4882a593Smuzhiyun 			if (status == 0)
1066*4882a593Smuzhiyun 				goto fail;
1067*4882a593Smuzhiyun 			if (ext4fs_log_journal(journal_buffer, b_bitmap_blk))
1068*4882a593Smuzhiyun 				goto fail;
1069*4882a593Smuzhiyun 
1070*4882a593Smuzhiyun 			prev_bg_bitmap_index = bg_idx;
1071*4882a593Smuzhiyun 		}
1072*4882a593Smuzhiyun 		ext4fs_bg_free_blocks_dec(bgd, fs);
1073*4882a593Smuzhiyun 		ext4fs_sb_free_blocks_dec(fs->sb);
1074*4882a593Smuzhiyun 		goto success;
1075*4882a593Smuzhiyun 	}
1076*4882a593Smuzhiyun success:
1077*4882a593Smuzhiyun 	free(journal_buffer);
1078*4882a593Smuzhiyun 	free(zero_buffer);
1079*4882a593Smuzhiyun 
1080*4882a593Smuzhiyun 	return fs->curr_blkno;
1081*4882a593Smuzhiyun fail:
1082*4882a593Smuzhiyun 	free(journal_buffer);
1083*4882a593Smuzhiyun 	free(zero_buffer);
1084*4882a593Smuzhiyun 
1085*4882a593Smuzhiyun 	return -1;
1086*4882a593Smuzhiyun }
1087*4882a593Smuzhiyun 
ext4fs_get_new_inode_no(void)1088*4882a593Smuzhiyun int ext4fs_get_new_inode_no(void)
1089*4882a593Smuzhiyun {
1090*4882a593Smuzhiyun 	short i;
1091*4882a593Smuzhiyun 	short status;
1092*4882a593Smuzhiyun 	unsigned int ibmap_idx;
1093*4882a593Smuzhiyun 	static int prev_inode_bitmap_index = -1;
1094*4882a593Smuzhiyun 	unsigned int inodes_per_grp = le32_to_cpu(ext4fs_root->sblock.inodes_per_group);
1095*4882a593Smuzhiyun 	struct ext_filesystem *fs = get_fs();
1096*4882a593Smuzhiyun 	char *journal_buffer = zalloc(fs->blksz);
1097*4882a593Smuzhiyun 	char *zero_buffer = zalloc(fs->blksz);
1098*4882a593Smuzhiyun 	if (!journal_buffer || !zero_buffer)
1099*4882a593Smuzhiyun 		goto fail;
1100*4882a593Smuzhiyun 	int has_gdt_chksum = le32_to_cpu(fs->sb->feature_ro_compat) &
1101*4882a593Smuzhiyun 		EXT4_FEATURE_RO_COMPAT_GDT_CSUM ? 1 : 0;
1102*4882a593Smuzhiyun 
1103*4882a593Smuzhiyun 	if (fs->first_pass_ibmap == 0) {
1104*4882a593Smuzhiyun 		for (i = 0; i < fs->no_blkgrp; i++) {
1105*4882a593Smuzhiyun 			uint32_t free_inodes;
1106*4882a593Smuzhiyun 			struct ext2_block_group *bgd = NULL;
1107*4882a593Smuzhiyun 			bgd = ext4fs_get_group_descriptor(fs, i);
1108*4882a593Smuzhiyun 			free_inodes = ext4fs_bg_get_free_inodes(bgd, fs);
1109*4882a593Smuzhiyun 			if (free_inodes) {
1110*4882a593Smuzhiyun 				uint16_t bg_flags = ext4fs_bg_get_flags(bgd);
1111*4882a593Smuzhiyun 				uint64_t i_bitmap_blk =
1112*4882a593Smuzhiyun 					ext4fs_bg_get_inode_id(bgd, fs);
1113*4882a593Smuzhiyun 				if (has_gdt_chksum)
1114*4882a593Smuzhiyun 					bgd->bg_itable_unused = free_inodes;
1115*4882a593Smuzhiyun 				if (bg_flags & EXT4_BG_INODE_UNINIT) {
1116*4882a593Smuzhiyun 					put_ext4(i_bitmap_blk * fs->blksz,
1117*4882a593Smuzhiyun 						 zero_buffer, fs->blksz);
1118*4882a593Smuzhiyun 					bg_flags &= ~EXT4_BG_INODE_UNINIT;
1119*4882a593Smuzhiyun 					ext4fs_bg_set_flags(bgd, bg_flags);
1120*4882a593Smuzhiyun 					memcpy(fs->inode_bmaps[i],
1121*4882a593Smuzhiyun 					       zero_buffer, fs->blksz);
1122*4882a593Smuzhiyun 				}
1123*4882a593Smuzhiyun 				fs->curr_inode_no =
1124*4882a593Smuzhiyun 				    _get_new_inode_no(fs->inode_bmaps[i]);
1125*4882a593Smuzhiyun 				if (fs->curr_inode_no == -1)
1126*4882a593Smuzhiyun 					/* inode bitmap is completely filled */
1127*4882a593Smuzhiyun 					continue;
1128*4882a593Smuzhiyun 				fs->curr_inode_no = fs->curr_inode_no +
1129*4882a593Smuzhiyun 							(i * inodes_per_grp);
1130*4882a593Smuzhiyun 				fs->first_pass_ibmap++;
1131*4882a593Smuzhiyun 				ext4fs_bg_free_inodes_dec(bgd, fs);
1132*4882a593Smuzhiyun 				if (has_gdt_chksum)
1133*4882a593Smuzhiyun 					ext4fs_bg_itable_unused_dec(bgd, fs);
1134*4882a593Smuzhiyun 				ext4fs_sb_free_inodes_dec(fs->sb);
1135*4882a593Smuzhiyun 				status = ext4fs_devread(i_bitmap_blk *
1136*4882a593Smuzhiyun 							fs->sect_perblk,
1137*4882a593Smuzhiyun 							0, fs->blksz,
1138*4882a593Smuzhiyun 							journal_buffer);
1139*4882a593Smuzhiyun 				if (status == 0)
1140*4882a593Smuzhiyun 					goto fail;
1141*4882a593Smuzhiyun 				if (ext4fs_log_journal(journal_buffer,
1142*4882a593Smuzhiyun 						       i_bitmap_blk))
1143*4882a593Smuzhiyun 					goto fail;
1144*4882a593Smuzhiyun 				goto success;
1145*4882a593Smuzhiyun 			} else
1146*4882a593Smuzhiyun 				debug("no inode left on block group %d\n", i);
1147*4882a593Smuzhiyun 		}
1148*4882a593Smuzhiyun 		goto fail;
1149*4882a593Smuzhiyun 	} else {
1150*4882a593Smuzhiyun restart:
1151*4882a593Smuzhiyun 		fs->curr_inode_no++;
1152*4882a593Smuzhiyun 		/* get the blockbitmap index respective to blockno */
1153*4882a593Smuzhiyun 		ibmap_idx = fs->curr_inode_no / inodes_per_grp;
1154*4882a593Smuzhiyun 		struct ext2_block_group *bgd =
1155*4882a593Smuzhiyun 			ext4fs_get_group_descriptor(fs, ibmap_idx);
1156*4882a593Smuzhiyun 		uint16_t bg_flags = ext4fs_bg_get_flags(bgd);
1157*4882a593Smuzhiyun 		uint64_t i_bitmap_blk = ext4fs_bg_get_inode_id(bgd, fs);
1158*4882a593Smuzhiyun 
1159*4882a593Smuzhiyun 		if (bg_flags & EXT4_BG_INODE_UNINIT) {
1160*4882a593Smuzhiyun 			put_ext4(i_bitmap_blk * fs->blksz,
1161*4882a593Smuzhiyun 				 zero_buffer, fs->blksz);
1162*4882a593Smuzhiyun 			bg_flags &= ~EXT4_BG_INODE_UNINIT;
1163*4882a593Smuzhiyun 			ext4fs_bg_set_flags(bgd, bg_flags);
1164*4882a593Smuzhiyun 			memcpy(fs->inode_bmaps[ibmap_idx], zero_buffer,
1165*4882a593Smuzhiyun 				fs->blksz);
1166*4882a593Smuzhiyun 		}
1167*4882a593Smuzhiyun 
1168*4882a593Smuzhiyun 		if (ext4fs_set_inode_bmap(fs->curr_inode_no,
1169*4882a593Smuzhiyun 					  fs->inode_bmaps[ibmap_idx],
1170*4882a593Smuzhiyun 					  ibmap_idx) != 0) {
1171*4882a593Smuzhiyun 			debug("going for restart for the block no %d %u\n",
1172*4882a593Smuzhiyun 			      fs->curr_inode_no, ibmap_idx);
1173*4882a593Smuzhiyun 			goto restart;
1174*4882a593Smuzhiyun 		}
1175*4882a593Smuzhiyun 
1176*4882a593Smuzhiyun 		/* journal backup */
1177*4882a593Smuzhiyun 		if (prev_inode_bitmap_index != ibmap_idx) {
1178*4882a593Smuzhiyun 			status = ext4fs_devread(i_bitmap_blk * fs->sect_perblk,
1179*4882a593Smuzhiyun 						0, fs->blksz, journal_buffer);
1180*4882a593Smuzhiyun 			if (status == 0)
1181*4882a593Smuzhiyun 				goto fail;
1182*4882a593Smuzhiyun 			if (ext4fs_log_journal(journal_buffer,
1183*4882a593Smuzhiyun 						le32_to_cpu(bgd->inode_id)))
1184*4882a593Smuzhiyun 				goto fail;
1185*4882a593Smuzhiyun 			prev_inode_bitmap_index = ibmap_idx;
1186*4882a593Smuzhiyun 		}
1187*4882a593Smuzhiyun 		ext4fs_bg_free_inodes_dec(bgd, fs);
1188*4882a593Smuzhiyun 		if (has_gdt_chksum)
1189*4882a593Smuzhiyun 			bgd->bg_itable_unused = bgd->free_inodes;
1190*4882a593Smuzhiyun 		ext4fs_sb_free_inodes_dec(fs->sb);
1191*4882a593Smuzhiyun 		goto success;
1192*4882a593Smuzhiyun 	}
1193*4882a593Smuzhiyun 
1194*4882a593Smuzhiyun success:
1195*4882a593Smuzhiyun 	free(journal_buffer);
1196*4882a593Smuzhiyun 	free(zero_buffer);
1197*4882a593Smuzhiyun 
1198*4882a593Smuzhiyun 	return fs->curr_inode_no;
1199*4882a593Smuzhiyun fail:
1200*4882a593Smuzhiyun 	free(journal_buffer);
1201*4882a593Smuzhiyun 	free(zero_buffer);
1202*4882a593Smuzhiyun 
1203*4882a593Smuzhiyun 	return -1;
1204*4882a593Smuzhiyun 
1205*4882a593Smuzhiyun }
1206*4882a593Smuzhiyun 
1207*4882a593Smuzhiyun 
alloc_single_indirect_block(struct ext2_inode * file_inode,unsigned int * total_remaining_blocks,unsigned int * no_blks_reqd)1208*4882a593Smuzhiyun static void alloc_single_indirect_block(struct ext2_inode *file_inode,
1209*4882a593Smuzhiyun 					unsigned int *total_remaining_blocks,
1210*4882a593Smuzhiyun 					unsigned int *no_blks_reqd)
1211*4882a593Smuzhiyun {
1212*4882a593Smuzhiyun 	short i;
1213*4882a593Smuzhiyun 	short status;
1214*4882a593Smuzhiyun 	long int actual_block_no;
1215*4882a593Smuzhiyun 	long int si_blockno;
1216*4882a593Smuzhiyun 	/* si :single indirect */
1217*4882a593Smuzhiyun 	__le32 *si_buffer = NULL;
1218*4882a593Smuzhiyun 	__le32 *si_start_addr = NULL;
1219*4882a593Smuzhiyun 	struct ext_filesystem *fs = get_fs();
1220*4882a593Smuzhiyun 
1221*4882a593Smuzhiyun 	if (*total_remaining_blocks != 0) {
1222*4882a593Smuzhiyun 		si_buffer = zalloc(fs->blksz);
1223*4882a593Smuzhiyun 		if (!si_buffer) {
1224*4882a593Smuzhiyun 			printf("No Memory\n");
1225*4882a593Smuzhiyun 			return;
1226*4882a593Smuzhiyun 		}
1227*4882a593Smuzhiyun 		si_start_addr = si_buffer;
1228*4882a593Smuzhiyun 		si_blockno = ext4fs_get_new_blk_no();
1229*4882a593Smuzhiyun 		if (si_blockno == -1) {
1230*4882a593Smuzhiyun 			printf("no block left to assign\n");
1231*4882a593Smuzhiyun 			goto fail;
1232*4882a593Smuzhiyun 		}
1233*4882a593Smuzhiyun 		(*no_blks_reqd)++;
1234*4882a593Smuzhiyun 		debug("SIPB %ld: %u\n", si_blockno, *total_remaining_blocks);
1235*4882a593Smuzhiyun 
1236*4882a593Smuzhiyun 		status = ext4fs_devread((lbaint_t)si_blockno * fs->sect_perblk,
1237*4882a593Smuzhiyun 					0, fs->blksz, (char *)si_buffer);
1238*4882a593Smuzhiyun 		memset(si_buffer, '\0', fs->blksz);
1239*4882a593Smuzhiyun 		if (status == 0)
1240*4882a593Smuzhiyun 			goto fail;
1241*4882a593Smuzhiyun 
1242*4882a593Smuzhiyun 		for (i = 0; i < (fs->blksz / sizeof(int)); i++) {
1243*4882a593Smuzhiyun 			actual_block_no = ext4fs_get_new_blk_no();
1244*4882a593Smuzhiyun 			if (actual_block_no == -1) {
1245*4882a593Smuzhiyun 				printf("no block left to assign\n");
1246*4882a593Smuzhiyun 				goto fail;
1247*4882a593Smuzhiyun 			}
1248*4882a593Smuzhiyun 			*si_buffer = cpu_to_le32(actual_block_no);
1249*4882a593Smuzhiyun 			debug("SIAB %u: %u\n", *si_buffer,
1250*4882a593Smuzhiyun 				*total_remaining_blocks);
1251*4882a593Smuzhiyun 
1252*4882a593Smuzhiyun 			si_buffer++;
1253*4882a593Smuzhiyun 			(*total_remaining_blocks)--;
1254*4882a593Smuzhiyun 			if (*total_remaining_blocks == 0)
1255*4882a593Smuzhiyun 				break;
1256*4882a593Smuzhiyun 		}
1257*4882a593Smuzhiyun 
1258*4882a593Smuzhiyun 		/* write the block to disk */
1259*4882a593Smuzhiyun 		put_ext4(((uint64_t) ((uint64_t)si_blockno * (uint64_t)fs->blksz)),
1260*4882a593Smuzhiyun 			 si_start_addr, fs->blksz);
1261*4882a593Smuzhiyun 		file_inode->b.blocks.indir_block = cpu_to_le32(si_blockno);
1262*4882a593Smuzhiyun 	}
1263*4882a593Smuzhiyun fail:
1264*4882a593Smuzhiyun 	free(si_start_addr);
1265*4882a593Smuzhiyun }
1266*4882a593Smuzhiyun 
alloc_double_indirect_block(struct ext2_inode * file_inode,unsigned int * total_remaining_blocks,unsigned int * no_blks_reqd)1267*4882a593Smuzhiyun static void alloc_double_indirect_block(struct ext2_inode *file_inode,
1268*4882a593Smuzhiyun 					unsigned int *total_remaining_blocks,
1269*4882a593Smuzhiyun 					unsigned int *no_blks_reqd)
1270*4882a593Smuzhiyun {
1271*4882a593Smuzhiyun 	short i;
1272*4882a593Smuzhiyun 	short j;
1273*4882a593Smuzhiyun 	short status;
1274*4882a593Smuzhiyun 	long int actual_block_no;
1275*4882a593Smuzhiyun 	/* di:double indirect */
1276*4882a593Smuzhiyun 	long int di_blockno_parent;
1277*4882a593Smuzhiyun 	long int di_blockno_child;
1278*4882a593Smuzhiyun 	__le32 *di_parent_buffer = NULL;
1279*4882a593Smuzhiyun 	__le32 *di_child_buff = NULL;
1280*4882a593Smuzhiyun 	__le32 *di_block_start_addr = NULL;
1281*4882a593Smuzhiyun 	__le32 *di_child_buff_start = NULL;
1282*4882a593Smuzhiyun 	struct ext_filesystem *fs = get_fs();
1283*4882a593Smuzhiyun 
1284*4882a593Smuzhiyun 	if (*total_remaining_blocks != 0) {
1285*4882a593Smuzhiyun 		/* double indirect parent block connecting to inode */
1286*4882a593Smuzhiyun 		di_blockno_parent = ext4fs_get_new_blk_no();
1287*4882a593Smuzhiyun 		if (di_blockno_parent == -1) {
1288*4882a593Smuzhiyun 			printf("no block left to assign\n");
1289*4882a593Smuzhiyun 			goto fail;
1290*4882a593Smuzhiyun 		}
1291*4882a593Smuzhiyun 		di_parent_buffer = zalloc(fs->blksz);
1292*4882a593Smuzhiyun 		if (!di_parent_buffer)
1293*4882a593Smuzhiyun 			goto fail;
1294*4882a593Smuzhiyun 
1295*4882a593Smuzhiyun 		di_block_start_addr = di_parent_buffer;
1296*4882a593Smuzhiyun 		(*no_blks_reqd)++;
1297*4882a593Smuzhiyun 		debug("DIPB %ld: %u\n", di_blockno_parent,
1298*4882a593Smuzhiyun 		      *total_remaining_blocks);
1299*4882a593Smuzhiyun 
1300*4882a593Smuzhiyun 		status = ext4fs_devread((lbaint_t)di_blockno_parent *
1301*4882a593Smuzhiyun 					fs->sect_perblk, 0,
1302*4882a593Smuzhiyun 					fs->blksz, (char *)di_parent_buffer);
1303*4882a593Smuzhiyun 
1304*4882a593Smuzhiyun 		if (!status) {
1305*4882a593Smuzhiyun 			printf("%s: Device read error!\n", __func__);
1306*4882a593Smuzhiyun 			goto fail;
1307*4882a593Smuzhiyun 		}
1308*4882a593Smuzhiyun 		memset(di_parent_buffer, '\0', fs->blksz);
1309*4882a593Smuzhiyun 
1310*4882a593Smuzhiyun 		/*
1311*4882a593Smuzhiyun 		 * start:for each double indirect parent
1312*4882a593Smuzhiyun 		 * block create one more block
1313*4882a593Smuzhiyun 		 */
1314*4882a593Smuzhiyun 		for (i = 0; i < (fs->blksz / sizeof(int)); i++) {
1315*4882a593Smuzhiyun 			di_blockno_child = ext4fs_get_new_blk_no();
1316*4882a593Smuzhiyun 			if (di_blockno_child == -1) {
1317*4882a593Smuzhiyun 				printf("no block left to assign\n");
1318*4882a593Smuzhiyun 				goto fail;
1319*4882a593Smuzhiyun 			}
1320*4882a593Smuzhiyun 			di_child_buff = zalloc(fs->blksz);
1321*4882a593Smuzhiyun 			if (!di_child_buff)
1322*4882a593Smuzhiyun 				goto fail;
1323*4882a593Smuzhiyun 
1324*4882a593Smuzhiyun 			di_child_buff_start = di_child_buff;
1325*4882a593Smuzhiyun 			*di_parent_buffer = cpu_to_le32(di_blockno_child);
1326*4882a593Smuzhiyun 			di_parent_buffer++;
1327*4882a593Smuzhiyun 			(*no_blks_reqd)++;
1328*4882a593Smuzhiyun 			debug("DICB %ld: %u\n", di_blockno_child,
1329*4882a593Smuzhiyun 			      *total_remaining_blocks);
1330*4882a593Smuzhiyun 
1331*4882a593Smuzhiyun 			status = ext4fs_devread((lbaint_t)di_blockno_child *
1332*4882a593Smuzhiyun 						fs->sect_perblk, 0,
1333*4882a593Smuzhiyun 						fs->blksz,
1334*4882a593Smuzhiyun 						(char *)di_child_buff);
1335*4882a593Smuzhiyun 
1336*4882a593Smuzhiyun 			if (!status) {
1337*4882a593Smuzhiyun 				printf("%s: Device read error!\n", __func__);
1338*4882a593Smuzhiyun 				goto fail;
1339*4882a593Smuzhiyun 			}
1340*4882a593Smuzhiyun 			memset(di_child_buff, '\0', fs->blksz);
1341*4882a593Smuzhiyun 			/* filling of actual datablocks for each child */
1342*4882a593Smuzhiyun 			for (j = 0; j < (fs->blksz / sizeof(int)); j++) {
1343*4882a593Smuzhiyun 				actual_block_no = ext4fs_get_new_blk_no();
1344*4882a593Smuzhiyun 				if (actual_block_no == -1) {
1345*4882a593Smuzhiyun 					printf("no block left to assign\n");
1346*4882a593Smuzhiyun 					goto fail;
1347*4882a593Smuzhiyun 				}
1348*4882a593Smuzhiyun 				*di_child_buff = cpu_to_le32(actual_block_no);
1349*4882a593Smuzhiyun 				debug("DIAB %ld: %u\n", actual_block_no,
1350*4882a593Smuzhiyun 				      *total_remaining_blocks);
1351*4882a593Smuzhiyun 
1352*4882a593Smuzhiyun 				di_child_buff++;
1353*4882a593Smuzhiyun 				(*total_remaining_blocks)--;
1354*4882a593Smuzhiyun 				if (*total_remaining_blocks == 0)
1355*4882a593Smuzhiyun 					break;
1356*4882a593Smuzhiyun 			}
1357*4882a593Smuzhiyun 			/* write the block  table */
1358*4882a593Smuzhiyun 			put_ext4(((uint64_t) ((uint64_t)di_blockno_child * (uint64_t)fs->blksz)),
1359*4882a593Smuzhiyun 				 di_child_buff_start, fs->blksz);
1360*4882a593Smuzhiyun 			free(di_child_buff_start);
1361*4882a593Smuzhiyun 			di_child_buff_start = NULL;
1362*4882a593Smuzhiyun 
1363*4882a593Smuzhiyun 			if (*total_remaining_blocks == 0)
1364*4882a593Smuzhiyun 				break;
1365*4882a593Smuzhiyun 		}
1366*4882a593Smuzhiyun 		put_ext4(((uint64_t) ((uint64_t)di_blockno_parent * (uint64_t)fs->blksz)),
1367*4882a593Smuzhiyun 			 di_block_start_addr, fs->blksz);
1368*4882a593Smuzhiyun 		file_inode->b.blocks.double_indir_block = cpu_to_le32(di_blockno_parent);
1369*4882a593Smuzhiyun 	}
1370*4882a593Smuzhiyun fail:
1371*4882a593Smuzhiyun 	free(di_block_start_addr);
1372*4882a593Smuzhiyun }
1373*4882a593Smuzhiyun 
alloc_triple_indirect_block(struct ext2_inode * file_inode,unsigned int * total_remaining_blocks,unsigned int * no_blks_reqd)1374*4882a593Smuzhiyun static void alloc_triple_indirect_block(struct ext2_inode *file_inode,
1375*4882a593Smuzhiyun 					unsigned int *total_remaining_blocks,
1376*4882a593Smuzhiyun 					unsigned int *no_blks_reqd)
1377*4882a593Smuzhiyun {
1378*4882a593Smuzhiyun 	short i;
1379*4882a593Smuzhiyun 	short j;
1380*4882a593Smuzhiyun 	short k;
1381*4882a593Smuzhiyun 	long int actual_block_no;
1382*4882a593Smuzhiyun 	/* ti: Triple Indirect */
1383*4882a593Smuzhiyun 	long int ti_gp_blockno;
1384*4882a593Smuzhiyun 	long int ti_parent_blockno;
1385*4882a593Smuzhiyun 	long int ti_child_blockno;
1386*4882a593Smuzhiyun 	__le32 *ti_gp_buff = NULL;
1387*4882a593Smuzhiyun 	__le32 *ti_parent_buff = NULL;
1388*4882a593Smuzhiyun 	__le32 *ti_child_buff = NULL;
1389*4882a593Smuzhiyun 	__le32 *ti_gp_buff_start_addr = NULL;
1390*4882a593Smuzhiyun 	__le32 *ti_pbuff_start_addr = NULL;
1391*4882a593Smuzhiyun 	__le32 *ti_cbuff_start_addr = NULL;
1392*4882a593Smuzhiyun 	struct ext_filesystem *fs = get_fs();
1393*4882a593Smuzhiyun 	if (*total_remaining_blocks != 0) {
1394*4882a593Smuzhiyun 		/* triple indirect grand parent block connecting to inode */
1395*4882a593Smuzhiyun 		ti_gp_blockno = ext4fs_get_new_blk_no();
1396*4882a593Smuzhiyun 		if (ti_gp_blockno == -1) {
1397*4882a593Smuzhiyun 			printf("no block left to assign\n");
1398*4882a593Smuzhiyun 			return;
1399*4882a593Smuzhiyun 		}
1400*4882a593Smuzhiyun 		ti_gp_buff = zalloc(fs->blksz);
1401*4882a593Smuzhiyun 		if (!ti_gp_buff)
1402*4882a593Smuzhiyun 			return;
1403*4882a593Smuzhiyun 
1404*4882a593Smuzhiyun 		ti_gp_buff_start_addr = ti_gp_buff;
1405*4882a593Smuzhiyun 		(*no_blks_reqd)++;
1406*4882a593Smuzhiyun 		debug("TIGPB %ld: %u\n", ti_gp_blockno,
1407*4882a593Smuzhiyun 		      *total_remaining_blocks);
1408*4882a593Smuzhiyun 
1409*4882a593Smuzhiyun 		/* for each 4 byte grand parent entry create one more block */
1410*4882a593Smuzhiyun 		for (i = 0; i < (fs->blksz / sizeof(int)); i++) {
1411*4882a593Smuzhiyun 			ti_parent_blockno = ext4fs_get_new_blk_no();
1412*4882a593Smuzhiyun 			if (ti_parent_blockno == -1) {
1413*4882a593Smuzhiyun 				printf("no block left to assign\n");
1414*4882a593Smuzhiyun 				goto fail;
1415*4882a593Smuzhiyun 			}
1416*4882a593Smuzhiyun 			ti_parent_buff = zalloc(fs->blksz);
1417*4882a593Smuzhiyun 			if (!ti_parent_buff)
1418*4882a593Smuzhiyun 				goto fail;
1419*4882a593Smuzhiyun 
1420*4882a593Smuzhiyun 			ti_pbuff_start_addr = ti_parent_buff;
1421*4882a593Smuzhiyun 			*ti_gp_buff = cpu_to_le32(ti_parent_blockno);
1422*4882a593Smuzhiyun 			ti_gp_buff++;
1423*4882a593Smuzhiyun 			(*no_blks_reqd)++;
1424*4882a593Smuzhiyun 			debug("TIPB %ld: %u\n", ti_parent_blockno,
1425*4882a593Smuzhiyun 			      *total_remaining_blocks);
1426*4882a593Smuzhiyun 
1427*4882a593Smuzhiyun 			/* for each 4 byte entry parent create one more block */
1428*4882a593Smuzhiyun 			for (j = 0; j < (fs->blksz / sizeof(int)); j++) {
1429*4882a593Smuzhiyun 				ti_child_blockno = ext4fs_get_new_blk_no();
1430*4882a593Smuzhiyun 				if (ti_child_blockno == -1) {
1431*4882a593Smuzhiyun 					printf("no block left assign\n");
1432*4882a593Smuzhiyun 					goto fail1;
1433*4882a593Smuzhiyun 				}
1434*4882a593Smuzhiyun 				ti_child_buff = zalloc(fs->blksz);
1435*4882a593Smuzhiyun 				if (!ti_child_buff)
1436*4882a593Smuzhiyun 					goto fail1;
1437*4882a593Smuzhiyun 
1438*4882a593Smuzhiyun 				ti_cbuff_start_addr = ti_child_buff;
1439*4882a593Smuzhiyun 				*ti_parent_buff = cpu_to_le32(ti_child_blockno);
1440*4882a593Smuzhiyun 				ti_parent_buff++;
1441*4882a593Smuzhiyun 				(*no_blks_reqd)++;
1442*4882a593Smuzhiyun 				debug("TICB %ld: %u\n", ti_parent_blockno,
1443*4882a593Smuzhiyun 				      *total_remaining_blocks);
1444*4882a593Smuzhiyun 
1445*4882a593Smuzhiyun 				/* fill actual datablocks for each child */
1446*4882a593Smuzhiyun 				for (k = 0; k < (fs->blksz / sizeof(int));
1447*4882a593Smuzhiyun 					k++) {
1448*4882a593Smuzhiyun 					actual_block_no =
1449*4882a593Smuzhiyun 					    ext4fs_get_new_blk_no();
1450*4882a593Smuzhiyun 					if (actual_block_no == -1) {
1451*4882a593Smuzhiyun 						printf("no block left\n");
1452*4882a593Smuzhiyun 						free(ti_cbuff_start_addr);
1453*4882a593Smuzhiyun 						goto fail1;
1454*4882a593Smuzhiyun 					}
1455*4882a593Smuzhiyun 					*ti_child_buff = cpu_to_le32(actual_block_no);
1456*4882a593Smuzhiyun 					debug("TIAB %ld: %u\n", actual_block_no,
1457*4882a593Smuzhiyun 					      *total_remaining_blocks);
1458*4882a593Smuzhiyun 
1459*4882a593Smuzhiyun 					ti_child_buff++;
1460*4882a593Smuzhiyun 					(*total_remaining_blocks)--;
1461*4882a593Smuzhiyun 					if (*total_remaining_blocks == 0)
1462*4882a593Smuzhiyun 						break;
1463*4882a593Smuzhiyun 				}
1464*4882a593Smuzhiyun 				/* write the child block */
1465*4882a593Smuzhiyun 				put_ext4(((uint64_t) ((uint64_t)ti_child_blockno *
1466*4882a593Smuzhiyun 						      (uint64_t)fs->blksz)),
1467*4882a593Smuzhiyun 					 ti_cbuff_start_addr, fs->blksz);
1468*4882a593Smuzhiyun 				free(ti_cbuff_start_addr);
1469*4882a593Smuzhiyun 
1470*4882a593Smuzhiyun 				if (*total_remaining_blocks == 0)
1471*4882a593Smuzhiyun 					break;
1472*4882a593Smuzhiyun 			}
1473*4882a593Smuzhiyun 			/* write the parent block */
1474*4882a593Smuzhiyun 			put_ext4(((uint64_t) ((uint64_t)ti_parent_blockno * (uint64_t)fs->blksz)),
1475*4882a593Smuzhiyun 				 ti_pbuff_start_addr, fs->blksz);
1476*4882a593Smuzhiyun 			free(ti_pbuff_start_addr);
1477*4882a593Smuzhiyun 
1478*4882a593Smuzhiyun 			if (*total_remaining_blocks == 0)
1479*4882a593Smuzhiyun 				break;
1480*4882a593Smuzhiyun 		}
1481*4882a593Smuzhiyun 		/* write the grand parent block */
1482*4882a593Smuzhiyun 		put_ext4(((uint64_t) ((uint64_t)ti_gp_blockno * (uint64_t)fs->blksz)),
1483*4882a593Smuzhiyun 			 ti_gp_buff_start_addr, fs->blksz);
1484*4882a593Smuzhiyun 		file_inode->b.blocks.triple_indir_block = cpu_to_le32(ti_gp_blockno);
1485*4882a593Smuzhiyun 		free(ti_gp_buff_start_addr);
1486*4882a593Smuzhiyun 		return;
1487*4882a593Smuzhiyun 	}
1488*4882a593Smuzhiyun fail1:
1489*4882a593Smuzhiyun 	free(ti_pbuff_start_addr);
1490*4882a593Smuzhiyun fail:
1491*4882a593Smuzhiyun 	free(ti_gp_buff_start_addr);
1492*4882a593Smuzhiyun }
1493*4882a593Smuzhiyun 
ext4fs_allocate_blocks(struct ext2_inode * file_inode,unsigned int total_remaining_blocks,unsigned int * total_no_of_block)1494*4882a593Smuzhiyun void ext4fs_allocate_blocks(struct ext2_inode *file_inode,
1495*4882a593Smuzhiyun 				unsigned int total_remaining_blocks,
1496*4882a593Smuzhiyun 				unsigned int *total_no_of_block)
1497*4882a593Smuzhiyun {
1498*4882a593Smuzhiyun 	short i;
1499*4882a593Smuzhiyun 	long int direct_blockno;
1500*4882a593Smuzhiyun 	unsigned int no_blks_reqd = 0;
1501*4882a593Smuzhiyun 
1502*4882a593Smuzhiyun 	/* allocation of direct blocks */
1503*4882a593Smuzhiyun 	for (i = 0; total_remaining_blocks && i < INDIRECT_BLOCKS; i++) {
1504*4882a593Smuzhiyun 		direct_blockno = ext4fs_get_new_blk_no();
1505*4882a593Smuzhiyun 		if (direct_blockno == -1) {
1506*4882a593Smuzhiyun 			printf("no block left to assign\n");
1507*4882a593Smuzhiyun 			return;
1508*4882a593Smuzhiyun 		}
1509*4882a593Smuzhiyun 		file_inode->b.blocks.dir_blocks[i] = cpu_to_le32(direct_blockno);
1510*4882a593Smuzhiyun 		debug("DB %ld: %u\n", direct_blockno, total_remaining_blocks);
1511*4882a593Smuzhiyun 
1512*4882a593Smuzhiyun 		total_remaining_blocks--;
1513*4882a593Smuzhiyun 	}
1514*4882a593Smuzhiyun 
1515*4882a593Smuzhiyun 	alloc_single_indirect_block(file_inode, &total_remaining_blocks,
1516*4882a593Smuzhiyun 				    &no_blks_reqd);
1517*4882a593Smuzhiyun 	alloc_double_indirect_block(file_inode, &total_remaining_blocks,
1518*4882a593Smuzhiyun 				    &no_blks_reqd);
1519*4882a593Smuzhiyun 	alloc_triple_indirect_block(file_inode, &total_remaining_blocks,
1520*4882a593Smuzhiyun 				    &no_blks_reqd);
1521*4882a593Smuzhiyun 	*total_no_of_block += no_blks_reqd;
1522*4882a593Smuzhiyun }
1523*4882a593Smuzhiyun 
1524*4882a593Smuzhiyun #endif
1525*4882a593Smuzhiyun 
ext4fs_get_extent_block(struct ext2_data * data,char * buf,struct ext4_extent_header * ext_block,uint32_t fileblock,int log2_blksz)1526*4882a593Smuzhiyun static struct ext4_extent_header *ext4fs_get_extent_block
1527*4882a593Smuzhiyun 	(struct ext2_data *data, char *buf,
1528*4882a593Smuzhiyun 		struct ext4_extent_header *ext_block,
1529*4882a593Smuzhiyun 		uint32_t fileblock, int log2_blksz)
1530*4882a593Smuzhiyun {
1531*4882a593Smuzhiyun 	struct ext4_extent_idx *index;
1532*4882a593Smuzhiyun 	unsigned long long block;
1533*4882a593Smuzhiyun 	int blksz = EXT2_BLOCK_SIZE(data);
1534*4882a593Smuzhiyun 	int i;
1535*4882a593Smuzhiyun 
1536*4882a593Smuzhiyun 	while (1) {
1537*4882a593Smuzhiyun 		index = (struct ext4_extent_idx *)(ext_block + 1);
1538*4882a593Smuzhiyun 
1539*4882a593Smuzhiyun 		if (le16_to_cpu(ext_block->eh_magic) != EXT4_EXT_MAGIC)
1540*4882a593Smuzhiyun 			return NULL;
1541*4882a593Smuzhiyun 
1542*4882a593Smuzhiyun 		if (ext_block->eh_depth == 0)
1543*4882a593Smuzhiyun 			return ext_block;
1544*4882a593Smuzhiyun 		i = -1;
1545*4882a593Smuzhiyun 		do {
1546*4882a593Smuzhiyun 			i++;
1547*4882a593Smuzhiyun 			if (i >= le16_to_cpu(ext_block->eh_entries))
1548*4882a593Smuzhiyun 				break;
1549*4882a593Smuzhiyun 		} while (fileblock >= le32_to_cpu(index[i].ei_block));
1550*4882a593Smuzhiyun 
1551*4882a593Smuzhiyun 		if (--i < 0)
1552*4882a593Smuzhiyun 			return NULL;
1553*4882a593Smuzhiyun 
1554*4882a593Smuzhiyun 		block = le16_to_cpu(index[i].ei_leaf_hi);
1555*4882a593Smuzhiyun 		block = (block << 32) + le32_to_cpu(index[i].ei_leaf_lo);
1556*4882a593Smuzhiyun 
1557*4882a593Smuzhiyun 		if (ext4fs_devread((lbaint_t)block << log2_blksz, 0, blksz,
1558*4882a593Smuzhiyun 				   buf))
1559*4882a593Smuzhiyun 			ext_block = (struct ext4_extent_header *)buf;
1560*4882a593Smuzhiyun 		else
1561*4882a593Smuzhiyun 			return NULL;
1562*4882a593Smuzhiyun 	}
1563*4882a593Smuzhiyun }
1564*4882a593Smuzhiyun 
ext4fs_blockgroup(struct ext2_data * data,int group,struct ext2_block_group * blkgrp)1565*4882a593Smuzhiyun static int ext4fs_blockgroup
1566*4882a593Smuzhiyun 	(struct ext2_data *data, int group, struct ext2_block_group *blkgrp)
1567*4882a593Smuzhiyun {
1568*4882a593Smuzhiyun 	long int blkno;
1569*4882a593Smuzhiyun 	unsigned int blkoff, desc_per_blk;
1570*4882a593Smuzhiyun 	int log2blksz = get_fs()->dev_desc->log2blksz;
1571*4882a593Smuzhiyun 	int desc_size = get_fs()->gdsize;
1572*4882a593Smuzhiyun 
1573*4882a593Smuzhiyun 	desc_per_blk = EXT2_BLOCK_SIZE(data) / desc_size;
1574*4882a593Smuzhiyun 
1575*4882a593Smuzhiyun 	blkno = le32_to_cpu(data->sblock.first_data_block) + 1 +
1576*4882a593Smuzhiyun 			group / desc_per_blk;
1577*4882a593Smuzhiyun 	blkoff = (group % desc_per_blk) * desc_size;
1578*4882a593Smuzhiyun 
1579*4882a593Smuzhiyun 	debug("ext4fs read %d group descriptor (blkno %ld blkoff %u)\n",
1580*4882a593Smuzhiyun 	      group, blkno, blkoff);
1581*4882a593Smuzhiyun 
1582*4882a593Smuzhiyun 	return ext4fs_devread((lbaint_t)blkno <<
1583*4882a593Smuzhiyun 			      (LOG2_BLOCK_SIZE(data) - log2blksz),
1584*4882a593Smuzhiyun 			      blkoff, desc_size, (char *)blkgrp);
1585*4882a593Smuzhiyun }
1586*4882a593Smuzhiyun 
ext4fs_read_inode(struct ext2_data * data,int ino,struct ext2_inode * inode)1587*4882a593Smuzhiyun int ext4fs_read_inode(struct ext2_data *data, int ino, struct ext2_inode *inode)
1588*4882a593Smuzhiyun {
1589*4882a593Smuzhiyun 	struct ext2_block_group blkgrp;
1590*4882a593Smuzhiyun 	struct ext2_sblock *sblock = &data->sblock;
1591*4882a593Smuzhiyun 	struct ext_filesystem *fs = get_fs();
1592*4882a593Smuzhiyun 	int log2blksz = get_fs()->dev_desc->log2blksz;
1593*4882a593Smuzhiyun 	int inodes_per_block, status;
1594*4882a593Smuzhiyun 	long int blkno;
1595*4882a593Smuzhiyun 	unsigned int blkoff;
1596*4882a593Smuzhiyun 
1597*4882a593Smuzhiyun 	/* It is easier to calculate if the first inode is 0. */
1598*4882a593Smuzhiyun 	ino--;
1599*4882a593Smuzhiyun 	status = ext4fs_blockgroup(data, ino / le32_to_cpu
1600*4882a593Smuzhiyun 				   (sblock->inodes_per_group), &blkgrp);
1601*4882a593Smuzhiyun 	if (status == 0)
1602*4882a593Smuzhiyun 		return 0;
1603*4882a593Smuzhiyun 
1604*4882a593Smuzhiyun 	inodes_per_block = EXT2_BLOCK_SIZE(data) / fs->inodesz;
1605*4882a593Smuzhiyun 	blkno = ext4fs_bg_get_inode_table_id(&blkgrp, fs) +
1606*4882a593Smuzhiyun 	    (ino % le32_to_cpu(sblock->inodes_per_group)) / inodes_per_block;
1607*4882a593Smuzhiyun 	blkoff = (ino % inodes_per_block) * fs->inodesz;
1608*4882a593Smuzhiyun 	/* Read the inode. */
1609*4882a593Smuzhiyun 	status = ext4fs_devread((lbaint_t)blkno << (LOG2_BLOCK_SIZE(data) -
1610*4882a593Smuzhiyun 				log2blksz), blkoff,
1611*4882a593Smuzhiyun 				sizeof(struct ext2_inode), (char *)inode);
1612*4882a593Smuzhiyun 	if (status == 0)
1613*4882a593Smuzhiyun 		return 0;
1614*4882a593Smuzhiyun 
1615*4882a593Smuzhiyun 	return 1;
1616*4882a593Smuzhiyun }
1617*4882a593Smuzhiyun 
read_allocated_block(struct ext2_inode * inode,int fileblock)1618*4882a593Smuzhiyun long int read_allocated_block(struct ext2_inode *inode, int fileblock)
1619*4882a593Smuzhiyun {
1620*4882a593Smuzhiyun 	long int blknr;
1621*4882a593Smuzhiyun 	int blksz;
1622*4882a593Smuzhiyun 	int log2_blksz;
1623*4882a593Smuzhiyun 	int status;
1624*4882a593Smuzhiyun 	long int rblock;
1625*4882a593Smuzhiyun 	long int perblock_parent;
1626*4882a593Smuzhiyun 	long int perblock_child;
1627*4882a593Smuzhiyun 	unsigned long long start;
1628*4882a593Smuzhiyun 	/* get the blocksize of the filesystem */
1629*4882a593Smuzhiyun 	blksz = EXT2_BLOCK_SIZE(ext4fs_root);
1630*4882a593Smuzhiyun 	log2_blksz = LOG2_BLOCK_SIZE(ext4fs_root)
1631*4882a593Smuzhiyun 		- get_fs()->dev_desc->log2blksz;
1632*4882a593Smuzhiyun 
1633*4882a593Smuzhiyun 	if (le32_to_cpu(inode->flags) & EXT4_EXTENTS_FL) {
1634*4882a593Smuzhiyun 		long int startblock, endblock;
1635*4882a593Smuzhiyun 		char *buf = zalloc(blksz);
1636*4882a593Smuzhiyun 		if (!buf)
1637*4882a593Smuzhiyun 			return -ENOMEM;
1638*4882a593Smuzhiyun 		struct ext4_extent_header *ext_block;
1639*4882a593Smuzhiyun 		struct ext4_extent *extent;
1640*4882a593Smuzhiyun 		int i;
1641*4882a593Smuzhiyun 		ext_block =
1642*4882a593Smuzhiyun 			ext4fs_get_extent_block(ext4fs_root, buf,
1643*4882a593Smuzhiyun 						(struct ext4_extent_header *)
1644*4882a593Smuzhiyun 						inode->b.blocks.dir_blocks,
1645*4882a593Smuzhiyun 						fileblock, log2_blksz);
1646*4882a593Smuzhiyun 		if (!ext_block) {
1647*4882a593Smuzhiyun 			printf("invalid extent block\n");
1648*4882a593Smuzhiyun 			free(buf);
1649*4882a593Smuzhiyun 			return -EINVAL;
1650*4882a593Smuzhiyun 		}
1651*4882a593Smuzhiyun 
1652*4882a593Smuzhiyun 		extent = (struct ext4_extent *)(ext_block + 1);
1653*4882a593Smuzhiyun 
1654*4882a593Smuzhiyun 		for (i = 0; i < le16_to_cpu(ext_block->eh_entries); i++) {
1655*4882a593Smuzhiyun 			startblock = le32_to_cpu(extent[i].ee_block);
1656*4882a593Smuzhiyun 			endblock = startblock + le16_to_cpu(extent[i].ee_len);
1657*4882a593Smuzhiyun 
1658*4882a593Smuzhiyun 			if (startblock > fileblock) {
1659*4882a593Smuzhiyun 				/* Sparse file */
1660*4882a593Smuzhiyun 				free(buf);
1661*4882a593Smuzhiyun 				return 0;
1662*4882a593Smuzhiyun 
1663*4882a593Smuzhiyun 			} else if (fileblock < endblock) {
1664*4882a593Smuzhiyun 				start = le16_to_cpu(extent[i].ee_start_hi);
1665*4882a593Smuzhiyun 				start = (start << 32) +
1666*4882a593Smuzhiyun 					le32_to_cpu(extent[i].ee_start_lo);
1667*4882a593Smuzhiyun 				free(buf);
1668*4882a593Smuzhiyun 				return (fileblock - startblock) + start;
1669*4882a593Smuzhiyun 			}
1670*4882a593Smuzhiyun 		}
1671*4882a593Smuzhiyun 
1672*4882a593Smuzhiyun 		free(buf);
1673*4882a593Smuzhiyun 		return 0;
1674*4882a593Smuzhiyun 	}
1675*4882a593Smuzhiyun 
1676*4882a593Smuzhiyun 	/* Direct blocks. */
1677*4882a593Smuzhiyun 	if (fileblock < INDIRECT_BLOCKS)
1678*4882a593Smuzhiyun 		blknr = le32_to_cpu(inode->b.blocks.dir_blocks[fileblock]);
1679*4882a593Smuzhiyun 
1680*4882a593Smuzhiyun 	/* Indirect. */
1681*4882a593Smuzhiyun 	else if (fileblock < (INDIRECT_BLOCKS + (blksz / 4))) {
1682*4882a593Smuzhiyun 		if (ext4fs_indir1_block == NULL) {
1683*4882a593Smuzhiyun 			ext4fs_indir1_block = zalloc(blksz);
1684*4882a593Smuzhiyun 			if (ext4fs_indir1_block == NULL) {
1685*4882a593Smuzhiyun 				printf("** SI ext2fs read block (indir 1)"
1686*4882a593Smuzhiyun 					"malloc failed. **\n");
1687*4882a593Smuzhiyun 				return -1;
1688*4882a593Smuzhiyun 			}
1689*4882a593Smuzhiyun 			ext4fs_indir1_size = blksz;
1690*4882a593Smuzhiyun 			ext4fs_indir1_blkno = -1;
1691*4882a593Smuzhiyun 		}
1692*4882a593Smuzhiyun 		if (blksz != ext4fs_indir1_size) {
1693*4882a593Smuzhiyun 			free(ext4fs_indir1_block);
1694*4882a593Smuzhiyun 			ext4fs_indir1_block = NULL;
1695*4882a593Smuzhiyun 			ext4fs_indir1_size = 0;
1696*4882a593Smuzhiyun 			ext4fs_indir1_blkno = -1;
1697*4882a593Smuzhiyun 			ext4fs_indir1_block = zalloc(blksz);
1698*4882a593Smuzhiyun 			if (ext4fs_indir1_block == NULL) {
1699*4882a593Smuzhiyun 				printf("** SI ext2fs read block (indir 1):"
1700*4882a593Smuzhiyun 					"malloc failed. **\n");
1701*4882a593Smuzhiyun 				return -1;
1702*4882a593Smuzhiyun 			}
1703*4882a593Smuzhiyun 			ext4fs_indir1_size = blksz;
1704*4882a593Smuzhiyun 		}
1705*4882a593Smuzhiyun 		if ((le32_to_cpu(inode->b.blocks.indir_block) <<
1706*4882a593Smuzhiyun 		     log2_blksz) != ext4fs_indir1_blkno) {
1707*4882a593Smuzhiyun 			status =
1708*4882a593Smuzhiyun 			    ext4fs_devread((lbaint_t)le32_to_cpu
1709*4882a593Smuzhiyun 					   (inode->b.blocks.
1710*4882a593Smuzhiyun 					    indir_block) << log2_blksz, 0,
1711*4882a593Smuzhiyun 					   blksz, (char *)ext4fs_indir1_block);
1712*4882a593Smuzhiyun 			if (status == 0) {
1713*4882a593Smuzhiyun 				printf("** SI ext2fs read block (indir 1)"
1714*4882a593Smuzhiyun 					"failed. **\n");
1715*4882a593Smuzhiyun 				return -1;
1716*4882a593Smuzhiyun 			}
1717*4882a593Smuzhiyun 			ext4fs_indir1_blkno =
1718*4882a593Smuzhiyun 				le32_to_cpu(inode->b.blocks.
1719*4882a593Smuzhiyun 					       indir_block) << log2_blksz;
1720*4882a593Smuzhiyun 		}
1721*4882a593Smuzhiyun 		blknr = le32_to_cpu(ext4fs_indir1_block
1722*4882a593Smuzhiyun 				      [fileblock - INDIRECT_BLOCKS]);
1723*4882a593Smuzhiyun 	}
1724*4882a593Smuzhiyun 	/* Double indirect. */
1725*4882a593Smuzhiyun 	else if (fileblock < (INDIRECT_BLOCKS + (blksz / 4 *
1726*4882a593Smuzhiyun 					(blksz / 4 + 1)))) {
1727*4882a593Smuzhiyun 
1728*4882a593Smuzhiyun 		long int perblock = blksz / 4;
1729*4882a593Smuzhiyun 		long int rblock = fileblock - (INDIRECT_BLOCKS + blksz / 4);
1730*4882a593Smuzhiyun 
1731*4882a593Smuzhiyun 		if (ext4fs_indir1_block == NULL) {
1732*4882a593Smuzhiyun 			ext4fs_indir1_block = zalloc(blksz);
1733*4882a593Smuzhiyun 			if (ext4fs_indir1_block == NULL) {
1734*4882a593Smuzhiyun 				printf("** DI ext2fs read block (indir 2 1)"
1735*4882a593Smuzhiyun 					"malloc failed. **\n");
1736*4882a593Smuzhiyun 				return -1;
1737*4882a593Smuzhiyun 			}
1738*4882a593Smuzhiyun 			ext4fs_indir1_size = blksz;
1739*4882a593Smuzhiyun 			ext4fs_indir1_blkno = -1;
1740*4882a593Smuzhiyun 		}
1741*4882a593Smuzhiyun 		if (blksz != ext4fs_indir1_size) {
1742*4882a593Smuzhiyun 			free(ext4fs_indir1_block);
1743*4882a593Smuzhiyun 			ext4fs_indir1_block = NULL;
1744*4882a593Smuzhiyun 			ext4fs_indir1_size = 0;
1745*4882a593Smuzhiyun 			ext4fs_indir1_blkno = -1;
1746*4882a593Smuzhiyun 			ext4fs_indir1_block = zalloc(blksz);
1747*4882a593Smuzhiyun 			if (ext4fs_indir1_block == NULL) {
1748*4882a593Smuzhiyun 				printf("** DI ext2fs read block (indir 2 1)"
1749*4882a593Smuzhiyun 					"malloc failed. **\n");
1750*4882a593Smuzhiyun 				return -1;
1751*4882a593Smuzhiyun 			}
1752*4882a593Smuzhiyun 			ext4fs_indir1_size = blksz;
1753*4882a593Smuzhiyun 		}
1754*4882a593Smuzhiyun 		if ((le32_to_cpu(inode->b.blocks.double_indir_block) <<
1755*4882a593Smuzhiyun 		     log2_blksz) != ext4fs_indir1_blkno) {
1756*4882a593Smuzhiyun 			status =
1757*4882a593Smuzhiyun 			    ext4fs_devread((lbaint_t)le32_to_cpu
1758*4882a593Smuzhiyun 					   (inode->b.blocks.
1759*4882a593Smuzhiyun 					    double_indir_block) << log2_blksz,
1760*4882a593Smuzhiyun 					   0, blksz,
1761*4882a593Smuzhiyun 					   (char *)ext4fs_indir1_block);
1762*4882a593Smuzhiyun 			if (status == 0) {
1763*4882a593Smuzhiyun 				printf("** DI ext2fs read block (indir 2 1)"
1764*4882a593Smuzhiyun 					"failed. **\n");
1765*4882a593Smuzhiyun 				return -1;
1766*4882a593Smuzhiyun 			}
1767*4882a593Smuzhiyun 			ext4fs_indir1_blkno =
1768*4882a593Smuzhiyun 			    le32_to_cpu(inode->b.blocks.double_indir_block) <<
1769*4882a593Smuzhiyun 			    log2_blksz;
1770*4882a593Smuzhiyun 		}
1771*4882a593Smuzhiyun 
1772*4882a593Smuzhiyun 		if (ext4fs_indir2_block == NULL) {
1773*4882a593Smuzhiyun 			ext4fs_indir2_block = zalloc(blksz);
1774*4882a593Smuzhiyun 			if (ext4fs_indir2_block == NULL) {
1775*4882a593Smuzhiyun 				printf("** DI ext2fs read block (indir 2 2)"
1776*4882a593Smuzhiyun 					"malloc failed. **\n");
1777*4882a593Smuzhiyun 				return -1;
1778*4882a593Smuzhiyun 			}
1779*4882a593Smuzhiyun 			ext4fs_indir2_size = blksz;
1780*4882a593Smuzhiyun 			ext4fs_indir2_blkno = -1;
1781*4882a593Smuzhiyun 		}
1782*4882a593Smuzhiyun 		if (blksz != ext4fs_indir2_size) {
1783*4882a593Smuzhiyun 			free(ext4fs_indir2_block);
1784*4882a593Smuzhiyun 			ext4fs_indir2_block = NULL;
1785*4882a593Smuzhiyun 			ext4fs_indir2_size = 0;
1786*4882a593Smuzhiyun 			ext4fs_indir2_blkno = -1;
1787*4882a593Smuzhiyun 			ext4fs_indir2_block = zalloc(blksz);
1788*4882a593Smuzhiyun 			if (ext4fs_indir2_block == NULL) {
1789*4882a593Smuzhiyun 				printf("** DI ext2fs read block (indir 2 2)"
1790*4882a593Smuzhiyun 					"malloc failed. **\n");
1791*4882a593Smuzhiyun 				return -1;
1792*4882a593Smuzhiyun 			}
1793*4882a593Smuzhiyun 			ext4fs_indir2_size = blksz;
1794*4882a593Smuzhiyun 		}
1795*4882a593Smuzhiyun 		if ((le32_to_cpu(ext4fs_indir1_block[rblock / perblock]) <<
1796*4882a593Smuzhiyun 		     log2_blksz) != ext4fs_indir2_blkno) {
1797*4882a593Smuzhiyun 			status = ext4fs_devread((lbaint_t)le32_to_cpu
1798*4882a593Smuzhiyun 						(ext4fs_indir1_block
1799*4882a593Smuzhiyun 						 [rblock /
1800*4882a593Smuzhiyun 						  perblock]) << log2_blksz, 0,
1801*4882a593Smuzhiyun 						blksz,
1802*4882a593Smuzhiyun 						(char *)ext4fs_indir2_block);
1803*4882a593Smuzhiyun 			if (status == 0) {
1804*4882a593Smuzhiyun 				printf("** DI ext2fs read block (indir 2 2)"
1805*4882a593Smuzhiyun 					"failed. **\n");
1806*4882a593Smuzhiyun 				return -1;
1807*4882a593Smuzhiyun 			}
1808*4882a593Smuzhiyun 			ext4fs_indir2_blkno =
1809*4882a593Smuzhiyun 			    le32_to_cpu(ext4fs_indir1_block[rblock
1810*4882a593Smuzhiyun 							      /
1811*4882a593Smuzhiyun 							      perblock]) <<
1812*4882a593Smuzhiyun 			    log2_blksz;
1813*4882a593Smuzhiyun 		}
1814*4882a593Smuzhiyun 		blknr = le32_to_cpu(ext4fs_indir2_block[rblock % perblock]);
1815*4882a593Smuzhiyun 	}
1816*4882a593Smuzhiyun 	/* Tripple indirect. */
1817*4882a593Smuzhiyun 	else {
1818*4882a593Smuzhiyun 		rblock = fileblock - (INDIRECT_BLOCKS + blksz / 4 +
1819*4882a593Smuzhiyun 				      (blksz / 4 * blksz / 4));
1820*4882a593Smuzhiyun 		perblock_child = blksz / 4;
1821*4882a593Smuzhiyun 		perblock_parent = ((blksz / 4) * (blksz / 4));
1822*4882a593Smuzhiyun 
1823*4882a593Smuzhiyun 		if (ext4fs_indir1_block == NULL) {
1824*4882a593Smuzhiyun 			ext4fs_indir1_block = zalloc(blksz);
1825*4882a593Smuzhiyun 			if (ext4fs_indir1_block == NULL) {
1826*4882a593Smuzhiyun 				printf("** TI ext2fs read block (indir 2 1)"
1827*4882a593Smuzhiyun 					"malloc failed. **\n");
1828*4882a593Smuzhiyun 				return -1;
1829*4882a593Smuzhiyun 			}
1830*4882a593Smuzhiyun 			ext4fs_indir1_size = blksz;
1831*4882a593Smuzhiyun 			ext4fs_indir1_blkno = -1;
1832*4882a593Smuzhiyun 		}
1833*4882a593Smuzhiyun 		if (blksz != ext4fs_indir1_size) {
1834*4882a593Smuzhiyun 			free(ext4fs_indir1_block);
1835*4882a593Smuzhiyun 			ext4fs_indir1_block = NULL;
1836*4882a593Smuzhiyun 			ext4fs_indir1_size = 0;
1837*4882a593Smuzhiyun 			ext4fs_indir1_blkno = -1;
1838*4882a593Smuzhiyun 			ext4fs_indir1_block = zalloc(blksz);
1839*4882a593Smuzhiyun 			if (ext4fs_indir1_block == NULL) {
1840*4882a593Smuzhiyun 				printf("** TI ext2fs read block (indir 2 1)"
1841*4882a593Smuzhiyun 					"malloc failed. **\n");
1842*4882a593Smuzhiyun 				return -1;
1843*4882a593Smuzhiyun 			}
1844*4882a593Smuzhiyun 			ext4fs_indir1_size = blksz;
1845*4882a593Smuzhiyun 		}
1846*4882a593Smuzhiyun 		if ((le32_to_cpu(inode->b.blocks.triple_indir_block) <<
1847*4882a593Smuzhiyun 		     log2_blksz) != ext4fs_indir1_blkno) {
1848*4882a593Smuzhiyun 			status = ext4fs_devread
1849*4882a593Smuzhiyun 			    ((lbaint_t)
1850*4882a593Smuzhiyun 			     le32_to_cpu(inode->b.blocks.triple_indir_block)
1851*4882a593Smuzhiyun 			     << log2_blksz, 0, blksz,
1852*4882a593Smuzhiyun 			     (char *)ext4fs_indir1_block);
1853*4882a593Smuzhiyun 			if (status == 0) {
1854*4882a593Smuzhiyun 				printf("** TI ext2fs read block (indir 2 1)"
1855*4882a593Smuzhiyun 					"failed. **\n");
1856*4882a593Smuzhiyun 				return -1;
1857*4882a593Smuzhiyun 			}
1858*4882a593Smuzhiyun 			ext4fs_indir1_blkno =
1859*4882a593Smuzhiyun 			    le32_to_cpu(inode->b.blocks.triple_indir_block) <<
1860*4882a593Smuzhiyun 			    log2_blksz;
1861*4882a593Smuzhiyun 		}
1862*4882a593Smuzhiyun 
1863*4882a593Smuzhiyun 		if (ext4fs_indir2_block == NULL) {
1864*4882a593Smuzhiyun 			ext4fs_indir2_block = zalloc(blksz);
1865*4882a593Smuzhiyun 			if (ext4fs_indir2_block == NULL) {
1866*4882a593Smuzhiyun 				printf("** TI ext2fs read block (indir 2 2)"
1867*4882a593Smuzhiyun 					"malloc failed. **\n");
1868*4882a593Smuzhiyun 				return -1;
1869*4882a593Smuzhiyun 			}
1870*4882a593Smuzhiyun 			ext4fs_indir2_size = blksz;
1871*4882a593Smuzhiyun 			ext4fs_indir2_blkno = -1;
1872*4882a593Smuzhiyun 		}
1873*4882a593Smuzhiyun 		if (blksz != ext4fs_indir2_size) {
1874*4882a593Smuzhiyun 			free(ext4fs_indir2_block);
1875*4882a593Smuzhiyun 			ext4fs_indir2_block = NULL;
1876*4882a593Smuzhiyun 			ext4fs_indir2_size = 0;
1877*4882a593Smuzhiyun 			ext4fs_indir2_blkno = -1;
1878*4882a593Smuzhiyun 			ext4fs_indir2_block = zalloc(blksz);
1879*4882a593Smuzhiyun 			if (ext4fs_indir2_block == NULL) {
1880*4882a593Smuzhiyun 				printf("** TI ext2fs read block (indir 2 2)"
1881*4882a593Smuzhiyun 					"malloc failed. **\n");
1882*4882a593Smuzhiyun 				return -1;
1883*4882a593Smuzhiyun 			}
1884*4882a593Smuzhiyun 			ext4fs_indir2_size = blksz;
1885*4882a593Smuzhiyun 		}
1886*4882a593Smuzhiyun 		if ((le32_to_cpu(ext4fs_indir1_block[rblock /
1887*4882a593Smuzhiyun 						       perblock_parent]) <<
1888*4882a593Smuzhiyun 		     log2_blksz)
1889*4882a593Smuzhiyun 		    != ext4fs_indir2_blkno) {
1890*4882a593Smuzhiyun 			status = ext4fs_devread((lbaint_t)le32_to_cpu
1891*4882a593Smuzhiyun 						(ext4fs_indir1_block
1892*4882a593Smuzhiyun 						 [rblock /
1893*4882a593Smuzhiyun 						  perblock_parent]) <<
1894*4882a593Smuzhiyun 						log2_blksz, 0, blksz,
1895*4882a593Smuzhiyun 						(char *)ext4fs_indir2_block);
1896*4882a593Smuzhiyun 			if (status == 0) {
1897*4882a593Smuzhiyun 				printf("** TI ext2fs read block (indir 2 2)"
1898*4882a593Smuzhiyun 					"failed. **\n");
1899*4882a593Smuzhiyun 				return -1;
1900*4882a593Smuzhiyun 			}
1901*4882a593Smuzhiyun 			ext4fs_indir2_blkno =
1902*4882a593Smuzhiyun 			    le32_to_cpu(ext4fs_indir1_block[rblock /
1903*4882a593Smuzhiyun 							      perblock_parent])
1904*4882a593Smuzhiyun 			    << log2_blksz;
1905*4882a593Smuzhiyun 		}
1906*4882a593Smuzhiyun 
1907*4882a593Smuzhiyun 		if (ext4fs_indir3_block == NULL) {
1908*4882a593Smuzhiyun 			ext4fs_indir3_block = zalloc(blksz);
1909*4882a593Smuzhiyun 			if (ext4fs_indir3_block == NULL) {
1910*4882a593Smuzhiyun 				printf("** TI ext2fs read block (indir 2 2)"
1911*4882a593Smuzhiyun 					"malloc failed. **\n");
1912*4882a593Smuzhiyun 				return -1;
1913*4882a593Smuzhiyun 			}
1914*4882a593Smuzhiyun 			ext4fs_indir3_size = blksz;
1915*4882a593Smuzhiyun 			ext4fs_indir3_blkno = -1;
1916*4882a593Smuzhiyun 		}
1917*4882a593Smuzhiyun 		if (blksz != ext4fs_indir3_size) {
1918*4882a593Smuzhiyun 			free(ext4fs_indir3_block);
1919*4882a593Smuzhiyun 			ext4fs_indir3_block = NULL;
1920*4882a593Smuzhiyun 			ext4fs_indir3_size = 0;
1921*4882a593Smuzhiyun 			ext4fs_indir3_blkno = -1;
1922*4882a593Smuzhiyun 			ext4fs_indir3_block = zalloc(blksz);
1923*4882a593Smuzhiyun 			if (ext4fs_indir3_block == NULL) {
1924*4882a593Smuzhiyun 				printf("** TI ext2fs read block (indir 2 2)"
1925*4882a593Smuzhiyun 					"malloc failed. **\n");
1926*4882a593Smuzhiyun 				return -1;
1927*4882a593Smuzhiyun 			}
1928*4882a593Smuzhiyun 			ext4fs_indir3_size = blksz;
1929*4882a593Smuzhiyun 		}
1930*4882a593Smuzhiyun 		if ((le32_to_cpu(ext4fs_indir2_block[rblock
1931*4882a593Smuzhiyun 						       /
1932*4882a593Smuzhiyun 						       perblock_child]) <<
1933*4882a593Smuzhiyun 		     log2_blksz) != ext4fs_indir3_blkno) {
1934*4882a593Smuzhiyun 			status =
1935*4882a593Smuzhiyun 			    ext4fs_devread((lbaint_t)le32_to_cpu
1936*4882a593Smuzhiyun 					   (ext4fs_indir2_block
1937*4882a593Smuzhiyun 					    [(rblock / perblock_child)
1938*4882a593Smuzhiyun 					     % (blksz / 4)]) << log2_blksz, 0,
1939*4882a593Smuzhiyun 					   blksz, (char *)ext4fs_indir3_block);
1940*4882a593Smuzhiyun 			if (status == 0) {
1941*4882a593Smuzhiyun 				printf("** TI ext2fs read block (indir 2 2)"
1942*4882a593Smuzhiyun 				       "failed. **\n");
1943*4882a593Smuzhiyun 				return -1;
1944*4882a593Smuzhiyun 			}
1945*4882a593Smuzhiyun 			ext4fs_indir3_blkno =
1946*4882a593Smuzhiyun 			    le32_to_cpu(ext4fs_indir2_block[(rblock /
1947*4882a593Smuzhiyun 							       perblock_child) %
1948*4882a593Smuzhiyun 							      (blksz /
1949*4882a593Smuzhiyun 							       4)]) <<
1950*4882a593Smuzhiyun 			    log2_blksz;
1951*4882a593Smuzhiyun 		}
1952*4882a593Smuzhiyun 
1953*4882a593Smuzhiyun 		blknr = le32_to_cpu(ext4fs_indir3_block
1954*4882a593Smuzhiyun 				      [rblock % perblock_child]);
1955*4882a593Smuzhiyun 	}
1956*4882a593Smuzhiyun 	debug("read_allocated_block %ld\n", blknr);
1957*4882a593Smuzhiyun 
1958*4882a593Smuzhiyun 	return blknr;
1959*4882a593Smuzhiyun }
1960*4882a593Smuzhiyun 
1961*4882a593Smuzhiyun /**
1962*4882a593Smuzhiyun  * ext4fs_reinit_global() - Reinitialize values of ext4 write implementation's
1963*4882a593Smuzhiyun  *			    global pointers
1964*4882a593Smuzhiyun  *
1965*4882a593Smuzhiyun  * This function assures that for a file with the same name but different size
1966*4882a593Smuzhiyun  * the sequential store on the ext4 filesystem will be correct.
1967*4882a593Smuzhiyun  *
1968*4882a593Smuzhiyun  * In this function the global data, responsible for internal representation
1969*4882a593Smuzhiyun  * of the ext4 data are initialized to the reset state. Without this, during
1970*4882a593Smuzhiyun  * replacement of the smaller file with the bigger truncation of new file was
1971*4882a593Smuzhiyun  * performed.
1972*4882a593Smuzhiyun  */
ext4fs_reinit_global(void)1973*4882a593Smuzhiyun void ext4fs_reinit_global(void)
1974*4882a593Smuzhiyun {
1975*4882a593Smuzhiyun 	if (ext4fs_indir1_block != NULL) {
1976*4882a593Smuzhiyun 		free(ext4fs_indir1_block);
1977*4882a593Smuzhiyun 		ext4fs_indir1_block = NULL;
1978*4882a593Smuzhiyun 		ext4fs_indir1_size = 0;
1979*4882a593Smuzhiyun 		ext4fs_indir1_blkno = -1;
1980*4882a593Smuzhiyun 	}
1981*4882a593Smuzhiyun 	if (ext4fs_indir2_block != NULL) {
1982*4882a593Smuzhiyun 		free(ext4fs_indir2_block);
1983*4882a593Smuzhiyun 		ext4fs_indir2_block = NULL;
1984*4882a593Smuzhiyun 		ext4fs_indir2_size = 0;
1985*4882a593Smuzhiyun 		ext4fs_indir2_blkno = -1;
1986*4882a593Smuzhiyun 	}
1987*4882a593Smuzhiyun 	if (ext4fs_indir3_block != NULL) {
1988*4882a593Smuzhiyun 		free(ext4fs_indir3_block);
1989*4882a593Smuzhiyun 		ext4fs_indir3_block = NULL;
1990*4882a593Smuzhiyun 		ext4fs_indir3_size = 0;
1991*4882a593Smuzhiyun 		ext4fs_indir3_blkno = -1;
1992*4882a593Smuzhiyun 	}
1993*4882a593Smuzhiyun }
ext4fs_close(void)1994*4882a593Smuzhiyun void ext4fs_close(void)
1995*4882a593Smuzhiyun {
1996*4882a593Smuzhiyun 	if ((ext4fs_file != NULL) && (ext4fs_root != NULL)) {
1997*4882a593Smuzhiyun 		ext4fs_free_node(ext4fs_file, &ext4fs_root->diropen);
1998*4882a593Smuzhiyun 		ext4fs_file = NULL;
1999*4882a593Smuzhiyun 	}
2000*4882a593Smuzhiyun 	if (ext4fs_root != NULL) {
2001*4882a593Smuzhiyun 		free(ext4fs_root);
2002*4882a593Smuzhiyun 		ext4fs_root = NULL;
2003*4882a593Smuzhiyun 	}
2004*4882a593Smuzhiyun 
2005*4882a593Smuzhiyun 	ext4fs_reinit_global();
2006*4882a593Smuzhiyun }
2007*4882a593Smuzhiyun 
ext4fs_iterate_dir(struct ext2fs_node * dir,char * name,struct ext2fs_node ** fnode,int * ftype)2008*4882a593Smuzhiyun int ext4fs_iterate_dir(struct ext2fs_node *dir, char *name,
2009*4882a593Smuzhiyun 				struct ext2fs_node **fnode, int *ftype)
2010*4882a593Smuzhiyun {
2011*4882a593Smuzhiyun 	unsigned int fpos = 0;
2012*4882a593Smuzhiyun 	int status;
2013*4882a593Smuzhiyun 	loff_t actread;
2014*4882a593Smuzhiyun 	struct ext2fs_node *diro = (struct ext2fs_node *) dir;
2015*4882a593Smuzhiyun 
2016*4882a593Smuzhiyun #ifdef DEBUG
2017*4882a593Smuzhiyun 	if (name != NULL)
2018*4882a593Smuzhiyun 		printf("Iterate dir %s\n", name);
2019*4882a593Smuzhiyun #endif /* of DEBUG */
2020*4882a593Smuzhiyun 	if (!diro->inode_read) {
2021*4882a593Smuzhiyun 		status = ext4fs_read_inode(diro->data, diro->ino, &diro->inode);
2022*4882a593Smuzhiyun 		if (status == 0)
2023*4882a593Smuzhiyun 			return 0;
2024*4882a593Smuzhiyun 	}
2025*4882a593Smuzhiyun 	/* Search the file.  */
2026*4882a593Smuzhiyun 	while (fpos < le32_to_cpu(diro->inode.size)) {
2027*4882a593Smuzhiyun 		struct ext2_dirent dirent;
2028*4882a593Smuzhiyun 
2029*4882a593Smuzhiyun 		status = ext4fs_read_file(diro, fpos,
2030*4882a593Smuzhiyun 					   sizeof(struct ext2_dirent),
2031*4882a593Smuzhiyun 					   (char *)&dirent, &actread);
2032*4882a593Smuzhiyun 		if (status < 0)
2033*4882a593Smuzhiyun 			return 0;
2034*4882a593Smuzhiyun 
2035*4882a593Smuzhiyun 		if (dirent.direntlen == 0) {
2036*4882a593Smuzhiyun 			printf("Failed to iterate over directory %s\n", name);
2037*4882a593Smuzhiyun 			return 0;
2038*4882a593Smuzhiyun 		}
2039*4882a593Smuzhiyun 
2040*4882a593Smuzhiyun 		if (dirent.namelen != 0) {
2041*4882a593Smuzhiyun 			char filename[dirent.namelen + 1];
2042*4882a593Smuzhiyun 			struct ext2fs_node *fdiro;
2043*4882a593Smuzhiyun 			int type = FILETYPE_UNKNOWN;
2044*4882a593Smuzhiyun 
2045*4882a593Smuzhiyun 			status = ext4fs_read_file(diro,
2046*4882a593Smuzhiyun 						  fpos +
2047*4882a593Smuzhiyun 						  sizeof(struct ext2_dirent),
2048*4882a593Smuzhiyun 						  dirent.namelen, filename,
2049*4882a593Smuzhiyun 						  &actread);
2050*4882a593Smuzhiyun 			if (status < 0)
2051*4882a593Smuzhiyun 				return 0;
2052*4882a593Smuzhiyun 
2053*4882a593Smuzhiyun 			fdiro = zalloc(sizeof(struct ext2fs_node));
2054*4882a593Smuzhiyun 			if (!fdiro)
2055*4882a593Smuzhiyun 				return 0;
2056*4882a593Smuzhiyun 
2057*4882a593Smuzhiyun 			fdiro->data = diro->data;
2058*4882a593Smuzhiyun 			fdiro->ino = le32_to_cpu(dirent.inode);
2059*4882a593Smuzhiyun 
2060*4882a593Smuzhiyun 			filename[dirent.namelen] = '\0';
2061*4882a593Smuzhiyun 
2062*4882a593Smuzhiyun 			if (dirent.filetype != FILETYPE_UNKNOWN) {
2063*4882a593Smuzhiyun 				fdiro->inode_read = 0;
2064*4882a593Smuzhiyun 
2065*4882a593Smuzhiyun 				if (dirent.filetype == FILETYPE_DIRECTORY)
2066*4882a593Smuzhiyun 					type = FILETYPE_DIRECTORY;
2067*4882a593Smuzhiyun 				else if (dirent.filetype == FILETYPE_SYMLINK)
2068*4882a593Smuzhiyun 					type = FILETYPE_SYMLINK;
2069*4882a593Smuzhiyun 				else if (dirent.filetype == FILETYPE_REG)
2070*4882a593Smuzhiyun 					type = FILETYPE_REG;
2071*4882a593Smuzhiyun 			} else {
2072*4882a593Smuzhiyun 				status = ext4fs_read_inode(diro->data,
2073*4882a593Smuzhiyun 							   le32_to_cpu
2074*4882a593Smuzhiyun 							   (dirent.inode),
2075*4882a593Smuzhiyun 							   &fdiro->inode);
2076*4882a593Smuzhiyun 				if (status == 0) {
2077*4882a593Smuzhiyun 					free(fdiro);
2078*4882a593Smuzhiyun 					return 0;
2079*4882a593Smuzhiyun 				}
2080*4882a593Smuzhiyun 				fdiro->inode_read = 1;
2081*4882a593Smuzhiyun 
2082*4882a593Smuzhiyun 				if ((le16_to_cpu(fdiro->inode.mode) &
2083*4882a593Smuzhiyun 				     FILETYPE_INO_MASK) ==
2084*4882a593Smuzhiyun 				    FILETYPE_INO_DIRECTORY) {
2085*4882a593Smuzhiyun 					type = FILETYPE_DIRECTORY;
2086*4882a593Smuzhiyun 				} else if ((le16_to_cpu(fdiro->inode.mode)
2087*4882a593Smuzhiyun 					    & FILETYPE_INO_MASK) ==
2088*4882a593Smuzhiyun 					   FILETYPE_INO_SYMLINK) {
2089*4882a593Smuzhiyun 					type = FILETYPE_SYMLINK;
2090*4882a593Smuzhiyun 				} else if ((le16_to_cpu(fdiro->inode.mode)
2091*4882a593Smuzhiyun 					    & FILETYPE_INO_MASK) ==
2092*4882a593Smuzhiyun 					   FILETYPE_INO_REG) {
2093*4882a593Smuzhiyun 					type = FILETYPE_REG;
2094*4882a593Smuzhiyun 				}
2095*4882a593Smuzhiyun 			}
2096*4882a593Smuzhiyun #ifdef DEBUG
2097*4882a593Smuzhiyun 			printf("iterate >%s<\n", filename);
2098*4882a593Smuzhiyun #endif /* of DEBUG */
2099*4882a593Smuzhiyun 			if ((name != NULL) && (fnode != NULL)
2100*4882a593Smuzhiyun 			    && (ftype != NULL)) {
2101*4882a593Smuzhiyun 				if (strcmp(filename, name) == 0) {
2102*4882a593Smuzhiyun 					*ftype = type;
2103*4882a593Smuzhiyun 					*fnode = fdiro;
2104*4882a593Smuzhiyun 					return 1;
2105*4882a593Smuzhiyun 				}
2106*4882a593Smuzhiyun 			} else {
2107*4882a593Smuzhiyun 				if (fdiro->inode_read == 0) {
2108*4882a593Smuzhiyun 					status = ext4fs_read_inode(diro->data,
2109*4882a593Smuzhiyun 								 le32_to_cpu(
2110*4882a593Smuzhiyun 								 dirent.inode),
2111*4882a593Smuzhiyun 								 &fdiro->inode);
2112*4882a593Smuzhiyun 					if (status == 0) {
2113*4882a593Smuzhiyun 						free(fdiro);
2114*4882a593Smuzhiyun 						return 0;
2115*4882a593Smuzhiyun 					}
2116*4882a593Smuzhiyun 					fdiro->inode_read = 1;
2117*4882a593Smuzhiyun 				}
2118*4882a593Smuzhiyun 				switch (type) {
2119*4882a593Smuzhiyun 				case FILETYPE_DIRECTORY:
2120*4882a593Smuzhiyun 					printf("<DIR> ");
2121*4882a593Smuzhiyun 					break;
2122*4882a593Smuzhiyun 				case FILETYPE_SYMLINK:
2123*4882a593Smuzhiyun 					printf("<SYM> ");
2124*4882a593Smuzhiyun 					break;
2125*4882a593Smuzhiyun 				case FILETYPE_REG:
2126*4882a593Smuzhiyun 					printf("      ");
2127*4882a593Smuzhiyun 					break;
2128*4882a593Smuzhiyun 				default:
2129*4882a593Smuzhiyun 					printf("< ? > ");
2130*4882a593Smuzhiyun 					break;
2131*4882a593Smuzhiyun 				}
2132*4882a593Smuzhiyun 				printf("%10u %s\n",
2133*4882a593Smuzhiyun 				       le32_to_cpu(fdiro->inode.size),
2134*4882a593Smuzhiyun 					filename);
2135*4882a593Smuzhiyun 			}
2136*4882a593Smuzhiyun 			free(fdiro);
2137*4882a593Smuzhiyun 		}
2138*4882a593Smuzhiyun 		fpos += le16_to_cpu(dirent.direntlen);
2139*4882a593Smuzhiyun 	}
2140*4882a593Smuzhiyun 	return 0;
2141*4882a593Smuzhiyun }
2142*4882a593Smuzhiyun 
ext4fs_read_symlink(struct ext2fs_node * node)2143*4882a593Smuzhiyun static char *ext4fs_read_symlink(struct ext2fs_node *node)
2144*4882a593Smuzhiyun {
2145*4882a593Smuzhiyun 	char *symlink;
2146*4882a593Smuzhiyun 	struct ext2fs_node *diro = node;
2147*4882a593Smuzhiyun 	int status;
2148*4882a593Smuzhiyun 	loff_t actread;
2149*4882a593Smuzhiyun 
2150*4882a593Smuzhiyun 	if (!diro->inode_read) {
2151*4882a593Smuzhiyun 		status = ext4fs_read_inode(diro->data, diro->ino, &diro->inode);
2152*4882a593Smuzhiyun 		if (status == 0)
2153*4882a593Smuzhiyun 			return NULL;
2154*4882a593Smuzhiyun 	}
2155*4882a593Smuzhiyun 	symlink = zalloc(le32_to_cpu(diro->inode.size) + 1);
2156*4882a593Smuzhiyun 	if (!symlink)
2157*4882a593Smuzhiyun 		return NULL;
2158*4882a593Smuzhiyun 
2159*4882a593Smuzhiyun 	if (le32_to_cpu(diro->inode.size) < sizeof(diro->inode.b.symlink)) {
2160*4882a593Smuzhiyun 		strncpy(symlink, diro->inode.b.symlink,
2161*4882a593Smuzhiyun 			 le32_to_cpu(diro->inode.size));
2162*4882a593Smuzhiyun 	} else {
2163*4882a593Smuzhiyun 		status = ext4fs_read_file(diro, 0,
2164*4882a593Smuzhiyun 					   le32_to_cpu(diro->inode.size),
2165*4882a593Smuzhiyun 					   symlink, &actread);
2166*4882a593Smuzhiyun 		if ((status < 0) || (actread == 0)) {
2167*4882a593Smuzhiyun 			free(symlink);
2168*4882a593Smuzhiyun 			return NULL;
2169*4882a593Smuzhiyun 		}
2170*4882a593Smuzhiyun 	}
2171*4882a593Smuzhiyun 	symlink[le32_to_cpu(diro->inode.size)] = '\0';
2172*4882a593Smuzhiyun 	return symlink;
2173*4882a593Smuzhiyun }
2174*4882a593Smuzhiyun 
ext4fs_find_file1(const char * currpath,struct ext2fs_node * currroot,struct ext2fs_node ** currfound,int * foundtype)2175*4882a593Smuzhiyun static int ext4fs_find_file1(const char *currpath,
2176*4882a593Smuzhiyun 			     struct ext2fs_node *currroot,
2177*4882a593Smuzhiyun 			     struct ext2fs_node **currfound, int *foundtype)
2178*4882a593Smuzhiyun {
2179*4882a593Smuzhiyun 	char fpath[strlen(currpath) + 1];
2180*4882a593Smuzhiyun 	char *name = fpath;
2181*4882a593Smuzhiyun 	char *next;
2182*4882a593Smuzhiyun 	int status;
2183*4882a593Smuzhiyun 	int type = FILETYPE_DIRECTORY;
2184*4882a593Smuzhiyun 	struct ext2fs_node *currnode = currroot;
2185*4882a593Smuzhiyun 	struct ext2fs_node *oldnode = currroot;
2186*4882a593Smuzhiyun 
2187*4882a593Smuzhiyun 	strncpy(fpath, currpath, strlen(currpath) + 1);
2188*4882a593Smuzhiyun 
2189*4882a593Smuzhiyun 	/* Remove all leading slashes. */
2190*4882a593Smuzhiyun 	while (*name == '/')
2191*4882a593Smuzhiyun 		name++;
2192*4882a593Smuzhiyun 
2193*4882a593Smuzhiyun 	if (!*name) {
2194*4882a593Smuzhiyun 		*currfound = currnode;
2195*4882a593Smuzhiyun 		return 1;
2196*4882a593Smuzhiyun 	}
2197*4882a593Smuzhiyun 
2198*4882a593Smuzhiyun 	for (;;) {
2199*4882a593Smuzhiyun 		int found;
2200*4882a593Smuzhiyun 
2201*4882a593Smuzhiyun 		/* Extract the actual part from the pathname. */
2202*4882a593Smuzhiyun 		next = strchr(name, '/');
2203*4882a593Smuzhiyun 		if (next) {
2204*4882a593Smuzhiyun 			/* Remove all leading slashes. */
2205*4882a593Smuzhiyun 			while (*next == '/')
2206*4882a593Smuzhiyun 				*(next++) = '\0';
2207*4882a593Smuzhiyun 		}
2208*4882a593Smuzhiyun 
2209*4882a593Smuzhiyun 		if (type != FILETYPE_DIRECTORY) {
2210*4882a593Smuzhiyun 			ext4fs_free_node(currnode, currroot);
2211*4882a593Smuzhiyun 			return 0;
2212*4882a593Smuzhiyun 		}
2213*4882a593Smuzhiyun 
2214*4882a593Smuzhiyun 		oldnode = currnode;
2215*4882a593Smuzhiyun 
2216*4882a593Smuzhiyun 		/* Iterate over the directory. */
2217*4882a593Smuzhiyun 		found = ext4fs_iterate_dir(currnode, name, &currnode, &type);
2218*4882a593Smuzhiyun 		if (found == 0)
2219*4882a593Smuzhiyun 			return 0;
2220*4882a593Smuzhiyun 
2221*4882a593Smuzhiyun 		if (found == -1)
2222*4882a593Smuzhiyun 			break;
2223*4882a593Smuzhiyun 
2224*4882a593Smuzhiyun 		/* Read in the symlink and follow it. */
2225*4882a593Smuzhiyun 		if (type == FILETYPE_SYMLINK) {
2226*4882a593Smuzhiyun 			char *symlink;
2227*4882a593Smuzhiyun 
2228*4882a593Smuzhiyun 			/* Test if the symlink does not loop. */
2229*4882a593Smuzhiyun 			if (++symlinknest == 8) {
2230*4882a593Smuzhiyun 				ext4fs_free_node(currnode, currroot);
2231*4882a593Smuzhiyun 				ext4fs_free_node(oldnode, currroot);
2232*4882a593Smuzhiyun 				return 0;
2233*4882a593Smuzhiyun 			}
2234*4882a593Smuzhiyun 
2235*4882a593Smuzhiyun 			symlink = ext4fs_read_symlink(currnode);
2236*4882a593Smuzhiyun 			ext4fs_free_node(currnode, currroot);
2237*4882a593Smuzhiyun 
2238*4882a593Smuzhiyun 			if (!symlink) {
2239*4882a593Smuzhiyun 				ext4fs_free_node(oldnode, currroot);
2240*4882a593Smuzhiyun 				return 0;
2241*4882a593Smuzhiyun 			}
2242*4882a593Smuzhiyun 
2243*4882a593Smuzhiyun 			debug("Got symlink >%s<\n", symlink);
2244*4882a593Smuzhiyun 
2245*4882a593Smuzhiyun 			if (symlink[0] == '/') {
2246*4882a593Smuzhiyun 				ext4fs_free_node(oldnode, currroot);
2247*4882a593Smuzhiyun 				oldnode = &ext4fs_root->diropen;
2248*4882a593Smuzhiyun 			}
2249*4882a593Smuzhiyun 
2250*4882a593Smuzhiyun 			/* Lookup the node the symlink points to. */
2251*4882a593Smuzhiyun 			status = ext4fs_find_file1(symlink, oldnode,
2252*4882a593Smuzhiyun 						    &currnode, &type);
2253*4882a593Smuzhiyun 
2254*4882a593Smuzhiyun 			free(symlink);
2255*4882a593Smuzhiyun 
2256*4882a593Smuzhiyun 			if (status == 0) {
2257*4882a593Smuzhiyun 				ext4fs_free_node(oldnode, currroot);
2258*4882a593Smuzhiyun 				return 0;
2259*4882a593Smuzhiyun 			}
2260*4882a593Smuzhiyun 		}
2261*4882a593Smuzhiyun 
2262*4882a593Smuzhiyun 		ext4fs_free_node(oldnode, currroot);
2263*4882a593Smuzhiyun 
2264*4882a593Smuzhiyun 		/* Found the node! */
2265*4882a593Smuzhiyun 		if (!next || *next == '\0') {
2266*4882a593Smuzhiyun 			*currfound = currnode;
2267*4882a593Smuzhiyun 			*foundtype = type;
2268*4882a593Smuzhiyun 			return 1;
2269*4882a593Smuzhiyun 		}
2270*4882a593Smuzhiyun 		name = next;
2271*4882a593Smuzhiyun 	}
2272*4882a593Smuzhiyun 	return -1;
2273*4882a593Smuzhiyun }
2274*4882a593Smuzhiyun 
ext4fs_find_file(const char * path,struct ext2fs_node * rootnode,struct ext2fs_node ** foundnode,int expecttype)2275*4882a593Smuzhiyun int ext4fs_find_file(const char *path, struct ext2fs_node *rootnode,
2276*4882a593Smuzhiyun 	struct ext2fs_node **foundnode, int expecttype)
2277*4882a593Smuzhiyun {
2278*4882a593Smuzhiyun 	int status;
2279*4882a593Smuzhiyun 	int foundtype = FILETYPE_DIRECTORY;
2280*4882a593Smuzhiyun 
2281*4882a593Smuzhiyun 	symlinknest = 0;
2282*4882a593Smuzhiyun 	if (!path)
2283*4882a593Smuzhiyun 		return 0;
2284*4882a593Smuzhiyun 
2285*4882a593Smuzhiyun 	status = ext4fs_find_file1(path, rootnode, foundnode, &foundtype);
2286*4882a593Smuzhiyun 	if (status == 0)
2287*4882a593Smuzhiyun 		return 0;
2288*4882a593Smuzhiyun 
2289*4882a593Smuzhiyun 	/* Check if the node that was found was of the expected type. */
2290*4882a593Smuzhiyun 	if ((expecttype == FILETYPE_REG) && (foundtype != expecttype))
2291*4882a593Smuzhiyun 		return 0;
2292*4882a593Smuzhiyun 	else if ((expecttype == FILETYPE_DIRECTORY)
2293*4882a593Smuzhiyun 		   && (foundtype != expecttype))
2294*4882a593Smuzhiyun 		return 0;
2295*4882a593Smuzhiyun 
2296*4882a593Smuzhiyun 	return 1;
2297*4882a593Smuzhiyun }
2298*4882a593Smuzhiyun 
ext4fs_open(const char * filename,loff_t * len)2299*4882a593Smuzhiyun int ext4fs_open(const char *filename, loff_t *len)
2300*4882a593Smuzhiyun {
2301*4882a593Smuzhiyun 	struct ext2fs_node *fdiro = NULL;
2302*4882a593Smuzhiyun 	int status;
2303*4882a593Smuzhiyun 
2304*4882a593Smuzhiyun 	if (ext4fs_root == NULL)
2305*4882a593Smuzhiyun 		return -1;
2306*4882a593Smuzhiyun 
2307*4882a593Smuzhiyun 	ext4fs_file = NULL;
2308*4882a593Smuzhiyun 	status = ext4fs_find_file(filename, &ext4fs_root->diropen, &fdiro,
2309*4882a593Smuzhiyun 				  FILETYPE_REG);
2310*4882a593Smuzhiyun 	if (status == 0)
2311*4882a593Smuzhiyun 		goto fail;
2312*4882a593Smuzhiyun 
2313*4882a593Smuzhiyun 	if (!fdiro->inode_read) {
2314*4882a593Smuzhiyun 		status = ext4fs_read_inode(fdiro->data, fdiro->ino,
2315*4882a593Smuzhiyun 				&fdiro->inode);
2316*4882a593Smuzhiyun 		if (status == 0)
2317*4882a593Smuzhiyun 			goto fail;
2318*4882a593Smuzhiyun 	}
2319*4882a593Smuzhiyun 	*len = le32_to_cpu(fdiro->inode.size);
2320*4882a593Smuzhiyun 	ext4fs_file = fdiro;
2321*4882a593Smuzhiyun 
2322*4882a593Smuzhiyun 	return 0;
2323*4882a593Smuzhiyun fail:
2324*4882a593Smuzhiyun 	ext4fs_free_node(fdiro, &ext4fs_root->diropen);
2325*4882a593Smuzhiyun 
2326*4882a593Smuzhiyun 	return -1;
2327*4882a593Smuzhiyun }
2328*4882a593Smuzhiyun 
ext4fs_mount(unsigned part_length)2329*4882a593Smuzhiyun int ext4fs_mount(unsigned part_length)
2330*4882a593Smuzhiyun {
2331*4882a593Smuzhiyun 	struct ext2_data *data;
2332*4882a593Smuzhiyun 	int status;
2333*4882a593Smuzhiyun 	struct ext_filesystem *fs = get_fs();
2334*4882a593Smuzhiyun 	data = zalloc(SUPERBLOCK_SIZE);
2335*4882a593Smuzhiyun 	if (!data)
2336*4882a593Smuzhiyun 		return 0;
2337*4882a593Smuzhiyun 
2338*4882a593Smuzhiyun 	/* Read the superblock. */
2339*4882a593Smuzhiyun 	status = ext4_read_superblock((char *)&data->sblock);
2340*4882a593Smuzhiyun 
2341*4882a593Smuzhiyun 	if (status == 0)
2342*4882a593Smuzhiyun 		goto fail;
2343*4882a593Smuzhiyun 
2344*4882a593Smuzhiyun 	/* Make sure this is an ext2 filesystem. */
2345*4882a593Smuzhiyun 	if (le16_to_cpu(data->sblock.magic) != EXT2_MAGIC)
2346*4882a593Smuzhiyun 		goto fail;
2347*4882a593Smuzhiyun 
2348*4882a593Smuzhiyun 
2349*4882a593Smuzhiyun 	if (le32_to_cpu(data->sblock.revision_level) == 0) {
2350*4882a593Smuzhiyun 		fs->inodesz = 128;
2351*4882a593Smuzhiyun 		fs->gdsize = 32;
2352*4882a593Smuzhiyun 	} else {
2353*4882a593Smuzhiyun 		debug("EXT4 features COMPAT: %08x INCOMPAT: %08x RO_COMPAT: %08x\n",
2354*4882a593Smuzhiyun 		      __le32_to_cpu(data->sblock.feature_compatibility),
2355*4882a593Smuzhiyun 		      __le32_to_cpu(data->sblock.feature_incompat),
2356*4882a593Smuzhiyun 		      __le32_to_cpu(data->sblock.feature_ro_compat));
2357*4882a593Smuzhiyun 
2358*4882a593Smuzhiyun 		fs->inodesz = le16_to_cpu(data->sblock.inode_size);
2359*4882a593Smuzhiyun 		fs->gdsize = le32_to_cpu(data->sblock.feature_incompat) &
2360*4882a593Smuzhiyun 			EXT4_FEATURE_INCOMPAT_64BIT ?
2361*4882a593Smuzhiyun 			le16_to_cpu(data->sblock.descriptor_size) : 32;
2362*4882a593Smuzhiyun 	}
2363*4882a593Smuzhiyun 
2364*4882a593Smuzhiyun 	debug("EXT2 rev %d, inode_size %d, descriptor size %d\n",
2365*4882a593Smuzhiyun 	      le32_to_cpu(data->sblock.revision_level),
2366*4882a593Smuzhiyun 	      fs->inodesz, fs->gdsize);
2367*4882a593Smuzhiyun 
2368*4882a593Smuzhiyun 	data->diropen.data = data;
2369*4882a593Smuzhiyun 	data->diropen.ino = 2;
2370*4882a593Smuzhiyun 	data->diropen.inode_read = 1;
2371*4882a593Smuzhiyun 	data->inode = &data->diropen.inode;
2372*4882a593Smuzhiyun 
2373*4882a593Smuzhiyun 	status = ext4fs_read_inode(data, 2, data->inode);
2374*4882a593Smuzhiyun 	if (status == 0)
2375*4882a593Smuzhiyun 		goto fail;
2376*4882a593Smuzhiyun 
2377*4882a593Smuzhiyun 	ext4fs_root = data;
2378*4882a593Smuzhiyun 
2379*4882a593Smuzhiyun 	return 1;
2380*4882a593Smuzhiyun fail:
2381*4882a593Smuzhiyun 	printf("Failed to mount ext2 filesystem...\n");
2382*4882a593Smuzhiyun 	free(data);
2383*4882a593Smuzhiyun 	ext4fs_root = NULL;
2384*4882a593Smuzhiyun 
2385*4882a593Smuzhiyun 	return 0;
2386*4882a593Smuzhiyun }
2387