ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

Inode.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.