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