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