#include "precomp.h"
#include "reiserfs.h"
#include "time.h"
char* g_szUseSpecificDevice = NULL;
#define S_IRUSR 0000400 /* read permission, owner */
#define S_IWUSR 0000200 /* write permission, owner */
#define S_IXUSR 0000100/* execute/search permission, owner */
#define S_IRGRP 0000040 /* read permission, group */
#define S_IWGRP 0000020 /* write permission, grougroup */
#define S_IXGRP 0000010/* execute/search permission, group */
#define S_IROTH 0000004 /* read permission, other */
#define S_IWOTH 0000002 /* write permission, other */
#define S_IXOTH 0000001/* execute/search permission, other */
void LinuxPermissionsAsString( LPSTR lpszBuffer, int mode )
{
*lpszBuffer++ = (S_ISFIFO(mode))? 'f' :
( (S_ISDIR(mode)) ? 'd' :
( (S_ISCHR(mode)) ? 'c' :
( (S_ISBLK(mode)) ? 'b' :
( (S_ISLNK(mode)) ? 'l' :
( (S_ISREG(mode)) ? '-' : '-' )))));
*lpszBuffer++ = (mode & S_IRUSR) ? 'r' : '-';
*lpszBuffer++ = (mode & S_IWUSR) ? 'w' : '-';
*lpszBuffer++ = (mode & S_IXUSR) ? 'x' : '-';
*lpszBuffer++ = (mode & S_IRGRP) ? 'r' : '-';
*lpszBuffer++ = (mode & S_IWGRP) ? 'w' : '-';
*lpszBuffer++ = (mode & S_IXGRP) ? 'x' : '-';
*lpszBuffer++ = (mode & S_IROTH) ? 'r' : '-';
*lpszBuffer++ = (mode & S_IWOTH) ? 'w' : '-';
*lpszBuffer++ = (mode & S_IXOTH) ? 'x' : '-';
*lpszBuffer = 0;
}
#define ACTION_LISTDIR 1
#define ACTION_GETFILE 2
#define ACTION_SHOWINFO 3
#define ACTION_AUTODETECT 4
#define ACTION_DUMPTREE 5
#define ACTION_BACKUP 6
#define ACTION_RESTORE 7
#define ACTION_SHOW 7
void TRACE(const char* fmt, ...)
{
/*#ifdef _DEBUG
va_list args;
va_start( args, fmt );
vprintf(fmt, args);
#endif*/
}
char* g_pszReadOnlyBackupFileName = NULL;
int comparefunc(const void *elem1, const void *elem2 )
{
return strcmp( (*((ReiserFsFileInfo**)elem1))->m_strName, (*((ReiserFsFileInfo**)elem2))->m_strName );
}
#ifdef _WIN32
void AutodetectPartitionsFromRegistry( int* piPartition, int* piDrive )
{
if( *piDrive == -1 )
{
HKEY hkSubkey;
DWORD dwDisposition, dwType, dwSize;
LONG lResult = RegCreateKeyEx( HKEY_CURRENT_USER,
"SOFTWARE\\p-nand-q.com\\rfstool",
0,
"",
REG_OPTION_NON_VOLATILE,
KEY_READ,
0,
&hkSubkey,
&dwDisposition );
if( lResult == ERROR_SUCCESS )
{
dwSize = sizeof(DWORD);
if( RegQueryValueEx(hkSubkey, "Drive", 0, &dwType, (BYTE*) &dwDisposition, &dwSize ) == ERROR_SUCCESS )
{
if( dwType == REG_DWORD )
{
*piDrive = (int) dwDisposition;
}
}
dwSize = sizeof(DWORD);
if( RegQueryValueEx(hkSubkey, "Partition", 0, &dwType, (BYTE*) &dwDisposition, &dwSize ) == ERROR_SUCCESS )
{
if( dwType == REG_DWORD )
{
*piPartition = (int) dwDisposition;
}
}
RegCloseKey( hkSubkey );
}
if( *piDrive == -1 || *piPartition == -1 )
{
ReiserFsPartition partition;
partition.AutodetectFirstUsable( piPartition, piDrive );
}
}
}
void SaveLastUsedPartitionInRegistry( int iPartition, int iDrive )
{
HKEY hkSubkey;
DWORD dwDisposition;
LONG lResult = RegCreateKeyEx( HKEY_CURRENT_USER,
"SOFTWARE\\p-nand-q.com\\rfstool",
0,
"",
REG_OPTION_NON_VOLATILE,
KEY_WRITE,
0,
&hkSubkey,
&dwDisposition );
if( lResult == ERROR_SUCCESS )
{
if( iDrive >= 0 )
{
dwDisposition = (DWORD) iDrive;
RegSetValueEx(hkSubkey, "Drive", 0, REG_DWORD, (CONST BYTE*) &dwDisposition, sizeof(DWORD) );
}
if( iPartition >= 0 )
{
dwDisposition = (DWORD) iPartition;
RegSetValueEx(hkSubkey, "Partition", 0, REG_DWORD, (CONST BYTE*) &dwDisposition, sizeof(DWORD) );
}
RegCloseKey( hkSubkey );
}
}
#endif
class dumpfile : public ICreateFileInfo
{
virtual BOOL SetFileSize( INT64 Size )
{
return TRUE;
}
virtual void Write( LPBYTE lpbData, DWORD dwSize )
{
fwrite(lpbData,dwSize,1,stdout);
}
};
void showVersion()
{
printf( "RFSTOOL - ReiserFS Read-support for Windows & Linux - Version 0.14\n"
"Copyright (C) [2001..9999] by Gerson Kurz\n"
"This is free software, licensed by the GPL.\n\n" );
}
int help()
{
showVersion();
printf("USAGE: rfstool [action] [options] directory-or-filename [target-filename]\n"
"ACTIONS: ls | cp | show | info | autodetect | backup | dumptree.\n"
"OPTIONS: \n"
" -pdrive.partition .... select partition\n"
" -x<backupfile> ....... restore from backup file\n"
" -r ................... recurse subdirectories (cp only)\n"
" -v ................... show version and exit\n"
"For more info, please go to http://p-nand-q.com/e/reiserfs.html");
return 0;
}
int main( int argc, char* argv[] )
{
int action = ACTION_LISTDIR;
char* pszRestoreFile = NULL;
int iPartition = -1, iDrive = -1;
bool bRecurseSubdirectories = false;
// I hate Cs cumbersome string ops, I really do.
char* p = getenv("REISERFS_PARTITION");
if( p )
{
char* q = strchr(p,'.');
if( q )
{
*(q++) = 0;
iDrive = atoi(p);
iPartition = atoi(q);
printf("REISERFS_PARTITION selects drive %d, partition %d\n", iDrive, iPartition );
}
else printf("Warning, environment variable REISERFS_PARTITION exists, but is of invalid format\n" );
}
char* dirname = NULL;
char* localfile = NULL;
for( int i = 1; i < argc; i++ )
{
char* arg = argv[i];
if( !stricmp(arg,"ls") )
{
action = ACTION_LISTDIR;
}
else if( !stricmp(arg,"cp") )
{
action = ACTION_GETFILE;
}
else if( !stricmp(arg,"backup") )
{
action = ACTION_BACKUP;
}
else if( !stricmp(arg,"info") )
{
action = ACTION_SHOWINFO;
}
else if( !stricmp(arg,"autodetect") || !stricmp(arg,"detect") )
{
action = ACTION_AUTODETECT;
}
else if( !stricmp(arg,"dumptree") )
{
action = ACTION_DUMPTREE;
}
else if( !stricmp(arg,"show") )
{
action = ACTION_SHOW;
}
else if( *arg == '-' )
{
switch(toupper(arg[1]))
{
case 'X':
{
pszRestoreFile = arg+2;
printf("Attempting to restore data from '%s'\n", pszRestoreFile );
break;
}
case 'R':
{
bRecurseSubdirectories = true;
break;
}
case 'V':
{
showVersion();
return 0;
}
case 'P':
{
if( strncmp( arg+2, "backup:", 7 ) == 0 )
{
iPartition = 0;
iDrive = USE_BACKUP_FILENAME;
g_szUseSpecificDevice = arg+2+7;
break;
}
#ifndef _WIN32
if( strncmp( arg+2, "/dev/", 5 ) == 0 )
{
iPartition = 0;
iDrive = USE_SPECIFIC_DEVICE;
g_szUseSpecificDevice = arg+2;
break;
}
#endif
char* q = strchr(arg+2,'.');
if( q )
{
*(q++) = 0;
iDrive = atoi(arg+2);
iPartition = atoi(q);
}
else
{
printf("ERROR, must specify partition in the form /p<drive>.<partition>\n" );
return 0;
}
} break;
default:
return help();
}
}
else if( !dirname )
{
dirname = arg;
}
else
{
localfile = arg;
}
}
if( action == ACTION_AUTODETECT )
{
ReiserFsPartition partition;
partition.Autodetect();
return 0;
}
if( action == ACTION_SHOWINFO )
{
IPhysicalDrive* drive = CreatePhysicalDriveInstance();
CHAR szDriveName[256];
if( iDrive == -1 || iPartition == -1 )
{
for( int i = 0; i < 8; i++ )
{
sprintf(szDriveName,"\\\\.\\PhysicalDrive%d", i );
if( drive->Open(i) )
{
drive->DumpDriveInfo(szDriveName);
drive->Close();
}
else
{
#ifdef _WIN32
DWORD dwLastError = GetLastError();
if( dwLastError != 2 )
#endif
printf("ERROR %s, unable to open drive %s\n", (LPCSTR) GetLastErrorString(), (LPCSTR) szDriveName );
}
}
}
delete drive;
return 0;
}
#ifdef _WIN32
if( iDrive == -1 || iPartition == -1 )
AutodetectPartitionsFromRegistry( &iPartition, &iDrive );
#endif
if( iDrive == -1 || iPartition == -1 )
{
printf("ERROR, must specify drive & partition.\n");
return 10;
}
#ifdef _WIN32
SaveLastUsedPartitionInRegistry( iPartition, iDrive );
#endif
ReiserFsPartition partition;
if( pszRestoreFile )
{
if( action == ACTION_BACKUP )
{
printf("ERROR, cannot backup from restore!!!\n" );
return 0;
}
if( !partition.PrepareForRestore(pszRestoreFile) )
{
return 0;
}
}
if( (iDrive == USE_BACKUP_FILENAME) && (action != ACTION_LISTDIR) )
{
printf("ERROR, reading from backup is only supported with 'ls' option\n" );
return 0;
}
if( partition.Open(iDrive,iPartition) )
{
if( action == ACTION_BACKUP )
{
partition.Backup(dirname);
}
else if( action == ACTION_LISTDIR )
{
if( !dirname )
dirname = "/";
PList directory;
if( partition.ListDir(&directory,dirname) )
{
// create array of pointers
ReiserFsFileInfo** array = new ReiserFsFileInfo*[directory.m_lCount];
if( array )
{
int index = 0;
ENUMERATE( &directory, ReiserFsFileInfo, pFile )
array[index++] = pFile;
size_t sc = (size_t) (directory.m_lCount - 2);
if( sc > 1 )
qsort( &(array[2]), sc, sizeof(ReiserFsFileInfo*), comparefunc );
for( index = 0; index < directory.m_lCount; index++ )
{
ReiserFsFileInfo* pFile = array[index];
char szAttributes[256];
LinuxPermissionsAsString( szAttributes, pFile->m_stat.sd_mode );
PString strDate(asctime(localtime((const time_t*) &pFile->m_stat.sd_mtime)));
LPSTR p = strDate;
p[strlen(p)-1] = 0;
if( S_ISDIR(pFile->m_stat.sd_mode) )
{
printf("%s %12s %s %s \n", szAttributes,
"<DIR>",
(LPCSTR) strDate,
(LPCSTR) pFile->m_strName );
}
else if( S_ISLNK(pFile->m_stat.sd_mode) )
{
printf("%s %12" FMT_QWORD " %s %s -> %s\n", szAttributes,
pFile->m_stat.sd_size,
(LPCSTR) strDate,
(LPCSTR) pFile->m_strName,
(LPCSTR) partition.GetFileAsString(pFile) );
}
else
{
printf("%s %12" FMT_QWORD " %s %s\n", szAttributes,
pFile->m_stat.sd_size,
(LPCSTR) strDate,
(LPCSTR) pFile->m_strName );
}
//printf("%d\n", pFile->m_stat.u.sd_generation );
}
}
}
}
else if( action == ACTION_SHOW )
{
if( !dirname )
{
printf("ERROR, must specify dirname\n" );
}
else
{
dumpfile info;
partition.GetFileEx(dirname,&info);
}
}
else if( action == ACTION_GETFILE )
{
if( !dirname || !localfile )
{
printf("ERROR, must specify both dirname and localfile\n" );
}
else
{
printf("about to copy %s -> %s...", dirname, localfile );
if( partition.GetFile(dirname,localfile,bRecurseSubdirectories) )
{
printf("done.\n");
}
else
{
printf("failed\n");
}
}
}
else if( action == ACTION_DUMPTREE )
{
partition.DumpTree();
}
}
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1