#include "precomp.h"
#include "reiserfs.h"
#include "string.h"
#include "assert.h"
#include "pdrivefile.h"
#include "time.h"
#define MAXLOOPTRY 10245
#ifndef ZeroMemory
#define ZeroMemory(Destination,Length) memset((Destination),0,(Length))
#endif
#define SIZE_OF_LAYOUT_BLOCK 20240
class LayoutBlock
{
public:
LayoutBlock()
{
m_lpbData = new BYTE[SIZE_OF_LAYOUT_BLOCK];
}
bool isValid()
{
return (m_lpbData != NULL);
}
int getSize()
{
return SIZE_OF_LAYOUT_BLOCK;
}
LPBYTE getData()
{
return m_lpbData;
}
virtual ~LayoutBlock()
{
delete [] m_lpbData;
}
protected:
int m_nSize;
LPBYTE m_lpbData;
};
DWORD dwTypeDirect = (DWORD) -1;
DWORD dwTypeIndirect = (DWORD) -2;
#ifdef _WIN32
void FileTimeFromUnixTime(FILETIME* pf, U32 unixtime )
{
struct tm* t = localtime((const time_t*) &unixtime );
ZeroMemory( pf, sizeof(FILETIME) );
if( t )
{
SYSTEMTIME st;
st.wYear = (WORD) t->tm_year + 1900;
st.wMonth = (WORD) t->tm_mon + 1;
st.wDayOfWeek = (WORD) t->tm_wday;
st.wDay = (WORD) t->tm_mday;
st.wHour = (WORD) t->tm_hour;
st.wMinute = (WORD) t->tm_min;
st.wSecond = (WORD) t->tm_sec;
st.wMilliseconds = (WORD) 0;
SystemTimeToFileTime(&st, pf);
}
}
#endif
void SetUnixFileTime( LPCSTR lpszPath, ReiserFsFileInfo* pFile )
{
#ifdef _WIN32
FILETIME f_atime, f_mtime, f_ctime;
FileTimeFromUnixTime(&f_atime, pFile->m_stat.sd_atime );
FileTimeFromUnixTime(&f_mtime, pFile->m_stat.sd_mtime );
FileTimeFromUnixTime(&f_ctime, pFile->m_stat.sd_ctime );
HANDLE hFile = CreateFile( lpszPath, GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0 );
if( hFile != INVALID_HANDLE_VALUE )
{
SetFileTime(hFile, &f_ctime, &f_atime, &f_mtime );
CloseHandle(hFile);
}
#endif
}
ReiserFsFileInfo::ReiserFsFileInfo(REISERFS_DIRECTORY_HEAD* pDH, LPCSTR lpszName)
{
DEBUGTRACE(("FOUND FILE %s\n", lpszName))
m_deh = *pDH;
m_strName = lpszName;
memset(&m_stat,0,sizeof(m_stat));
// rfs does not store file info for special dirs "." and "..", so simulate this here...
if( (stricmp(lpszName, ".") == 0) ||
(stricmp(lpszName, "..") == 0) )
{
m_stat.sd_mode |= S_IFDIR;
}
}
int comp_keys(REISERFS_CPU_KEY* a, REISERFS_CPU_KEY *b)
{
if( a->k_dir_id < b->k_dir_id )
return -1;
if( a->k_dir_id > b->k_dir_id )
return 1;
if( a->k_objectid < b->k_objectid )
return -1;
if( a->k_objectid > b->k_objectid )
return 1;
if( a->k_offset < b->k_offset )
return -1;
if( a->k_offset > b->k_offset )
return 1;
if( a->k_type < b->k_type )
return -1;
if( a->k_type > b->k_type )
return 1;
return 0;
}
int comp_keys_no_offset (REISERFS_CPU_KEY * le_key, REISERFS_CPU_KEY * cpu_key)
{
if( le_key->k_dir_id < cpu_key->k_dir_id )
return -1;
if( le_key->k_dir_id > cpu_key->k_dir_id )
return 1;
if( le_key->k_objectid < cpu_key->k_objectid )
return -1;
if( le_key->k_objectid > cpu_key->k_objectid )
return 1;
if (le_key->k_type < cpu_key->k_type)
return -1;
if (le_key->k_type > cpu_key->k_type)
return 1;
return 0;
}
ReiserFsPartition::ReiserFsPartition()
{
m_dwBlockSize = 4096;
m_pDrive = CreatePhysicalDriveInstance();
} // ReiserFsPartition()
ReiserFsPartition::~ReiserFsPartition()
{
delete m_pDrive;
} // ~ReiserFsPartition()
BOOL ReiserFsPartition::Read( LPBYTE lpbMemory, DWORD dwSize, INT64 BlockNumber )
{
INT64 offset = m_sb.s_blocksize;
offset *= BlockNumber;
offset += m_PartitionStartingOffset;
return m_pDrive->ReadAbsolute( lpbMemory, dwSize, offset );
} // Read()
bool ReiserFsPartition::CheckReiserFsPartition()
{
INT64 diskoffset = (m_PartitionStartingOffset + REISERFS_DISK_OFFSET_IN_BYTES);
BYTE* lpbMemory = new BYTE[ (DWORD)( m_BytesPerSector*2 ) ];
if( !m_pDrive->ReadAbsolute(lpbMemory, (DWORD) m_BytesPerSector, diskoffset ) )
{
printf("ERROR %s, unable to read ReiserFS superblock\n", (LPCSTR) GetLastErrorString() );
return false;
}
LPREISERFS_SUPER_BLOCK p = (LPREISERFS_SUPER_BLOCK) lpbMemory;
if( stricmp(p->s_magic,REISERFS_SUPER_MAGIC_STRING) )
{
if( stricmp(p->s_magic,REISER2FS_SUPER_MAGIC_STRING) )
{
if( stricmp(p->s_magic,REISER3FS_SUPER_MAGIC_STRING) )
{
return false;
}
}
}
return true;
}
void ReiserFsPartition::AutodetectFirstUsable( int* piPartition, int* piDrive )
{
DISK_GEOMETRY dg;
LayoutBlock layout;
printf("No drives specified, performing an autodetect...\n" );
for( int iDrive = 0; iDrive < 10; iDrive++ )
{
if( !m_pDrive->Open(iDrive) )
continue;
printf("Testing drive %d\n", iDrive );
#ifdef SUPPORT_WINDOWS_XP_PARTITIONS
if( m_pDrive->GetDriveGeometryEx( (DISK_GEOMETRY_EX*) layout.getData(), layout.getSize() ) )
{
DISK_GEOMETRY_EX* pDG = (DISK_GEOMETRY_EX*) layout.getData();
m_BytesPerSector = pDG->Geometry.BytesPerSector;
}
else
#endif
if( m_pDrive->GetDriveGeometry(&dg) )
{
m_BytesPerSector = dg.BytesPerSector;
}
else
{
printf("ERROR %s, unable to get drive geometry from this drive\n", (LPCSTR) GetLastErrorString() );
continue;
}
memset( layout.getData(), 0, layout.getSize() );
#ifdef SUPPORT_WINDOWS_XP_PARTITIONS
if( m_pDrive->GetDriveLayoutEx(layout.getData(), layout.getSize()) )
{
PDRIVE_LAYOUT_INFORMATION_EX pLI = (PDRIVE_LAYOUT_INFORMATION_EX)layout.getData();
for( DWORD iPartition = 0; iPartition < pLI->PartitionCount; iPartition++ )
{
m_PartitionStartingOffset = pLI->PartitionEntry[iPartition].StartingOffset.QuadPart;
if( CheckReiserFsPartition() )
{
printf( "Drive %d, Partition %d is a ReiserFS\n",iDrive, iPartition );
printf( "Partition Size: %" FMT_QWORD " Bytes (%.2f MB)\n",
pLI->PartitionEntry[iPartition].PartitionLength.QuadPart,
PBytesInMBytes(pLI->PartitionEntry[iPartition].PartitionLength.QuadPart) );
}
}
}
else
#endif
if( m_pDrive->GetDriveLayout(layout.getData(), layout.getSize()) )
{
PDRIVE_LAYOUT_INFORMATION pLI = (PDRIVE_LAYOUT_INFORMATION)layout.getData();
for( DWORD iPartition = 0; iPartition < pLI->PartitionCount; iPartition++ )
{
m_PartitionStartingOffset = pLI->PartitionEntry[iPartition].StartingOffset.QuadPart;
if( CheckReiserFsPartition() )
{
*piPartition = iPartition;
*piDrive = iDrive;
printf( "Drive %d, Partition %d is a ReiserFS -> using that\n",iDrive, iPartition );
printf( "Partition Size: %" FMT_QWORD " Bytes (%.2f MB)\n",
pLI->PartitionEntry[iPartition].PartitionLength.QuadPart,
PBytesInMBytes(pLI->PartitionEntry[iPartition].PartitionLength.QuadPart) );
break;
}
}
}
else
{
printf("ERROR %s, unable to get drive layout from this drive\n", (LPCSTR) GetLastErrorString() );
continue;
}
}
}
void ReiserFsPartition::Autodetect( int iMaxDrive, LPFNFoundPartition lpCallback, LPVOID lpContext )
{
DISK_GEOMETRY dg;
LayoutBlock layout;
for( int iDrive = 0; iDrive < 10; iDrive++ )
{
if( !m_pDrive->Open(iDrive) )
continue;
//printf("Testing drive %d\n", iDrive );
#ifdef SUPPORT_WINDOWS_XP_PARTITIONS
if( m_pDrive->GetDriveGeometryEx( (DISK_GEOMETRY_EX*) layout.getData(), layout.getSize() ) )
{
DISK_GEOMETRY_EX* pDG = (DISK_GEOMETRY_EX*) layout.getData();
m_BytesPerSector = pDG->Geometry.BytesPerSector;
}
else
#endif
if( m_pDrive->GetDriveGeometry(&dg) )
{
m_BytesPerSector = dg.BytesPerSector;
}
else
{
printf("ERROR %s, unable to get drive geometry from this drive\n", (LPCSTR) GetLastErrorString() );
continue;
}
memset( layout.getData(), 0, layout.getSize() );
#ifdef SUPPORT_WINDOWS_XP_PARTITIONS
if( m_pDrive->GetDriveLayoutEx(layout.getData(), layout.getSize()) )
{
PDRIVE_LAYOUT_INFORMATION_EX pLI = (PDRIVE_LAYOUT_INFORMATION_EX)layout.getData();
for( DWORD iPartition = 0; iPartition < pLI->PartitionCount; iPartition++ )
{
m_PartitionStartingOffset = pLI->PartitionEntry[iPartition].StartingOffset.QuadPart;
if( CheckReiserFsPartition() )
{
if( lpCallback )
{
static char szDriveLetters[] = "abcdefghijklmnopqrstuvwxyz";
lpCallback( PString( 0, "/dev/hd%c%d", szDriveLetters[iDrive], iPartition ), lpContext );
}
else
{
printf( "Drive %d, Partition %d is a ReiserFS\n",iDrive, iPartition );
printf( "Partition Size: %" FMT_QWORD " Bytes (%.2f MB)\n",
pLI->PartitionEntry[iPartition].PartitionLength.QuadPart,
PBytesInMBytes(pLI->PartitionEntry[iPartition].PartitionLength.QuadPart) );
}
}
}
}
else
#endif
if( m_pDrive->GetDriveLayout(layout.getData(), layout.getSize()) )
{
PDRIVE_LAYOUT_INFORMATION pLI = (PDRIVE_LAYOUT_INFORMATION)layout.getData();
for( DWORD iPartition = 0; iPartition < pLI->PartitionCount; iPartition++ )
{
m_PartitionStartingOffset = pLI->PartitionEntry[iPartition].StartingOffset.QuadPart;
if( CheckReiserFsPartition() )
{
if( lpCallback )
{
static char szDriveLetters[] = "abcdefghijklmnopqrstuvwxyz";
lpCallback( PString( 0, "/dev/hd%c%d", szDriveLetters[iDrive], iPartition ), lpContext );
}
else
{
printf( "Drive %d, Partition %d is a ReiserFS\n",iDrive, iPartition );
printf( "Partition Size: %" FMT_QWORD " Bytes (%.2f MB)\n",
pLI->PartitionEntry[iPartition].PartitionLength.QuadPart,
PBytesInMBytes(pLI->PartitionEntry[iPartition].PartitionLength.QuadPart) );
}
}
}
}
else
{
printf("ERROR %s, unable to get drive layout from this drive\n", (LPCSTR) GetLastErrorString() );
continue;
}
}
}
bool ReiserFsPartition::Open( int iDrive, int iPartition )
{
if( iDrive == USE_BACKUP_FILENAME )
{
delete m_pDrive;
m_pDrive = new PSimulatedDriveFromBackupFile(g_szUseSpecificDevice);
}
if( !m_pDrive->Open(iDrive) )
{
printf("ERROR %s, unable to open drive %d\n", (LPCSTR) GetLastErrorString(), iDrive );
return false;
}
DISK_GEOMETRY dg;
LayoutBlock layout;
#ifdef SUPPORT_WINDOWS_XP_PARTITIONS
if( m_pDrive->GetDriveGeometryEx( (DISK_GEOMETRY_EX*) layout.getData(), layout.getSize()) )
{
DISK_GEOMETRY_EX* pDG = (DISK_GEOMETRY_EX*) layout.getData();
m_BytesPerSector = pDG->Geometry.BytesPerSector;
}
else
#endif
if( m_pDrive->GetDriveGeometry(&dg) )
{
m_BytesPerSector = dg.BytesPerSector;
}
else
{
printf("ERROR %s, unable to get drive geometry from this drive\n", (LPCSTR) GetLastErrorString() );
return false;
}
memset( layout.getData(), 0, layout.getSize() );
#ifdef SUPPORT_WINDOWS_XP_PARTITIONS
if( m_pDrive->GetDriveLayoutEx(layout.getData(), layout.getSize()) )
{
printf("Got newstyle partition information, assuming Windows XP\n" );
PDRIVE_LAYOUT_INFORMATION_EX pLI = (PDRIVE_LAYOUT_INFORMATION_EX)layout.getData();
if( iPartition < 0 || iPartition >= (int) pLI->PartitionCount )
{
printf("ERROR, drive only has partitions [0..%d]\n", pLI->PartitionCount );
return false;
}
m_PartitionStartingOffset = pLI->PartitionEntry[iPartition].StartingOffset.QuadPart;
}
else
#endif
if( m_pDrive->GetDriveLayout(layout.getData(), layout.getSize()) )
{
PDRIVE_LAYOUT_INFORMATION pLI = (PDRIVE_LAYOUT_INFORMATION)layout.getData();
if( iPartition < 0 || iPartition >= (int) pLI->PartitionCount )
{
printf("ERROR, drive only has partitions [0..%d]\n", pLI->PartitionCount );
return false;
}
m_PartitionStartingOffset = pLI->PartitionEntry[iPartition].StartingOffset.QuadPart;
}
else
{
printf("ERROR %s, unable to get drive layout from this drive\n", (LPCSTR) GetLastErrorString() );
return false;
}
INT64 diskoffset = (m_PartitionStartingOffset + REISERFS_DISK_OFFSET_IN_BYTES);
BYTE* lpbMemory = new BYTE[ (DWORD)( m_BytesPerSector*2 ) ];
if( !m_pDrive->ReadAbsolute(lpbMemory, (DWORD) m_BytesPerSector, diskoffset ) )
{
printf("ERROR %s, unable to read ReiserFS superblock\n", (LPCSTR) GetLastErrorString() );
return false;
}
LPREISERFS_SUPER_BLOCK p = (LPREISERFS_SUPER_BLOCK) lpbMemory;
if( stricmp(p->s_magic,REISERFS_SUPER_MAGIC_STRING) )
{
if( stricmp(p->s_magic,REISER2FS_SUPER_MAGIC_STRING) &&
stricmp(p->s_magic,REISER3FS_SUPER_MAGIC_STRING) )
{
printf("ERROR, doesn't seem to be a ReiserFS partition (magic string invalid)\n" );
return false;
}
else
{
dwTypeDirect = (DWORD) 2;
dwTypeIndirect = (DWORD) 1;
}
}
else
{
dwTypeDirect = (DWORD) -1;
dwTypeIndirect = (DWORD) -2;
}
memcpy(&m_sb,p,sizeof(REISERFS_SUPER_BLOCK));
// { // code to dump a directory item
// BYTE bMemory[559];
// //FILE* fp = fopen("T:\\dir\\8211.007.dat","rb");
// FILE* fp = fopen(TARGETDIR "dir\\10708.004.dat","rb");
// fread(bMemory,1,103,fp);
// bMemory[103] = 0;
// fclose(fp);
// int dh_offset = 0;
// int dh_strpos = 103;
// int i = 0;
//
// while( dh_offset < dh_strpos )
// {
// printf(" ----------------- %d --------------------\n", i++ );
// REISERFS_DIRECTORY_HEAD* pDH = (REISERFS_DIRECTORY_HEAD*) (bMemory+dh_offset);
//
// printf(" deh_offset = %d\n", pDH->deh_offset);
// printf(" deh_dir_id = %d\n", pDH->deh_dir_id);
// printf(" deh_objectid = %d\n", pDH->deh_objectid);
// printf(" deh_location = %d\n", (int)pDH->deh_location);
// printf(" deh_state = %d\n", pDH->deh_state);
// printf(" name='%s'\n",bMemory+pDH->deh_location);
// printf("\n");
// (bMemory+pDH->deh_location)[0] = 0;
// dh_strpos = pDH->deh_location;
// dh_offset += sizeof(REISERFS_DIRECTORY_HEAD);
//
// }
// }
//
//
// m_dwBitmapSize = p->s_blocksize * p->s_bmap_nr;
// m_lpbBitmap = new BYTE[m_dwBitmapSize];
// if( !m_lpbBitmap )
// {
// printf("ERROR, unable to allocate %d bytes for bitmap information\n", m_dwBitmapSize );
// return false;
// }
//
//
// // read the whole bitmap in memory. The bitmap format is...well...weird.
// // The first block is at (REISERFS_DISK_OFFSET_IN_BYTES + p->s_blocksize)
// // all following blocks are at (8*p->s_blocksize*i)
//
// INT64 iBitmapBlock = (m_pi.StartingOffset.QuadPart + REISERFS_DISK_OFFSET_IN_BYTES + p->s_blocksize) / m_dg.BytesPerSector;
//
// // read first block
// if( m_pDrive->ReadSector(m_lpbBitmap,p->s_blocksize,iBitmapBlock) )
// {
// for( int iBlock = 1; iBlock < p->s_bmap_nr; iBlock++ )
// {
// INT64 faktor;
// INT64 offset = p->s_blocksize;
// offset *= offset;
// faktor = 8;
// offset *= faktor;
// faktor = iBlock;
// offset *= faktor;
// offset += m_pi.StartingOffset.QuadPart;
// offset /= m_dg.BytesPerSector;
// m_pDrive->ReadSector(m_lpbBitmap+(iBlock*p->s_blocksize),p->s_blocksize,offset);
// }
// }
//printf("p->s_root_block=%d\n", p->s_root_block );
// code to dump the whole directory structure
//DumpBlock(p->s_root_block,0);
// static REISERFS_CPU_KEY rootkey = { 1, 2, 1, 500 };
//
///*
//~~> dir_id = 2
//~~> objectid = 15
//~~> location = 422
//~~> state = 4
//~~> name = 'boot'
//*/
//
// static REISERFS_CPU_KEY bootkey = { 2, 17, 1, 500 };
// static REISERFS_CPU_KEY usrkey = { 2, 137, 1, 500 };
// static REISERFS_CPU_KEY includekey = { 79249, 80823, 1, 500 };
// static REISERFS_CPU_KEY filestat = { 80823, 80824, 1, -1 };
//DWORD BlockNumber = FindBlockFromKey(&filestat,p->s_root_block);
return true;
}
void WINAPI ListDirCallback(ReiserFsPartition* partition,
REISERFS_CPU_KEY* lpKey, LPBYTE lpbMemory,
int nSize, void* lpContext )
{
PList* pDirectory = (PList*) lpContext;
int dh_offset = 0;
int dh_strpos = nSize;
int i = 0, dh_strlen;
CHAR szTempBuffer[512];
while( dh_offset < dh_strpos )
{
REISERFS_DIRECTORY_HEAD* pDH = (REISERFS_DIRECTORY_HEAD*) (lpbMemory+dh_offset);
dh_strlen = dh_strpos-pDH->deh_location;
memcpy(szTempBuffer, lpbMemory+pDH->deh_location, dh_strlen);
szTempBuffer[dh_strlen] = 0;
pDirectory->AddTail( new ReiserFsFileInfo(pDH,szTempBuffer) );
dh_strpos = pDH->deh_location;
dh_offset += sizeof(REISERFS_DIRECTORY_HEAD);
}
}
void WINAPI GetFileStat(ReiserFsPartition* partition, REISERFS_CPU_KEY* lpKey, LPBYTE lpbMemory, int nSize, void* lpContext )
{
ReiserFsFileInfo* pFile = (ReiserFsFileInfo*) lpContext;
if( nSize == sizeof(REISERFS_STAT2) )
{
pFile->m_stat = *(REISERFS_STAT2*) lpbMemory;
}
else if( nSize == sizeof(REISERFS_STAT1) )
{
REISERFS_STAT1* v1 = (REISERFS_STAT1*) lpbMemory;
pFile->m_stat.sd_mode = v1->sd_mode;
pFile->m_stat.sd_nlink = v1->sd_nlink;
pFile->m_stat.sd_uid = v1->sd_uid;
pFile->m_stat.sd_gid = v1->sd_gid;
pFile->m_stat.sd_size = v1->sd_size;
pFile->m_stat.sd_atime = v1->sd_atime;
pFile->m_stat.sd_mtime = v1->sd_mtime;
pFile->m_stat.sd_ctime = v1->sd_ctime;
pFile->m_stat.u.sd_rdev = v1->u.sd_rdev;
}
else assert(false);
}
typedef struct
{
FILE* fp;
PString* pString;
ICreateFileInfo* pCFI;
INT64 FileSize;
} GETFILEINDIRECTCONTEXT;
void WINAPI GetFileIndirect(ReiserFsPartition* partition, REISERFS_CPU_KEY* lpKey, LPBYTE lpbMemory, int nSize, void* lpContext )
{
GETFILEINDIRECTCONTEXT* pc = (GETFILEINDIRECTCONTEXT*) lpContext;
DWORD dwBlockSize = partition->m_dwBlockSize;
LPBYTE bMemory = new BYTE[dwBlockSize];
assert(bMemory);
long* pBlocks = (long*) lpbMemory;
int count = nSize / 4;
INT64 SizeLeft = pc->FileSize;
for( int index = 0; index < count; index++ )
{
long block2 = pBlocks[index];
if(partition->Read(bMemory,dwBlockSize,block2) )
{
if( SizeLeft >= dwBlockSize )
{
//printf("found %d bytes in indirect item at block %d\n", dwBlockSize, block2 );
//putchar('.');
if( pc->fp )
{
fwrite(bMemory,1,dwBlockSize,pc->fp);
}
else if( pc->pCFI )
{
pc->pCFI->Write(bMemory, dwBlockSize);
}
else
{
pc->pString->Append((LPSTR)bMemory,dwBlockSize);
}
SizeLeft -= dwBlockSize;
}
else
{
//printf("found %d bytes in indirect item at block %d\n", (int)SizeLeft, block2 );
//putchar('.');
if( pc->fp )
{
fwrite(bMemory,1,(int)SizeLeft,pc->fp);
}
else if( pc->pCFI )
{
pc->pCFI->Write(bMemory, (DWORD) SizeLeft);
}
else
{
pc->pString->Append((LPSTR)bMemory,(int)SizeLeft);
}
break;
}
}
}
delete bMemory;
pc->FileSize=SizeLeft;
}
void WINAPI GetFileDirect(ReiserFsPartition* partition, REISERFS_CPU_KEY* lpKey, LPBYTE lpbMemory, int nSize, void* lpContext )
{
GETFILEINDIRECTCONTEXT* pc = (GETFILEINDIRECTCONTEXT*) lpContext;
int toWrite=pc->FileSize>nSize?nSize:(int)pc->FileSize;
pc->FileSize-=toWrite;
//putchar('.');
if( pc->fp )
{
fwrite(lpbMemory,1,toWrite,pc->fp);
}
else if( pc->pCFI )
{
pc->pCFI->Write(lpbMemory, (DWORD) toWrite);
}
else
{
pc->pString->Append((LPSTR)lpbMemory,toWrite);
}
}
PString ReiserFsPartition::GetFileAsString(ReiserFsFileInfo* pFile)
{
GETFILEINDIRECTCONTEXT context;
ZeroMemory(&context, sizeof(context));
REISERFS_CPU_KEY key;
PString strResult;
BOOL bSuccess = FALSE;
// get indirect parts
context.fp = NULL;
context.pString = &strResult;
context.FileSize = pFile->m_stat.sd_size;
if( pFile->m_stat.sd_size > 500 )
{
key.k_dir_id = pFile->m_deh.deh_dir_id;
key.k_objectid = pFile->m_deh.deh_objectid;
key.k_offset = 1;
key.k_type = dwTypeIndirect;
ParseTreeRecursive( &bSuccess, &key, m_sb.s_root_block, &::GetFileIndirect, &context );
}
// get direct parts
context.fp = NULL;
context.pString = &strResult;
// context.FileSize = pFile->m_stat.sd_size; // do not set file size again
key.k_dir_id = pFile->m_deh.deh_dir_id;
key.k_objectid = pFile->m_deh.deh_objectid;
key.k_offset = 1;
key.k_type = -1;
DEBUGTRACE(("READ SYMBOLIC LINK !!!! %s", (LPCSTR) pFile->m_strName ))
ParseTreeRecursive( &bSuccess, &key, m_sb.s_root_block, &::GetFileDirect, &context );
return strResult;
}
bool ReiserFsPartition::CopyFilesRecursive( PList* Directory, LPCSTR lpszName )
{
REISERFS_CPU_KEY key = { 1, 2, 1, 500 };
BOOL bSuccess;
ENUMERATE( Directory, ReiserFsFileInfo, pFile )
{
if( !strcmp(pFile->m_strName,".") ||
!strcmp(pFile->m_strName,"..") )
continue;
key.k_dir_id = pFile->m_deh.deh_dir_id;
key.k_objectid = pFile->m_deh.deh_objectid;
key.k_offset = 0;
key.k_type = 0;
ParseTreeRecursive( &bSuccess, &key, m_sb.s_root_block, &::GetFileStat, pFile );
// if( !bSuccess )
// {
// printf("ERROR, unable to stat %s, ignoring\n", (char*) pFile->m_strName );
// continue;
// }
PString strLocalPath( 0, "%s" SLASH_STRING "%s", lpszName, (char*) pFile->m_strName );
if( S_ISDIR(pFile->m_stat.sd_mode) )
{
printf("Directory %s\n", (char*) strLocalPath );
if( !MakeSurePathExists(strLocalPath) )
continue;
key.k_dir_id = pFile->m_deh.deh_dir_id;
key.k_objectid = pFile->m_deh.deh_objectid;
key.k_offset = 1;
key.k_type = 500;
PList Subdir;
bSuccess = FALSE;
ParseTreeRecursive( &bSuccess, &key, m_sb.s_root_block, &::ListDirCallback, &Subdir );
CopyFilesRecursive( &Subdir, strLocalPath );
}
else if( pFile->isSymlink() )
{
printf("Warning, link '%s' ignored\n", (const char*) strLocalPath );
}
else
{
printf("File %s (%"FMT_QWORD" Bytes)\n", (const char*) strLocalPath, pFile->m_stat.sd_size );
FILE* fp = fopen( strLocalPath,"wb");
if( fp != NULL )
{
GETFILEINDIRECTCONTEXT context;
ZeroMemory(&context, sizeof(context));
// get indirect parts
context.fp = fp;
context.FileSize = pFile->m_stat.sd_size;
key.k_dir_id = pFile->m_deh.deh_dir_id;
key.k_objectid = pFile->m_deh.deh_objectid;
key.k_offset = 1; // perhaps, file offset ???
key.k_type = dwTypeIndirect;
ParseTreeRecursive( &bSuccess, &key, m_sb.s_root_block, &::GetFileIndirect, &context );
// get direct parts
context.fp = fp;
// context.FileSize = pFile->m_stat.sd_size; // do not set file size again
key.k_dir_id = pFile->m_deh.deh_dir_id;
key.k_objectid = pFile->m_deh.deh_objectid;
key.k_offset = 1;
key.k_type = dwTypeDirect;
ParseTreeRecursive( &bSuccess, &key, m_sb.s_root_block, &::GetFileDirect, &context );
fclose(fp);
SetUnixFileTime(strLocalPath, pFile );
}
else
printf("ERROR, unable to open local file %s\n", (char*) strLocalPath );
}
}
return true;
}
bool ReiserFsPartition::GetFile( LPCSTR lpszReiserFsName, LPCSTR lpszLocalName, bool bRecurseSubdirectories )
{
// get array of tokens
PList Tokens;
PString strTemp(lpszReiserFsName);
char* token = strtok( strTemp, "/" );
while( token != NULL )
{
Tokens.AddTail( new PString(token) );
token = strtok( NULL, "/" );
}
if( !Tokens.m_lCount )
{
printf("ERROR, you must specify a filename\n" );
return false;
}
// find root directory first
REISERFS_CPU_KEY key = { 1, 2, 1, 500 };
// find root directory
BOOL bSuccess = FALSE;
PList Directory;
ParseTreeRecursive( &bSuccess, &key, m_sb.s_root_block, &::ListDirCallback, &Directory );
ENUMERATE( &Tokens, PString, pToken )
{
int found = 0;
ENUMERATE( &Directory, ReiserFsFileInfo, pFile )
{
if( strcmp( pFile->m_strName, *pToken ) == 0 )
{
// read file|dir stat
bSuccess = FALSE;
key.k_dir_id = pFile->m_deh.deh_dir_id;
key.k_objectid = pFile->m_deh.deh_objectid;
key.k_offset = 0;
key.k_type = 0;
DEBUGTRACE(("**** BEGIN GETFILESTAT\n" ))
ParseTreeRecursive( &bSuccess, &key, m_sb.s_root_block, &::GetFileStat, pFile );
DEBUGTRACE(("**** END GETFILESTAT\n" ))
if( S_ISDIR(pFile->m_stat.sd_mode) )
{
key.k_dir_id = pFile->m_deh.deh_dir_id;
key.k_objectid = pFile->m_deh.deh_objectid;
key.k_offset = 1;
key.k_type = 500;
Directory.DeleteContents();
bSuccess = FALSE;
ParseTreeRecursive( &bSuccess, &key, m_sb.s_root_block, &::ListDirCallback, &Directory );
found = 1;
if( pToken->m_pNext == 0 )
{
MakeSurePathExists(lpszLocalName);
return CopyFilesRecursive( &Directory, lpszLocalName );
}
break;
}
else if( pFile->isSymlink() )
{
PString strData(GetFileAsString(pFile) );
if( !IsEmptyString(strData) )
{
token = strtok( strData, "/" );
PString* pInsertPos = pToken;
while( token != NULL )
{
PString* pNewToken = new PString(token);
Tokens.InsertAfter( pNewToken, pInsertPos );
pInsertPos = pNewToken;
token = strtok( NULL, "/" );
}
found = 1;
break;
}
else
{
return false;
}
}
else if( pToken->m_pNext )
{
printf("ERROR, directory '%s' contains file or link\n", lpszReiserFsName );
return false;
}
else
{
printf("found\nRetrieving a total of %"FMT_QWORD" bytes\n", pFile->m_stat.sd_size );
FILE* fp = fopen( lpszLocalName,"wb");
if( fp != NULL )
{
GETFILEINDIRECTCONTEXT context;
ZeroMemory(&context, sizeof(context));
// get indirect parts
context.fp = fp;
context.FileSize = pFile->m_stat.sd_size;
key.k_dir_id = pFile->m_deh.deh_dir_id;
key.k_objectid = pFile->m_deh.deh_objectid;
key.k_offset = 1; // perhaps, file offset ???
key.k_type = dwTypeIndirect;
ParseTreeRecursive( &bSuccess, &key, m_sb.s_root_block, &::GetFileIndirect, &context );
// get direct parts
context.fp = fp;
// context.FileSize = pFile->m_stat.sd_size; // do not set file size again
key.k_dir_id = pFile->m_deh.deh_dir_id;
key.k_objectid = pFile->m_deh.deh_objectid;
key.k_offset = 1;
key.k_type = dwTypeDirect;
ParseTreeRecursive( &bSuccess, &key, m_sb.s_root_block, &::GetFileDirect, &context );
fclose(fp);
SetUnixFileTime(lpszLocalName, pFile );
return true;
}
printf("ERROR, unable to open local file %s\n", lpszLocalName );
return false;
}
}
}
if( !found )
{
printf("ERROR, directory '%s' not found\n", lpszReiserFsName );
return false;
}
token = strtok( NULL, "/" );
}
return false;
}
bool ReiserFsPartition::GetFileEx( LPCSTR lpszReiserFsName, ICreateFileInfo* pCFI )
{
// get array of tokens
PList Tokens;
PString strTemp(lpszReiserFsName);
char* token = strtok( strTemp, "/" );
while( token != NULL )
{
Tokens.AddTail( new PString(token) );
token = strtok( NULL, "/" );
}
if( !Tokens.m_lCount )
{
printf("ERROR, you must specify a filename\n" );
return false;
}
// find root directory first
REISERFS_CPU_KEY key = { 1, 2, 1, 500 };
// find root directory
BOOL bSuccess = FALSE;
PList Directory;
ParseTreeRecursive( &bSuccess, &key, m_sb.s_root_block, &::ListDirCallback, &Directory );
ENUMERATE( &Tokens, PString, pToken )
{
int found = 0;
ENUMERATE( &Directory, ReiserFsFileInfo, pFile )
{
if( strcmp( pFile->m_strName, *pToken ) == 0 )
{
// read file|dir stat
bSuccess = FALSE;
key.k_dir_id = pFile->m_deh.deh_dir_id;
key.k_objectid = pFile->m_deh.deh_objectid;
key.k_offset = 0;
key.k_type = 0;
DEBUGTRACE(("**** BEGIN GETFILESTAT\n" ))
ParseTreeRecursive( &bSuccess, &key, m_sb.s_root_block, &::GetFileStat, pFile );
DEBUGTRACE(("**** END GETFILESTAT\n" ))
if( S_ISDIR(pFile->m_stat.sd_mode) )
{
key.k_dir_id = pFile->m_deh.deh_dir_id;
key.k_objectid = pFile->m_deh.deh_objectid;
key.k_offset = 1;
key.k_type = 500;
Directory.DeleteContents();
bSuccess = FALSE;
ParseTreeRecursive( &bSuccess, &key, m_sb.s_root_block, &::ListDirCallback, &Directory );
found = 1;
if( pToken->m_pNext == 0 )
{
return false;
}
break;
}
else if( pFile->isSymlink() )
{
PString strData(GetFileAsString(pFile) );
if( !IsEmptyString(strData) )
{
token = strtok( strData, "/" );
PString* pInsertPos = pToken;
while( token != NULL )
{
PString* pNewToken = new PString(token);
Tokens.InsertAfter( pNewToken, pInsertPos );
pInsertPos = pNewToken;
token = strtok( NULL, "/" );
}
found = 1;
break;
}
else
{
// this is an empty link
pCFI->SetFileSize(0);
return true;
}
}
else if( pToken->m_pNext )
{
printf("ERROR, directory '%s' contains file or link\n", lpszReiserFsName );
return false;
}
else
{
GETFILEINDIRECTCONTEXT context;
ZeroMemory(&context, sizeof(context));
// get indirect parts
context.pCFI = pCFI;
context.FileSize = pFile->m_stat.sd_size;
key.k_dir_id = pFile->m_deh.deh_dir_id;
key.k_objectid = pFile->m_deh.deh_objectid;
pCFI->SetFileSize(context.FileSize);
key.k_offset = 1; // perhaps, file offset ???
key.k_type = dwTypeIndirect;
ParseTreeRecursive( &bSuccess, &key, m_sb.s_root_block, &::GetFileIndirect, &context );
// get direct parts
context.pCFI = pCFI;
//context.FileSize = pFile->m_stat.sd_size;
key.k_dir_id = pFile->m_deh.deh_dir_id;
key.k_objectid = pFile->m_deh.deh_objectid;
key.k_offset = 1;
key.k_type = dwTypeDirect;
ParseTreeRecursive( &bSuccess, &key, m_sb.s_root_block, &::GetFileDirect, &context );
return true;
}
}
}
if( !found )
{
printf("ERROR, directory '%s' not found\n", lpszReiserFsName );
return false;
}
token = strtok( NULL, "/" );
}
return false;
}
bool ReiserFsPartition::ListDir( PList* pDirectory, LPCSTR lpszDirectory )
{
PList Tokens;
PString strTemp(lpszDirectory);
char* token = strtok( strTemp, "/" );
while( token != NULL )
{
Tokens.AddTail( new PString(token) );
token = strtok( NULL, "/" );
}
// find root directory first
REISERFS_CPU_KEY key = { 1, 2, 1, 500 };
// find root directory
BOOL bSuccess = FALSE;
ParseTreeRecursive( &bSuccess, &key, m_sb.s_root_block, &::ListDirCallback, pDirectory );
ENUMERATE( &Tokens, PString, pToken )
{
int found = 0;
char* token = *pToken;
ENUMERATE( pDirectory, ReiserFsFileInfo, pFile )
{
if( strcmp( pFile->m_strName, token ) == 0 )
{
// read file|dir stat
key.k_dir_id = pFile->m_deh.deh_dir_id;
key.k_objectid = pFile->m_deh.deh_objectid;
key.k_offset = 0;
key.k_type = 0;
bSuccess = FALSE;
ParseTreeRecursive( &bSuccess, &key, m_sb.s_root_block, &::GetFileStat, pFile );
if( S_ISDIR(pFile->m_stat.sd_mode) )
{
key.k_dir_id = pFile->m_deh.deh_dir_id;
key.k_objectid = pFile->m_deh.deh_objectid;
key.k_offset = 1;
key.k_type = 500;
pDirectory->DeleteContents();
bSuccess = FALSE;
ParseTreeRecursive( &bSuccess, &key, m_sb.s_root_block, &::ListDirCallback, pDirectory );
found = 1;
break;
}
else if( pFile->isSymlink() )
{
PString strData(GetFileAsString(pFile) );
if( !IsEmptyString(strData) )
{
token = strtok( strData, "/" );
PString* pInsertPos = pToken;
while( token != NULL )
{
PString* pNewToken = new PString(token);
Tokens.InsertAfter( pNewToken, pInsertPos );
pInsertPos = pNewToken;
token = strtok( NULL, "/" );
}
found = 1;
break;
}
else
{
return false;
}
}
else
{
printf("ERROR, Directory '%s' contains file or link '%s'\n", lpszDirectory, token );
pDirectory->DeleteContents();
return false;
}
}
}
if( !found )
{
printf("ERROR, directory '%s' not found\n", lpszDirectory );
pDirectory->DeleteContents();
return false;
}
}
if( pDirectory->m_lCount )
{
// populate statistics
int count = 0;
ENUMERATE( pDirectory, ReiserFsFileInfo, pFile )
{
if( count++ < 2 )
continue;
BOOL bSuccess = FALSE;
REISERFS_CPU_KEY key;
key.k_dir_id = pFile->m_deh.deh_dir_id;
key.k_objectid = pFile->m_deh.deh_objectid;
key.k_offset = 0;
key.k_type = 0;
ParseTreeRecursive( &bSuccess, &key, m_sb.s_root_block, &::GetFileStat, pFile );
}
return true;
}
return false;
}
LPBYTE ReiserFsPartition::GetBlock( DWORD BlockNumber )
{
ENUMERATE(&m_BlockCache,ReiserFsBlock,p)
{
if( p->m_dwBlockNumber == BlockNumber )
return p->m_lpbMemory;
}
LPBYTE lpbMemory = new BYTE[m_dwBlockSize];
BOOL bSuccess;
if( m_Metafile.m_pDataFile )
{
bSuccess = m_Metafile.Read( lpbMemory, m_dwBlockSize, BlockNumber );
}
else
{
bSuccess = Read( lpbMemory, m_dwBlockSize, BlockNumber );
}
if( bSuccess )
{
m_BlockCache.AddHead(new ReiserFsBlock(BlockNumber, lpbMemory));
return lpbMemory;
}
printf("*** FATAL ERROR, unable to read block %d\n", BlockNumber );
return NULL;
}
LPBYTE ReiserFsPartition::GetBlockUncached( DWORD BlockNumber )
{
ENUMERATE(&m_BlockCache,ReiserFsBlock,p)
{
if( p->m_dwBlockNumber == BlockNumber )
return NULL;
}
LPBYTE lpbMemory = new BYTE[m_dwBlockSize];
Read( lpbMemory, m_dwBlockSize, BlockNumber );
m_BlockCache.AddHead(new ReiserFsBlock(BlockNumber, lpbMemory));
return lpbMemory;
}
BOOL ReiserFsPartition::PrepareForRestore( const char* pszFilename )
{
return m_Metafile.Open( this, pszFilename );
}
void ReiserFsPartition::Backup( const char* pszFilename )
{
FILE* fpData = fopen(pszFilename,"wb");
if( fpData != NULL )
{
PString strIndexName( 0, "%s.index", pszFilename );
FILE* fpIndex = fopen(strIndexName,"wb");
if( fpIndex != NULL )
{
fwrite(&m_sb,sizeof(REISERFS_SUPER_BLOCK),1,fpIndex);
BackupTreeRecursive(fpData,fpIndex,m_sb.s_root_block);
printf("done.\n");
fclose(fpIndex);
}
else printf("ERROR, unable to open file '%s' for writing\n", (char*)strIndexName );
printf("done.\n");
fclose(fpData);
}
else printf("ERROR, unable to open file '%s' for writing\n", pszFilename );
}
void ReiserFsPartition::BackupTreeRecursive( FILE* fpData, FILE* fpIndex, int nBlock )
{
BYTE* bMemory = GetBlockUncached( nBlock );
if( !bMemory )
{
// assume this block has already been written
return;
}
// write block header
fwrite(&nBlock,sizeof(int),1,fpIndex);
// write block data
fwrite(bMemory,m_dwBlockSize,1,fpData);
//putchar('.');
LPREISERFS_BLOCK_HEAD pH = (LPREISERFS_BLOCK_HEAD)bMemory;
if( pH->blk_level != 1 )
{
LPBYTE lpbHeaderData = bMemory+sizeof(REISERFS_BLOCK_HEAD);
LPBYTE lpbPointerData = bMemory+sizeof(REISERFS_BLOCK_HEAD)+(pH->blk_nr_item*sizeof(REISERFS_KEY));
int i;
for( i = 0; i < pH->blk_nr_item; i++ )
{
REISERFS_KEY* key = (REISERFS_KEY*)(lpbHeaderData+i*sizeof(REISERFS_KEY));
REISERFS_CPU_KEY cpukey;
cpukey.k_dir_id = key->k_dir_id;
cpukey.k_objectid = key->k_objectid;
cpukey.k_type = (int) key->u.k_offset_v1.k_uniqueness; // WAS: v2
cpukey.k_offset = key->u.k_offset_v1.k_offset;
REISERFS_DISK_KEY* pointer = (REISERFS_DISK_KEY*) (lpbPointerData+i*sizeof(REISERFS_DISK_KEY));
BackupTreeRecursive( fpData, fpIndex, pointer->dc_block_number );
}
REISERFS_DISK_KEY* pointer = (REISERFS_DISK_KEY*) (lpbPointerData+i*sizeof(REISERFS_DISK_KEY));
BackupTreeRecursive( fpData, fpIndex, pointer->dc_block_number );
}
}
void ReiserFsPartition::DumpTree()
{
DumpTreeRecursive(m_sb.s_root_block,0);
}
void ReiserFsPartition::DumpTreeRecursive( int nBlock, int nIndent )
{
CHAR szIndent[64];
if( nIndent )
memset(szIndent,'\t',nIndent);
szIndent[nIndent] = 0;
BYTE* bMemory = GetBlock( nBlock );
if( !bMemory ) return;
printf("%s---------------- BEGIN BLOCK %d ---------------\n", szIndent, nBlock );
LPREISERFS_BLOCK_HEAD pH = (LPREISERFS_BLOCK_HEAD)bMemory;
if( pH->blk_level == 1 )
{
printf("%sIS LEAF BLOCK (%d ITEMS)\n", szIndent, pH->blk_nr_item );
LPBYTE lpbHeaderData = bMemory+sizeof(REISERFS_BLOCK_HEAD);
bool result = false;
for( int i = 0; i < pH->blk_nr_item; i++ )
{
LPREISERFS_ITEM_HEAD iH = (LPREISERFS_ITEM_HEAD)lpbHeaderData;
REISERFS_KEY* key = &(iH->ih_key);
REISERFS_CPU_KEY cpukey;
cpukey.k_dir_id = key->k_dir_id;
cpukey.k_objectid = key->k_objectid;
if( iH->ih_version == ITEM_VERSION_1 )
{
cpukey.k_type = iH->ih_key.u.k_offset_v1.k_uniqueness;
cpukey.k_offset = iH->ih_key.u.k_offset_v1.k_offset;
}
else if ( iH->ih_version == ITEM_VERSION_2 )
{
cpukey.k_type = (int) iH->ih_key.u.k_offset_v2.k_type;
cpukey.k_offset = iH->ih_key.u.k_offset_v2.k_offset;
}
else assert(false);
if( cpukey.k_type == 500 )
{
printf("%s(%d,%d,%"FMT_QWORD",%d) DIRECTORY:\n", szIndent, cpukey.k_dir_id, cpukey.k_objectid, cpukey.k_offset, cpukey.k_type );
// given:
// SIZE_OF_BLOCK size of the item on disk.
// DATA_OF_BLOCK data of the directory item on disk. You should allocate one
// byte more and make sure the buffer is zero-terminated for the code below to work.
int dh_offset = 0;
int dh_strpos = iH->ih_item_len;
int i = 0, dh_strlen;
LPBYTE lpbMemory = bMemory + iH->ih_item_location;
CHAR szTempBuffer[512];
while( dh_offset < dh_strpos )
{
REISERFS_DIRECTORY_HEAD* pDH = (REISERFS_DIRECTORY_HEAD*) (lpbMemory+dh_offset);
dh_strlen = dh_strpos-pDH->deh_location;
memcpy(szTempBuffer, lpbMemory+pDH->deh_location, dh_strlen);
szTempBuffer[dh_strlen] = 0;
printf("%s\t(%d,%d,%d,%d,%d)=\"%s\"\n", szIndent,
pDH->deh_offset,
pDH->deh_dir_id,
pDH->deh_objectid,
pDH->deh_location,
(int) pDH->deh_state,
szTempBuffer );
dh_strpos = pDH->deh_location;
dh_offset += sizeof(REISERFS_DIRECTORY_HEAD);
}
}
else if( cpukey.k_type == 0 )
{
int nSize = iH->ih_item_len;
LPBYTE lpbMemory = bMemory + iH->ih_item_location;
REISERFS_STAT2 m_stat;
if( nSize == sizeof(REISERFS_STAT2) )
{
m_stat = *(REISERFS_STAT2*) lpbMemory;
printf("%s(%d,%d,%"FMT_QWORD",%d) STAT2 (%d)\n", szIndent, cpukey.k_dir_id, cpukey.k_objectid, cpukey.k_offset, cpukey.k_type, m_stat.sd_size );
}
else if( nSize == sizeof(REISERFS_STAT1) )
{
printf("%s(%d,%d,%"FMT_QWORD",%d) STAT1 (%d)\n", szIndent, cpukey.k_dir_id, cpukey.k_objectid, cpukey.k_offset, cpukey.k_type, m_stat.sd_size );
REISERFS_STAT1* v1 = (REISERFS_STAT1*) lpbMemory;
m_stat.sd_mode = v1->sd_mode;
m_stat.sd_nlink = v1->sd_nlink;
m_stat.sd_uid = v1->sd_uid;
m_stat.sd_gid = v1->sd_gid;
m_stat.sd_size = v1->sd_size;
m_stat.sd_atime = v1->sd_atime;
m_stat.sd_mtime = v1->sd_mtime;
m_stat.sd_ctime = v1->sd_ctime;
m_stat.u.sd_rdev = v1->u.sd_rdev;
}
else
{
printf("%s(%d,%d,%"FMT_QWORD",%d) UNKNOWN ???\n", szIndent, cpukey.k_dir_id, cpukey.k_objectid, cpukey.k_offset, cpukey.k_type );
}
}
else if( cpukey.k_type == -1 )
{
printf("%s(%d,%d,%"FMT_QWORD",%d) DIRECT\n", szIndent, cpukey.k_dir_id, cpukey.k_objectid, cpukey.k_offset, cpukey.k_type );
}
else if( cpukey.k_type == -2 )
{
printf("%s(%d,%d,%"FMT_QWORD",%d) INDIRECT\n", szIndent, cpukey.k_dir_id, cpukey.k_objectid, cpukey.k_offset, cpukey.k_type );
}
else
{
printf("%s(%d,%d,%"FMT_QWORD",%d) UNKNOWN ???\n", szIndent, cpukey.k_dir_id, cpukey.k_objectid, cpukey.k_offset, cpukey.k_type );
}
lpbHeaderData += sizeof(REISERFS_ITEM_HEAD);
}
}
else
{
int i;
printf("%sIS DATA BLOCK (%d ITEMS)\n", szIndent, pH->blk_nr_item );
LPBYTE lpbHeaderData = bMemory+sizeof(REISERFS_BLOCK_HEAD);
LPBYTE lpbPointerData = bMemory+sizeof(REISERFS_BLOCK_HEAD)+(pH->blk_nr_item*sizeof(REISERFS_KEY));
for( i = 0; i < pH->blk_nr_item; i++ )
{
REISERFS_KEY* key = (REISERFS_KEY*)(lpbHeaderData+i*sizeof(REISERFS_KEY));
REISERFS_CPU_KEY cpukey;
cpukey.k_dir_id = key->k_dir_id;
cpukey.k_objectid = key->k_objectid;
cpukey.k_type = (int) key->u.k_offset_v1.k_uniqueness; // WAS: v2
cpukey.k_offset = key->u.k_offset_v1.k_offset;
REISERFS_DISK_KEY* pointer = (REISERFS_DISK_KEY*) (lpbPointerData+i*sizeof(REISERFS_DISK_KEY));
printf("%s(%d,%d,%"FMT_QWORD",%d)->%d\n", szIndent, cpukey.k_dir_id, cpukey.k_objectid, cpukey.k_offset, cpukey.k_type, pointer->dc_block_number );
DumpTreeRecursive( pointer->dc_block_number, nIndent+1 );
}
REISERFS_DISK_KEY* pointer = (REISERFS_DISK_KEY*) (lpbPointerData+i*sizeof(REISERFS_DISK_KEY));
printf("%s(right)->%d\n", szIndent, pointer->dc_block_number );
DumpTreeRecursive( pointer->dc_block_number, nIndent+1 );
}
printf("%s---------------- END BLOCK %d ---------------\n", szIndent, nBlock );
}
void ReiserFsPartition::ParseTreeRecursive( BOOL* lpbSuccess, REISERFS_CPU_KEY* lpKeyToFind, int nBlock, LPFNReiserFsSearchCallback lpCallback, void* lpContext )
{
m_lpKeyToFind = lpKeyToFind;
m_lpCallback = lpCallback;
m_lpContext = lpContext;
m_nIndent = 0;
DEBUGTRACE(("\nBEGIN ParseTreeRecursive (%ld,%ld,%" FMT_QWORD ",%ld)\n",
lpKeyToFind->k_dir_id,
lpKeyToFind->k_objectid,
lpKeyToFind->k_offset,
lpKeyToFind->k_type ))
*lpbSuccess = IParseTreeRecursive( nBlock );
DEBUGTRACE(("END ParseTreeRecursive\n" ))
}
BOOL ReiserFsPartition::IParseTreeRecursive( int nBlock )
{
BOOL bResult = FALSE;
#ifdef _DEBUG
char szIndent[60];
int nMax = sizeof(szIndent)-1;
nMax = m_nIndent>nMax?nMax:m_nIndent;
memset( szIndent, '\t', nMax );
szIndent[nMax] = 0;
m_nIndent++;
#endif
DEBUGTRACE(("%sBEGIN BLOCK %d -----------------------------\n", szIndent, nBlock ))
if( nBlock == 526541 )
{
DEBUGTRACE(("%sBEGIN BLOCK %d -----------------------------\n", szIndent, nBlock ))
}
BYTE* bMemory = GetBlock(nBlock);
if( !bMemory )
{
bResult = FALSE;
}
else
{
LPREISERFS_BLOCK_HEAD pH = (LPREISERFS_BLOCK_HEAD)bMemory;
if( pH->blk_level == 1 )
{
DEBUGTRACE(("%sANALYZING LEAF BLOCK\n", szIndent ))
LPBYTE lpbHeaderData = bMemory+sizeof(REISERFS_BLOCK_HEAD);
for( int i = 0; i < pH->blk_nr_item; i++ )
{
LPREISERFS_ITEM_HEAD iH = (LPREISERFS_ITEM_HEAD)lpbHeaderData;
REISERFS_KEY* key = &(iH->ih_key);
REISERFS_CPU_KEY cpukey;
cpukey.k_dir_id = key->k_dir_id;
cpukey.k_objectid = key->k_objectid;
if( iH->ih_version == ITEM_VERSION_1 )
{
cpukey.k_type = iH->ih_key.u.k_offset_v1.k_uniqueness;
cpukey.k_offset = iH->ih_key.u.k_offset_v1.k_offset;
}
else if ( iH->ih_version == ITEM_VERSION_2 )
{
cpukey.k_type = (int) iH->ih_key.u.k_offset_v2.k_type;
cpukey.k_offset = iH->ih_key.u.k_offset_v2.k_offset;
}
else assert(false);
int cres = comp_keys_no_offset(m_lpKeyToFind,&cpukey);
if( cres == 0 )
{
DEBUGTRACE(("%s**** CALLBACK ****\n", szIndent ))
m_lpCallback(this, &cpukey, bMemory + iH->ih_item_location, iH->ih_item_len, m_lpContext);
bResult = TRUE;
//goto bailout;
}
else if( cres < 0 )
{
//DEBUGTRACE(("%s**** QUICK TO BAILOUT ****\n", szIndent ))
//goto bailout;
}
lpbHeaderData += sizeof(REISERFS_ITEM_HEAD);
}
}
else
{
DEBUGTRACE(("%sANALYZING TREE BLOCK\n", szIndent ))
LPBYTE lpbHeaderData = bMemory+sizeof(REISERFS_BLOCK_HEAD);
LPBYTE lpbPointerData = bMemory+sizeof(REISERFS_BLOCK_HEAD)+(pH->blk_nr_item*sizeof(REISERFS_KEY));
int i, nLastCres = -1;
bool oldFound = false;
for( i = 0; i < pH->blk_nr_item; i++ )
{
REISERFS_KEY* key = (REISERFS_KEY*)(lpbHeaderData+i*sizeof(REISERFS_KEY));
REISERFS_CPU_KEY cpukey;
cpukey.k_dir_id = key->k_dir_id;
cpukey.k_objectid = key->k_objectid;
cpukey.k_type = (int) key->u.k_offset_v2.k_type;
cpukey.k_offset = (U64) key->u.k_offset_v2.k_offset;
int cres = comp_keys(&cpukey,m_lpKeyToFind);
if( cres == 1 || cres == 0 )
{
REISERFS_DISK_KEY* pointer = (REISERFS_DISK_KEY*) (lpbPointerData+i*sizeof(REISERFS_DISK_KEY));
if( IParseTreeRecursive( pointer->dc_block_number ) )
{
oldFound = true;
}
else
{
if( oldFound )
{
bResult = TRUE;
goto bailout;
}
else if( nLastCres == 1 && cres == 1 )
{
goto bailout;
}
}
}
nLastCres = cres;
}
REISERFS_DISK_KEY* pointer = (REISERFS_DISK_KEY*) (lpbPointerData+i*sizeof(REISERFS_DISK_KEY));
if( IParseTreeRecursive( pointer->dc_block_number ) )
{
bResult = TRUE;
}
}
}
bailout:
DEBUGTRACE(("%sEND BLOCK %d WITH %s -----------------------------\n", szIndent, nBlock, bResult ? "TRUE" : "FALSE" ))
#ifdef _DEBUG
m_nIndent--;
#endif
return bResult;
}
// potential code for bitmap dumiong
// BYTE* pBitmap = m_lpbBitmap;
//
// int BitmapSize = 0x9000;
// int BitmapOffset = 0;
// int iLastBitUsed = -1;
// BYTE bitmap_map[8] = { 1, 2, 4, 8, 16, 32, 64, 128 };
// int iBit = 0;
// while( iBit < BitmapSize )
// {
// if( pBitmap[iBit/8] & bitmap_map[iBit%8] )
// {
// if( iLastBitUsed == -1 )
// iLastBitUsed = iBit;
// }
// else
// {
// // bit is not set
// if( iLastBitUsed != -1 )
// {
// fprintf(fp,"used: %d..%d\r\n", BitmapOffset+iLastBitUsed, BitmapOffset+iBit-1 );
// iLastBitUsed = -1;
// }
// }
// iBit++;
// }
// fclose(fp);
ReiserFsMetafile::ReiserFsMetafile()
{
m_pBlockIndices = NULL;
m_pDataFile = NULL;
}
ReiserFsMetafile::~ReiserFsMetafile()
{
delete m_pBlockIndices;
if( m_pDataFile )
fclose( m_pDataFile );
}
BOOL ReiserFsMetafile::Open( ReiserFsPartition* partition, const char* pszFilename )
{
// read index file first
PString strIndexName( 0, "%s.index", pszFilename );
FILE* fpIndex = fopen(strIndexName,"rb");
if( fpIndex != NULL )
{
// determine file size
fseek(fpIndex,0,SEEK_END);
long filesize = ftell(fpIndex);
fseek(fpIndex,0,SEEK_SET);
if( filesize < sizeof(REISERFS_SUPER_BLOCK) )
{
printf("ERROR, file '%s' too small to be a valid index file, aborting.\n", (char*) strIndexName );
fclose(fpIndex);
return FALSE;
}
fread(&m_Superblock,sizeof(REISERFS_SUPER_BLOCK),1,fpIndex);
m_dwBlocksize = m_Superblock.s_blocksize;
if( partition )
{
partition->m_sb = m_Superblock;
}
long indexsize = filesize - sizeof(REISERFS_SUPER_BLOCK);
m_iNumberOfIndices = (int)(indexsize / sizeof(int));
m_pBlockIndices = new int[m_iNumberOfIndices];
if( !m_pBlockIndices )
{
printf("ERROR, not enough memory to allocate %d bytes for indices, aborting\n", indexsize );
fclose(fpIndex);
return FALSE;
}
fread(m_pBlockIndices,indexsize,1,fpIndex);
fclose(fpIndex);
printf("Read %d indices successfully.\n", m_iNumberOfIndices );
}
else
{
printf("ERROR, unable to open file '%s' for reading\n", (char*)strIndexName );
return FALSE;
}
m_pDataFile = fopen(pszFilename,"rb");
if( m_pDataFile == NULL )
{
printf("ERROR, unable to open file '%s' for reading\n", pszFilename );
return FALSE;
}
return TRUE;
}
BOOL ReiserFsMetafile::Read( LPBYTE lpbMemory, DWORD dwSize, INT64 BlockNumber )
{
if( dwSize != m_dwBlocksize )
{
printf("ERROR, expected block size %d, got %d\n", m_dwBlocksize, dwSize );
return FALSE;
}
int index, blocknr = (int) BlockNumber;
for( index = 0; index < m_iNumberOfIndices; index++ )
{
if( m_pBlockIndices[index] == blocknr )
{
fseek(m_pDataFile,index*m_dwBlocksize,SEEK_SET);
fread(lpbMemory,m_dwBlocksize,1,m_pDataFile);
return TRUE;
}
}
return FALSE;
} // Read()
syntax highlighted by Code2HTML, v. 0.9.1