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