From 6cf39363196b32805beff2b78a7443d8c9e8ffa4 Mon Sep 17 00:00:00 2001 From: Brian Cox Date: Sun, 10 Sep 2017 20:29:53 -0700 Subject: [PATCH 1/7] Test-harness tweaks for DragonflyBSD, where we expect a few fewer changes (access/modify times). Tweak one test expected values to pass, skip 2 more with notes saying they need refactoring. --- src/test-harness/tests/dbupdate.pm | 5 +++-- src/test-harness/tests/dirs.pm | 4 ++-- src/test-harness/tests/integritycheck.pm | 12 +++++++++--- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/test-harness/tests/dbupdate.pm b/src/test-harness/tests/dbupdate.pm index 9bab52b..8ba982d 100644 --- a/src/test-harness/tests/dbupdate.pm +++ b/src/test-harness/tests/dbupdate.pm @@ -158,9 +158,10 @@ sub RunBasicTest # Make sure we got 4 violations: 2 mod, 1 add, 1 rm. # + my $dir_mods = (($^O ne "skyos") && ($^O ne "dragonfly")) ? 0 : 1; my ($n, $a, $r, $c) = twtools::AnalyzeReport( twtools::RunReport() ); - my $n_expected = ($^O ne "skyos") ? 4 : 3; - my $c_expected = ($^O ne "skyos") ? 2 : 1; + my $n_expected = $dir_mods ? 4 : 3; + my $c_expected = $dir_mods ? 2 : 1; if( ($n != $n_expected) || ($a != 1) || ($r != 1) || ($c != $c_expected) ) { diff --git a/src/test-harness/tests/dirs.pm b/src/test-harness/tests/dirs.pm index 071b76f..dfbb37a 100644 --- a/src/test-harness/tests/dirs.pm +++ b/src/test-harness/tests/dirs.pm @@ -123,9 +123,9 @@ sub run() { twtools::logStatus("*** Beginning $description\n"); printf("%-30s", "-- $description"); - if ($^O eq "skyos") { + if (($^O eq "skyos") || ($^O eq "dragonfly")) { ++$twtools::twskippedtests; - print "SKIPPED; TODO: SkyOS has fewer expected changes here; refactor so we can test for correct values\n"; + print "SKIPPED; TODO: OS has fewer expected changes here; refactor so we can test for correct values\n"; return; } diff --git a/src/test-harness/tests/integritycheck.pm b/src/test-harness/tests/integritycheck.pm index e37dcc3..b72383b 100644 --- a/src/test-harness/tests/integritycheck.pm +++ b/src/test-harness/tests/integritycheck.pm @@ -160,12 +160,18 @@ sub PrepareForTest # sub run { + twtools::logStatus("*** Beginning $description\n"); + printf("%-30s", "-- $description"); + + if ($^O eq "dragonfly") { + ++$twtools::twskippedtests; + print "SKIPPED; TODO: DragonflyBSD has fewer expected changes here; refactor so we can test for correct values\n"; + return; + } + my $twpassed = 1; my $dir_mods = ($^O eq "skyos") ? 0 : 1; - twtools::logStatus("*** Beginning integrity check test\n"); - printf("%-30s", "-- $description"); - PrepareForTest(); # make some violations... From 4abec97664c4c005a3bbb8b9e7a2a1cf67c1e478 Mon Sep 17 00:00:00 2001 From: Brian Cox Date: Sun, 10 Sep 2017 21:01:46 -0700 Subject: [PATCH 2/7] Last tweak to dbupdate harness test needed help --- src/test-harness/tests/dbupdate.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test-harness/tests/dbupdate.pm b/src/test-harness/tests/dbupdate.pm index 8ba982d..d9c5875 100644 --- a/src/test-harness/tests/dbupdate.pm +++ b/src/test-harness/tests/dbupdate.pm @@ -158,7 +158,7 @@ sub RunBasicTest # Make sure we got 4 violations: 2 mod, 1 add, 1 rm. # - my $dir_mods = (($^O ne "skyos") && ($^O ne "dragonfly")) ? 0 : 1; + my $dir_mods = (($^O eq "skyos") || ($^O eq "dragonfly")) ? 0 : 1; my ($n, $a, $r, $c) = twtools::AnalyzeReport( twtools::RunReport() ); my $n_expected = $dir_mods ? 4 : 3; my $c_expected = $dir_mods ? 2 : 1; From 769874d34b574dbc5ea879f7601256f00c48255b Mon Sep 17 00:00:00 2001 From: Brian Cox Date: Wed, 13 Sep 2017 21:35:56 -0700 Subject: [PATCH 3/7] 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 From f67c370f29f0f0f4654ed381a1a66e971e4d02f4 Mon Sep 17 00:00:00 2001 From: Brian Cox Date: Wed, 13 Sep 2017 23:01:22 -0700 Subject: [PATCH 4/7] Enable some new path unit tests --- src/core/file_unix.cpp | 13 +++++++------ src/twtest/file_t.cpp | 9 ++------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/src/core/file_unix.cpp b/src/core/file_unix.cpp index aa963dc..f5bad8a 100644 --- a/src/core/file_unix.cpp +++ b/src/core/file_unix.cpp @@ -527,7 +527,7 @@ bool cArosPath::IsAbsolutePath(const TSTRING& in) if (in[0] == '/') return true; - if (in.find(":/") != std::string::npos) + if (in.find(":") != std::string::npos) return true; return false; @@ -554,12 +554,13 @@ TSTRING cArosPath::AsNative( const TSTRING& in ) return in; } - int x = 1; - for ( x; in[x] == '/' && x Date: Wed, 13 Sep 2017 23:39:50 -0700 Subject: [PATCH 5/7] AROS path fix --- src/core/unixfsservices.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/core/unixfsservices.cpp b/src/core/unixfsservices.cpp index b9b0c96..7ad946b 100644 --- a/src/core/unixfsservices.cpp +++ b/src/core/unixfsservices.cpp @@ -829,6 +829,10 @@ bool cUnixFSServices::FullPath( TSTRING& strFullPath, const TSTRING& strRelPathC d.TraceDebug("FullPath is now %s\n", strFullPath.c_str()); } +#if IS_AROS + strFullPath = cDevicePath::AsNative(strFullPath); +#endif + d.TraceDebug("Done, returning %s\n", strFullPath.c_str()); return true; } From a4ae3af444a5e402190cb848e2ac4c383643a7bb Mon Sep 17 00:00:00 2001 From: brc0x1 Date: Mon, 18 Sep 2017 17:55:17 -0700 Subject: [PATCH 6/7] Fix/implement RISC OS path handling --- src/core/file.h | 10 ++++++ src/core/file_unix.cpp | 70 ++++++++++++++++++++++++++++++++++++-- src/core/platform.h | 2 +- src/tripwire/twcmdline.cpp | 13 ++++++- 4 files changed, 91 insertions(+), 4 deletions(-) diff --git a/src/core/file.h b/src/core/file.h index e9de698..da9f45b 100644 --- a/src/core/file.h +++ b/src/core/file.h @@ -155,10 +155,20 @@ public: static bool IsAbsolutePath(const TSTRING& in); }; +class cRiscosPath +{ +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 +#elif IS_RISCOS +#define cDevicePath cRiscosPath #endif diff --git a/src/core/file_unix.cpp b/src/core/file_unix.cpp index f5bad8a..2bda72b 100644 --- a/src/core/file_unix.cpp +++ b/src/core/file_unix.cpp @@ -62,6 +62,10 @@ #include "core/fsservices.h" #include "core/errorutil.h" +#if IS_RISCOS +#include +#endif + /////////////////////////////////////////////////////////////////////////// // cFile_i : Insulated implementation for cFile objects. /////////////////////////////////////////////////////////////////////////// @@ -89,7 +93,7 @@ cFile_i::~cFile_i() fclose( mpCurrStream ); mpCurrStream = NULL; -#if IS_AROS +#if IS_AROS || IS_RISCOS if( mFlags & cFile::OPEN_LOCKED_TEMP ) { // unlink this file @@ -205,7 +209,7 @@ void cFile::Open( const TSTRING& sFileNameC, uint32 flags ) } mpData->m_fd = fh; -#if !IS_AROS +#if !IS_AROS && !IS_RISCOS if( flags & OPEN_LOCKED_TEMP ) { // unlink this file @@ -565,3 +569,65 @@ TSTRING cArosPath::AsNative( const TSTRING& in ) return out; } + +bool cRiscosPath::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 SDFS::Volume.$.dir.file +TSTRING cRiscosPath::AsPosix( const TSTRING& in ) +{ +#if IS_RISCOS + if (in[0] == '/') + { + return in; + } + + TSTRING out; + char* unixified = __unixify(in.c_str(), 0,0,0,0); + if(unixified) + { + out.assign(unixified); + free(unixified); + return out; + } + return in; + +#else + return in; +#endif +} + +TSTRING cRiscosPath::AsNative( const TSTRING& in ) +{ +#if IS_RISCOS + if (in[0] != '/') + { + return in; + } + + TSTRING out; + int buf_size = in.length() + 100; // examples pad by 100 + std::vector buf(buf_size); + __riscosify(in.c_str(), 0,0, &buf[0], buf_size, 0); + if(buf[0]) + { + out.assign(&buf[0]); + return out; + } + return in; +#else + return in; +#endif +} + diff --git a/src/core/platform.h b/src/core/platform.h index cfb424f..c58e3c8 100644 --- a/src/core/platform.h +++ b/src/core/platform.h @@ -305,7 +305,7 @@ #define SUPPORTS_SYSLOG (HAVE_SYSLOG_H && !IS_SKYOS && !IS_RISCOS) #define NEEDS_SWAB_IMPL (IS_CYGWIN || IS_SYLLABLE || IS_ANDROID || IS_SORTIX) #define USES_MBLEN (!IS_ANDROID && !IS_AROS) -#define USES_DEVICE_PATH (IS_AROS || IS_DOS_DJGPP) +#define USES_DEVICE_PATH (IS_AROS || IS_DOS_DJGPP || IS_RISCOS) #define ICONV_CONST_SOURCE (IS_MINIX) #define SUPPORTS_DIRECT_IO (IS_LINUX) // Linux is the only platform where direct i/o hashing has been tested & works properly so far. diff --git a/src/tripwire/twcmdline.cpp b/src/tripwire/twcmdline.cpp index 5a855d0..39e9577 100644 --- a/src/tripwire/twcmdline.cpp +++ b/src/tripwire/twcmdline.cpp @@ -264,22 +264,26 @@ static void util_InitTempDirectory(const cConfigFile& cf) temp_directory = "T:"; #elif IS_DOS_DJGPP temp_directory = "/dev/c/temp/"; +#elif IS_RISCOS + temp_directory = "/!BOOT/Resources/!Scrap/ScrapDirs/ScrapDir"; #else temp_directory = "/tmp/"; #endif } +#if !IS_RISCOS // make sure we have a trailing slash -- thanks Jarno... // if (*temp_directory.rbegin() != '/') { temp_directory.push_back('/'); } +#endif // make sure it exists... // -#if IS_AROS +#if IS_AROS || IS_RISCOS temp_directory = cDevicePath::AsNative(temp_directory); #elif IS_DOS_DJGPP temp_directory = cDevicePath::AsPosix(temp_directory); @@ -295,6 +299,13 @@ static void util_InitTempDirectory(const cConfigFile& cf) } else { +#if IS_RISCOS + if (*temp_directory.rbegin() != '.') + { + temp_directory.push_back('.'); + } +#endif + iFSServices::GetInstance()->SetTempDirName(temp_directory); } } From 7545beb0e6192f0bc56fcd1481dba56cd3ab7ef4 Mon Sep 17 00:00:00 2001 From: Brian Cox Date: Thu, 21 Sep 2017 01:12:28 -0700 Subject: [PATCH 7/7] Make sure cFile_i is constructed & destructed cleanly; clean up GetSymLinkStr a bit more; improve Debug/Basic & UnixFSServices/GetExecutableFilename unit tests --- src/core/file_unix.cpp | 20 ++++++++++---------- src/fs/fspropcalc.cpp | 6 +++--- src/twtest/debug_t.cpp | 5 +++++ src/twtest/unixfsservices_t.cpp | 5 +++++ 4 files changed, 23 insertions(+), 13 deletions(-) diff --git a/src/core/file_unix.cpp b/src/core/file_unix.cpp index 2bda72b..ae9fed9 100644 --- a/src/core/file_unix.cpp +++ b/src/core/file_unix.cpp @@ -83,28 +83,28 @@ struct cFile_i //Ctor cFile_i::cFile_i() : - mpCurrStream(NULL) + m_fd(-1), mpCurrStream(NULL), mFlags(0) {} //Dtor cFile_i::~cFile_i() { if (mpCurrStream != NULL) + { fclose( mpCurrStream ); - mpCurrStream = NULL; + mpCurrStream = NULL; #if IS_AROS || IS_RISCOS - if( mFlags & cFile::OPEN_LOCKED_TEMP ) - { - // unlink this file - if( 0 != unlink(mFileName.c_str())) + if( mFlags & cFile::OPEN_LOCKED_TEMP ) { - throw( eFileOpen( mFileName, iFSServices::GetInstance()->GetErrString() ) ); + // unlink this file + if( 0 != unlink(mFileName.c_str())) + { + throw( eFileOpen( mFileName, iFSServices::GetInstance()->GetErrString() ) ); + } } - } #endif - - mFileName.empty(); + } } /////////////////////////////////////////////////////////////////////////// diff --git a/src/fs/fspropcalc.cpp b/src/fs/fspropcalc.cpp index 2c3fd65..9c2e8de 100644 --- a/src/fs/fspropcalc.cpp +++ b/src/fs/fspropcalc.cpp @@ -90,7 +90,7 @@ bool cFSPropCalc::GetSymLinkStr(const TSTRING& strName, cArchive& arch, size_t s std::vector data(size+1); char* buf = &data[0]; -#if defined(O_PATH) +#if defined(O_PATH) // A Linuxism that lets us read symlinks w/o bumping the access time. int fd = open(strName.c_str(), (O_PATH | O_NOFOLLOW | O_NOATIME)); int rtn = readlinkat(fd, 0, buf, size); close(fd); @@ -98,13 +98,13 @@ bool cFSPropCalc::GetSymLinkStr(const TSTRING& strName, cArchive& arch, size_t s int rtn = readlink( strName.c_str(), buf, size ); #endif - if(rtn == -1) + if(rtn < 0) { // Some OSes (like HP-UX) return ERANGE if buffer is too small. // This is nonstandard but better than the usual truncate-and-say-you-succeeded // if(ERANGE == errno) - return GetSymLinkStr(strName, arch, size*2); + return GetSymLinkStr(strName, arch, size*2); return false; } diff --git a/src/twtest/debug_t.cpp b/src/twtest/debug_t.cpp index 2b3be0f..c30e353 100644 --- a/src/twtest/debug_t.cpp +++ b/src/twtest/debug_t.cpp @@ -88,6 +88,11 @@ void TestDebug() if(oldOutTarget & cDebug::OUT_FILE) cDebug::AddOutTarget(cDebug::OUT_FILE); else cDebug::RemoveOutTarget(cDebug::OUT_FILE); d.TraceDebug("Exiting...\n"); + +#ifndef DEBUG + TEST("Should always succeed in release builds & cDebug should do nothing"); +#endif + } void RegisterSuite_Debug() diff --git a/src/twtest/unixfsservices_t.cpp b/src/twtest/unixfsservices_t.cpp index ac82a24..34a5654 100644 --- a/src/twtest/unixfsservices_t.cpp +++ b/src/twtest/unixfsservices_t.cpp @@ -42,6 +42,8 @@ #include "twtest/test.h" #endif +#include + using namespace std; @@ -177,6 +179,9 @@ void TestGetIPAddress() void TestGetExecutableFilename() { + if( -1 == access("/bin/sh", F_OK)) + skip("/bin/sh not found/accessible"); + TSTRING filename = _T("sh"); TSTRING fullpath = _T("/bin/"); TEST( iFSServices::GetInstance()->GetExecutableFilename(fullpath, filename));