Expanded exception handling for file operations during a check, plus some refactoring & cleanup

This commit is contained in:
Brian Cox 2017-04-11 21:23:25 -07:00
parent 7af2781a19
commit e653e83058
5 changed files with 271 additions and 186 deletions

View File

@ -42,7 +42,6 @@
#include "fsdatasourceiter.h"
#include "fco/fcodatasourceiter.h"
#include "fsobject.h"
#include "core/fsservices.h"
#include "core/errorbucket.h"
#include "core/corestrings.h"
#include "core/usernotify.h"
@ -99,6 +98,12 @@ static bool gCrossFileSystems = false;
gCrossFileSystems = crossFS;
}
void cFSDataSourceIter::AddIterationError(const eError& e)
{
if(mpErrorBucket)
mpErrorBucket->AddError(e);
}
///////////////////////////////////////////////////////////////////////////////
// CreateCopy
///////////////////////////////////////////////////////////////////////////////
@ -151,15 +156,42 @@ void cFSDataSourceIter::GetChildrenNames( const TSTRING& strParentName, std::vec
}
catch( eError& e )
{
cDebug d("cFSDataSourceIter::GeneratePeers");
d.TraceError("**** ReadDir failed for %s\n", strParentName.c_str() );
if( mpErrorBucket )
{
eFSDataSourceIterReadDir eReadDir(e.GetMsg(), eError::NON_FATAL);
mpErrorBucket->AddError( eReadDir );
}
AddIterationError( eFSDataSourceIterReadDir( strParentName, e.GetMsg(), eError::NON_FATAL) );
}
catch( std::exception& e )
{
AddIterationError( eFSDataSourceIterReadDir( strParentName, e.what(), eError::NON_FATAL) );
}
catch(...)
{
AddIterationError( eFSDataSourceIterReadDir( strParentName, "unknown", eError::NON_FATAL) );
}
}
bool cFSDataSourceIter::DoStat( const TSTRING& name, cFSStatArgs& statArgs )
{
try
{
iFSServices::GetInstance()->Stat( name, statArgs);
}
catch(eError& e)
{
e.SetFatality(false);
AddIterationError(e);
return false;
}
catch(std::exception& e)
{
AddIterationError( eFSDataSourceIter( name, e.what(), eError::NON_FATAL) );
return false;
}
catch(...)
{
AddIterationError( eFSDataSourceIter( name, "unknown", eError::NON_FATAL) );
return false;
}
return true;
}
///////////////////////////////////////////////////////////////////////////////
@ -173,30 +205,15 @@ bool cFSDataSourceIter::InitializeTypeInfo(iFCO* pFCO)
if( pObj->GetFSPropSet().GetValidVector().ContainsItem( cFSPropSet::PROP_FILETYPE) )
return true;
//
// assume invalid by default...
//
cFSPropSet& propSet = pObj->GetFSPropSet();
propSet.SetFileType(cFSPropSet::FT_INVALID);
cFSStatArgs statArgs;
try
{
iFSServices::GetInstance()->Stat( pTrans->ToStringAPI( pObj->GetName() ), statArgs);
}
catch(eError& e)
{
cDebug d("CreateObject");
d.TraceError( "*** Stat of %s failed!!!\n", pObj->GetName().AsString().c_str() );
if( mpErrorBucket )
{
e.SetFatality( false );
mpErrorBucket->AddError( e );
}
if( !DoStat( pObj->GetName().AsString(), statArgs ))
return false;
}
//
// don't create the object if it is on a different file system...
//
if( gCrossFileSystems == false && (mDev != 0) && (statArgs.dev != mDev) )

View File

@ -39,9 +39,11 @@
// INCLUDES
//=========================================================================
#include "fco/fcodatasourceiterimpl.h"
#include "core/fileerror.h"
#include "core/fsservices.h"
TSS_EXCEPTION( eFSDataSourceIter, eError )
TSS_EXCEPTION( eFSDataSourceIterReadDir, eFSDataSourceIter )
TSS_FILE_EXCEPTION( eFSDataSourceIter, eFileError )
TSS_FILE_EXCEPTION( eFSDataSourceIterReadDir, eFSDataSourceIter )
//=========================================================================
@ -83,6 +85,9 @@ private:
virtual iFCO* CreateObject(const cFCOName& name, bool bCreatingPeers );
virtual bool InitializeTypeInfo(iFCO* pFCO) ;
void AddIterationError(const eError& e);
bool DoStat(const TSTRING& name, cFSStatArgs& statArgs);
};
#endif //__FSDATASOURCEITER_H

