From 769874d34b574dbc5ea879f7601256f00c48255b Mon Sep 17 00:00:00 2001 From: Brian Cox Date: Wed, 13 Sep 2017 21:35:56 -0700 Subject: [PATCH] Path fixes for FreeDOS/DJGPP --- src/core/file.h | 18 +- src/core/file_unix.cpp | 103 +++++++++-- src/core/unixfsservices.cpp | 25 ++- src/fs/fsparserutil.cpp | 8 +- src/tripwire/twcmdline.cpp | 312 ++++++++++++++++++---------------- src/tw/twinit.cpp | 3 + src/twtest/file_t.cpp | 139 +++++++++++++++ src/twtest/fsspec_t.cpp | 4 + src/twtest/policyparser_t.cpp | 7 +- src/util/fileutil.cpp | 5 + 10 files changed, 456 insertions(+), 168 deletions(-) diff --git a/src/core/file.h b/src/core/file.h index 2092968..e9de698 100644 --- a/src/core/file.h +++ b/src/core/file.h @@ -138,13 +138,27 @@ public: }; -#if USES_DEVICE_PATH -class cDevicePath +class cDosPath { public: static TSTRING AsPosix(const TSTRING& in); static TSTRING AsNative(const TSTRING& in); + static bool IsAbsolutePath(const TSTRING& in); + static TSTRING BackupName(const TSTRING& in); }; + +class cArosPath +{ +public: + static TSTRING AsPosix(const TSTRING& in); + static TSTRING AsNative(const TSTRING& in); + static bool IsAbsolutePath(const TSTRING& in); +}; + +#if IS_DOS_DJGPP +#define cDevicePath cDosPath +#elif IS_AROS +#define cDevicePath cArosPath #endif diff --git a/src/core/file_unix.cpp b/src/core/file_unix.cpp index 49f5e3c..aa963dc 100644 --- a/src/core/file_unix.cpp +++ b/src/core/file_unix.cpp @@ -449,31 +449,46 @@ void cFile::Truncate( File_t offset ) // throw(eFile) } -#if USES_DEVICE_PATH -// For paths of type DH0:/dir/file -TSTRING cDevicePath::AsPosix( const TSTRING& in ) +///////////////////////////////////////////////////////////////////////// +// Platform path conversion methods +///////////////////////////////////////////////////////////////////////// + +bool cDosPath::IsAbsolutePath(const TSTRING& in) +{ + if (in.empty()) + return false; + + if (in[0] == '/') + return true; + + if (in.length() >= 2 && in[1] == ':') + return true; + + return false; +} + +// For paths of type C:\DOS +TSTRING cDosPath::AsPosix( const TSTRING& in ) { if (in[0] == '/') + { return in; + } -#if IS_DOS_DJGPP - TSTRING out = "/dev/" + in; + TSTRING out = (cDosPath::IsAbsolutePath(in)) ? ("/dev/" + in) : in; std::replace(out.begin(), out.end(), '\\', '/'); -#else - TSTRING out = '/' + in; -#endif - - std::replace(out.begin(), out.end(), ':', '/'); + out.erase( std::remove(out.begin(), out.end(), ':'), out.end()); return out; } -TSTRING cDevicePath::AsNative( const TSTRING& in ) +TSTRING cDosPath::AsNative( const TSTRING& in ) { if (in[0] != '/') + { return in; + } -#if IS_DOS_DJGPP if (in.find("/dev") != 0 || in.length() < 6) return in; @@ -482,18 +497,70 @@ TSTRING cDevicePath::AsNative( const TSTRING& in ) if (in.length() >= 8) out.append(in.substr(7)); - + + std::replace(out.begin(), out.end(), '/', '\\'); + return out; +} + +TSTRING cDosPath::BackupName( const TSTRING& in ) +{ + TSTRING out = in; + std::string::size_type pos = out.find_last_of("\\"); + if( std::string::npos == pos) + return in; + + TSTRING path = in.substr(0, pos); + TSTRING name = in.substr(pos,9); + std::replace(name.begin(), name.end(), '.', '_'); + path.append(name); + + return path; +} + -#elif IS_AROS +bool cArosPath::IsAbsolutePath(const TSTRING& in) +{ + if (in.empty()) + return false; + + if (in[0] == '/') + return true; + + if (in.find(":/") != std::string::npos) + return true; + + return false; +} + +// For paths of type DH0:dir/file +TSTRING cArosPath::AsPosix( const TSTRING& in ) +{ + if (in[0] == '/') + { + return in; + } + + TSTRING out = IsAbsolutePath(in) ? '/' + in : in; + std::replace(out.begin(), out.end(), ':', '/'); + + return out; +} + +TSTRING cArosPath::AsNative( const TSTRING& in ) +{ + if (in[0] != '/') + { + return in; + } + int x = 1; for ( x; in[x] == '/' && x 0 && ( _T('/') == strPath[0] || _T('\\') == strPath[0] ) ); +#if USES_DEVICE_PATH + return cDevicePath::IsAbsolutePath(strPath); +#else + // IF there's a first character AND it's a '/', it's absolute. + return( strPath.size() > 0 && ( _T('/') == strPath[0] ) ); +#endif } diff --git a/src/tripwire/twcmdline.cpp b/src/tripwire/twcmdline.cpp index 4cf28f9..5a855d0 100644 --- a/src/tripwire/twcmdline.cpp +++ b/src/tripwire/twcmdline.cpp @@ -249,6 +249,172 @@ static void InitCmdLineCommon(cCmdLineParser& parser) } + +/////////////////////////////////////////////////////////////////////////////// +// Set up temp directory +/////////////////////////////////////////////////////////////////////////////// +static void util_InitTempDirectory(const cConfigFile& cf) +{ + TSTRING temp_directory; + cf.Lookup(TSTRING(_T("TEMPDIRECTORY")), temp_directory); + + if (temp_directory.empty()) + { +#if IS_AROS + temp_directory = "T:"; +#elif IS_DOS_DJGPP + temp_directory = "/dev/c/temp/"; +#else + temp_directory = "/tmp/"; +#endif + } + + // make sure we have a trailing slash -- thanks Jarno... + // + if (*temp_directory.rbegin() != '/') + { + temp_directory.push_back('/'); + } + + // make sure it exists... + // + +#if IS_AROS + temp_directory = cDevicePath::AsNative(temp_directory); +#elif IS_DOS_DJGPP + temp_directory = cDevicePath::AsPosix(temp_directory); +#endif + + if (access(temp_directory.c_str(), F_OK) != 0) + { + TSTRING errStr = TSS_GetString( cCore, core::STR_BAD_TEMPDIRECTORY ); + TSTRING tmpStr = _T("Directory: "); + tmpStr += (temp_directory + _T("\n")); + tmpStr += errStr; + throw eTWInvalidTempDirectory(tmpStr); + } + else + { + iFSServices::GetInstance()->SetTempDirName(temp_directory); + } +} + + +/////////////////////////////////////////////////////////////////////////////// +// Set up various email reporting options +/////////////////////////////////////////////////////////////////////////////// +static void util_InitEmailOptions(cTWModeCommon* pModeInfo, const cConfigFile& cf) +{ + TSTRING str; + if (cf.Lookup(TSTRING(_T("GLOBALEMAIL")), str)) + { + if (str.length() != 0) + pModeInfo->mGlobalEmail = str; + } + + // + // Set the report-viewing level if one has been specified, use + // default level otherwise. + // + if(cf.Lookup(TSTRING(_T("EMAILREPORTLEVEL")), str)) + { + if (_tcsicmp(str.c_str(), _T("0")) == 0) + pModeInfo->mEmailReportLevel = cTextReportViewer::SINGLE_LINE; + else if (_tcsicmp(str.c_str(), _T("1")) == 0) + pModeInfo->mEmailReportLevel = cTextReportViewer::PARSEABLE; + else if (_tcsicmp(str.c_str(), _T("2")) == 0) + pModeInfo->mEmailReportLevel = cTextReportViewer::SUMMARY_ONLY; + else if (_tcsicmp(str.c_str(), _T("3")) == 0) + pModeInfo->mEmailReportLevel = cTextReportViewer::CONCISE_REPORT; + else if (_tcsicmp(str.c_str(), _T("4")) == 0) + pModeInfo->mEmailReportLevel = cTextReportViewer::FULL_REPORT; + else + { + // They specified an illegal level, error. + TSTRING errStr = _T("Invalid Level: "); + errStr += str; + throw eTWInvalidReportLevelCfg( errStr ); + } + } + else + { + // no level was specified in the configuration file, use default. + pModeInfo->mEmailReportLevel = cTextReportViewer::CONCISE_REPORT; + } + + // Decide what mail method should be used to email reports + if(cf.Lookup(TSTRING(_T("MAILMETHOD")), str)) + { + if (_tcsicmp(str.c_str(), _T("SENDMAIL")) == 0) + pModeInfo->mMailMethod = cMailMessage::MAIL_BY_PIPE; + else if( _tcsicmp( str.c_str(), _T("SMTP") ) == 0 ) + pModeInfo->mMailMethod = cMailMessage::MAIL_BY_SMTP; + else + pModeInfo->mMailMethod = cMailMessage::INVALID_METHOD; + } + else + { + pModeInfo->mMailMethod = cMailMessage::NO_METHOD; + } + +#if !SUPPORTS_NETWORKING + if (pModeInfo->mMailMethod == cMailMessage::MAIL_BY_SMTP) + throw eMailSMTPNotSupported(); +#endif + + // Get the SMTP server + if(cf.Lookup(TSTRING(_T("SMTPHOST")), str)) + { + pModeInfo->mSmtpHost = str; + } + else + { + pModeInfo->mSmtpHost = _T("127.0.0.1"); // this is the default + } + + // Get the SMTP port number + if(cf.Lookup(TSTRING(_T("SMTPPORT")), str)) + { + int i = _ttoi( str.c_str() ); + if( i < 0 || i > SHRT_MAX ) + throw eTWInvalidPortNumber( str ); + pModeInfo->mSmtpPort = static_cast( i ); + } + else + { + pModeInfo->mSmtpPort = 25; // this is the default + } + + // Get the mail program to use if we're piping our email + if(cf.Lookup(TSTRING(_T("MAILPROGRAM")), str)) + { + pModeInfo->mMailProgram = str; + } + else + { + pModeInfo->mMailProgram.erase(); // MAILPROGRAM is not required to be specified + } + + // Get the mail program to use if we're piping our email + if(cf.Lookup(TSTRING(_T("MAILNOVIOLATIONS")), str)) + { + if (_tcsicmp(str.c_str(), _T("true")) == 0) + pModeInfo->mMailNoViolations = true; + else + pModeInfo->mMailNoViolations = false; + } + else + { + pModeInfo->mMailNoViolations = true; // MAILPROGRAM is not required to be specified + } + + if(cf.Lookup(TSTRING(_T("MAILFROMADDRESS")), str)) + { + pModeInfo->mMailFrom = str; + } +} + + /////////////////////////////////////////////////////////////////////////////// // FillOutConfigInfo -- fills out all the common info with config file information /////////////////////////////////////////////////////////////////////////////// @@ -297,151 +463,9 @@ static void FillOutConfigInfo(cTWModeCommon* pModeInfo, const cConfigFile& cf) pModeInfo->mfLooseDirs = true; } - TSTRING temp_directory; - cf.Lookup(TSTRING(_T("TEMPDIRECTORY")), temp_directory); + util_InitTempDirectory(cf); - if (temp_directory.empty()) - { -#if IS_AROS - temp_directory = "T:"; -#else - temp_directory = "/tmp/"; -#endif - } - - // make sure we have a trailing slash -- thanks Jarno... - // - if (*temp_directory.rbegin() != '/') - { - temp_directory.push_back('/'); - } - // make sure it exists... - // - -#if USES_DEVICE_PATH - temp_directory = cDevicePath::AsNative(temp_directory); -#endif - - if (access(temp_directory.c_str(), F_OK) != 0) - { - TSTRING errStr = TSS_GetString( cCore, core::STR_BAD_TEMPDIRECTORY ); - TSTRING tmpStr = _T("Directory: "); - tmpStr += (temp_directory + _T("\n")); - tmpStr += errStr; - throw eTWInvalidTempDirectory(tmpStr); - } - else - { - iFSServices::GetInstance()->SetTempDirName(temp_directory); - } - - - if (cf.Lookup(TSTRING(_T("GLOBALEMAIL")), str)) - { - if (str.length() != 0) - pModeInfo->mGlobalEmail = str; - } - - // - // Set the report-viewing level if one has been specified, use - // default level otherwise. - // - if(cf.Lookup(TSTRING(_T("EMAILREPORTLEVEL")), str)) - { - if (_tcsicmp(str.c_str(), _T("0")) == 0) - pModeInfo->mEmailReportLevel = cTextReportViewer::SINGLE_LINE; - else if (_tcsicmp(str.c_str(), _T("1")) == 0) - pModeInfo->mEmailReportLevel = cTextReportViewer::PARSEABLE; - else if (_tcsicmp(str.c_str(), _T("2")) == 0) - pModeInfo->mEmailReportLevel = cTextReportViewer::SUMMARY_ONLY; - else if (_tcsicmp(str.c_str(), _T("3")) == 0) - pModeInfo->mEmailReportLevel = cTextReportViewer::CONCISE_REPORT; - else if (_tcsicmp(str.c_str(), _T("4")) == 0) - pModeInfo->mEmailReportLevel = cTextReportViewer::FULL_REPORT; - else - { - // They specified an illegal level, error. - TSTRING errStr = _T("Invalid Level: "); - errStr += str; - throw eTWInvalidReportLevelCfg( errStr ); - } - } - else - { - // no level was specified in the configuration file, use default. - pModeInfo->mEmailReportLevel = cTextReportViewer::CONCISE_REPORT; - } - - // Decide what mail method should be used to email reports - if(cf.Lookup(TSTRING(_T("MAILMETHOD")), str)) - { - if (_tcsicmp(str.c_str(), _T("SENDMAIL")) == 0) - pModeInfo->mMailMethod = cMailMessage::MAIL_BY_PIPE; - else if( _tcsicmp( str.c_str(), _T("SMTP") ) == 0 ) - pModeInfo->mMailMethod = cMailMessage::MAIL_BY_SMTP; - else - pModeInfo->mMailMethod = cMailMessage::INVALID_METHOD; - } - else - { - pModeInfo->mMailMethod = cMailMessage::NO_METHOD; - } - -#if !SUPPORTS_NETWORKING - if (pModeInfo->mMailMethod == cMailMessage::MAIL_BY_SMTP) - throw eMailSMTPNotSupported(); -#endif - - // Get the SMTP server - if(cf.Lookup(TSTRING(_T("SMTPHOST")), str)) - { - pModeInfo->mSmtpHost = str; - } - else - { - pModeInfo->mSmtpHost = _T("127.0.0.1"); // this is the default - } - - // Get the SMTP port number - if(cf.Lookup(TSTRING(_T("SMTPPORT")), str)) - { - int i = _ttoi( str.c_str() ); - if( i < 0 || i > SHRT_MAX ) - throw eTWInvalidPortNumber( str ); - pModeInfo->mSmtpPort = static_cast( i ); - } - else - { - pModeInfo->mSmtpPort = 25; // this is the default - } - - // Get the mail program to use if we're piping our email - if(cf.Lookup(TSTRING(_T("MAILPROGRAM")), str)) - { - pModeInfo->mMailProgram = str; - } - else - { - pModeInfo->mMailProgram.erase(); // MAILPROGRAM is not required to be specified - } - - // Get the mail program to use if we're piping our email - if(cf.Lookup(TSTRING(_T("MAILNOVIOLATIONS")), str)) - { - if (_tcsicmp(str.c_str(), _T("true")) == 0) - pModeInfo->mMailNoViolations = true; - else - pModeInfo->mMailNoViolations = false; - } - else - { - pModeInfo->mMailNoViolations = true; // MAILPROGRAM is not required to be specified - } - - if(cf.Lookup(TSTRING(_T("MAILFROMADDRESS")), str)) - { - pModeInfo->mMailFrom = str; - } + util_InitEmailOptions(pModeInfo, cf); // SYSLOG reporting if(cf.Lookup(TSTRING(_T("SYSLOGREPORTING")), str)) diff --git a/src/tw/twinit.cpp b/src/tw/twinit.cpp index 63afb63..5d98cc5 100644 --- a/src/tw/twinit.cpp +++ b/src/tw/twinit.cpp @@ -157,6 +157,9 @@ static bool SetExeDir( const TSTRING& strArgv0 ) TSTRING strFullPath; if( iFSServices::GetInstance()->GetExecutableFilename( strFullPath, strArgv0 ) && !strFullPath.empty() ) { +#if USES_DEVICE_PATH + strFullPath = cDevicePath::AsPosix(strFullPath); +#endif cSystemInfo::SetExePath(strFullPath); TSTRING::size_type s = strFullPath.find_last_of( _T('/') ); diff --git a/src/twtest/file_t.cpp b/src/twtest/file_t.cpp index 1e55a96..3384f0f 100644 --- a/src/twtest/file_t.cpp +++ b/src/twtest/file_t.cpp @@ -58,7 +58,146 @@ void TestFile() TEST(testStream); } +////////////////// + +void testDosAsPosix(const std::string& in, const std::string& expected) +{ + TEST( expected == cDosPath::AsPosix(in) ); +} + +void TestDosAsPosix() +{ + testDosAsPosix("c:\\foo", "/dev/c/foo"); + testDosAsPosix("c:\\foo\\bar\\baz.txt", "/dev/c/foo/bar/baz.txt"); + testDosAsPosix("c:/foo/bar/baz.txt", "/dev/c/foo/bar/baz.txt"); + + testDosAsPosix("c:\\", "/dev/c/"); + testDosAsPosix("c:", "/dev/c"); + + testDosAsPosix("foo.txt", "foo.txt"); + testDosAsPosix("bar\\foo.txt", "bar/foo.txt"); + testDosAsPosix("bar/foo.txt", "bar/foo.txt"); + + testDosAsPosix("/foo/bar/baz.txt", "/foo/bar/baz.txt"); +} + + +void testDosAsNative(const std::string& in, const std::string& expected) +{ + TEST( expected == cDosPath::AsNative(in) ); +} + +void TestDosAsNative() +{ + testDosAsNative("/dev/c/foo", "c:\\foo"); + testDosAsNative("/dev/c/", "c:\\"); + testDosAsNative("/dev/c", "c:\\"); + + testDosAsNative("/foo/bar/baz", "/foo/bar/baz"); +} + + +void testDosIsAbsolute(const std::string& in, bool expected) +{ + TEST( expected == cDosPath::IsAbsolutePath(in) ); +} + +void TestDosIsAbsolute() +{ + testDosIsAbsolute("C:\\", true); + testDosIsAbsolute("C:", true); + testDosIsAbsolute("C:\\foo", true); + testDosIsAbsolute("C:\\foo\\bar\\baz.txt", true); + + testDosIsAbsolute("/foo", true); + + testDosIsAbsolute("foo.txt", false); + testDosIsAbsolute("bar\\foo.txt", false); + testDosIsAbsolute("bar/foo.txt", false); +} + +void testDosBackupName(const std::string& in, const std::string& expected) +{ + TCERR << "In: " << in << " | Expected: " << expected << " | Observed: " << cDosPath::BackupName(in) << std::endl; + + TEST( expected == cDosPath::BackupName(in) ); +} + +void TestDosBackupName() +{ + testDosBackupName("C:\\12345678.123", "C:\\12345678"); + testDosBackupName("C:\\12345678", "C:\\12345678"); + testDosBackupName("C:\\1.123", "C:\\1_123"); + testDosBackupName("C:\\1", "C:\\1"); + + testDosBackupName("C:\\FOO\\12345678.123", "C:\\FOO\\12345678"); + testDosBackupName("C:\\FOO.BAR\\1234.123", "C:\\FOO.BAR\\1234_123"); +} + +void testArosAsPosix(const std::string& in, const std::string& expected) +{ + TCERR << "In: " << in << " | Expected: " << expected << " | Observed: " << cArosPath::AsPosix(in) << std::endl ; + TEST( expected == cArosPath::AsPosix(in) ); +} + +void TestArosAsPosix() +{ +// testArosAsPosix("DH0:", "/DH0/"); + testArosAsPosix("DH0:Foo", "/DH0/Foo"); + testArosAsPosix("DH0:Foo/Bar", "/DH0/Foo/Bar"); + + testArosAsPosix("/DH0/Foo/Bar", "/DH0/Foo/Bar"); + + testArosAsPosix("Foo", "Foo"); + testArosAsPosix("Foo/Bar", "Foo/Bar"); +} + +void testArosAsNative(const std::string& in, const std::string& expected) +{ + TEST( expected == cArosPath::AsNative(in) ); +} + +void TestArosAsNative() +{ + testArosAsNative("/DH0", "DH0:"); + testArosAsNative("/DH0/Foo", "DH0:Foo" ); + testArosAsNative("/DH0/Foo/Bar", "DH0:Foo/Bar" ); + + testArosAsNative("DH0:Foo/Bar", "DH0:Foo/Bar"); + + testArosAsNative("Foo", "Foo"); + testArosAsNative("Foo/Bar", "Foo/Bar"); +} + +void testArosIsAbsolute(const std::string& in, bool expected) +{ + TEST( expected == cArosPath::IsAbsolutePath(in) ); +} + +void TestArosIsAbsolute() +{ + testArosIsAbsolute("DH0:", true); + testArosIsAbsolute("DH0:Foo", true); + testArosIsAbsolute("DH0:Foo/bar", true); + + testArosIsAbsolute("/DH0/Foo/bar", true); + + testArosIsAbsolute("Foo/bar", false); + testArosIsAbsolute("Foo", false); +} + + void RegisterSuite_File() { RegisterTest("File", "Basic", TestFile); + RegisterTest("File", "DosAsPosix", TestDosAsPosix); + RegisterTest("File", "DosAsNative", TestDosAsNative); + RegisterTest("File", "DosIsAbsolute", TestDosIsAbsolute); + RegisterTest("File", "DosBackupName", TestDosBackupName); +// TODO: Finish these +/* + RegisterTest("File", "ArosAsPosix", TestArosAsPosix); + RegisterTest("File", "ArosAsNative", TestArosAsNative); + RegisterTest("File", "ArosIsAbsolute", TestArosIsAbsolute); +*/ } diff --git a/src/twtest/fsspec_t.cpp b/src/twtest/fsspec_t.cpp index c354434..c948d2f 100644 --- a/src/twtest/fsspec_t.cpp +++ b/src/twtest/fsspec_t.cpp @@ -41,6 +41,7 @@ #include "fco/fcospechelper.h" #include "core/fsservices.h" +#include /////////////////////////////////////////////////////////////////////////////// // PrintFCOTree -- recursively prints an fco's name and all of it's children's @@ -92,6 +93,9 @@ void TestFCOSpecImpl2() cDebug d("TestFCOSpecImpl2"); d.TraceDebug("Entering...\n"); + if( -1 == access("/etc", F_OK)) + skip("/etc not found/accessible"); + cFSDataSourceIter dataSrc; // create an FSSpec and set up some start and stop points... diff --git a/src/twtest/policyparser_t.cpp b/src/twtest/policyparser_t.cpp index 828080b..6dfba0f 100644 --- a/src/twtest/policyparser_t.cpp +++ b/src/twtest/policyparser_t.cpp @@ -45,7 +45,9 @@ #include "fco/fcospeclist.h" #include "twtest/test.h" #include "util/fileutil.h" + #include +#include // helper class that checks output of each fcospec class cPolicyParserTester { @@ -71,7 +73,10 @@ void test_policy_file(const std::string& polfile) TSTRING pol_path = get_test_file_dir(); pol_path.append("/"); pol_path.append(polfile); - + + if(-1 == access(pol_path.c_str(), F_OK)) + skip("policy parser test file not found/accessible"); + std::ifstream in; in.open(pol_path.c_str()); if( ! in.good() ) diff --git a/src/util/fileutil.cpp b/src/util/fileutil.cpp index c608d55..37e5cac 100644 --- a/src/util/fileutil.cpp +++ b/src/util/fileutil.cpp @@ -208,7 +208,12 @@ bool cFileUtil::BackupFile(const TSTRING& filename, bool printWarningOnFailure) throw eFileWrite(filename, iFSServices::GetInstance()->GetErrString() ); } +#if IS_DOS_DJGPP + TSTRING backup_filename = cDosPath::BackupName( cDosPath::AsNative(filename) ); +#else TSTRING backup_filename = filename; +#endif + backup_filename += iFSServices::GetInstance()->GetStandardBackupExtension(); // remove the backup file if it exists. We ingore the return value from