Commit 3a4038b2 authored by mark's avatar mark
Browse files

ENH: various general improvments to the POSIX functions

- ensure proper and sensible handling of empty names.
  Eg, isDir(""), isFile("") are no-ops, and avoid file-stat

- rmDir:
  * optional 'silent' option to suppress messages.
  * removes all possible sub-entries, instead of just giving up on
    the first problem encountered.

- reduced code duplication in etcFiles

ENH: provide WM_USER_RESOURCE_DIRNAME define (in foamVersion.H)

- this is still a hard-coded value, but at least centrally available
parent 62335ee7
Test-etcFiles.C
EXE = $(FOAM_USER_APPBIN)/Test-etcFiles
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2017 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Application
Test-etcFiles
Description
Test etcFiles functionality.
Similar to foamEtcFile script, but automatically prunes nonexistent
directories from the list.
\*---------------------------------------------------------------------------*/
#include "argList.H"
#include "etcFiles.H"
using namespace Foam;
void printList(const fileNameList& list)
{
forAll(list, i)
{
Info<< list[i].c_str() << nl;
}
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Main program:
int main(int argc, char *argv[])
{
argList::noBanner();
argList::noParallel();
argList::noFunctionObjects();
argList::removeOption("case");
argList::addBoolOption
(
"all",
"Return all files (otherwise stop after the first match)"
);
argList::addBoolOption
(
"list",
"List directories or files to be checked"
);
argList::validArgs.insert("file...");
argList::addNote
(
"Locate user/group/other file with semantics similar to the "
"~OpenFOAM/fileName expansion."
);
argList args(argc, argv, false, true);
// First handle no parameters
if (args.size() == 1)
{
if (args.optionFound("list"))
{
fileNameList results = findEtcDirs();
printList(results);
return 0;
}
else
{
Info<<"Error: Missing filename" << endl;
args.printUsage();
return 1;
}
}
const bool listAll = (args.optionFound("all") || args.optionFound("list"));
int error = 0;
for (int argi = 1; argi < args.size(); ++argi)
{
const std::string file = args[argi];
fileNameList results = findEtcFiles(file);
if (results.empty())
{
Info<<"Not found: " << file << nl;
error = 2;
}
else if (listAll)
{
printList(results);
}
else
{
Info<<results[0].c_str() << nl;
}
}
return error;
}
// ************************************************************************* //
......@@ -3,7 +3,7 @@
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
\\/ M anipulation | Copyright (C) 2016 OpenCFD Ltd.
\\/ M anipulation | Copyright (C) 2016-2017 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
......@@ -76,6 +76,41 @@ namespace Foam
}
// * * * * * * * * * * * * * * Static Functions * * * * * * * * * * * * * * //
//
//! \cond fileScope
//
// Return true if filename appears to be a backup file
//
static inline bool isBackupName(const Foam::fileName& name)
{
if (name.empty())
{
return false;
}
else if (name[name.size()-1] == '~')
{
return true;
}
// Now check the extension
const Foam::word ext = name.ext();
if (ext.empty())
{
return false;
}
return
(
ext == "bak" || ext == "BAK"
|| ext == "old" || ext == "save"
);
}
//! \endcond
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
pid_t Foam::pid()
......@@ -98,13 +133,15 @@ pid_t Foam::pgid()
bool Foam::env(const std::string& envName)
{
return ::getenv(envName.c_str()) != nullptr;
// An empty envName => always false
return !envName.empty() && ::getenv(envName.c_str()) != nullptr;
}
Foam::string Foam::getEnv(const std::string& envName)
{
char* env = ::getenv(envName.c_str());
// Ignore an empty envName => always ""
char* env = envName.empty() ? nullptr : ::getenv(envName.c_str());
if (env)
{
......@@ -126,7 +163,12 @@ bool Foam::setEnv
const bool overwrite
)
{
return ::setenv(envName.c_str(), value.c_str(), overwrite) == 0;
// Ignore an empty envName => always false
return
(
!envName.empty()
&& ::setenv(envName.c_str(), value.c_str(), overwrite) == 0
);
}
......@@ -173,14 +215,13 @@ Foam::string Foam::domainName()
Foam::string Foam::userName()
{
struct passwd* pw = ::getpwuid(::getuid());
if (pw != nullptr)
{
return pw->pw_name;
}
else
{
return string::null;
return string();
}
}
......@@ -194,54 +235,39 @@ bool Foam::isAdministrator()
Foam::fileName Foam::home()
{
char* env = ::getenv("HOME");
if (env != nullptr)
if (env)
{
return fileName(env);
}
struct passwd* pw = ::getpwuid(::getuid());
if (pw)
{
return pw->pw_dir;
}
else
{
struct passwd* pw = ::getpwuid(getuid());
if (pw != nullptr)
{
return pw->pw_dir;
}
else
{
return fileName::null;
}
return fileName();
}
}
Foam::fileName Foam::home(const std::string& userName)
{
struct passwd* pw;
if (userName.size())
// An empty userName => same as home()
if (userName.empty())
{
pw = ::getpwnam(userName.c_str());
}
else
{
char* env = ::getenv("HOME");
if (env != nullptr)
{
return fileName(env);
}
pw = ::getpwuid(::getuid());
return Foam::home();
}
if (pw != nullptr)
struct passwd* pw = ::getpwnam(userName.c_str());
if (pw)
{
return pw->pw_dir;
}
else
{
return fileName::null;
return fileName();
}
}
......@@ -260,7 +286,7 @@ Foam::fileName Foam::cwd()
}
else if (errno == ERANGE)
{
// Increment path length upto the pathLengthMax limit
// Increment path length up to the pathLengthMax limit
if
(
(pathLengthLimit += POSIX::pathLengthChunk)
......@@ -291,19 +317,20 @@ Foam::fileName Foam::cwd()
bool Foam::chDir(const fileName& dir)
{
return ::chdir(dir.c_str()) == 0;
// Ignore an empty dir name => always false
return !dir.empty() && ::chdir(dir.c_str()) == 0;
}
bool Foam::mkDir(const fileName& pathName, mode_t mode)
{
// empty names are meaningless
// Ignore an empty pathName => always false
if (pathName.empty())
{
return false;
}
// Construct instance path directory if does not exist
// Construct path directory if does not exist
if (::mkdir(pathName.c_str(), mode) == 0)
{
// Directory made OK so return true
......@@ -443,26 +470,35 @@ bool Foam::mkDir(const fileName& pathName, mode_t mode)
bool Foam::chMod(const fileName& name, const mode_t m)
{
return ::chmod(name.c_str(), m) == 0;
// Ignore an empty name => always false
return !name.empty() && ::chmod(name.c_str(), m) == 0;
}
mode_t Foam::mode(const fileName& name, const bool followLink)
{
fileStat fileStatus(name, followLink);
if (fileStatus.isValid())
{
return fileStatus.status().st_mode;
}
else
// Ignore an empty name => always 0
if (!name.empty())
{
return 0;
fileStat fileStatus(name, followLink);
if (fileStatus.isValid())
{
return fileStatus.status().st_mode;
}
}
return 0;
}
Foam::fileName::Type Foam::type(const fileName& name, const bool followLink)
{
// Ignore an empty name => always UNDEFINED
if (name.empty())
{
return fileName::UNDEFINED;
}
mode_t m = mode(name, followLink);
if (S_ISREG(m))
......@@ -477,10 +513,8 @@ Foam::fileName::Type Foam::type(const fileName& name, const bool followLink)
{
return fileName::DIRECTORY;
}
else
{
return fileName::UNDEFINED;
}
return fileName::UNDEFINED;
}
......@@ -491,13 +525,19 @@ bool Foam::exists
const bool followLink
)
{
return mode(name, followLink) || isFile(name, checkGzip, followLink);
// Ignore an empty name => always false
return
(
!name.empty()
&& (mode(name, followLink) || isFile(name, checkGzip, followLink))
);
}
bool Foam::isDir(const fileName& name, const bool followLink)
{
return S_ISDIR(mode(name, followLink));
// Ignore an empty name => always false
return !name.empty() && S_ISDIR(mode(name, followLink));
}
......@@ -508,53 +548,65 @@ bool Foam::isFile
const bool followLink
)
{
// Ignore an empty name => always false
return
S_ISREG(mode(name, followLink))
|| (checkGzip && S_ISREG(mode(name + ".gz", followLink)));
(
!name.empty()
&& (
S_ISREG(mode(name, followLink))
|| (checkGzip && S_ISREG(mode(name + ".gz", followLink)))
)
);
}
off_t Foam::fileSize(const fileName& name, const bool followLink)
{
fileStat fileStatus(name, followLink);
if (fileStatus.isValid())
// Ignore an empty name
if (!name.empty())
{
return fileStatus.status().st_size;
}
else
{
return -1;
fileStat fileStatus(name, followLink);
if (fileStatus.isValid())
{
return fileStatus.status().st_size;
}
}
return -1;
}
time_t Foam::lastModified(const fileName& name, const bool followLink)
{
fileStat fileStatus(name, followLink);
if (fileStatus.isValid())
{
return fileStatus.status().st_mtime;
}
else
// Ignore an empty name
if (!name.empty())
{
return 0;
fileStat fileStatus(name, followLink);
if (fileStatus.isValid())
{
return fileStatus.status().st_mtime;
}
}
return 0;
}
double Foam::highResLastModified(const fileName& name)
{
fileStat fileStatus(name);
if (fileStatus.isValid())
// Ignore an empty name
if (!name.empty())
{
return
fileStatus.status().st_mtime
+ 1e-9*fileStatus.status().st_atim.tv_nsec;
}
else
{
return 0;
fileStat fileStatus(name);
if (fileStatus.isValid())
{
return
fileStatus.status().st_mtime
+ 1e-9*fileStatus.status().st_atim.tv_nsec;
}
}
return 0;
}
......@@ -570,92 +622,85 @@ Foam::fileNameList Foam::readDir
// also used as increment if initial size found to be insufficient
static const int maxNnames = 100;
// Basic sanity: cannot strip '.gz' from directory names
const bool stripgz = filtergz && (type != fileName::DIRECTORY);
const word extgz("gz");
// Open directory and set the structure pointer
// Do not attempt to open an empty directory name
DIR *source;
if
(
directory.empty()
|| (source = ::opendir(directory.c_str())) == nullptr
)
{
if (POSIX::debug)
{
InfoInFunction
<< "cannot open directory " << directory << endl;
}
return fileNameList();
}
if (POSIX::debug)
{
InfoInFunction
<< "reading directory " << directory << endl;
}
// Setup empty string list MAXTVALUES long
fileNameList dirEntries(maxNnames);
// Pointers to the directory entries
DIR *source;
struct dirent *list;
// Temporary variables and counters
label nEntries = 0;
fileNameList dirEntries(maxNnames);
// Attempt to open directory and set the structure pointer
if ((source = ::opendir(directory.c_str())) == nullptr)
// Read and parse all the entries in the directory
for (struct dirent *list; (list = ::readdir(source)) != nullptr; /*nil*/)
{
dirEntries.setSize(0);
const fileName name(list->d_name);
if (POSIX::debug)
// Ignore files/directories beginning with "."
// These are the ".", ".." directories and any hidden files/dirs
if (name.empty() || name[0] == '.')
{
InfoInFunction
<< "cannot open directory " << directory << endl;
continue;
}
}
else
{
// Read and parse all the entries in the directory
while ((list = ::readdir(source)) != nullptr)
{
fileName fName(list->d_name);
// ignore files beginning with ., i.e. '.', '..' and '.*'
if (fName.size() && fName[0] != '.')
if
(
(type == fileName::DIRECTORY)
|| (type == fileName::FILE && !isBackupName(name))
)
{
if ((directory/name).type(followLink) == type)
{
const word fExt = fName.ext();
if
(
(type == fileName::DIRECTORY)
||
(
type == fileName::FILE
&& fName[fName.size()-1] != '~'
&& fExt != "bak"
&& fExt != "BAK"
&& fExt != "old"
&& fExt != "save"
)
)
if (nEntries >= dirEntries.size())
{
dirEntries.setSize(dirEntries.size() + maxNnames);
}
if (stripgz && name.hasExt(extgz))
{
dirEntries[nEntries++] = name.lessExt();
}
else
{
if ((directory/fName).type(followLink) == type)
{
if (nEntries >= dirEntries.size())
{
dirEntries.setSize(dirEntries.size() + maxNnames);
}
if (filtergz && fExt == "gz")
{
dirEntries[nEntries++] = fName.lessExt();
}
else
{
dirEntries[nEntries++] = fName;
}
}
dirEntries[nEntries++] = name;
}
}
}
// Reset the length of the entries list
dirEntries.setSize(nEntries);
::closedir(source);
}