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