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