Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > DoxygenInode.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: Mke2fs 00003 * FILE: Inode.c 00004 * PROGRAMMER: Matt Wu <mattwu@163.com> 00005 * HOMEPAGE: http://ext2.yeah.net 00006 */ 00007 00008 /* INCLUDES **************************************************************/ 00009 00010 #include "Mke2fs.h" 00011 #include <debug.h> 00012 00013 /* DEFINITIONS ***********************************************************/ 00014 00015 extern char *device_name; 00016 00017 /* FUNCTIONS *************************************************************/ 00018 00019 00020 bool ext2_get_inode_lba(PEXT2_FILESYS Ext2Sys, ULONG no, LONGLONG *offset) 00021 { 00022 LONGLONG loc = 0; 00023 PEXT2_SUPER_BLOCK pExt2Sb = Ext2Sys->ext2_sb; 00024 00025 if (no < 1 || no > pExt2Sb->s_inodes_count) 00026 { 00027 DPRINT1("Mke2fs: Inode value %lu was out of range in load_inode.(1-%ld)\n", 00028 no, pExt2Sb->s_inodes_count); 00029 *offset = 0; 00030 return false; 00031 } 00032 00033 loc = (LONGLONG)(Ext2Sys->blocksize) * Ext2Sys->group_desc[(no - 1) / pExt2Sb->s_inodes_per_group].bg_inode_table + 00034 ((no - 1) % pExt2Sb->s_inodes_per_group) * sizeof(EXT2_INODE); 00035 00036 *offset = loc; 00037 00038 return true; 00039 } 00040 00041 bool ext2_load_inode(PEXT2_FILESYS Ext2Sys, ULONG no, PEXT2_INODE pInode) 00042 { 00043 LONGLONG Offset; 00044 bool bRet = false; 00045 00046 if (ext2_get_inode_lba(Ext2Sys, no, &Offset)) 00047 { 00048 bRet = NT_SUCCESS(Ext2ReadDisk( 00049 Ext2Sys, 00050 Offset, 00051 sizeof(EXT2_INODE), 00052 (unsigned char *)pInode)); 00053 } 00054 00055 return bRet; 00056 } 00057 00058 00059 bool ext2_save_inode(PEXT2_FILESYS Ext2Sys, ULONG no, PEXT2_INODE pInode) 00060 { 00061 LONGLONG offset; 00062 bool bRet = false; 00063 00064 if (ext2_get_inode_lba(Ext2Sys, no, &offset)) 00065 { 00066 bRet = NT_SUCCESS(Ext2WriteDisk( 00067 Ext2Sys, 00068 offset, 00069 sizeof(EXT2_INODE), 00070 (unsigned char *)pInode)); 00071 } 00072 00073 return bRet; 00074 } 00075 00076 00077 /* 00078 * Right now, just search forward from the parent directory's block 00079 * group to find the next free inode. 00080 * 00081 * Should have a special policy for directories. 00082 */ 00083 00084 bool ext2_new_inode(PEXT2_FILESYS fs, ULONG dir, int mode, 00085 PEXT2_INODE_BITMAP map, ULONG *ret) 00086 { 00087 ULONG dir_group = 0; 00088 ULONG i; 00089 ULONG start_inode; 00090 00091 if (!map) 00092 map = fs->inode_map; 00093 00094 if (!map) 00095 return false; 00096 00097 if (dir > 0) 00098 dir_group = (dir - 1) / EXT2_INODES_PER_GROUP(fs->ext2_sb); 00099 00100 start_inode = (dir_group * EXT2_INODES_PER_GROUP(fs->ext2_sb)) + 1; 00101 00102 if (start_inode < EXT2_FIRST_INODE(fs->ext2_sb)) 00103 start_inode = EXT2_FIRST_INODE(fs->ext2_sb); 00104 00105 i = start_inode; 00106 00107 do 00108 { 00109 if (!ext2_test_inode_bitmap(map, i)) 00110 break; 00111 00112 i++; 00113 00114 if (i > fs->ext2_sb->s_inodes_count) 00115 i = EXT2_FIRST_INODE(fs->ext2_sb); 00116 00117 } while (i != start_inode); 00118 00119 if (ext2_test_inode_bitmap(map, i)) 00120 return false; 00121 00122 *ret = i; 00123 00124 return true; 00125 } 00126 00127 00128 bool ext2_expand_block( PEXT2_FILESYS Ext2Sys, PEXT2_INODE Inode, 00129 ULONG dwContent, ULONG Index, int layer, 00130 ULONG newBlk, ULONG *dwRet, ULONG *off ) 00131 { 00132 ULONG *pData = NULL; 00133 ULONG i = 0, j = 0, temp = 1; 00134 ULONG dwBlk; 00135 ULONG dwNewBlk = newBlk; 00136 bool bDirty = false; 00137 bool bRet = true; 00138 ULONG Offset = 0; 00139 00140 PEXT2_SUPER_BLOCK pExt2Sb = Ext2Sys->ext2_sb; 00141 00142 pData = (ULONG *)RtlAllocateHeap(RtlGetProcessHeap(), 0, Ext2Sys->blocksize); 00143 00144 if (!pData) 00145 { 00146 bRet = false; 00147 goto errorout; 00148 } 00149 00150 if (!ext2_read_block(Ext2Sys, dwContent, (void *)pData)) 00151 { 00152 bRet = false; 00153 goto errorout; 00154 } 00155 00156 if (layer == 1) 00157 { 00158 *dwRet = dwContent; 00159 *off = Index; 00160 pData[Index] = newBlk; 00161 00162 bDirty = TRUE; 00163 } 00164 else if (layer <= 3) 00165 { 00166 temp = 1 << ((10 + pExt2Sb->s_log_block_size - 2) * (layer - 1)); 00167 00168 i = Index / temp; 00169 j = Index % temp; 00170 00171 dwBlk = pData[i]; 00172 00173 if (dwBlk == 0) 00174 { 00175 if (ext2_alloc_block(Ext2Sys, 0, &dwBlk) ) 00176 { 00177 pData[i] = dwBlk; 00178 bDirty = true; 00179 00180 Inode->i_blocks += (Ext2Sys->blocksize / SECTOR_SIZE); 00181 } 00182 00183 if (!bDirty) 00184 goto errorout; 00185 } 00186 00187 if (!ext2_expand_block(Ext2Sys, Inode, dwBlk, j, layer - 1, bDirty, &dwNewBlk, &Offset)) 00188 { 00189 bRet = false; 00190 DPRINT1("Mke2fs: ext2_expand_block: ... error recuise...\n"); 00191 goto errorout; 00192 } 00193 } 00194 00195 if (bDirty) 00196 { 00197 bRet = ext2_write_block(Ext2Sys, dwContent, (void *)pData); 00198 } 00199 00200 00201 errorout: 00202 00203 if (pData) 00204 RtlFreeHeap(RtlGetProcessHeap(), 0, pData); 00205 00206 if (bRet && dwRet) 00207 *dwRet = dwNewBlk; 00208 00209 return bRet; 00210 } 00211 00212 bool ext2_expand_inode( PEXT2_FILESYS Ext2Sys, 00213 PEXT2_INODE Inode, 00214 ULONG newBlk ) 00215 { 00216 ULONG dwSizes[4] = {12, 1, 1, 1}; 00217 ULONG Index = 0; 00218 ULONG dwTotal = 0; 00219 ULONG dwBlk = 0, dwNewBlk = 0, Offset = 0; 00220 PEXT2_SUPER_BLOCK pExt2Sb = Ext2Sys->ext2_sb; 00221 int i = 0; 00222 bool bRet = true; 00223 bool bDirty = false; 00224 ULONG TotalBlocks; 00225 00226 TotalBlocks = Inode->i_blocks / (Ext2Sys->blocksize / SECTOR_SIZE); 00227 Index = Ext2DataBlocks(Ext2Sys, TotalBlocks); 00228 00229 for (i = 0; i < 4; i++) 00230 { 00231 dwSizes[i] = dwSizes[i] << ((10 + pExt2Sb->s_log_block_size - 2) * i); 00232 dwTotal += dwSizes[i]; 00233 } 00234 00235 if (Index >= dwTotal) 00236 { 00237 DPRINT1("Mke2fs: ext2_expand_inode: beyond the maxinum size of an inode.\n"); 00238 return false; 00239 } 00240 00241 for (i = 0; i < 4; i++) 00242 { 00243 if (Index < dwSizes[i]) 00244 { 00245 if (i == 0) 00246 { 00247 Inode->i_block[Index] = newBlk; 00248 bDirty = true; 00249 } 00250 else 00251 { 00252 dwBlk = Inode->i_block[(i + 12 - 1)]; 00253 00254 if (dwBlk == 0) 00255 { 00256 if (ext2_alloc_block(Ext2Sys, 0, &dwBlk)) 00257 { 00258 Inode->i_block[(i + 12 - 1)] = dwBlk; 00259 bDirty = true; 00260 00261 Inode->i_blocks += (Ext2Sys->blocksize / SECTOR_SIZE); 00262 } 00263 else 00264 { 00265 break; 00266 } 00267 } 00268 00269 dwNewBlk = 0; 00270 bRet = ext2_expand_block( 00271 Ext2Sys, 00272 Inode, 00273 dwBlk, 00274 Index, 00275 i, 00276 newBlk, 00277 &dwNewBlk, 00278 &Offset ); 00279 } 00280 00281 break; 00282 } 00283 00284 Index -= dwSizes[i]; 00285 } 00286 00287 return bRet; 00288 } 00289 00290 00291 bool ext2_get_block(PEXT2_FILESYS Ext2Sys, ULONG dwContent, ULONG Index, int layer, ULONG *dwRet) 00292 { 00293 ULONG *pData = NULL; 00294 LONGLONG Offset = 0; 00295 ULONG i = 0, j = 0, temp = 1; 00296 ULONG dwBlk = 0; 00297 bool bRet = true; 00298 00299 PEXT2_SUPER_BLOCK pExt2Sb = Ext2Sys->ext2_sb; 00300 00301 Offset = (LONGLONG) dwContent; 00302 Offset = Offset * Ext2Sys->blocksize; 00303 00304 pData = (ULONG *)RtlAllocateHeap(RtlGetProcessHeap(), 0, Ext2Sys->blocksize); 00305 00306 if (!pData) 00307 { 00308 return false; 00309 } 00310 memset(pData, 0, Ext2Sys->blocksize); 00311 00312 if (layer == 0) 00313 { 00314 dwBlk = dwContent; 00315 } 00316 else if (layer <= 3) 00317 { 00318 00319 if (!ext2_read_block(Ext2Sys, dwContent, (void *)pData)) 00320 { 00321 bRet = false; 00322 goto errorout; 00323 } 00324 00325 temp = 1 << ((10 + pExt2Sb->s_log_block_size - 2) * (layer - 1)); 00326 00327 i = Index / temp; 00328 j = Index % temp; 00329 00330 if (!ext2_get_block(Ext2Sys, pData[i], j, layer - 1, &dwBlk)) 00331 { 00332 bRet = false; 00333 DPRINT1("Mke2fs: ext2_get_block: ... error recuise...\n"); 00334 goto errorout; 00335 } 00336 } 00337 00338 errorout: 00339 00340 if (pData) 00341 RtlFreeHeap(RtlGetProcessHeap(), 0, pData); 00342 00343 if (bRet && dwRet) 00344 *dwRet = dwBlk; 00345 00346 return bRet; 00347 } 00348 00349 bool ext2_block_map(PEXT2_FILESYS Ext2Sys, PEXT2_INODE inode, ULONG block, ULONG *dwRet) 00350 { 00351 ULONG dwSizes[4] = { 12, 1, 1, 1 }; 00352 ULONG Index = 0; 00353 ULONG dwBlk = 0; 00354 PEXT2_SUPER_BLOCK pExt2Sb = Ext2Sys->ext2_sb; 00355 UINT i; 00356 bool bRet = false; 00357 00358 Index = block; 00359 00360 for (i = 0; i < 4; i++) 00361 { 00362 dwSizes[i] = dwSizes[i] << ((10 + pExt2Sb->s_log_block_size - 2) * i); 00363 } 00364 00365 if (Index >= inode->i_blocks / (Ext2Sys->blocksize / SECTOR_SIZE)) 00366 { 00367 DPRINT1("Mke2fs: ext2_block_map: beyond the size of the inode.\n"); 00368 return false; 00369 } 00370 00371 for (i = 0; i < 4; i++) 00372 { 00373 if (Index < dwSizes[i]) 00374 { 00375 dwBlk = inode->i_block[i==0 ? (Index):(i + 12 - 1)]; 00376 00377 bRet = ext2_get_block(Ext2Sys, dwBlk, Index , i, &dwBlk); 00378 00379 break; 00380 } 00381 Index -= dwSizes[i]; 00382 } 00383 00384 if (bRet && dwBlk) 00385 { 00386 if (dwRet) 00387 *dwRet = dwBlk; 00388 00389 return true; 00390 } 00391 else 00392 return false; 00393 } 00394 00395 ULONG ext2_build_bdl(PEXT2_FILESYS Ext2Sys, 00396 PEXT2_INODE ext2_inode, 00397 IN ULONG offset, 00398 IN ULONG size, 00399 OUT PEXT2_BDL *ext2_bdl ) 00400 { 00401 ULONG nBeg, nEnd, nBlocks; 00402 ULONG dwBlk; 00403 ULONG i; 00404 ULONG dwBytes = 0; 00405 LONGLONG lba; 00406 00407 PEXT2_BDL ext2bdl = NULL; 00408 00409 *ext2_bdl = NULL; 00410 00411 if (offset >= ext2_inode->i_size) 00412 { 00413 DPRINT1("Mke2fs: ext2_build_bdl: beyond the file range.\n"); 00414 return 0; 00415 } 00416 00417 /* 00418 if (offset + size > ext2_inode->i_size) 00419 { 00420 size = ext2_inode->i_size - offset; 00421 } 00422 */ 00423 00424 nBeg = offset / Ext2Sys->blocksize; 00425 nEnd = (size + offset + Ext2Sys->blocksize - 1) / Ext2Sys->blocksize; 00426 00427 nBlocks = nEnd - nBeg; 00428 00429 if (nBlocks > 0) 00430 { 00431 ext2bdl = (PEXT2_BDL) 00432 RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(EXT2_BDL) * nBlocks); 00433 00434 if (ext2bdl) 00435 { 00436 00437 memset(ext2bdl, 0, sizeof(EXT2_BDL) * nBlocks); 00438 00439 for (i = nBeg; i < nEnd; i++) 00440 { 00441 if (!ext2_block_map(Ext2Sys, ext2_inode, i, &dwBlk)) 00442 { 00443 goto fail; 00444 } 00445 00446 lba = (LONGLONG) dwBlk; 00447 lba = lba * Ext2Sys->blocksize; 00448 00449 if (nBlocks == 1) // ie. (nBeg == nEnd - 1) 00450 { 00451 dwBytes = size; 00452 ext2bdl[i - nBeg].Lba = lba + (LONGLONG)(offset % (Ext2Sys->blocksize)); 00453 ext2bdl[i - nBeg].Length = dwBytes; 00454 ext2bdl[i - nBeg].Offset = 0; 00455 } 00456 else 00457 { 00458 if (i == nBeg) 00459 { 00460 dwBytes = Ext2Sys->blocksize - (offset % (Ext2Sys->blocksize)); 00461 ext2bdl[i - nBeg].Lba = lba + (LONGLONG)(offset % (Ext2Sys->blocksize)); 00462 ext2bdl[i - nBeg].Length = dwBytes; 00463 ext2bdl[i - nBeg].Offset = 0; 00464 } 00465 else if (i == nEnd - 1) 00466 { 00467 ext2bdl[i - nBeg].Lba = lba; 00468 ext2bdl[i - nBeg].Length = size - dwBytes; 00469 ext2bdl[i - nBeg].Offset = dwBytes; 00470 dwBytes = size; 00471 } 00472 else 00473 { 00474 ext2bdl[i - nBeg].Lba = lba; 00475 ext2bdl[i - nBeg].Length = Ext2Sys->blocksize; 00476 ext2bdl[i - nBeg].Offset = dwBytes; 00477 dwBytes += Ext2Sys->blocksize; 00478 } 00479 } 00480 } 00481 00482 *ext2_bdl = ext2bdl; 00483 return nBlocks; 00484 } 00485 } 00486 00487 fail: 00488 00489 if (ext2bdl) 00490 RtlFreeHeap(RtlGetProcessHeap(), 0, ext2bdl); 00491 00492 // Error 00493 return 0; 00494 } 00495 00496 00497 bool ext2_read_inode(PEXT2_FILESYS Ext2Sys, 00498 ULONG ino, 00499 ULONG offset, 00500 PVOID Buffer, 00501 ULONG size, 00502 PULONG dwReturn) 00503 { 00504 PEXT2_BDL ext2_bdl = NULL; 00505 ULONG blocks, i; 00506 bool bRet = true; 00507 EXT2_INODE ext2_inode; 00508 ULONG dwTotal = 0; 00509 00510 if (!ext2_load_inode(Ext2Sys, ino, &ext2_inode)) 00511 { 00512 return false; 00513 } 00514 00515 blocks = ext2_build_bdl(Ext2Sys, &ext2_inode, offset, size, &ext2_bdl); 00516 00517 if (blocks <= 0) 00518 return false; 00519 00520 00521 for(i = 0; i < blocks; i++) 00522 { 00523 bRet = NT_SUCCESS(Ext2ReadDisk( 00524 Ext2Sys, 00525 ext2_bdl[i].Lba, 00526 ext2_bdl[i].Length, 00527 (PUCHAR)Buffer + ext2_bdl[i].Offset 00528 )); 00529 00530 if (!bRet) 00531 break; 00532 dwTotal += ext2_bdl[i].Length; 00533 } 00534 00535 *dwReturn = dwTotal; 00536 00537 if (ext2_bdl) 00538 RtlFreeHeap(RtlGetProcessHeap(), 0, ext2_bdl); 00539 00540 return bRet; 00541 } 00542 00543 00544 bool ext2_write_inode (PEXT2_FILESYS Ext2Sys, 00545 ULONG ino, 00546 ULONG offset, 00547 PVOID Buffer, 00548 ULONG size, 00549 PULONG dwReturn ) 00550 { 00551 PEXT2_BDL ext2_bdl = NULL; 00552 ULONG blocks, i; 00553 bool bRet = true; 00554 EXT2_INODE inode; 00555 ULONG dwTotal = 0; 00556 ULONG dwBlk = 0; 00557 ULONG TotalBlks; 00558 00559 blocks = (size + offset + Ext2Sys->blocksize - 1) / Ext2Sys->blocksize; 00560 00561 if (!ext2_load_inode(Ext2Sys, ino, &inode)) 00562 { 00563 return false; 00564 } 00565 00566 TotalBlks = inode.i_blocks / (Ext2Sys->blocksize / SECTOR_SIZE); 00567 TotalBlks = Ext2DataBlocks(Ext2Sys, TotalBlks); 00568 00569 if (blocks > TotalBlks) 00570 { 00571 for (i=0; i < (blocks - TotalBlks); i++) 00572 { 00573 if (ext2_alloc_block(Ext2Sys, 0, &dwBlk) ) 00574 { 00575 ext2_expand_inode(Ext2Sys, &inode, dwBlk); 00576 inode.i_blocks += (Ext2Sys->blocksize/SECTOR_SIZE); 00577 } 00578 } 00579 } 00580 00581 blocks = ext2_build_bdl(Ext2Sys, &inode, offset, size, &ext2_bdl); 00582 00583 if (blocks <= 0) 00584 return false; 00585 00586 for(i = 0; i < blocks; i++) 00587 { 00588 bRet = NT_SUCCESS(Ext2WriteDisk( 00589 Ext2Sys, 00590 ext2_bdl[i].Lba, 00591 ext2_bdl[i].Length, 00592 (PUCHAR)Buffer + ext2_bdl[i].Offset 00593 )); 00594 00595 if (!bRet) 00596 { 00597 goto errorout; 00598 } 00599 00600 dwTotal += ext2_bdl[i].Length; 00601 } 00602 00603 *dwReturn = dwTotal; 00604 00605 if (size + offset > inode.i_size) 00606 { 00607 inode.i_size = size + offset; 00608 } 00609 00610 ext2_save_inode(Ext2Sys, ino, &inode); 00611 00612 00613 errorout: 00614 00615 if (ext2_bdl) 00616 RtlFreeHeap(RtlGetProcessHeap(), 0, ext2_bdl); 00617 00618 return bRet; 00619 } 00620 00621 bool 00622 ext2_add_entry( PEXT2_FILESYS Ext2Sys, 00623 ULONG parent, ULONG inode, 00624 int filetype, char *name ) 00625 { 00626 PEXT2_DIR_ENTRY2 dir = NULL, newdir = NULL; 00627 EXT2_INODE parent_inode; 00628 ULONG dwRet; 00629 char *buf; 00630 int rec_len; 00631 bool bRet = false; 00632 00633 rec_len = EXT2_DIR_REC_LEN(strlen(name)); 00634 00635 if (!ext2_load_inode(Ext2Sys, parent, &parent_inode)) 00636 { 00637 return false; 00638 } 00639 00640 buf = (char *)RtlAllocateHeap(RtlGetProcessHeap(), 0, parent_inode.i_size); 00641 00642 if (!ext2_read_inode(Ext2Sys, parent, 0, buf, parent_inode.i_size, &dwRet)) 00643 { 00644 return false; 00645 } 00646 00647 dir = (PEXT2_DIR_ENTRY2) buf; 00648 00649 while ((char *)dir < buf + parent_inode.i_size) 00650 { 00651 if ((dir->inode == 0 && dir->rec_len >= rec_len) || 00652 (dir->rec_len >= dir->name_len + rec_len) ) 00653 { 00654 if (dir->inode) 00655 { 00656 newdir = (PEXT2_DIR_ENTRY2) ((PUCHAR)dir + EXT2_DIR_REC_LEN(dir->name_len)); 00657 newdir->rec_len = dir->rec_len - EXT2_DIR_REC_LEN(dir->name_len); 00658 00659 dir->rec_len = EXT2_DIR_REC_LEN(dir->name_len); 00660 00661 dir = newdir; 00662 } 00663 00664 dir->file_type = filetype; 00665 dir->inode = inode; 00666 dir->name_len = strlen(name); 00667 memcpy(dir->name, name, strlen(name)); 00668 00669 bRet = true; 00670 break; 00671 } 00672 00673 dir = (PEXT2_DIR_ENTRY2) (dir->rec_len + (PUCHAR) dir); 00674 } 00675 00676 00677 if (bRet) 00678 return ext2_write_inode(Ext2Sys, parent, 0, buf, parent_inode.i_size, &dwRet); 00679 00680 return bRet; 00681 } 00682 00683 00684 bool ext2_reserve_inodes(PEXT2_FILESYS fs) 00685 { 00686 ULONG i; 00687 int group; 00688 00689 for (i = EXT2_ROOT_INO + 1; i < EXT2_FIRST_INODE(fs->ext2_sb); i++) 00690 { 00691 ext2_mark_inode_bitmap(fs->inode_map, i); 00692 group = ext2_group_of_ino(fs, i); 00693 fs->group_desc[group].bg_free_inodes_count--; 00694 fs->ext2_sb->s_free_inodes_count--; 00695 } 00696 00697 return true; 00698 } Generated on Sun May 27 2012 04:36:13 for ReactOS by
1.7.6.1
|