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 * This program is free software; you can redistribute it and/or modify 18 * it under the terms of the GNU General Public License as published by 19 * the Free Software Foundation; either version 2 of the License, or 20 * (at your option) any later version. 21 * 22 * This program is distributed in the hope that it will be useful, 23 * but WITHOUT ANY WARRANTY; without even the implied warranty of 24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25 * GNU General Public License for more details. 26 * 27 * You should have received a copy of the GNU General Public License 28 * along with this program; if not, write to the Free Software 29 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 30 */ 31 32 #include <common.h> 33 #include <ext_common.h> 34 #include <ext4fs.h> 35 #include <malloc.h> 36 #include <stddef.h> 37 #include <linux/stat.h> 38 #include <linux/time.h> 39 #include <asm/byteorder.h> 40 #include "ext4_common.h" 41 42 struct ext2_data *ext4fs_root; 43 struct ext2fs_node *ext4fs_file; 44 uint32_t *ext4fs_indir1_block; 45 int ext4fs_indir1_size; 46 int ext4fs_indir1_blkno = -1; 47 uint32_t *ext4fs_indir2_block; 48 int ext4fs_indir2_size; 49 int ext4fs_indir2_blkno = -1; 50 51 uint32_t *ext4fs_indir3_block; 52 int ext4fs_indir3_size; 53 int ext4fs_indir3_blkno = -1; 54 struct ext2_inode *g_parent_inode; 55 static int symlinknest; 56 57 static struct ext4_extent_header *ext4fs_get_extent_block 58 (struct ext2_data *data, char *buf, 59 struct ext4_extent_header *ext_block, 60 uint32_t fileblock, int log2_blksz) 61 { 62 struct ext4_extent_idx *index; 63 unsigned long long block; 64 struct ext_filesystem *fs = get_fs(); 65 int i; 66 67 while (1) { 68 index = (struct ext4_extent_idx *)(ext_block + 1); 69 70 if (le32_to_cpu(ext_block->eh_magic) != EXT4_EXT_MAGIC) 71 return 0; 72 73 if (ext_block->eh_depth == 0) 74 return ext_block; 75 i = -1; 76 do { 77 i++; 78 if (i >= le32_to_cpu(ext_block->eh_entries)) 79 break; 80 } while (fileblock > le32_to_cpu(index[i].ei_block)); 81 82 if (--i < 0) 83 return 0; 84 85 block = le32_to_cpu(index[i].ei_leaf_hi); 86 block = (block << 32) + le32_to_cpu(index[i].ei_leaf_lo); 87 88 if (ext4fs_devread(block << log2_blksz, 0, fs->blksz, buf)) 89 ext_block = (struct ext4_extent_header *)buf; 90 else 91 return 0; 92 } 93 } 94 95 static int ext4fs_blockgroup 96 (struct ext2_data *data, int group, struct ext2_block_group *blkgrp) 97 { 98 long int blkno; 99 unsigned int blkoff, desc_per_blk; 100 101 desc_per_blk = EXT2_BLOCK_SIZE(data) / sizeof(struct ext2_block_group); 102 103 blkno = __le32_to_cpu(data->sblock.first_data_block) + 1 + 104 group / desc_per_blk; 105 blkoff = (group % desc_per_blk) * sizeof(struct ext2_block_group); 106 107 debug("ext4fs read %d group descriptor (blkno %ld blkoff %u)\n", 108 group, blkno, blkoff); 109 110 return ext4fs_devread(blkno << LOG2_EXT2_BLOCK_SIZE(data), 111 blkoff, sizeof(struct ext2_block_group), 112 (char *)blkgrp); 113 } 114 115 int ext4fs_read_inode(struct ext2_data *data, int ino, struct ext2_inode *inode) 116 { 117 struct ext2_block_group blkgrp; 118 struct ext2_sblock *sblock = &data->sblock; 119 struct ext_filesystem *fs = get_fs(); 120 int inodes_per_block, status; 121 long int blkno; 122 unsigned int blkoff; 123 124 /* It is easier to calculate if the first inode is 0. */ 125 ino--; 126 status = ext4fs_blockgroup(data, ino / __le32_to_cpu 127 (sblock->inodes_per_group), &blkgrp); 128 if (status == 0) 129 return 0; 130 131 inodes_per_block = EXT2_BLOCK_SIZE(data) / fs->inodesz; 132 blkno = __le32_to_cpu(blkgrp.inode_table_id) + 133 (ino % __le32_to_cpu(sblock->inodes_per_group)) / inodes_per_block; 134 blkoff = (ino % inodes_per_block) * fs->inodesz; 135 /* Read the inode. */ 136 status = ext4fs_devread(blkno << LOG2_EXT2_BLOCK_SIZE(data), blkoff, 137 sizeof(struct ext2_inode), (char *)inode); 138 if (status == 0) 139 return 0; 140 141 return 1; 142 } 143 144 long int read_allocated_block(struct ext2_inode *inode, int fileblock) 145 { 146 long int blknr; 147 int blksz; 148 int log2_blksz; 149 int status; 150 long int rblock; 151 long int perblock_parent; 152 long int perblock_child; 153 unsigned long long start; 154 /* get the blocksize of the filesystem */ 155 blksz = EXT2_BLOCK_SIZE(ext4fs_root); 156 log2_blksz = LOG2_EXT2_BLOCK_SIZE(ext4fs_root); 157 if (le32_to_cpu(inode->flags) & EXT4_EXTENTS_FL) { 158 char *buf = zalloc(blksz); 159 if (!buf) 160 return -ENOMEM; 161 struct ext4_extent_header *ext_block; 162 struct ext4_extent *extent; 163 int i = -1; 164 ext_block = ext4fs_get_extent_block(ext4fs_root, buf, 165 (struct ext4_extent_header 166 *)inode->b. 167 blocks.dir_blocks, 168 fileblock, log2_blksz); 169 if (!ext_block) { 170 printf("invalid extent block\n"); 171 free(buf); 172 return -EINVAL; 173 } 174 175 extent = (struct ext4_extent *)(ext_block + 1); 176 177 do { 178 i++; 179 if (i >= le32_to_cpu(ext_block->eh_entries)) 180 break; 181 } while (fileblock >= le32_to_cpu(extent[i].ee_block)); 182 if (--i >= 0) { 183 fileblock -= le32_to_cpu(extent[i].ee_block); 184 if (fileblock >= le32_to_cpu(extent[i].ee_len)) { 185 free(buf); 186 return 0; 187 } 188 189 start = le32_to_cpu(extent[i].ee_start_hi); 190 start = (start << 32) + 191 le32_to_cpu(extent[i].ee_start_lo); 192 free(buf); 193 return fileblock + start; 194 } 195 196 printf("Extent Error\n"); 197 free(buf); 198 return -1; 199 } 200 201 /* Direct blocks. */ 202 if (fileblock < INDIRECT_BLOCKS) 203 blknr = __le32_to_cpu(inode->b.blocks.dir_blocks[fileblock]); 204 205 /* Indirect. */ 206 else if (fileblock < (INDIRECT_BLOCKS + (blksz / 4))) { 207 if (ext4fs_indir1_block == NULL) { 208 ext4fs_indir1_block = zalloc(blksz); 209 if (ext4fs_indir1_block == NULL) { 210 printf("** SI ext2fs read block (indir 1)" 211 "malloc failed. **\n"); 212 return -1; 213 } 214 ext4fs_indir1_size = blksz; 215 ext4fs_indir1_blkno = -1; 216 } 217 if (blksz != ext4fs_indir1_size) { 218 free(ext4fs_indir1_block); 219 ext4fs_indir1_block = NULL; 220 ext4fs_indir1_size = 0; 221 ext4fs_indir1_blkno = -1; 222 ext4fs_indir1_block = zalloc(blksz); 223 if (ext4fs_indir1_block == NULL) { 224 printf("** SI ext2fs read block (indir 1):" 225 "malloc failed. **\n"); 226 return -1; 227 } 228 ext4fs_indir1_size = blksz; 229 } 230 if ((__le32_to_cpu(inode->b.blocks.indir_block) << 231 log2_blksz) != ext4fs_indir1_blkno) { 232 status = 233 ext4fs_devread(__le32_to_cpu 234 (inode->b.blocks. 235 indir_block) << log2_blksz, 0, 236 blksz, (char *)ext4fs_indir1_block); 237 if (status == 0) { 238 printf("** SI ext2fs read block (indir 1)" 239 "failed. **\n"); 240 return 0; 241 } 242 ext4fs_indir1_blkno = 243 __le32_to_cpu(inode->b.blocks. 244 indir_block) << log2_blksz; 245 } 246 blknr = __le32_to_cpu(ext4fs_indir1_block 247 [fileblock - INDIRECT_BLOCKS]); 248 } 249 /* Double indirect. */ 250 else if (fileblock < (INDIRECT_BLOCKS + (blksz / 4 * 251 (blksz / 4 + 1)))) { 252 253 long int perblock = blksz / 4; 254 long int rblock = fileblock - (INDIRECT_BLOCKS + blksz / 4); 255 256 if (ext4fs_indir1_block == NULL) { 257 ext4fs_indir1_block = zalloc(blksz); 258 if (ext4fs_indir1_block == NULL) { 259 printf("** DI ext2fs read block (indir 2 1)" 260 "malloc failed. **\n"); 261 return -1; 262 } 263 ext4fs_indir1_size = blksz; 264 ext4fs_indir1_blkno = -1; 265 } 266 if (blksz != ext4fs_indir1_size) { 267 free(ext4fs_indir1_block); 268 ext4fs_indir1_block = NULL; 269 ext4fs_indir1_size = 0; 270 ext4fs_indir1_blkno = -1; 271 ext4fs_indir1_block = zalloc(blksz); 272 if (ext4fs_indir1_block == NULL) { 273 printf("** DI ext2fs read block (indir 2 1)" 274 "malloc failed. **\n"); 275 return -1; 276 } 277 ext4fs_indir1_size = blksz; 278 } 279 if ((__le32_to_cpu(inode->b.blocks.double_indir_block) << 280 log2_blksz) != ext4fs_indir1_blkno) { 281 status = 282 ext4fs_devread(__le32_to_cpu 283 (inode->b.blocks. 284 double_indir_block) << log2_blksz, 285 0, blksz, 286 (char *)ext4fs_indir1_block); 287 if (status == 0) { 288 printf("** DI ext2fs read block (indir 2 1)" 289 "failed. **\n"); 290 return -1; 291 } 292 ext4fs_indir1_blkno = 293 __le32_to_cpu(inode->b.blocks.double_indir_block) << 294 log2_blksz; 295 } 296 297 if (ext4fs_indir2_block == NULL) { 298 ext4fs_indir2_block = zalloc(blksz); 299 if (ext4fs_indir2_block == NULL) { 300 printf("** DI ext2fs read block (indir 2 2)" 301 "malloc failed. **\n"); 302 return -1; 303 } 304 ext4fs_indir2_size = blksz; 305 ext4fs_indir2_blkno = -1; 306 } 307 if (blksz != ext4fs_indir2_size) { 308 free(ext4fs_indir2_block); 309 ext4fs_indir2_block = NULL; 310 ext4fs_indir2_size = 0; 311 ext4fs_indir2_blkno = -1; 312 ext4fs_indir2_block = zalloc(blksz); 313 if (ext4fs_indir2_block == NULL) { 314 printf("** DI ext2fs read block (indir 2 2)" 315 "malloc failed. **\n"); 316 return -1; 317 } 318 ext4fs_indir2_size = blksz; 319 } 320 if ((__le32_to_cpu(ext4fs_indir1_block[rblock / perblock]) << 321 log2_blksz) != ext4fs_indir2_blkno) { 322 status = ext4fs_devread(__le32_to_cpu 323 (ext4fs_indir1_block 324 [rblock / 325 perblock]) << log2_blksz, 0, 326 blksz, 327 (char *)ext4fs_indir2_block); 328 if (status == 0) { 329 printf("** DI ext2fs read block (indir 2 2)" 330 "failed. **\n"); 331 return -1; 332 } 333 ext4fs_indir2_blkno = 334 __le32_to_cpu(ext4fs_indir1_block[rblock 335 / 336 perblock]) << 337 log2_blksz; 338 } 339 blknr = __le32_to_cpu(ext4fs_indir2_block[rblock % perblock]); 340 } 341 /* Tripple indirect. */ 342 else { 343 rblock = fileblock - (INDIRECT_BLOCKS + blksz / 4 + 344 (blksz / 4 * blksz / 4)); 345 perblock_child = blksz / 4; 346 perblock_parent = ((blksz / 4) * (blksz / 4)); 347 348 if (ext4fs_indir1_block == NULL) { 349 ext4fs_indir1_block = zalloc(blksz); 350 if (ext4fs_indir1_block == NULL) { 351 printf("** TI ext2fs read block (indir 2 1)" 352 "malloc failed. **\n"); 353 return -1; 354 } 355 ext4fs_indir1_size = blksz; 356 ext4fs_indir1_blkno = -1; 357 } 358 if (blksz != ext4fs_indir1_size) { 359 free(ext4fs_indir1_block); 360 ext4fs_indir1_block = NULL; 361 ext4fs_indir1_size = 0; 362 ext4fs_indir1_blkno = -1; 363 ext4fs_indir1_block = zalloc(blksz); 364 if (ext4fs_indir1_block == NULL) { 365 printf("** TI ext2fs read block (indir 2 1)" 366 "malloc failed. **\n"); 367 return -1; 368 } 369 ext4fs_indir1_size = blksz; 370 } 371 if ((__le32_to_cpu(inode->b.blocks.triple_indir_block) << 372 log2_blksz) != ext4fs_indir1_blkno) { 373 status = ext4fs_devread 374 (__le32_to_cpu(inode->b.blocks.triple_indir_block) 375 << log2_blksz, 0, blksz, 376 (char *)ext4fs_indir1_block); 377 if (status == 0) { 378 printf("** TI ext2fs read block (indir 2 1)" 379 "failed. **\n"); 380 return -1; 381 } 382 ext4fs_indir1_blkno = 383 __le32_to_cpu(inode->b.blocks.triple_indir_block) << 384 log2_blksz; 385 } 386 387 if (ext4fs_indir2_block == NULL) { 388 ext4fs_indir2_block = zalloc(blksz); 389 if (ext4fs_indir2_block == NULL) { 390 printf("** TI ext2fs read block (indir 2 2)" 391 "malloc failed. **\n"); 392 return -1; 393 } 394 ext4fs_indir2_size = blksz; 395 ext4fs_indir2_blkno = -1; 396 } 397 if (blksz != ext4fs_indir2_size) { 398 free(ext4fs_indir2_block); 399 ext4fs_indir2_block = NULL; 400 ext4fs_indir2_size = 0; 401 ext4fs_indir2_blkno = -1; 402 ext4fs_indir2_block = zalloc(blksz); 403 if (ext4fs_indir2_block == NULL) { 404 printf("** TI ext2fs read block (indir 2 2)" 405 "malloc failed. **\n"); 406 return -1; 407 } 408 ext4fs_indir2_size = blksz; 409 } 410 if ((__le32_to_cpu(ext4fs_indir1_block[rblock / 411 perblock_parent]) << 412 log2_blksz) 413 != ext4fs_indir2_blkno) { 414 status = ext4fs_devread(__le32_to_cpu 415 (ext4fs_indir1_block 416 [rblock / 417 perblock_parent]) << 418 log2_blksz, 0, blksz, 419 (char *)ext4fs_indir2_block); 420 if (status == 0) { 421 printf("** TI ext2fs read block (indir 2 2)" 422 "failed. **\n"); 423 return -1; 424 } 425 ext4fs_indir2_blkno = 426 __le32_to_cpu(ext4fs_indir1_block[rblock / 427 perblock_parent]) 428 << log2_blksz; 429 } 430 431 if (ext4fs_indir3_block == NULL) { 432 ext4fs_indir3_block = zalloc(blksz); 433 if (ext4fs_indir3_block == NULL) { 434 printf("** TI ext2fs read block (indir 2 2)" 435 "malloc failed. **\n"); 436 return -1; 437 } 438 ext4fs_indir3_size = blksz; 439 ext4fs_indir3_blkno = -1; 440 } 441 if (blksz != ext4fs_indir3_size) { 442 free(ext4fs_indir3_block); 443 ext4fs_indir3_block = NULL; 444 ext4fs_indir3_size = 0; 445 ext4fs_indir3_blkno = -1; 446 ext4fs_indir3_block = zalloc(blksz); 447 if (ext4fs_indir3_block == NULL) { 448 printf("** TI ext2fs read block (indir 2 2)" 449 "malloc failed. **\n"); 450 return -1; 451 } 452 ext4fs_indir3_size = blksz; 453 } 454 if ((__le32_to_cpu(ext4fs_indir2_block[rblock 455 / 456 perblock_child]) << 457 log2_blksz) != ext4fs_indir3_blkno) { 458 status = 459 ext4fs_devread(__le32_to_cpu 460 (ext4fs_indir2_block 461 [(rblock / perblock_child) 462 % (blksz / 4)]) << log2_blksz, 0, 463 blksz, (char *)ext4fs_indir3_block); 464 if (status == 0) { 465 printf("** TI ext2fs read block (indir 2 2)" 466 "failed. **\n"); 467 return -1; 468 } 469 ext4fs_indir3_blkno = 470 __le32_to_cpu(ext4fs_indir2_block[(rblock / 471 perblock_child) % 472 (blksz / 473 4)]) << 474 log2_blksz; 475 } 476 477 blknr = __le32_to_cpu(ext4fs_indir3_block 478 [rblock % perblock_child]); 479 } 480 debug("ext4fs_read_block %ld\n", blknr); 481 482 return blknr; 483 } 484 485 void ext4fs_close(void) 486 { 487 if ((ext4fs_file != NULL) && (ext4fs_root != NULL)) { 488 ext4fs_free_node(ext4fs_file, &ext4fs_root->diropen); 489 ext4fs_file = NULL; 490 } 491 if (ext4fs_root != NULL) { 492 free(ext4fs_root); 493 ext4fs_root = NULL; 494 } 495 if (ext4fs_indir1_block != NULL) { 496 free(ext4fs_indir1_block); 497 ext4fs_indir1_block = NULL; 498 ext4fs_indir1_size = 0; 499 ext4fs_indir1_blkno = -1; 500 } 501 if (ext4fs_indir2_block != NULL) { 502 free(ext4fs_indir2_block); 503 ext4fs_indir2_block = NULL; 504 ext4fs_indir2_size = 0; 505 ext4fs_indir2_blkno = -1; 506 } 507 if (ext4fs_indir3_block != NULL) { 508 free(ext4fs_indir3_block); 509 ext4fs_indir3_block = NULL; 510 ext4fs_indir3_size = 0; 511 ext4fs_indir3_blkno = -1; 512 } 513 } 514 515 int ext4fs_iterate_dir(struct ext2fs_node *dir, char *name, 516 struct ext2fs_node **fnode, int *ftype) 517 { 518 unsigned int fpos = 0; 519 int status; 520 struct ext2fs_node *diro = (struct ext2fs_node *) dir; 521 522 #ifdef DEBUG 523 if (name != NULL) 524 printf("Iterate dir %s\n", name); 525 #endif /* of DEBUG */ 526 if (!diro->inode_read) { 527 status = ext4fs_read_inode(diro->data, diro->ino, &diro->inode); 528 if (status == 0) 529 return 0; 530 } 531 /* Search the file. */ 532 while (fpos < __le32_to_cpu(diro->inode.size)) { 533 struct ext2_dirent dirent; 534 535 status = ext4fs_read_file(diro, fpos, 536 sizeof(struct ext2_dirent), 537 (char *) &dirent); 538 if (status < 1) 539 return 0; 540 541 if (dirent.namelen != 0) { 542 char filename[dirent.namelen + 1]; 543 struct ext2fs_node *fdiro; 544 int type = FILETYPE_UNKNOWN; 545 546 status = ext4fs_read_file(diro, 547 fpos + 548 sizeof(struct ext2_dirent), 549 dirent.namelen, filename); 550 if (status < 1) 551 return 0; 552 553 fdiro = zalloc(sizeof(struct ext2fs_node)); 554 if (!fdiro) 555 return 0; 556 557 fdiro->data = diro->data; 558 fdiro->ino = __le32_to_cpu(dirent.inode); 559 560 filename[dirent.namelen] = '\0'; 561 562 if (dirent.filetype != FILETYPE_UNKNOWN) { 563 fdiro->inode_read = 0; 564 565 if (dirent.filetype == FILETYPE_DIRECTORY) 566 type = FILETYPE_DIRECTORY; 567 else if (dirent.filetype == FILETYPE_SYMLINK) 568 type = FILETYPE_SYMLINK; 569 else if (dirent.filetype == FILETYPE_REG) 570 type = FILETYPE_REG; 571 } else { 572 status = ext4fs_read_inode(diro->data, 573 __le32_to_cpu 574 (dirent.inode), 575 &fdiro->inode); 576 if (status == 0) { 577 free(fdiro); 578 return 0; 579 } 580 fdiro->inode_read = 1; 581 582 if ((__le16_to_cpu(fdiro->inode.mode) & 583 FILETYPE_INO_MASK) == 584 FILETYPE_INO_DIRECTORY) { 585 type = FILETYPE_DIRECTORY; 586 } else if ((__le16_to_cpu(fdiro->inode.mode) 587 & FILETYPE_INO_MASK) == 588 FILETYPE_INO_SYMLINK) { 589 type = FILETYPE_SYMLINK; 590 } else if ((__le16_to_cpu(fdiro->inode.mode) 591 & FILETYPE_INO_MASK) == 592 FILETYPE_INO_REG) { 593 type = FILETYPE_REG; 594 } 595 } 596 #ifdef DEBUG 597 printf("iterate >%s<\n", filename); 598 #endif /* of DEBUG */ 599 if ((name != NULL) && (fnode != NULL) 600 && (ftype != NULL)) { 601 if (strcmp(filename, name) == 0) { 602 *ftype = type; 603 *fnode = fdiro; 604 return 1; 605 } 606 } else { 607 if (fdiro->inode_read == 0) { 608 status = ext4fs_read_inode(diro->data, 609 __le32_to_cpu( 610 dirent.inode), 611 &fdiro->inode); 612 if (status == 0) { 613 free(fdiro); 614 return 0; 615 } 616 fdiro->inode_read = 1; 617 } 618 switch (type) { 619 case FILETYPE_DIRECTORY: 620 printf("<DIR> "); 621 break; 622 case FILETYPE_SYMLINK: 623 printf("<SYM> "); 624 break; 625 case FILETYPE_REG: 626 printf(" "); 627 break; 628 default: 629 printf("< ? > "); 630 break; 631 } 632 printf("%10d %s\n", 633 __le32_to_cpu(fdiro->inode.size), 634 filename); 635 } 636 free(fdiro); 637 } 638 fpos += __le16_to_cpu(dirent.direntlen); 639 } 640 return 0; 641 } 642 643 static char *ext4fs_read_symlink(struct ext2fs_node *node) 644 { 645 char *symlink; 646 struct ext2fs_node *diro = node; 647 int status; 648 649 if (!diro->inode_read) { 650 status = ext4fs_read_inode(diro->data, diro->ino, &diro->inode); 651 if (status == 0) 652 return 0; 653 } 654 symlink = zalloc(__le32_to_cpu(diro->inode.size) + 1); 655 if (!symlink) 656 return 0; 657 658 if (__le32_to_cpu(diro->inode.size) <= 60) { 659 strncpy(symlink, diro->inode.b.symlink, 660 __le32_to_cpu(diro->inode.size)); 661 } else { 662 status = ext4fs_read_file(diro, 0, 663 __le32_to_cpu(diro->inode.size), 664 symlink); 665 if (status == 0) { 666 free(symlink); 667 return 0; 668 } 669 } 670 symlink[__le32_to_cpu(diro->inode.size)] = '\0'; 671 return symlink; 672 } 673 674 static int ext4fs_find_file1(const char *currpath, 675 struct ext2fs_node *currroot, 676 struct ext2fs_node **currfound, int *foundtype) 677 { 678 char fpath[strlen(currpath) + 1]; 679 char *name = fpath; 680 char *next; 681 int status; 682 int type = FILETYPE_DIRECTORY; 683 struct ext2fs_node *currnode = currroot; 684 struct ext2fs_node *oldnode = currroot; 685 686 strncpy(fpath, currpath, strlen(currpath) + 1); 687 688 /* Remove all leading slashes. */ 689 while (*name == '/') 690 name++; 691 692 if (!*name) { 693 *currfound = currnode; 694 return 1; 695 } 696 697 for (;;) { 698 int found; 699 700 /* Extract the actual part from the pathname. */ 701 next = strchr(name, '/'); 702 if (next) { 703 /* Remove all leading slashes. */ 704 while (*next == '/') 705 *(next++) = '\0'; 706 } 707 708 if (type != FILETYPE_DIRECTORY) { 709 ext4fs_free_node(currnode, currroot); 710 return 0; 711 } 712 713 oldnode = currnode; 714 715 /* Iterate over the directory. */ 716 found = ext4fs_iterate_dir(currnode, name, &currnode, &type); 717 if (found == 0) 718 return 0; 719 720 if (found == -1) 721 break; 722 723 /* Read in the symlink and follow it. */ 724 if (type == FILETYPE_SYMLINK) { 725 char *symlink; 726 727 /* Test if the symlink does not loop. */ 728 if (++symlinknest == 8) { 729 ext4fs_free_node(currnode, currroot); 730 ext4fs_free_node(oldnode, currroot); 731 return 0; 732 } 733 734 symlink = ext4fs_read_symlink(currnode); 735 ext4fs_free_node(currnode, currroot); 736 737 if (!symlink) { 738 ext4fs_free_node(oldnode, currroot); 739 return 0; 740 } 741 742 debug("Got symlink >%s<\n", symlink); 743 744 if (symlink[0] == '/') { 745 ext4fs_free_node(oldnode, currroot); 746 oldnode = &ext4fs_root->diropen; 747 } 748 749 /* Lookup the node the symlink points to. */ 750 status = ext4fs_find_file1(symlink, oldnode, 751 &currnode, &type); 752 753 free(symlink); 754 755 if (status == 0) { 756 ext4fs_free_node(oldnode, currroot); 757 return 0; 758 } 759 } 760 761 ext4fs_free_node(oldnode, currroot); 762 763 /* Found the node! */ 764 if (!next || *next == '\0') { 765 *currfound = currnode; 766 *foundtype = type; 767 return 1; 768 } 769 name = next; 770 } 771 return -1; 772 } 773 774 int ext4fs_find_file(const char *path, struct ext2fs_node *rootnode, 775 struct ext2fs_node **foundnode, int expecttype) 776 { 777 int status; 778 int foundtype = FILETYPE_DIRECTORY; 779 780 symlinknest = 0; 781 if (!path) 782 return 0; 783 784 status = ext4fs_find_file1(path, rootnode, foundnode, &foundtype); 785 if (status == 0) 786 return 0; 787 788 /* Check if the node that was found was of the expected type. */ 789 if ((expecttype == FILETYPE_REG) && (foundtype != expecttype)) 790 return 0; 791 else if ((expecttype == FILETYPE_DIRECTORY) 792 && (foundtype != expecttype)) 793 return 0; 794 795 return 1; 796 } 797 798 int ext4fs_open(const char *filename) 799 { 800 struct ext2fs_node *fdiro = NULL; 801 int status; 802 int len; 803 804 if (ext4fs_root == NULL) 805 return -1; 806 807 ext4fs_file = NULL; 808 status = ext4fs_find_file(filename, &ext4fs_root->diropen, &fdiro, 809 FILETYPE_REG); 810 if (status == 0) 811 goto fail; 812 813 if (!fdiro->inode_read) { 814 status = ext4fs_read_inode(fdiro->data, fdiro->ino, 815 &fdiro->inode); 816 if (status == 0) 817 goto fail; 818 } 819 len = __le32_to_cpu(fdiro->inode.size); 820 ext4fs_file = fdiro; 821 822 return len; 823 fail: 824 ext4fs_free_node(fdiro, &ext4fs_root->diropen); 825 826 return -1; 827 } 828 829 int ext4fs_mount(unsigned part_length) 830 { 831 struct ext2_data *data; 832 int status; 833 struct ext_filesystem *fs = get_fs(); 834 data = zalloc(sizeof(struct ext2_data)); 835 if (!data) 836 return 0; 837 838 /* Read the superblock. */ 839 status = ext4fs_devread(1 * 2, 0, sizeof(struct ext2_sblock), 840 (char *)&data->sblock); 841 842 if (status == 0) 843 goto fail; 844 845 /* Make sure this is an ext2 filesystem. */ 846 if (__le16_to_cpu(data->sblock.magic) != EXT2_MAGIC) 847 goto fail; 848 849 if (__le32_to_cpu(data->sblock.revision_level == 0)) 850 fs->inodesz = 128; 851 else 852 fs->inodesz = __le16_to_cpu(data->sblock.inode_size); 853 854 debug("EXT2 rev %d, inode_size %d\n", 855 __le32_to_cpu(data->sblock.revision_level), fs->inodesz); 856 857 data->diropen.data = data; 858 data->diropen.ino = 2; 859 data->diropen.inode_read = 1; 860 data->inode = &data->diropen.inode; 861 862 status = ext4fs_read_inode(data, 2, data->inode); 863 if (status == 0) 864 goto fail; 865 866 ext4fs_root = data; 867 868 return 1; 869 fail: 870 printf("Failed to mount ext2 filesystem...\n"); 871 free(data); 872 ext4fs_root = NULL; 873 874 return 0; 875 } 876