1 /* 2 * PROJECT: Mke2fs 3 * FILE: Inode.c 4 * PROGRAMMER: Matt Wu <mattwu@163.com> 5 * HOMEPAGE: http://ext2.yeah.net 6 */ 7 8 /* INCLUDES **************************************************************/ 9 10 #include "Mke2fs.h" 11 #include <debug.h> 12 13 /* DEFINITIONS ***********************************************************/ 14 15 extern char *device_name; 16 17 /* FUNCTIONS *************************************************************/ 18 19 20 bool ext2_get_inode_lba(PEXT2_FILESYS Ext2Sys, ULONG no, LONGLONG *offset) 21 { 22 LONGLONG loc = 0; 23 PEXT2_SUPER_BLOCK pExt2Sb = Ext2Sys->ext2_sb; 24 25 if (no < 1 || no > pExt2Sb->s_inodes_count) 26 { 27 DPRINT1("Mke2fs: Inode value %lu was out of range in load_inode.(1-%ld)\n", 28 no, pExt2Sb->s_inodes_count); 29 *offset = 0; 30 return false; 31 } 32 33 loc = (LONGLONG)(Ext2Sys->blocksize) * Ext2Sys->group_desc[(no - 1) / pExt2Sb->s_inodes_per_group].bg_inode_table + 34 ((no - 1) % pExt2Sb->s_inodes_per_group) * sizeof(EXT2_INODE); 35 36 *offset = loc; 37 38 return true; 39 } 40 41 bool ext2_load_inode(PEXT2_FILESYS Ext2Sys, ULONG no, PEXT2_INODE pInode) 42 { 43 LONGLONG Offset; 44 bool bRet = false; 45 46 if (ext2_get_inode_lba(Ext2Sys, no, &Offset)) 47 { 48 bRet = NT_SUCCESS(Ext2ReadDisk( 49 Ext2Sys, 50 Offset, 51 sizeof(EXT2_INODE), 52 (unsigned char *)pInode)); 53 } 54 55 return bRet; 56 } 57 58 59 bool ext2_save_inode(PEXT2_FILESYS Ext2Sys, ULONG no, PEXT2_INODE pInode) 60 { 61 LONGLONG offset; 62 bool bRet = false; 63 64 if (ext2_get_inode_lba(Ext2Sys, no, &offset)) 65 { 66 bRet = NT_SUCCESS(Ext2WriteDisk( 67 Ext2Sys, 68 offset, 69 sizeof(EXT2_INODE), 70 (unsigned char *)pInode)); 71 } 72 73 return bRet; 74 } 75 76 77 /* 78 * Right now, just search forward from the parent directory's block 79 * group to find the next free inode. 80 * 81 * Should have a special policy for directories. 82 */ 83 84 bool ext2_new_inode(PEXT2_FILESYS fs, ULONG dir, int mode, 85 PEXT2_INODE_BITMAP map, ULONG *ret) 86 { 87 ULONG dir_group = 0; 88 ULONG i; 89 ULONG start_inode; 90 91 if (!map) 92 map = fs->inode_map; 93 94 if (!map) 95 return false; 96 97 if (dir > 0) 98 dir_group = (dir - 1) / EXT2_INODES_PER_GROUP(fs->ext2_sb); 99 100 start_inode = (dir_group * EXT2_INODES_PER_GROUP(fs->ext2_sb)) + 1; 101 102 if (start_inode < EXT2_FIRST_INODE(fs->ext2_sb)) 103 start_inode = EXT2_FIRST_INODE(fs->ext2_sb); 104 105 i = start_inode; 106 107 do 108 { 109 if (!ext2_test_inode_bitmap(map, i)) 110 break; 111 112 i++; 113 114 if (i > fs->ext2_sb->s_inodes_count) 115 i = EXT2_FIRST_INODE(fs->ext2_sb); 116 117 } while (i != start_inode); 118 119 if (ext2_test_inode_bitmap(map, i)) 120 return false; 121 122 *ret = i; 123 124 return true; 125 } 126 127 128 bool ext2_expand_block( PEXT2_FILESYS Ext2Sys, PEXT2_INODE Inode, 129 ULONG dwContent, ULONG Index, int layer, 130 ULONG newBlk, ULONG *dwRet, ULONG *off ) 131 { 132 ULONG *pData = NULL; 133 ULONG i = 0, j = 0, temp = 1; 134 ULONG dwBlk; 135 ULONG dwNewBlk = newBlk; 136 bool bDirty = false; 137 bool bRet = true; 138 ULONG Offset = 0; 139 140 PEXT2_SUPER_BLOCK pExt2Sb = Ext2Sys->ext2_sb; 141 142 pData = (ULONG *)RtlAllocateHeap(RtlGetProcessHeap(), 0, Ext2Sys->blocksize); 143 144 if (!pData) 145 { 146 bRet = false; 147 goto errorout; 148 } 149 150 if (!ext2_read_block(Ext2Sys, dwContent, (void *)pData)) 151 { 152 bRet = false; 153 goto errorout; 154 } 155 156 if (layer == 1) 157 { 158 *dwRet = dwContent; 159 *off = Index; 160 pData[Index] = newBlk; 161 162 bDirty = TRUE; 163 } 164 else if (layer <= 3) 165 { 166 temp = 1 << ((10 + pExt2Sb->s_log_block_size - 2) * (layer - 1)); 167 168 i = Index / temp; 169 j = Index % temp; 170 171 dwBlk = pData[i]; 172 173 if (dwBlk == 0) 174 { 175 if (ext2_alloc_block(Ext2Sys, 0, &dwBlk) ) 176 { 177 pData[i] = dwBlk; 178 bDirty = true; 179 180 Inode->i_blocks += (Ext2Sys->blocksize / SECTOR_SIZE); 181 } 182 183 if (!bDirty) 184 goto errorout; 185 } 186 187 if (!ext2_expand_block(Ext2Sys, Inode, dwBlk, j, layer - 1, bDirty, &dwNewBlk, &Offset)) 188 { 189 bRet = false; 190 DPRINT1("Mke2fs: ext2_expand_block: ... error recuise...\n"); 191 goto errorout; 192 } 193 } 194 195 if (bDirty) 196 { 197 bRet = ext2_write_block(Ext2Sys, dwContent, (void *)pData); 198 } 199 200 201 errorout: 202 203 if (pData) 204 RtlFreeHeap(RtlGetProcessHeap(), 0, pData); 205 206 if (bRet && dwRet) 207 *dwRet = dwNewBlk; 208 209 return bRet; 210 } 211 212 bool ext2_expand_inode( PEXT2_FILESYS Ext2Sys, 213 PEXT2_INODE Inode, 214 ULONG newBlk ) 215 { 216 ULONG dwSizes[4] = {12, 1, 1, 1}; 217 ULONG Index = 0; 218 ULONG dwTotal = 0; 219 ULONG dwBlk = 0, dwNewBlk = 0, Offset = 0; 220 PEXT2_SUPER_BLOCK pExt2Sb = Ext2Sys->ext2_sb; 221 int i = 0; 222 bool bRet = true; 223 ULONG TotalBlocks; 224 225 TotalBlocks = Inode->i_blocks / (Ext2Sys->blocksize / SECTOR_SIZE); 226 Index = Ext2DataBlocks(Ext2Sys, TotalBlocks); 227 228 for (i = 0; i < 4; i++) 229 { 230 dwSizes[i] = dwSizes[i] << ((10 + pExt2Sb->s_log_block_size - 2) * i); 231 dwTotal += dwSizes[i]; 232 } 233 234 if (Index >= dwTotal) 235 { 236 DPRINT1("Mke2fs: ext2_expand_inode: beyond the maxinum size of an inode.\n"); 237 return false; 238 } 239 240 for (i = 0; i < 4; i++) 241 { 242 if (Index < dwSizes[i]) 243 { 244 if (i == 0) 245 { 246 Inode->i_block[Index] = newBlk; 247 } 248 else 249 { 250 dwBlk = Inode->i_block[(i + 12 - 1)]; 251 252 if (dwBlk == 0) 253 { 254 if (ext2_alloc_block(Ext2Sys, 0, &dwBlk)) 255 { 256 Inode->i_block[(i + 12 - 1)] = dwBlk; 257 258 Inode->i_blocks += (Ext2Sys->blocksize / SECTOR_SIZE); 259 } 260 else 261 { 262 break; 263 } 264 } 265 266 dwNewBlk = 0; 267 bRet = ext2_expand_block( 268 Ext2Sys, 269 Inode, 270 dwBlk, 271 Index, 272 i, 273 newBlk, 274 &dwNewBlk, 275 &Offset ); 276 } 277 278 break; 279 } 280 281 Index -= dwSizes[i]; 282 } 283 284 return bRet; 285 } 286 287 288 bool ext2_get_block(PEXT2_FILESYS Ext2Sys, ULONG dwContent, ULONG Index, int layer, ULONG *dwRet) 289 { 290 ULONG *pData = NULL; 291 LONGLONG Offset = 0; 292 ULONG i = 0, j = 0, temp = 1; 293 ULONG dwBlk = 0; 294 bool bRet = true; 295 296 PEXT2_SUPER_BLOCK pExt2Sb = Ext2Sys->ext2_sb; 297 298 Offset = (LONGLONG) dwContent; 299 Offset = Offset * Ext2Sys->blocksize; 300 301 pData = (ULONG *)RtlAllocateHeap(RtlGetProcessHeap(), 0, Ext2Sys->blocksize); 302 303 if (!pData) 304 { 305 return false; 306 } 307 memset(pData, 0, Ext2Sys->blocksize); 308 309 if (layer == 0) 310 { 311 dwBlk = dwContent; 312 } 313 else if (layer <= 3) 314 { 315 316 if (!ext2_read_block(Ext2Sys, dwContent, (void *)pData)) 317 { 318 bRet = false; 319 goto errorout; 320 } 321 322 temp = 1 << ((10 + pExt2Sb->s_log_block_size - 2) * (layer - 1)); 323 324 i = Index / temp; 325 j = Index % temp; 326 327 if (!ext2_get_block(Ext2Sys, pData[i], j, layer - 1, &dwBlk)) 328 { 329 bRet = false; 330 DPRINT1("Mke2fs: ext2_get_block: ... error recuise...\n"); 331 goto errorout; 332 } 333 } 334 335 errorout: 336 337 if (pData) 338 RtlFreeHeap(RtlGetProcessHeap(), 0, pData); 339 340 if (bRet && dwRet) 341 *dwRet = dwBlk; 342 343 return bRet; 344 } 345 346 bool ext2_block_map(PEXT2_FILESYS Ext2Sys, PEXT2_INODE inode, ULONG block, ULONG *dwRet) 347 { 348 ULONG dwSizes[4] = { 12, 1, 1, 1 }; 349 ULONG Index = 0; 350 ULONG dwBlk = 0; 351 PEXT2_SUPER_BLOCK pExt2Sb = Ext2Sys->ext2_sb; 352 UINT i; 353 bool bRet = false; 354 355 Index = block; 356 357 for (i = 0; i < 4; i++) 358 { 359 dwSizes[i] = dwSizes[i] << ((10 + pExt2Sb->s_log_block_size - 2) * i); 360 } 361 362 if (Index >= inode->i_blocks / (Ext2Sys->blocksize / SECTOR_SIZE)) 363 { 364 DPRINT1("Mke2fs: ext2_block_map: beyond the size of the inode.\n"); 365 return false; 366 } 367 368 for (i = 0; i < 4; i++) 369 { 370 if (Index < dwSizes[i]) 371 { 372 dwBlk = inode->i_block[i==0 ? (Index):(i + 12 - 1)]; 373 374 bRet = ext2_get_block(Ext2Sys, dwBlk, Index , i, &dwBlk); 375 376 break; 377 } 378 Index -= dwSizes[i]; 379 } 380 381 if (bRet && dwBlk) 382 { 383 if (dwRet) 384 *dwRet = dwBlk; 385 386 return true; 387 } 388 else 389 return false; 390 } 391 392 ULONG ext2_build_bdl(PEXT2_FILESYS Ext2Sys, 393 PEXT2_INODE ext2_inode, 394 IN ULONG offset, 395 IN ULONG size, 396 OUT PEXT2_BDL *ext2_bdl ) 397 { 398 ULONG nBeg, nEnd, nBlocks; 399 ULONG dwBlk; 400 ULONG i; 401 ULONG dwBytes = 0; 402 LONGLONG lba; 403 404 PEXT2_BDL ext2bdl = NULL; 405 406 *ext2_bdl = NULL; 407 408 if (offset >= ext2_inode->i_size) 409 { 410 DPRINT1("Mke2fs: ext2_build_bdl: beyond the file range.\n"); 411 return 0; 412 } 413 414 /* 415 if (offset + size > ext2_inode->i_size) 416 { 417 size = ext2_inode->i_size - offset; 418 } 419 */ 420 421 nBeg = offset / Ext2Sys->blocksize; 422 nEnd = (size + offset + Ext2Sys->blocksize - 1) / Ext2Sys->blocksize; 423 424 nBlocks = nEnd - nBeg; 425 426 if (nBlocks > 0) 427 { 428 ext2bdl = (PEXT2_BDL) 429 RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(EXT2_BDL) * nBlocks); 430 431 if (ext2bdl) 432 { 433 434 memset(ext2bdl, 0, sizeof(EXT2_BDL) * nBlocks); 435 436 for (i = nBeg; i < nEnd; i++) 437 { 438 if (!ext2_block_map(Ext2Sys, ext2_inode, i, &dwBlk)) 439 { 440 goto fail; 441 } 442 443 lba = (LONGLONG) dwBlk; 444 lba = lba * Ext2Sys->blocksize; 445 446 if (nBlocks == 1) // ie. (nBeg == nEnd - 1) 447 { 448 dwBytes = size; 449 ext2bdl[i - nBeg].Lba = lba + (LONGLONG)(offset % (Ext2Sys->blocksize)); 450 ext2bdl[i - nBeg].Length = dwBytes; 451 ext2bdl[i - nBeg].Offset = 0; 452 } 453 else 454 { 455 if (i == nBeg) 456 { 457 dwBytes = Ext2Sys->blocksize - (offset % (Ext2Sys->blocksize)); 458 ext2bdl[i - nBeg].Lba = lba + (LONGLONG)(offset % (Ext2Sys->blocksize)); 459 ext2bdl[i - nBeg].Length = dwBytes; 460 ext2bdl[i - nBeg].Offset = 0; 461 } 462 else if (i == nEnd - 1) 463 { 464 ext2bdl[i - nBeg].Lba = lba; 465 ext2bdl[i - nBeg].Length = size - dwBytes; 466 ext2bdl[i - nBeg].Offset = dwBytes; 467 dwBytes = size; 468 } 469 else 470 { 471 ext2bdl[i - nBeg].Lba = lba; 472 ext2bdl[i - nBeg].Length = Ext2Sys->blocksize; 473 ext2bdl[i - nBeg].Offset = dwBytes; 474 dwBytes += Ext2Sys->blocksize; 475 } 476 } 477 } 478 479 *ext2_bdl = ext2bdl; 480 return nBlocks; 481 } 482 } 483 484 fail: 485 486 if (ext2bdl) 487 RtlFreeHeap(RtlGetProcessHeap(), 0, ext2bdl); 488 489 // Error 490 return 0; 491 } 492 493 494 bool ext2_read_inode(PEXT2_FILESYS Ext2Sys, 495 ULONG ino, 496 ULONG offset, 497 PVOID Buffer, 498 ULONG size, 499 PULONG dwReturn) 500 { 501 PEXT2_BDL ext2_bdl = NULL; 502 ULONG blocks, i; 503 bool bRet = true; 504 EXT2_INODE ext2_inode; 505 ULONG dwTotal = 0; 506 507 if (!ext2_load_inode(Ext2Sys, ino, &ext2_inode)) 508 { 509 return false; 510 } 511 512 blocks = ext2_build_bdl(Ext2Sys, &ext2_inode, offset, size, &ext2_bdl); 513 514 if (blocks <= 0) 515 return false; 516 517 518 for(i = 0; i < blocks; i++) 519 { 520 bRet = NT_SUCCESS(Ext2ReadDisk( 521 Ext2Sys, 522 ext2_bdl[i].Lba, 523 ext2_bdl[i].Length, 524 (PUCHAR)Buffer + ext2_bdl[i].Offset 525 )); 526 527 if (!bRet) 528 break; 529 dwTotal += ext2_bdl[i].Length; 530 } 531 532 *dwReturn = dwTotal; 533 534 if (ext2_bdl) 535 RtlFreeHeap(RtlGetProcessHeap(), 0, ext2_bdl); 536 537 return bRet; 538 } 539 540 541 bool ext2_write_inode (PEXT2_FILESYS Ext2Sys, 542 ULONG ino, 543 ULONG offset, 544 PVOID Buffer, 545 ULONG size, 546 PULONG dwReturn ) 547 { 548 PEXT2_BDL ext2_bdl = NULL; 549 ULONG blocks, i; 550 bool bRet = true; 551 EXT2_INODE inode; 552 ULONG dwTotal = 0; 553 ULONG dwBlk = 0; 554 ULONG TotalBlks; 555 556 blocks = (size + offset + Ext2Sys->blocksize - 1) / Ext2Sys->blocksize; 557 558 if (!ext2_load_inode(Ext2Sys, ino, &inode)) 559 { 560 return false; 561 } 562 563 TotalBlks = inode.i_blocks / (Ext2Sys->blocksize / SECTOR_SIZE); 564 TotalBlks = Ext2DataBlocks(Ext2Sys, TotalBlks); 565 566 if (blocks > TotalBlks) 567 { 568 for (i=0; i < (blocks - TotalBlks); i++) 569 { 570 if (ext2_alloc_block(Ext2Sys, 0, &dwBlk) ) 571 { 572 ext2_expand_inode(Ext2Sys, &inode, dwBlk); 573 inode.i_blocks += (Ext2Sys->blocksize/SECTOR_SIZE); 574 } 575 } 576 } 577 578 blocks = ext2_build_bdl(Ext2Sys, &inode, offset, size, &ext2_bdl); 579 580 if (blocks <= 0) 581 return false; 582 583 for(i = 0; i < blocks; i++) 584 { 585 bRet = NT_SUCCESS(Ext2WriteDisk( 586 Ext2Sys, 587 ext2_bdl[i].Lba, 588 ext2_bdl[i].Length, 589 (PUCHAR)Buffer + ext2_bdl[i].Offset 590 )); 591 592 if (!bRet) 593 { 594 goto errorout; 595 } 596 597 dwTotal += ext2_bdl[i].Length; 598 } 599 600 *dwReturn = dwTotal; 601 602 if (size + offset > inode.i_size) 603 { 604 inode.i_size = size + offset; 605 } 606 607 ext2_save_inode(Ext2Sys, ino, &inode); 608 609 610 errorout: 611 612 if (ext2_bdl) 613 RtlFreeHeap(RtlGetProcessHeap(), 0, ext2_bdl); 614 615 return bRet; 616 } 617 618 bool 619 ext2_add_entry( PEXT2_FILESYS Ext2Sys, 620 ULONG parent, ULONG inode, 621 int filetype, char *name ) 622 { 623 PEXT2_DIR_ENTRY2 dir = NULL, newdir = NULL; 624 EXT2_INODE parent_inode; 625 ULONG dwRet; 626 char *buf; 627 int rec_len; 628 bool bRet = false; 629 630 rec_len = EXT2_DIR_REC_LEN(strlen(name)); 631 632 if (!ext2_load_inode(Ext2Sys, parent, &parent_inode)) 633 { 634 return false; 635 } 636 637 buf = (char *)RtlAllocateHeap(RtlGetProcessHeap(), 0, parent_inode.i_size); 638 639 if (!ext2_read_inode(Ext2Sys, parent, 0, buf, parent_inode.i_size, &dwRet)) 640 { 641 return false; 642 } 643 644 dir = (PEXT2_DIR_ENTRY2) buf; 645 646 while ((char *)dir < buf + parent_inode.i_size) 647 { 648 if ((dir->inode == 0 && dir->rec_len >= rec_len) || 649 (dir->rec_len >= dir->name_len + rec_len) ) 650 { 651 if (dir->inode) 652 { 653 newdir = (PEXT2_DIR_ENTRY2) ((PUCHAR)dir + EXT2_DIR_REC_LEN(dir->name_len)); 654 newdir->rec_len = dir->rec_len - EXT2_DIR_REC_LEN(dir->name_len); 655 656 dir->rec_len = EXT2_DIR_REC_LEN(dir->name_len); 657 658 dir = newdir; 659 } 660 661 dir->file_type = filetype; 662 dir->inode = inode; 663 dir->name_len = strlen(name); 664 memcpy(dir->name, name, strlen(name)); 665 666 bRet = true; 667 break; 668 } 669 670 dir = (PEXT2_DIR_ENTRY2) (dir->rec_len + (PUCHAR) dir); 671 } 672 673 674 if (bRet) 675 return ext2_write_inode(Ext2Sys, parent, 0, buf, parent_inode.i_size, &dwRet); 676 677 return bRet; 678 } 679 680 681 bool ext2_reserve_inodes(PEXT2_FILESYS fs) 682 { 683 ULONG i; 684 int group; 685 686 for (i = EXT2_ROOT_INO + 1; i < EXT2_FIRST_INODE(fs->ext2_sb); i++) 687 { 688 ext2_mark_inode_bitmap(fs->inode_map, i); 689 group = ext2_group_of_ino(fs, i); 690 fs->group_desc[group].bg_free_inodes_count--; 691 fs->ext2_sb->s_free_inodes_count--; 692 } 693 694 return true; 695 } 696