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