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