View File

@ -43,7 +43,7 @@
TSS_BEGIN_ERROR_REGISTRATION( fs )
TSS_REGISTER_ERROR( eFSPropCalc(), _T("NTFS property calculation error.") )
TSS_REGISTER_ERROR( eFSPropCalc(), _T("Property calculation error.") )
//TSS_REGISTER_ERROR( eFSPropCalcResetAccessTime(), _T("Could not reset access time for file.") )
TSS_REGISTER_ERROR( eFSDataSourceIter(), _T("Data source iterator error.") )
TSS_REGISTER_ERROR( eFSDataSourceIterReadDir(), _T("Could not access directory contents.") )

View File

@ -35,13 +35,10 @@
#include "stdfs.h"
#include "core/debug.h"
#include "core/errorbucket.h"
#include "core/fsservices.h"
#include "core/errorbucket.h"
#include "fco/fconame.h"
#include "fco/fconametranslator.h"
#include "fco/twfactory.h"
#include "core/archive.h"
#include "fspropcalc.h"
#include "fsobject.h"
@ -88,17 +85,15 @@ static bool NeedsStat(const cFCOPropVector& v)
///////////////////////////////////////////////////////////////////////////////
static bool GetSymLinkStr(const cFCOName& fileName, cArchive& arch)
static bool GetSymLinkStr(const TSTRING& strName, cArchive& arch)
{
char buf[1024];
char buf[1024]; // TODO: is this big enough?
#if defined(O_PATH)
int fd = open(iTWFactory::GetInstance()->GetNameTranslator()->ToStringAPI( fileName ).c_str(),
(O_PATH | O_NOFOLLOW | O_NOATIME));
int fd = open(strName.c_str(), (O_PATH | O_NOFOLLOW | O_NOATIME));
int rtn = readlinkat(fd, 0, buf, 1024);
close(fd);
#else
int rtn = readlink( iTWFactory::GetInstance()->GetNameTranslator()->ToStringAPI( fileName ).c_str(),
buf, 1024 );
int rtn = readlink( strName.c_str(), buf, 1024 );
#endif
if(rtn == -1)
@ -110,127 +105,154 @@ static bool GetSymLinkStr(const cFCOName& fileName, cArchive& arch)
return true;
}
///////////////////////////////////////////////////////////////////////////////
// VisitFSObject -- this is the workhorse method that actually fills out the
// passed in FSObject' properties
///////////////////////////////////////////////////////////////////////////////
void cFSPropCalc::VisitFSObject(cFSObject& obj)
void cFSPropCalc::AddPropCalcError(const eError& e)
{
cDebug d("cFSPropCalc::VisitFSObject");
d.TraceDetail(_T("Visiting %s\n"), obj.GetName().AsString().c_str());
if(mpErrorBucket)
mpErrorBucket->AddError(e);
}
// if we are not in overwrite mode, we need to alter the
// properties we are calculating...
cFCOPropVector propsToCheck(mPropVector);
if(mCollAction == iFCOPropCalc::PROP_LEAVE)
{
cFCOPropVector inBoth = propsToCheck;
inBoth &= obj.GetPropSet()->GetValidVector();
propsToCheck ^= inBoth;
}
#ifdef _DEBUG
d.TraceDetail("----->Collision Action = %s\n", mCollAction == iFCOPropCalc::PROP_LEAVE ? "Leave" : "Replace");
d.TraceDetail("----->Object's valid properties (a):\n");
obj.GetPropSet()->GetValidVector().TraceContents(cDebug::D_DETAIL);
d.TraceDetail("----->Properties to calculate: (b)\n");
mPropVector.TraceContents(cDebug::D_DETAIL);
d.TraceDetail("----->Properties to change in object ((a&b)^b for Leave or b for Replace):\n");
propsToCheck.TraceContents(cDebug::D_DETAIL);
#endif //_DEBUG
// only do the stat() if it is necessary
iFSServices* pFSServices = iFSServices::GetInstance();
cFSStatArgs ss;
bool bDidStat = false;
TSTRING strName = iTWFactory::GetInstance()->GetNameTranslator()->ToStringAPI( obj.GetName() );
// get a reference to the fco's property set
cFSPropSet& propSet = obj.GetFSPropSet();
bool cFSPropCalc::DoStat( const TSTRING& strName, cFSStatArgs& statArgs )
{
cDebug d("cFSPropCalc::DoStat");
//
// just return if this object is invalid
//
if( propSet.GetFileType() == cFSPropSet::FT_INVALID )
return;
try
{
if( NeedsStat(propsToCheck) )
{
d.TraceDetail("---Performing Stat()\n");
pFSServices->Stat(strName, ss);
bDidStat = true;
}
d.TraceDetail("---Performing Stat()\n");
iFSServices::GetInstance()->Stat(strName, statArgs);
}
catch(eError& e)
{
d.TraceError("Error getting stat info for %s : %s\n", strName.c_str(), e.GetMsg().c_str());
// add this fco to the error set...
// it is assumed that the file name that the error is associated with is in the exception's
// GetMsg()
e.SetFatality( false );
if(mpErrorBucket)
mpErrorBucket->AddError( e );
return;
e.SetFatality(false);
AddPropCalcError(e);
return false;
}
catch(std::exception& e)
{
d.TraceError("Error getting stat info for %s : %s\n", strName.c_str(), e.what());
AddPropCalcError( eFSPropCalc( strName, e.what(), eError::NON_FATAL ) );
return false;
}
catch(...)
{
d.TraceError("Unknown error getting stat info for %s\n", strName.c_str());
AddPropCalcError( eFSPropCalc( strName, "unknown", eError::NON_FATAL ) );
return false;
}
// for now, I will only fill out the stat info indicated in the property vector,
// but in reality, there is no reason not to fill out everything, since we have the
// extra information for free!
if(bDidStat)
return true;
}
bool cFSPropCalc::DoOpen( const TSTRING& strName, cFileArchive& arch )
{
try
{
if(propsToCheck.ContainsItem(cFSPropSet::PROP_DEV))
propSet.SetDev(ss.dev);
if(propsToCheck.ContainsItem(cFSPropSet::PROP_RDEV))
propSet.SetRDev(ss.rdev);
arch.OpenRead(strName.c_str(), ((mCalcFlags & iFCOPropCalc::DIRECT_IO) ?
cFileArchive::FA_SCANNING | cFileArchive::FA_DIRECT :
cFileArchive::FA_SCANNING) );
}
catch (eError&)
{
AddPropCalcError( eArchiveOpen( strName, iFSServices::GetInstance()->GetErrString(), eError::NON_FATAL));
return false;
}
catch (std::exception& e)
{
AddPropCalcError( eArchiveOpen( strName, e.what(), eError::NON_FATAL ) );
return false;
}
catch (...)
{
AddPropCalcError( eArchiveOpen( strName, "unknown", eError::NON_FATAL ) );
return false;
}
if(propsToCheck.ContainsItem(cFSPropSet::PROP_INODE))
propSet.SetInode(ss.ino);
if(propsToCheck.ContainsItem(cFSPropSet::PROP_MODE))
propSet.SetMode(ss.mode);
if(propsToCheck.ContainsItem(cFSPropSet::PROP_NLINK))
propSet.SetNLink(ss.nlink);
if(propsToCheck.ContainsItem(cFSPropSet::PROP_UID))
propSet.SetUID(ss.uid);
if(propsToCheck.ContainsItem(cFSPropSet::PROP_GID))
propSet.SetGID(ss.gid);
if(propsToCheck.ContainsItem(cFSPropSet::PROP_SIZE))
propSet.SetSize(ss.size);
if(propsToCheck.ContainsItem(cFSPropSet::PROP_ATIME))
propSet.SetAccessTime(ss.atime);
if(propsToCheck.ContainsItem(cFSPropSet::PROP_MTIME))
propSet.SetModifyTime(ss.mtime);
if(propsToCheck.ContainsItem(cFSPropSet::PROP_CTIME))
propSet.SetCreateTime(ss.ctime);
return true;
}
if(propsToCheck.ContainsItem(cFSPropSet::PROP_BLOCK_SIZE))
propSet.SetBlockSize(ss.blksize);
if(propsToCheck.ContainsItem(cFSPropSet::PROP_BLOCKS))
propSet.SetBlocks(ss.blocks);
bool cFSPropCalc::DoHash( const TSTRING& strName, cBidirArchive* pTheArch, cArchiveSigGen& asg, cFileArchive& arch )
{
cDebug d("cFSPropCalc::DoHash");
try
{
pTheArch->Seek( 0, cBidirArchive::BEGINNING );
asg.CalculateSignatures( *pTheArch );
arch.Close();
}
catch (eError& e)
{
d.TraceError("Error generating hashes for %s : %s\n", strName.c_str(), e.GetMsg().c_str());
e.SetFatality(false);
AddPropCalcError(e);
return false;
}
catch (std::exception& e)
{
d.TraceError("Error generating hashes for %s : %s\n", strName.c_str(), e.what());
AddPropCalcError( eArchiveRead( strName, e.what(), eError::NON_FATAL ) );
return false;
}
catch (...)
{
d.TraceError("Unknown error generating hashes for %s\n", strName.c_str());
AddPropCalcError( eArchiveRead( strName, "unknown", eError::NON_FATAL ) );
return false;
}
return true;
}
if(propsToCheck.ContainsItem(cFSPropSet::PROP_GROWING_FILE))
propSet.SetGrowingFile(ss.size);
void cFSPropCalc::HandleStatProperties( const cFCOPropVector& propsToCheck, const cFSStatArgs& ss, cFSPropSet& propSet)
{
if(propsToCheck.ContainsItem(cFSPropSet::PROP_DEV))
propSet.SetDev(ss.dev);
if(propsToCheck.ContainsItem(cFSPropSet::PROP_FILETYPE))
if(propsToCheck.ContainsItem(cFSPropSet::PROP_RDEV))
propSet.SetRDev(ss.rdev);
if(propsToCheck.ContainsItem(cFSPropSet::PROP_INODE))
propSet.SetInode(ss.ino);
if(propsToCheck.ContainsItem(cFSPropSet::PROP_MODE))
propSet.SetMode(ss.mode);
if(propsToCheck.ContainsItem(cFSPropSet::PROP_NLINK))
propSet.SetNLink(ss.nlink);
if(propsToCheck.ContainsItem(cFSPropSet::PROP_UID))
propSet.SetUID(ss.uid);
if(propsToCheck.ContainsItem(cFSPropSet::PROP_GID))
propSet.SetGID(ss.gid);
if(propsToCheck.ContainsItem(cFSPropSet::PROP_SIZE))
propSet.SetSize(ss.size);
if(propsToCheck.ContainsItem(cFSPropSet::PROP_ATIME))
propSet.SetAccessTime(ss.atime);
if(propsToCheck.ContainsItem(cFSPropSet::PROP_MTIME))
propSet.SetModifyTime(ss.mtime);
if(propsToCheck.ContainsItem(cFSPropSet::PROP_CTIME))
propSet.SetCreateTime(ss.ctime);
if(propsToCheck.ContainsItem(cFSPropSet::PROP_BLOCK_SIZE))
propSet.SetBlockSize(ss.blksize);
if(propsToCheck.ContainsItem(cFSPropSet::PROP_BLOCKS))
propSet.SetBlocks(ss.blocks);
if(propsToCheck.ContainsItem(cFSPropSet::PROP_GROWING_FILE))
propSet.SetGrowingFile(ss.size);
if(propsToCheck.ContainsItem(cFSPropSet::PROP_FILETYPE))
{
// TODO -- It _really_ bites duplicating code here and in fsdatasource.cpp
// *** This _has_ to be remedied somehow!
// set the file type
switch(ss.mFileType)
{
// TODO -- It _really_ bites duplicating code here and in fsdatasource.cpp
// *** This _has_ to be remedied somehow!
// set the file type
switch(ss.mFileType)
{
case cFSStatArgs::TY_FILE:
propSet.SetFileType(cFSPropSet::FT_FILE);
break;
@ -261,10 +283,12 @@ void cFSPropCalc::VisitFSObject(cFSObject& obj)
default:
// set it to invalid
propSet.SetFileType(cFSPropSet::FT_INVALID);
}
}
}
}
}
void cFSPropCalc::HandleHashes( const cFCOPropVector& propsToCheck, const TSTRING& strName, cFSPropSet& propSet)
{
bool hash_success = false;
// if the file type is not a regular file, we will
@ -273,45 +297,31 @@ void cFSPropCalc::VisitFSObject(cFSObject& obj)
if( propSet.GetFileType() == cFSPropSet::FT_FILE || propSet.GetFileType() == cFSPropSet::FT_SYMLINK )
{
if( // if we need to open the file
propsToCheck.ContainsItem(cFSPropSet::PROP_CRC32) ||
propsToCheck.ContainsItem(cFSPropSet::PROP_MD5) ||
propsToCheck.ContainsItem(cFSPropSet::PROP_SHA) ||
propsToCheck.ContainsItem(cFSPropSet::PROP_HAVAL)
)
propsToCheck.ContainsItem(cFSPropSet::PROP_CRC32) ||
propsToCheck.ContainsItem(cFSPropSet::PROP_MD5) ||
propsToCheck.ContainsItem(cFSPropSet::PROP_SHA) ||
propsToCheck.ContainsItem(cFSPropSet::PROP_HAVAL)
)
{
cFileArchive arch;
cMemoryArchive memArch;
cBidirArchive* pTheArch;
cBidirArchive* pTheArch;
hash_success = true;
if(propSet.GetFileType() == cFSPropSet::FT_SYMLINK)
{
pTheArch = &memArch;
if(! GetSymLinkStr(obj.GetName(), memArch))
if(! GetSymLinkStr(strName, memArch))
{
// add it to the bucket...
if(mpErrorBucket)
mpErrorBucket->AddError( eArchiveOpen( strName, iFSServices::GetInstance()->GetErrString(), eError::NON_FATAL ) );
AddPropCalcError( eArchiveOpen( strName, iFSServices::GetInstance()->GetErrString(), eError::NON_FATAL ) );
hash_success = false;
}
}
else
{
pTheArch = &arch;
try
{
arch.OpenRead(strName.c_str(), ((mCalcFlags & iFCOPropCalc::DIRECT_IO) ?
cFileArchive::FA_SCANNING | cFileArchive::FA_DIRECT :
cFileArchive::FA_SCANNING) );
}
catch (eError&)
{
// add it to the bucket...
if(mpErrorBucket)
mpErrorBucket->AddError( eArchiveOpen( strName, iFSServices::GetInstance()->GetErrString(), eError::NON_FATAL ) );
hash_success = false;
}
hash_success = DoOpen(strName, arch);
}
//
@ -326,43 +336,29 @@ void cFSPropCalc::VisitFSObject(cFSObject& obj)
propSet.SetDefinedCRC32(true);
asg.AddSig( propSet.GetCRC32() );
}
if(propsToCheck.ContainsItem(cFSPropSet::PROP_MD5))
{
propSet.SetDefinedMD5(true);
asg.AddSig( propSet.GetMD5() );
}
if(propsToCheck.ContainsItem(cFSPropSet::PROP_SHA))
{
propSet.SetDefinedSHA(true);
asg.AddSig( propSet.GetSHA() );
}
if(propsToCheck.ContainsItem(cFSPropSet::PROP_HAVAL))
{
propSet.SetDefinedHAVAL(true);
asg.AddSig( propSet.GetHAVAL() );
}
//
// calculate the signatures
//
try
{
pTheArch->Seek( 0, cBidirArchive::BEGINNING );
asg.CalculateSignatures( *pTheArch );
arch.Close();
}
catch (eError& e)
{
d.TraceError("Error generating hashes for %s : %s\n", strName.c_str(), e.GetMsg().c_str());
e.SetFatality(false);
if(mpErrorBucket)
mpErrorBucket->AddError(e);
hash_success = false;
}
hash_success = DoHash(strName, pTheArch, asg, arch);
}
}
}
@ -384,6 +380,59 @@ void cFSPropCalc::VisitFSObject(cFSObject& obj)
}
}
///////////////////////////////////////////////////////////////////////////////
// VisitFSObject -- this is the workhorse method that actually fills out the
// passed in FSObject' properties
///////////////////////////////////////////////////////////////////////////////
void cFSPropCalc::VisitFSObject(cFSObject& obj)
{
cDebug d("cFSPropCalc::VisitFSObject");
d.TraceDetail(_T("Visiting %s\n"), obj.GetName().AsString().c_str());
// if we are not in overwrite mode, we need to alter the
// properties we are calculating...
cFCOPropVector propsToCheck(mPropVector);
if(mCollAction == iFCOPropCalc::PROP_LEAVE)
{
cFCOPropVector inBoth = propsToCheck;
inBoth &= obj.GetPropSet()->GetValidVector();
propsToCheck ^= inBoth;
}
#ifdef _DEBUG
d.TraceDetail("----->Collision Action = %s\n", mCollAction == iFCOPropCalc::PROP_LEAVE ? "Leave" : "Replace");
d.TraceDetail("----->Object's valid properties (a):\n");
obj.GetPropSet()->GetValidVector().TraceContents(cDebug::D_DETAIL);
d.TraceDetail("----->Properties to calculate: (b)\n");
mPropVector.TraceContents(cDebug::D_DETAIL);
d.TraceDetail("----->Properties to change in object ((a&b)^b for Leave or b for Replace):\n");
propsToCheck.TraceContents(cDebug::D_DETAIL);
#endif //_DEBUG
// only do the stat() if it is necessary
cFSStatArgs ss;
TSTRING strName = iTWFactory::GetInstance()->GetNameTranslator()->ToStringAPI( obj.GetName() );
// get a reference to the fco's property set
cFSPropSet& propSet = obj.GetFSPropSet();
//
// just return if this object is invalid
//
if( propSet.GetFileType() == cFSPropSet::FT_INVALID )
return;
if( NeedsStat(propsToCheck) )
{
if (!DoStat(strName, ss))
return;
HandleStatProperties(propsToCheck, ss, propSet);
}
HandleHashes(propsToCheck, strName, propSet);
}
void cFSPropCalc::SetPropVector(const cFCOPropVector& pv)
{
mPropVector = pv;

View File

@ -47,7 +47,13 @@
#include "fco/fcopropvector.h"
#endif
TSS_EXCEPTION( eFSPropCalc, eError )
#include "fco/signature.h"
#include "core/fileerror.h"
#include "core/fsservices.h"
#include "core/archive.h"
#include "fspropset.h"
TSS_FILE_EXCEPTION( eFSPropCalc, eFileError )
//TSS_EXCEPTION( eFSPropCalcResetAccessTime, eFSPropCalc ) // this was never used
class cFSPropCalc : public iFCOPropCalc, public iFSVisitor
@ -78,6 +84,14 @@ private:
cFSPropCalc( const cFSPropCalc& );
void operator =( const cFSPropCalc& );
void AddPropCalcError(const eError& e);
bool DoStat(const TSTRING& name, cFSStatArgs& statArgs);
bool DoOpen(const TSTRING& name, cFileArchive& arch);
bool DoHash( const TSTRING& name, cBidirArchive* pTheArch, cArchiveSigGen& asg, cFileArchive& arch );
void HandleStatProperties( const cFCOPropVector& propsToCheck, const cFSStatArgs& ss, cFSPropSet& propSet);
void HandleHashes( const cFCOPropVector& propsToCheck, const TSTRING& strName, cFSPropSet& propSet);
cFCOPropVector mPropVector;
iFCOPropCalc::CollisionAction mCollAction;
int mCalcFlags;