Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696/* * PROJECT: Mke2fs * FILE: Inode.c * PROGRAMMER: Matt Wu <mattwu@163.com> * HOMEPAGE: http://ext2.yeah.net */
/* INCLUDES **************************************************************/
#include "Mke2fs.h"#include <debug.h>
/* DEFINITIONS ***********************************************************/
extern char *device_name;
/* FUNCTIONS *************************************************************/
bool ext2_get_inode_lba(PEXT2_FILESYS Ext2Sys, ULONG no, LONGLONG *offset){ LONGLONG loc = 0; PEXT2_SUPER_BLOCK pExt2Sb = Ext2Sys->ext2_sb;
if (no < 1 || no > pExt2Sb->s_inodes_count) { DPRINT1("Mke2fs: Inode value %lu was out of range in load_inode.(1-%ld)\n", no, pExt2Sb->s_inodes_count); *offset = 0; return false; }
loc = (LONGLONG)(Ext2Sys->blocksize) * Ext2Sys->group_desc[(no - 1) / pExt2Sb->s_inodes_per_group].bg_inode_table + ((no - 1) % pExt2Sb->s_inodes_per_group) * sizeof(EXT2_INODE);
*offset = loc;
return true;}
bool ext2_load_inode(PEXT2_FILESYS Ext2Sys, ULONG no, PEXT2_INODE pInode){ LONGLONG Offset; bool bRet = false;
if (ext2_get_inode_lba(Ext2Sys, no, &Offset)) { bRet = NT_SUCCESS(Ext2ReadDisk( Ext2Sys, Offset, sizeof(EXT2_INODE), (unsigned char *)pInode)); }
return bRet;}
bool ext2_save_inode(PEXT2_FILESYS Ext2Sys, ULONG no, PEXT2_INODE pInode){ LONGLONG offset; bool bRet = false;
if (ext2_get_inode_lba(Ext2Sys, no, &offset)) { bRet = NT_SUCCESS(Ext2WriteDisk( Ext2Sys, offset, sizeof(EXT2_INODE), (unsigned char *)pInode)); }
return bRet;}
/* * Right now, just search forward from the parent directory's block * group to find the next free inode. * * Should have a special policy for directories. */
bool ext2_new_inode(PEXT2_FILESYS fs, ULONG dir, int mode, PEXT2_INODE_BITMAP map, ULONG *ret){ ULONG dir_group = 0; ULONG i; ULONG start_inode;
if (!map) map = fs->inode_map;
if (!map) return false;
if (dir > 0) dir_group = (dir - 1) / EXT2_INODES_PER_GROUP(fs->ext2_sb);
start_inode = (dir_group * EXT2_INODES_PER_GROUP(fs->ext2_sb)) + 1;
if (start_inode < EXT2_FIRST_INODE(fs->ext2_sb)) start_inode = EXT2_FIRST_INODE(fs->ext2_sb);
i = start_inode;
do { if (!ext2_test_inode_bitmap(map, i)) break;
i++;
if (i > fs->ext2_sb->s_inodes_count) i = EXT2_FIRST_INODE(fs->ext2_sb);
} while (i != start_inode);
if (ext2_test_inode_bitmap(map, i)) return false;
*ret = i;
return true;}
bool ext2_expand_block( PEXT2_FILESYS Ext2Sys, PEXT2_INODE Inode, ULONG dwContent, ULONG Index, int layer, ULONG newBlk, ULONG *dwRet, ULONG *off ){ ULONG *pData = NULL; ULONG i = 0, j = 0, temp = 1; ULONG dwBlk; ULONG dwNewBlk = newBlk; bool bDirty = false; bool bRet = true; ULONG Offset = 0;
PEXT2_SUPER_BLOCK pExt2Sb = Ext2Sys->ext2_sb;
pData = (ULONG *)RtlAllocateHeap(RtlGetProcessHeap(), 0, Ext2Sys->blocksize);
if (!pData) { bRet = false; goto errorout; }
if (!ext2_read_block(Ext2Sys, dwContent, (void *)pData)) { bRet = false; goto errorout; }
if (layer == 1) { *dwRet = dwContent; *off = Index; pData[Index] = newBlk;
bDirty = TRUE; } else if (layer <= 3) { temp = 1 << ((10 + pExt2Sb->s_log_block_size - 2) * (layer - 1));
i = Index / temp; j = Index % temp;
dwBlk = pData[i];
if (dwBlk == 0) { if (ext2_alloc_block(Ext2Sys, 0, &dwBlk) ) { pData[i] = dwBlk; bDirty = true;
Inode->i_blocks += (Ext2Sys->blocksize / SECTOR_SIZE); }
if (!bDirty) goto errorout; }
if (!ext2_expand_block(Ext2Sys, Inode, dwBlk, j, layer - 1, bDirty, &dwNewBlk, &Offset)) { bRet = false; DPRINT1("Mke2fs: ext2_expand_block: ... error recuise...\n"); goto errorout; } }
if (bDirty) { bRet = ext2_write_block(Ext2Sys, dwContent, (void *)pData); }
errorout:
if (pData) RtlFreeHeap(RtlGetProcessHeap(), 0, pData);
if (bRet && dwRet) *dwRet = dwNewBlk;
return bRet;}
bool ext2_expand_inode( PEXT2_FILESYS Ext2Sys, PEXT2_INODE Inode, ULONG newBlk ){ ULONG dwSizes[4] = {12, 1, 1, 1}; ULONG Index = 0; ULONG dwTotal = 0; ULONG dwBlk = 0, dwNewBlk = 0, Offset = 0; PEXT2_SUPER_BLOCK pExt2Sb = Ext2Sys->ext2_sb; int i = 0; bool bRet = true; ULONG TotalBlocks;
TotalBlocks = Inode->i_blocks / (Ext2Sys->blocksize / SECTOR_SIZE); Index = Ext2DataBlocks(Ext2Sys, TotalBlocks);
for (i = 0; i < 4; i++) { dwSizes[i] = dwSizes[i] << ((10 + pExt2Sb->s_log_block_size - 2) * i); dwTotal += dwSizes[i]; }
if (Index >= dwTotal) { DPRINT1("Mke2fs: ext2_expand_inode: beyond the maxinum size of an inode.\n"); return false; }
for (i = 0; i < 4; i++) { if (Index < dwSizes[i]) { if (i == 0) { Inode->i_block[Index] = newBlk; } else { dwBlk = Inode->i_block[(i + 12 - 1)];
if (dwBlk == 0) { if (ext2_alloc_block(Ext2Sys, 0, &dwBlk)) { Inode->i_block[(i + 12 - 1)] = dwBlk;
Inode->i_blocks += (Ext2Sys->blocksize / SECTOR_SIZE); } else { break; } }
dwNewBlk = 0; bRet = ext2_expand_block( Ext2Sys, Inode, dwBlk, Index, i, newBlk, &dwNewBlk, &Offset ); }
break; }
Index -= dwSizes[i]; }
return bRet;}
bool ext2_get_block(PEXT2_FILESYS Ext2Sys, ULONG dwContent, ULONG Index, int layer, ULONG *dwRet){ ULONG *pData = NULL; LONGLONG Offset = 0; ULONG i = 0, j = 0, temp = 1; ULONG dwBlk = 0; bool bRet = true;
PEXT2_SUPER_BLOCK pExt2Sb = Ext2Sys->ext2_sb;
Offset = (LONGLONG) dwContent; Offset = Offset * Ext2Sys->blocksize;
pData = (ULONG *)RtlAllocateHeap(RtlGetProcessHeap(), 0, Ext2Sys->blocksize);
if (!pData) { return false; } memset(pData, 0, Ext2Sys->blocksize);
if (layer == 0) { dwBlk = dwContent; } else if (layer <= 3) {
if (!ext2_read_block(Ext2Sys, dwContent, (void *)pData)) { bRet = false; goto errorout; }
temp = 1 << ((10 + pExt2Sb->s_log_block_size - 2) * (layer - 1));
i = Index / temp; j = Index % temp;
if (!ext2_get_block(Ext2Sys, pData[i], j, layer - 1, &dwBlk)) { bRet = false; DPRINT1("Mke2fs: ext2_get_block: ... error recuise...\n"); goto errorout; } }
errorout:
if (pData) RtlFreeHeap(RtlGetProcessHeap(), 0, pData);
if (bRet && dwRet) *dwRet = dwBlk;
return bRet;}
bool ext2_block_map(PEXT2_FILESYS Ext2Sys, PEXT2_INODE inode, ULONG block, ULONG *dwRet){ ULONG dwSizes[4] = { 12, 1, 1, 1 }; ULONG Index = 0; ULONG dwBlk = 0; PEXT2_SUPER_BLOCK pExt2Sb = Ext2Sys->ext2_sb; UINT i; bool bRet = false;
Index = block;
for (i = 0; i < 4; i++) { dwSizes[i] = dwSizes[i] << ((10 + pExt2Sb->s_log_block_size - 2) * i); }
if (Index >= inode->i_blocks / (Ext2Sys->blocksize / SECTOR_SIZE)) { DPRINT1("Mke2fs: ext2_block_map: beyond the size of the inode.\n"); return false; }
for (i = 0; i < 4; i++) { if (Index < dwSizes[i]) { dwBlk = inode->i_block[i==0 ? (Index):(i + 12 - 1)];
bRet = ext2_get_block(Ext2Sys, dwBlk, Index , i, &dwBlk);
break; } Index -= dwSizes[i]; }
if (bRet && dwBlk) { if (dwRet) *dwRet = dwBlk;
return true; } else return false;}
ULONG ext2_build_bdl(PEXT2_FILESYS Ext2Sys, PEXT2_INODE ext2_inode, IN ULONG offset, IN ULONG size, OUT PEXT2_BDL *ext2_bdl ){ ULONG nBeg, nEnd, nBlocks; ULONG dwBlk; ULONG i; ULONG dwBytes = 0; LONGLONG lba;
PEXT2_BDL ext2bdl = NULL;
*ext2_bdl = NULL;
if (offset >= ext2_inode->i_size) { DPRINT1("Mke2fs: ext2_build_bdl: beyond the file range.\n"); return 0; }
/* if (offset + size > ext2_inode->i_size) { size = ext2_inode->i_size - offset; }*/
nBeg = offset / Ext2Sys->blocksize; nEnd = (size + offset + Ext2Sys->blocksize - 1) / Ext2Sys->blocksize;
nBlocks = nEnd - nBeg;
if (nBlocks > 0) { ext2bdl = (PEXT2_BDL) RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(EXT2_BDL) * nBlocks);
if (ext2bdl) {
memset(ext2bdl, 0, sizeof(EXT2_BDL) * nBlocks);
for (i = nBeg; i < nEnd; i++) { if (!ext2_block_map(Ext2Sys, ext2_inode, i, &dwBlk)) { goto fail; }
lba = (LONGLONG) dwBlk; lba = lba * Ext2Sys->blocksize;
if (nBlocks == 1) // ie. (nBeg == nEnd - 1) { dwBytes = size; ext2bdl[i - nBeg].Lba = lba + (LONGLONG)(offset % (Ext2Sys->blocksize)); ext2bdl[i - nBeg].Length = dwBytes; ext2bdl[i - nBeg].Offset = 0; } else { if (i == nBeg) { dwBytes = Ext2Sys->blocksize - (offset % (Ext2Sys->blocksize)); ext2bdl[i - nBeg].Lba = lba + (LONGLONG)(offset % (Ext2Sys->blocksize)); ext2bdl[i - nBeg].Length = dwBytes; ext2bdl[i - nBeg].Offset = 0; } else if (i == nEnd - 1) { ext2bdl[i - nBeg].Lba = lba; ext2bdl[i - nBeg].Length = size - dwBytes; ext2bdl[i - nBeg].Offset = dwBytes; dwBytes = size; } else { ext2bdl[i - nBeg].Lba = lba; ext2bdl[i - nBeg].Length = Ext2Sys->blocksize; ext2bdl[i - nBeg].Offset = dwBytes; dwBytes += Ext2Sys->blocksize; } } }
*ext2_bdl = ext2bdl; return nBlocks; } }
fail:
if (ext2bdl) RtlFreeHeap(RtlGetProcessHeap(), 0, ext2bdl);
// Error return 0;}
bool ext2_read_inode(PEXT2_FILESYS Ext2Sys, ULONG ino, ULONG offset, PVOID Buffer, ULONG size, PULONG dwReturn){ PEXT2_BDL ext2_bdl = NULL; ULONG blocks, i; bool bRet = true; EXT2_INODE ext2_inode; ULONG dwTotal = 0;
if (!ext2_load_inode(Ext2Sys, ino, &ext2_inode)) { return false; }
blocks = ext2_build_bdl(Ext2Sys, &ext2_inode, offset, size, &ext2_bdl);
if (blocks <= 0) return false;
for(i = 0; i < blocks; i++) { bRet = NT_SUCCESS(Ext2ReadDisk( Ext2Sys, ext2_bdl[i].Lba, ext2_bdl[i].Length, (PUCHAR)Buffer + ext2_bdl[i].Offset ));
if (!bRet) break; dwTotal += ext2_bdl[i].Length; }
*dwReturn = dwTotal;
if (ext2_bdl) RtlFreeHeap(RtlGetProcessHeap(), 0, ext2_bdl);
return bRet;}
bool ext2_write_inode (PEXT2_FILESYS Ext2Sys, ULONG ino, ULONG offset, PVOID Buffer, ULONG size, PULONG dwReturn ){ PEXT2_BDL ext2_bdl = NULL; ULONG blocks, i; bool bRet = true; EXT2_INODE inode; ULONG dwTotal = 0; ULONG dwBlk = 0; ULONG TotalBlks;
blocks = (size + offset + Ext2Sys->blocksize - 1) / Ext2Sys->blocksize;
if (!ext2_load_inode(Ext2Sys, ino, &inode)) { return false; }
TotalBlks = inode.i_blocks / (Ext2Sys->blocksize / SECTOR_SIZE); TotalBlks = Ext2DataBlocks(Ext2Sys, TotalBlks);
if (blocks > TotalBlks) { for (i=0; i < (blocks - TotalBlks); i++) { if (ext2_alloc_block(Ext2Sys, 0, &dwBlk) ) { ext2_expand_inode(Ext2Sys, &inode, dwBlk); inode.i_blocks += (Ext2Sys->blocksize/SECTOR_SIZE); } } }
blocks = ext2_build_bdl(Ext2Sys, &inode, offset, size, &ext2_bdl);
if (blocks <= 0) return false;
for(i = 0; i < blocks; i++) { bRet = NT_SUCCESS(Ext2WriteDisk( Ext2Sys, ext2_bdl[i].Lba, ext2_bdl[i].Length, (PUCHAR)Buffer + ext2_bdl[i].Offset ));
if (!bRet) { goto errorout; }
dwTotal += ext2_bdl[i].Length; }
*dwReturn = dwTotal;
if (size + offset > inode.i_size) { inode.i_size = size + offset; }
ext2_save_inode(Ext2Sys, ino, &inode);
errorout:
if (ext2_bdl) RtlFreeHeap(RtlGetProcessHeap(), 0, ext2_bdl);
return bRet;}
boolext2_add_entry( PEXT2_FILESYS Ext2Sys, ULONG parent, ULONG inode, int filetype, char *name ){ PEXT2_DIR_ENTRY2 dir = NULL, newdir = NULL; EXT2_INODE parent_inode; ULONG dwRet; char *buf; int rec_len; bool bRet = false;
rec_len = EXT2_DIR_REC_LEN(strlen(name));
if (!ext2_load_inode(Ext2Sys, parent, &parent_inode)) { return false; }
buf = (char *)RtlAllocateHeap(RtlGetProcessHeap(), 0, parent_inode.i_size);
if (!ext2_read_inode(Ext2Sys, parent, 0, buf, parent_inode.i_size, &dwRet)) { return false; }
dir = (PEXT2_DIR_ENTRY2) buf;
while ((char *)dir < buf + parent_inode.i_size) { if ((dir->inode == 0 && dir->rec_len >= rec_len) || (dir->rec_len >= dir->name_len + rec_len) ) { if (dir->inode) { newdir = (PEXT2_DIR_ENTRY2) ((PUCHAR)dir + EXT2_DIR_REC_LEN(dir->name_len)); newdir->rec_len = dir->rec_len - EXT2_DIR_REC_LEN(dir->name_len);
dir->rec_len = EXT2_DIR_REC_LEN(dir->name_len);
dir = newdir; }
dir->file_type = filetype; dir->inode = inode; dir->name_len = strlen(name); memcpy(dir->name, name, strlen(name));
bRet = true; break; }
dir = (PEXT2_DIR_ENTRY2) (dir->rec_len + (PUCHAR) dir); }
if (bRet) return ext2_write_inode(Ext2Sys, parent, 0, buf, parent_inode.i_size, &dwRet);
return bRet;}
bool ext2_reserve_inodes(PEXT2_FILESYS fs){ ULONG i; int group;
for (i = EXT2_ROOT_INO + 1; i < EXT2_FIRST_INODE(fs->ext2_sb); i++) { ext2_mark_inode_bitmap(fs->inode_map, i); group = ext2_group_of_ino(fs, i); fs->group_desc[group].bg_free_inodes_count--; fs->ext2_sb->s_free_inodes_count--; }
return true;}