From b7054272989a0e5fddbaf6dfbdbfb726f7db8539 Mon Sep 17 00:00:00 2001 From: Mark Olesen <Mark.Olesen@esi-group.com> Date: Tue, 16 Oct 2018 01:30:44 +0200 Subject: [PATCH] ENH: make cwd() behaviour user-adjustable (issue #1007) - with the 'cwd' optimization switch it is possible to select the preferred behaviour for the cwd() function. A value of 0 causes cwd() to return the physical directory, which is what getcwd() and `pwd -P` return. Until now, this was always the standard behaviour. With a value of 1, cwd() instead returns the logical directory, which what $PWD contains and `pwd -L` returns. If any of the sanity checks fail (eg, PWD points to something other than ".", etc), a warning is emitted and the physical cwd() is returned instead. Apart from the optical difference in the output, this additional control helps workaround file systems with whitespace or other characters in the directory that normally cause OpenFOAM to balk. Using a cleaner symlink elsewhere should skirt this issue. Eg, cd $HOME ln -s "/mounted volume/user/workdir" workdir cd workdir # start working with OpenFOAM --- applications/test/POSIX/Test-POSIX.C | 6 +- etc/controlDict | 3 + src/OSspecific/POSIX/POSIX.C | 91 +++++++++++++++++++++++++++- src/OSspecific/POSIX/fileStat.C | 19 ++++-- src/OSspecific/POSIX/fileStat.H | 28 ++++++--- src/OpenFOAM/include/OSspecific.H | 10 ++- 6 files changed, 140 insertions(+), 17 deletions(-) diff --git a/applications/test/POSIX/Test-POSIX.C b/applications/test/POSIX/Test-POSIX.C index e38899ec92..ad7639825f 100644 --- a/applications/test/POSIX/Test-POSIX.C +++ b/applications/test/POSIX/Test-POSIX.C @@ -3,7 +3,7 @@ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | Copyright (C) 2011 OpenFOAM Foundation - \\/ M anipulation | + \\/ M anipulation | Copyright (C) 2018 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -37,6 +37,10 @@ using namespace Foam; int main(int argc, char *argv[]) { + Info<<"cwd() " << cwd() << nl; + Info<<"cwd(-P) " << cwd(false) << nl; + Info<<"cwd(-L) " << cwd(true) << nl; + Info<<"rmDir" << nl; rmDir("hmm"); diff --git a/etc/controlDict b/etc/controlDict index 950e5adc2b..c5b0c7cd0a 100644 --- a/etc/controlDict +++ b/etc/controlDict @@ -69,6 +69,9 @@ InfoSwitches OptimisationSwitches { + // Use physical (0) or logical (1) value for the cwd. + cwd 0; + // On NFS mounted file system: maximum wait for files to appear/get // updated. Set to 0 on distributed case. fileModificationSkew 10; diff --git a/src/OSspecific/POSIX/POSIX.C b/src/OSspecific/POSIX/POSIX.C index 1953935f3c..05e134d9c4 100644 --- a/src/OSspecific/POSIX/POSIX.C +++ b/src/OSspecific/POSIX/POSIX.C @@ -74,6 +74,8 @@ namespace Foam defineTypeNameAndDebug(POSIX, 0); } +static bool cwdPreference_(Foam::debug::optimisationSwitch("cwd", 0)); + // * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * // @@ -280,7 +282,11 @@ Foam::fileName Foam::home(const std::string& userName) } -Foam::fileName Foam::cwd() +namespace Foam +{ + +//- The physical current working directory path name (pwd -P). +static Foam::fileName cwd_P() { label pathLengthLimit = POSIX::pathLengthChunk; List<char> path(pathLengthLimit); @@ -307,7 +313,7 @@ Foam::fileName Foam::cwd() << exit(FatalError); } - path.setSize(pathLengthLimit); + path.resize(pathLengthLimit); } else { @@ -319,7 +325,86 @@ Foam::fileName Foam::cwd() << "Couldn't get the current working directory" << exit(FatalError); - return fileName::null; + return fileName(); +} + + +//- The logical current working directory path name. +// From the PWD environment, same as pwd -L. +static Foam::fileName cwd_L() +{ + const char* env = ::getenv("PWD"); + + // Basic check + if (!env || env[0] != '/') + { + WarningInFunction + << "PWD is invalid - reverting to physical description" + << nl; + + return cwd_P(); + } + + fileName dir(env); + + // Check for "/." + for + ( + std::string::size_type pos = 0; + std::string::npos != (pos = dir.find("/.", pos)); + /*nil*/ + ) + { + pos += 2; + + if + ( + // Ends in "/." or has "/./" + !dir[pos] || dir[pos] == '/' + + // Ends in "/.." or has "/../" + || (dir[pos] == '.' && (!dir[pos+1] || dir[pos+1] == '/')) + ) + { + WarningInFunction + << "PWD contains /. or /.. - reverting to physical description" + << nl; + + return cwd_P(); + } + } + + // Finally, verify that PWD actually corresponds to the "." directory + if (!fileStat(dir, true).sameINode(fileStat(".", true))) + { + WarningInFunction + << "PWD is not the cwd() - reverting to physical description" + << nl; + + return cwd_P(); + } + + + return fileName(dir); +} + +} // End namespace Foam + + +Foam::fileName Foam::cwd() +{ + return cwd(cwdPreference_); +} + + +Foam::fileName Foam::cwd(bool logical) +{ + if (logical) + { + return cwd_L(); + } + + return cwd_P(); } diff --git a/src/OSspecific/POSIX/fileStat.C b/src/OSspecific/POSIX/fileStat.C index 0d50a72186..706640a1a0 100644 --- a/src/OSspecific/POSIX/fileStat.C +++ b/src/OSspecific/POSIX/fileStat.C @@ -43,14 +43,14 @@ Foam::fileStat::fileStat() Foam::fileStat::fileStat ( - const fileName& fName, + const char* fName, const bool followLink, const unsigned int maxTime ) : isValid_(false) { - if (fName.empty()) + if (!fName || !fName[0]) { return; } @@ -64,11 +64,11 @@ Foam::fileStat::fileStat { if (followLink) { - locIsValid = (::stat(fName.c_str(), &status_) == 0); + locIsValid = (::stat(fName, &status_) == 0); } else { - locIsValid = (::lstat(fName.c_str(), &status_) == 0); + locIsValid = (::lstat(fName, &status_) == 0); } } @@ -77,6 +77,17 @@ Foam::fileStat::fileStat } +Foam::fileStat::fileStat +( + const fileName& fName, + const bool followLink, + const unsigned int maxTime +) +: + fileStat(fName.c_str(), followLink, maxTime) +{} + + Foam::fileStat::fileStat(Istream& is) { is >> *this; diff --git a/src/OSspecific/POSIX/fileStat.H b/src/OSspecific/POSIX/fileStat.H index 62a61afbbf..e1a997b205 100644 --- a/src/OSspecific/POSIX/fileStat.H +++ b/src/OSspecific/POSIX/fileStat.H @@ -28,7 +28,7 @@ Description Wrapper for stat() and lstat() system calls. Warning - on Linux (an maybe on others) a stat() of an nfs mounted (remote) + On Linux (an maybe on others) a stat() of an nfs mounted (remote) file does never timeout and cannot be interrupted! So e.g. Foam::ping first and hope nfs is running. @@ -79,16 +79,28 @@ public: fileStat(); //- Construct from components. - // \param fName \n - // The file name or directory name to stat. // - // \param followLink \n - // If it is a link, get the status of the source file/directory. + // \param fName The file name or directory name to stat. + // \param followLink If it is a link, get the status of the source + // file/directory. + // \param maxTime The timeout value. // - // \param maxTime \n - // The timeout value. + // \note An empty filename is a no-op. + fileStat + ( + const char* fName, + const bool followLink = true, + const unsigned int maxTime = 0 + ); + + //- Construct from components. + // + // \param fName The file name or directory name to stat. + // \param followLink If it is a link, get the status of the source + // file/directory. + // \param maxTime The timeout value. // - // \note an empty filename is a no-op. + // \note An empty filename is a no-op. fileStat ( const fileName& fName, diff --git a/src/OpenFOAM/include/OSspecific.H b/src/OpenFOAM/include/OSspecific.H index 85c84c1ae5..d8535cf8e9 100644 --- a/src/OpenFOAM/include/OSspecific.H +++ b/src/OpenFOAM/include/OSspecific.H @@ -92,9 +92,17 @@ fileName home(); //- Return home directory path name for a particular user fileName home(const std::string& userName); -//- Return current working directory path name +//- The physical or logical current working directory path name. +// The behaviour is controlled by the \c cwd optimisation Switch +// A value of 0 corresponds to the physical value, which is identical +// to what getcwd and pwd -P would deliver. +// A value of 1 corresponds to the logical value, which corresponds +// to the PWD environment value and to what pwd -L would deliver. fileName cwd(); +//- The physical or logical current working directory path name. +fileName cwd(bool logical); + //- Change current directory to the one specified and return true on success. // Using an empty name is a no-op and always returns false. bool chDir(const fileName& dir); -- GitLab