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