mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
ENH: add fileName::validate static method (issue #628)
- similar to word::validate to allow stripping of invalid characters without triggering a FatalError. - use this validated fileName in Foam::readDir to avoid problems when a directory contains files with invalid characters in their names - adjust rmDir to handle filenames with invalid characters - fileName::equals() static method to compare strings while ignoring any differences that are solely due to duplicate slashes
This commit is contained in:
@ -3,7 +3,7 @@
|
|||||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
\\ / O peration |
|
\\ / O peration |
|
||||||
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
|
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
|
||||||
\\/ M anipulation | Copyright (C) 2016 OpenCFD Ltd.
|
\\/ M anipulation | Copyright (C) 2016-2017 OpenCFD Ltd.
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
License
|
License
|
||||||
This file is part of OpenFOAM.
|
This file is part of OpenFOAM.
|
||||||
@ -39,15 +39,135 @@ Description
|
|||||||
#include "POSIX.H"
|
#include "POSIX.H"
|
||||||
#include "Switch.H"
|
#include "Switch.H"
|
||||||
#include "etcFiles.H"
|
#include "etcFiles.H"
|
||||||
|
#include "Pair.H"
|
||||||
|
#include "Tuple2.H"
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
using namespace Foam;
|
using namespace Foam;
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
unsigned testStrip
|
||||||
|
(
|
||||||
|
const bool doClean,
|
||||||
|
std::initializer_list
|
||||||
|
<
|
||||||
|
Tuple2<bool, std::string>
|
||||||
|
> tests
|
||||||
|
)
|
||||||
|
{
|
||||||
|
Info<< nl << "Checking with clean=" << Switch(doClean) << nl << endl;
|
||||||
|
|
||||||
|
unsigned nFail = 0;
|
||||||
|
|
||||||
|
for (const Tuple2<bool, std::string>& test : tests)
|
||||||
|
{
|
||||||
|
const bool expected = test.first();
|
||||||
|
const std::string& input = test.second();
|
||||||
|
|
||||||
|
fileName output(fileName::validate(input, doClean));
|
||||||
|
|
||||||
|
// Check for real failure (invalid chars) vs.
|
||||||
|
// spurious failure (removed double slashes with 'doClean').
|
||||||
|
|
||||||
|
const bool same =
|
||||||
|
(
|
||||||
|
doClean
|
||||||
|
? fileName::equals(input, output)
|
||||||
|
: (input == output)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (same)
|
||||||
|
{
|
||||||
|
if (expected)
|
||||||
|
{
|
||||||
|
Info<< "(pass) validated " << input << " = " << output << nl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++nFail;
|
||||||
|
Info<< "(fail) unexpected success for " << input << nl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (expected)
|
||||||
|
{
|
||||||
|
++nFail;
|
||||||
|
Info<< "(fail) unexpected";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Info<< "(pass) expected";
|
||||||
|
}
|
||||||
|
|
||||||
|
Info<< " failure for " << input << nl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nFail;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unsigned testEquals
|
||||||
|
(
|
||||||
|
std::initializer_list
|
||||||
|
<
|
||||||
|
Tuple2<bool, Pair<std::string>>
|
||||||
|
> tests
|
||||||
|
)
|
||||||
|
{
|
||||||
|
Info<< nl << "Checking fileName::equals()" << nl << endl;
|
||||||
|
|
||||||
|
unsigned nFail = 0;
|
||||||
|
|
||||||
|
for (const Tuple2<bool, Pair<std::string>>& test : tests)
|
||||||
|
{
|
||||||
|
const bool expected = test.first();
|
||||||
|
const std::string& s1 = test.second().first();
|
||||||
|
const std::string& s2 = test.second().second();
|
||||||
|
|
||||||
|
const bool same = fileName::equals(s1, s2);
|
||||||
|
|
||||||
|
if (same)
|
||||||
|
{
|
||||||
|
if (expected)
|
||||||
|
{
|
||||||
|
Info<< "(pass) success";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++nFail;
|
||||||
|
Info<< "(fail) unexpected success";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (expected)
|
||||||
|
{
|
||||||
|
++nFail;
|
||||||
|
Info<< "(fail) unexpected failure";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Info<< "(pass) expected failure";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Info<< " for " << s1 << " == " << s2 << nl;
|
||||||
|
}
|
||||||
|
return nFail;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
// Main program:
|
// Main program:
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
argList::noParallel();
|
argList::noParallel();
|
||||||
|
argList::addBoolOption("validate", "test fileName::validate");
|
||||||
argList::addBoolOption("ext", "test handing of file extensions");
|
argList::addBoolOption("ext", "test handing of file extensions");
|
||||||
argList::addBoolOption("construct", "test constructors");
|
argList::addBoolOption("construct", "test constructors");
|
||||||
argList::addBoolOption("default", "reinstate default tests");
|
argList::addBoolOption("default", "reinstate default tests");
|
||||||
@ -235,6 +355,69 @@ int main(int argc, char *argv[])
|
|||||||
Info<< nl;
|
Info<< nl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (args.optionFound("validate"))
|
||||||
|
{
|
||||||
|
unsigned nFail = 0;
|
||||||
|
Info<< nl << "Test fileName::validate" << nl;
|
||||||
|
|
||||||
|
// Without clean
|
||||||
|
nFail += testEquals
|
||||||
|
(
|
||||||
|
{
|
||||||
|
{ true, { "abc", "abc/" } },
|
||||||
|
{ true, { "///abc/", "//abc///" } },
|
||||||
|
{ false, { " ab //c/", "ab/c" } },
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
Info<< nl << "Test fileName::validate" << nl;
|
||||||
|
|
||||||
|
// Without clean
|
||||||
|
nFail += testStrip
|
||||||
|
(
|
||||||
|
false,
|
||||||
|
{
|
||||||
|
{ true, "abc/" },
|
||||||
|
{ true, "/", },
|
||||||
|
{ true, "//", },
|
||||||
|
{ true, "/abc/def", },
|
||||||
|
{ true, "/abc/def/", },
|
||||||
|
{ false, "/abc def" },
|
||||||
|
{ true, "/abc////def///", },
|
||||||
|
{ false, "/abc//// def///" },
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// With clean
|
||||||
|
nFail += testStrip
|
||||||
|
(
|
||||||
|
true,
|
||||||
|
{
|
||||||
|
{ true, "abc/" },
|
||||||
|
{ true, "/" },
|
||||||
|
{ true, "//" },
|
||||||
|
{ true, "/abc/def" },
|
||||||
|
{ true, "/abc/def/" },
|
||||||
|
{ false, "/abc def" },
|
||||||
|
{ true, "/abc////def///" },
|
||||||
|
{ false, "/abc//// def///" },
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
Info<< nl;
|
||||||
|
if (nFail)
|
||||||
|
{
|
||||||
|
Info<< "failed " << nFail;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Info<< "passed all";
|
||||||
|
}
|
||||||
|
Info<< " fileName::validate tests" << nl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!defaultTests)
|
if (!defaultTests)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
@ -312,10 +495,32 @@ int main(int argc, char *argv[])
|
|||||||
Foam::rm(lnB);
|
Foam::rm(lnB);
|
||||||
Foam::rmDir(dirB);
|
Foam::rmDir(dirB);
|
||||||
|
|
||||||
|
Info<< nl << "=========================" << nl
|
||||||
|
<< "Test some copying and deletion" << endl;
|
||||||
|
|
||||||
|
|
||||||
Info<< "Creating directory " << dirA << endl;
|
Info<< "Creating directory " << dirA << endl;
|
||||||
Foam::mkDir(dirA);
|
Foam::mkDir(dirA);
|
||||||
|
|
||||||
|
Info<< "Populating with various files" << endl;
|
||||||
|
for
|
||||||
|
(
|
||||||
|
const std::string name
|
||||||
|
: { "file-1", "file-2", "bad name one", "bad name 2" }
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// Full path, but without any stripping
|
||||||
|
const fileName file
|
||||||
|
(
|
||||||
|
(static_cast<const std::string&>(dirA) + "/" + name),
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
Info<<" create: " << file << endl;
|
||||||
|
|
||||||
|
std::ofstream os(file);
|
||||||
|
os << "file=<" << file << ">" << nl;
|
||||||
|
}
|
||||||
|
|
||||||
const int oldPosix = POSIX::debug;
|
const int oldPosix = POSIX::debug;
|
||||||
POSIX::debug = 1;
|
POSIX::debug = 1;
|
||||||
@ -362,7 +567,7 @@ int main(int argc, char *argv[])
|
|||||||
<< " but is " << lnB.type(true) << exit(FatalError);
|
<< " but is " << lnB.type(true) << exit(FatalError);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete
|
// Delete (link)
|
||||||
Foam::rm(lnB);
|
Foam::rm(lnB);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -379,12 +584,13 @@ int main(int argc, char *argv[])
|
|||||||
<< " but is " << lnB.type(false) << exit(FatalError);
|
<< " but is " << lnB.type(false) << exit(FatalError);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete
|
// Delete (directory, not link)
|
||||||
Foam::rm(lnB);
|
Foam::rmDir(lnB);
|
||||||
}
|
}
|
||||||
|
|
||||||
POSIX::debug = oldPosix;
|
POSIX::debug = oldPosix;
|
||||||
|
|
||||||
|
// Verify that rmDir works with bad names too
|
||||||
Foam::rmDir(dirA);
|
Foam::rmDir(dirA);
|
||||||
Foam::rm(lnA);
|
Foam::rm(lnA);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -51,7 +51,10 @@ template<class TYPE>
|
|||||||
unsigned testParsing
|
unsigned testParsing
|
||||||
(
|
(
|
||||||
TYPE (*function)(const std::string&),
|
TYPE (*function)(const std::string&),
|
||||||
const List<Tuple2<std::string, bool>>& tests
|
std::initializer_list
|
||||||
|
<
|
||||||
|
Tuple2<bool, std::string>
|
||||||
|
> tests
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
unsigned nFail = 0;
|
unsigned nFail = 0;
|
||||||
@ -60,10 +63,10 @@ unsigned testParsing
|
|||||||
// Expect some failures
|
// Expect some failures
|
||||||
const bool prev = FatalIOError.throwExceptions();
|
const bool prev = FatalIOError.throwExceptions();
|
||||||
|
|
||||||
for (const Tuple2<std::string, bool>& test : tests)
|
for (const Tuple2<bool, std::string>& test : tests)
|
||||||
{
|
{
|
||||||
const std::string& str = test.first();
|
const bool expected = test.first();
|
||||||
const bool expected = test.second();
|
const std::string& str = test.second();
|
||||||
|
|
||||||
bool parsed = true;
|
bool parsed = true;
|
||||||
|
|
||||||
@ -124,18 +127,18 @@ int main(int argc, char *argv[])
|
|||||||
(
|
(
|
||||||
&readDouble,
|
&readDouble,
|
||||||
{
|
{
|
||||||
{ "", false },
|
{ false, "" },
|
||||||
{ " ", false },
|
{ false, " " },
|
||||||
{ " xxx ", false },
|
{ false, " xxx " },
|
||||||
{ " 1234E-", false },
|
{ false, " 1234E-" },
|
||||||
{ " 1234E junk", false },
|
{ false, " 1234E junk" },
|
||||||
{ " 3.14159 ", true },
|
{ true, " 3.14159 " },
|
||||||
{ " 31.4159E-1 " , true },
|
{ true, " 31.4159E-1 " },
|
||||||
{ " 100E1000 " , false },
|
{ false, " 100E1000 " },
|
||||||
{ " 1E-40 " , true },
|
{ true, " 1E-40 " },
|
||||||
{ " 1E-305 " , true },
|
{ true, " 1E-305 " },
|
||||||
{ " 1E-37 " , true },
|
{ true, " 1E-37 " },
|
||||||
{ " 1E-300 " , true },
|
{ true, " 1E-300 " },
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -148,14 +151,14 @@ int main(int argc, char *argv[])
|
|||||||
(
|
(
|
||||||
&readFloat,
|
&readFloat,
|
||||||
{
|
{
|
||||||
{ " 3.14159 ", true },
|
{ true, " 3.14159 " },
|
||||||
{ " 31.4159E-1 " , true },
|
{ true, " 31.4159E-1 " },
|
||||||
{ " 31.4159E200 " , false },
|
{ false, " 31.4159E200 " },
|
||||||
{ " 31.4159E20 " , true },
|
{ true, " 31.4159E20 " },
|
||||||
{ " 1E-40 " , true },
|
{ true, " 1E-40 " },
|
||||||
{ " 1E-305 " , true },
|
{ true, " 1E-305 " },
|
||||||
{ " 1E-37 " , true },
|
{ true, " 1E-37 " },
|
||||||
{ " 1E-300 " , true },
|
{ true, " 1E-300 " },
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -166,15 +169,15 @@ int main(int argc, char *argv[])
|
|||||||
(
|
(
|
||||||
&readNasScalar,
|
&readNasScalar,
|
||||||
{
|
{
|
||||||
{ " 3.14159 ", true },
|
{ true, " 3.14159 " },
|
||||||
{ " 31.4159E-1 " , true },
|
{ true, " 31.4159E-1 " },
|
||||||
{ " 314.159-2 " , true },
|
{ true, " 314.159-2 " },
|
||||||
{ " 31.4159E200 " , true },
|
{ true, " 31.4159E200 " },
|
||||||
{ " 31.4159E20 " , true },
|
{ true, " 31.4159E20 " },
|
||||||
{ " 1E-40 " , true },
|
{ true, " 1E-40 " },
|
||||||
{ " 1E-305 " , true },
|
{ true, " 1E-305 " },
|
||||||
{ " 1E-37 " , true },
|
{ true, " 1E-37 " },
|
||||||
{ " 1E-300 " , true },
|
{ true, " 1E-300 " },
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -185,12 +188,12 @@ int main(int argc, char *argv[])
|
|||||||
(
|
(
|
||||||
&readInt32,
|
&readInt32,
|
||||||
{
|
{
|
||||||
{ " 3.14159 ", false },
|
{ false, " 3.14159 " },
|
||||||
{ " 31E1 ", false },
|
{ false, " 31E1 " },
|
||||||
{ " 31.4159E-1 " , false },
|
{ false, " 31.4159E-1 " },
|
||||||
{ "100" , true },
|
{ true, "100" },
|
||||||
{ " 2147483644" , true },
|
{ true, " 2147483644" },
|
||||||
{ " 2147483700 " , false },
|
{ false, " 2147483700 " },
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -202,10 +205,10 @@ int main(int argc, char *argv[])
|
|||||||
(
|
(
|
||||||
&readUint32,
|
&readUint32,
|
||||||
{
|
{
|
||||||
{ " 2147483644" , true },
|
{ true, "\t2147483644" },
|
||||||
{ " 2147483700 " , true },
|
{ true, " 2147483700 " },
|
||||||
{ " 4294967295 " , true },
|
{ true, " 4294967295 " },
|
||||||
{ " 4294968000 " , false },
|
{ false, " 4294968000 " },
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -109,6 +109,35 @@ static inline bool isBackupName(const Foam::fileName& name)
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Like fileName "/" global operator, but retain any invalid characters
|
||||||
|
static inline Foam::fileName fileNameConcat
|
||||||
|
(
|
||||||
|
const std::string& a,
|
||||||
|
const std::string& b
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (a.size())
|
||||||
|
{
|
||||||
|
if (b.size())
|
||||||
|
{
|
||||||
|
// Two non-empty strings: can concatenate
|
||||||
|
return Foam::fileName((a + '/' + b), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Foam::fileName(a, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Or, if the first string is empty
|
||||||
|
|
||||||
|
if (b.size())
|
||||||
|
{
|
||||||
|
return Foam::fileName(b, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Both strings are empty
|
||||||
|
return Foam::fileName();
|
||||||
|
}
|
||||||
//! \endcond
|
//! \endcond
|
||||||
|
|
||||||
|
|
||||||
@ -148,12 +177,10 @@ Foam::string Foam::getEnv(const std::string& envName)
|
|||||||
{
|
{
|
||||||
return string(env);
|
return string(env);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
// Return null-constructed string rather than string::null
|
||||||
// Return null-constructed string rather than string::null
|
// to avoid cyclic dependencies in the construction of globals
|
||||||
// to avoid cyclic dependencies in the construction of globals
|
return string();
|
||||||
return string();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -220,10 +247,8 @@ Foam::string Foam::userName()
|
|||||||
{
|
{
|
||||||
return pw->pw_name;
|
return pw->pw_name;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
return string();
|
||||||
return string();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -246,10 +271,8 @@ Foam::fileName Foam::home()
|
|||||||
{
|
{
|
||||||
return pw->pw_dir;
|
return pw->pw_dir;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
return fileName();
|
||||||
return fileName();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -266,10 +289,8 @@ Foam::fileName Foam::home(const std::string& userName)
|
|||||||
{
|
{
|
||||||
return pw->pw_dir;
|
return pw->pw_dir;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
return fileName();
|
||||||
return fileName();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -708,14 +729,15 @@ Foam::fileNameList Foam::readDir
|
|||||||
const bool followLink
|
const bool followLink
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
// Initial filename list size
|
// Initial filename list size and the increment when resizing the list
|
||||||
// also used as increment if initial size found to be insufficient
|
|
||||||
static const int maxNnames = 100;
|
static const int maxNnames = 100;
|
||||||
|
|
||||||
// Basic sanity: cannot strip '.gz' from directory names
|
// Basic sanity: cannot strip '.gz' from directory names
|
||||||
const bool stripgz = filtergz && (type != fileName::DIRECTORY);
|
const bool stripgz = filtergz && (type != fileName::DIRECTORY);
|
||||||
const word extgz("gz");
|
const word extgz("gz");
|
||||||
|
|
||||||
|
fileNameList dirEntries;
|
||||||
|
|
||||||
// Open directory and set the structure pointer
|
// Open directory and set the structure pointer
|
||||||
// Do not attempt to open an empty directory name
|
// Do not attempt to open an empty directory name
|
||||||
DIR *source;
|
DIR *source;
|
||||||
@ -731,12 +753,12 @@ Foam::fileNameList Foam::readDir
|
|||||||
<< "cannot open directory " << directory << endl;
|
<< "cannot open directory " << directory << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
return fileNameList();
|
return dirEntries;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (POSIX::debug)
|
if (POSIX::debug)
|
||||||
{
|
{
|
||||||
//InfoInFunction
|
// InfoInFunction
|
||||||
Pout<< FUNCTION_NAME << " : reading directory " << directory << endl;
|
Pout<< FUNCTION_NAME << " : reading directory " << directory << endl;
|
||||||
if ((POSIX::debug & 2) && !Pstream::master())
|
if ((POSIX::debug & 2) && !Pstream::master())
|
||||||
{
|
{
|
||||||
@ -744,22 +766,31 @@ Foam::fileNameList Foam::readDir
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
label nEntries = 0;
|
label nFailed = 0; // Entries with invalid characters
|
||||||
fileNameList dirEntries(maxNnames);
|
label nEntries = 0; // Number of selected entries
|
||||||
|
dirEntries.setSize(maxNnames);
|
||||||
|
|
||||||
// Read and parse all the entries in the directory
|
// Read and parse all the entries in the directory
|
||||||
for (struct dirent *list; (list = ::readdir(source)) != nullptr; /*nil*/)
|
for (struct dirent *list; (list = ::readdir(source)) != nullptr; /*nil*/)
|
||||||
{
|
{
|
||||||
const fileName name(list->d_name);
|
const std::string item(list->d_name);
|
||||||
|
|
||||||
// Ignore files/directories beginning with "."
|
// Ignore files/directories beginning with "."
|
||||||
// These are the ".", ".." directories and any hidden files/dirs
|
// These are the ".", ".." directories and any hidden files/dirs
|
||||||
if (name.empty() || name[0] == '.')
|
if (item.empty() || item[0] == '.')
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if
|
// Validate filename without spaces, quotes, etc in the name.
|
||||||
|
// No duplicate slashes to strip - dirent will not have them anyhow.
|
||||||
|
|
||||||
|
const fileName name(fileName::validate(item));
|
||||||
|
if (name != item)
|
||||||
|
{
|
||||||
|
++nFailed;
|
||||||
|
}
|
||||||
|
else if
|
||||||
(
|
(
|
||||||
(type == fileName::DIRECTORY)
|
(type == fileName::DIRECTORY)
|
||||||
|| (type == fileName::FILE && !isBackupName(name))
|
|| (type == fileName::FILE && !isBackupName(name))
|
||||||
@ -783,11 +814,19 @@ Foam::fileNameList Foam::readDir
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset the length of the entries list
|
|
||||||
dirEntries.setSize(nEntries);
|
|
||||||
::closedir(source);
|
::closedir(source);
|
||||||
|
|
||||||
|
// Finalize the length of the entries list
|
||||||
|
dirEntries.setSize(nEntries);
|
||||||
|
|
||||||
|
if (nFailed && POSIX::debug)
|
||||||
|
{
|
||||||
|
std::cerr
|
||||||
|
<< "Foam::readDir() : reading directory " << directory << nl
|
||||||
|
<< nFailed << " entries with invalid characters in their name"
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
return dirEntries;
|
return dirEntries;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -911,22 +950,22 @@ bool Foam::cp(const fileName& src, const fileName& dest, const bool followLink)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Copy files
|
// Copy files
|
||||||
fileNameList contents = readDir(src, fileName::FILE, false, followLink);
|
fileNameList files = readDir(src, fileName::FILE, false, followLink);
|
||||||
forAll(contents, i)
|
for (const fileName& item : files)
|
||||||
{
|
{
|
||||||
if (POSIX::debug)
|
if (POSIX::debug)
|
||||||
{
|
{
|
||||||
InfoInFunction
|
InfoInFunction
|
||||||
<< "Copying : " << src/contents[i]
|
<< "Copying : " << src/item
|
||||||
<< " to " << destFile/contents[i] << endl;
|
<< " to " << destFile/item << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
// File to file.
|
// File to file.
|
||||||
cp(src/contents[i], destFile/contents[i], followLink);
|
cp(src/item, destFile/item, followLink);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy sub directories.
|
// Copy sub directories.
|
||||||
fileNameList subdirs = readDir
|
fileNameList dirs = readDir
|
||||||
(
|
(
|
||||||
src,
|
src,
|
||||||
fileName::DIRECTORY,
|
fileName::DIRECTORY,
|
||||||
@ -934,17 +973,17 @@ bool Foam::cp(const fileName& src, const fileName& dest, const bool followLink)
|
|||||||
followLink
|
followLink
|
||||||
);
|
);
|
||||||
|
|
||||||
forAll(subdirs, i)
|
for (const fileName& item : dirs)
|
||||||
{
|
{
|
||||||
if (POSIX::debug)
|
if (POSIX::debug)
|
||||||
{
|
{
|
||||||
InfoInFunction
|
InfoInFunction
|
||||||
<< "Copying : " << src/subdirs[i]
|
<< "Copying : " << src/item
|
||||||
<< " to " << destFile << endl;
|
<< " to " << destFile << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dir to Dir.
|
// Dir to Dir.
|
||||||
cp(src/subdirs[i], destFile, followLink);
|
cp(src/item, destFile, followLink);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -1002,12 +1041,10 @@ bool Foam::ln(const fileName& src, const fileName& dst)
|
|||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
WarningInFunction
|
||||||
WarningInFunction
|
<< "symlink from " << src << " to " << dst << " failed." << endl;
|
||||||
<< "symlink from " << src << " to " << dst << " failed." << endl;
|
return false;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1157,14 +1194,20 @@ bool Foam::rmDir(const fileName& directory, const bool silent)
|
|||||||
label nErrors = 0;
|
label nErrors = 0;
|
||||||
for (struct dirent *list; (list = ::readdir(source)) != nullptr; /*nil*/)
|
for (struct dirent *list; (list = ::readdir(source)) != nullptr; /*nil*/)
|
||||||
{
|
{
|
||||||
const fileName name(list->d_name);
|
const std::string item(list->d_name);
|
||||||
if (name.empty() || name == "." || name == "..")
|
|
||||||
|
// Ignore "." and ".." directories
|
||||||
|
if (item.empty() || item == "." || item == "..")
|
||||||
{
|
{
|
||||||
// Ignore "." and ".." directories
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const fileName path = directory/name;
|
// Allow invalid characters (spaces, quotes, etc),
|
||||||
|
// otherwise we cannot subdirs with these types of names.
|
||||||
|
// -> const fileName path = directory/name; <-
|
||||||
|
|
||||||
|
const fileName path(fileNameConcat(directory, item));
|
||||||
|
|
||||||
if (path.type(false) == fileName::DIRECTORY)
|
if (path.type(false) == fileName::DIRECTORY)
|
||||||
{
|
{
|
||||||
if (!rmDir(path, true)) // Only report errors at the top-level
|
if (!rmDir(path, true)) // Only report errors at the top-level
|
||||||
@ -1548,10 +1591,8 @@ bool Foam::dlSymFound(void* handle, const std::string& symbol)
|
|||||||
// symbol can be found if there was no error
|
// symbol can be found if there was no error
|
||||||
return !::dlerror();
|
return !::dlerror();
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
return false;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1680,7 +1721,7 @@ Foam::label Foam::allocateThread()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
label index = threads_.size();
|
const label index = threads_.size();
|
||||||
if (POSIX::debug)
|
if (POSIX::debug)
|
||||||
{
|
{
|
||||||
Pout<< "allocateThread : new index:" << index << endl;
|
Pout<< "allocateThread : new index:" << index << endl;
|
||||||
@ -1750,7 +1791,7 @@ Foam::label Foam::allocateMutex()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
label index = mutexes_.size();
|
const label index = mutexes_.size();
|
||||||
|
|
||||||
if (POSIX::debug)
|
if (POSIX::debug)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -37,20 +37,105 @@ int Foam::fileName::debug(debug::debugSwitch(fileName::typeName, 0));
|
|||||||
const Foam::fileName Foam::fileName::null;
|
const Foam::fileName Foam::fileName::null;
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
Foam::fileName Foam::fileName::validate
|
||||||
|
(
|
||||||
|
const std::string& s,
|
||||||
|
const bool doClean
|
||||||
|
)
|
||||||
|
{
|
||||||
|
fileName out;
|
||||||
|
out.resize(s.size());
|
||||||
|
|
||||||
|
char prev = 0;
|
||||||
|
std::string::size_type count = 0;
|
||||||
|
|
||||||
|
// Largely as per stripInvalid
|
||||||
|
for (auto iter = s.cbegin(); iter != s.cend(); ++iter)
|
||||||
|
{
|
||||||
|
const char c = *iter;
|
||||||
|
|
||||||
|
if (fileName::valid(c))
|
||||||
|
{
|
||||||
|
if (doClean && prev == '/' && c == '/')
|
||||||
|
{
|
||||||
|
// Avoid repeated '/';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only track valid chars
|
||||||
|
out[count++] = prev = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (doClean && prev == '/' && count > 1)
|
||||||
|
{
|
||||||
|
// Avoid trailing '/'
|
||||||
|
--count;
|
||||||
|
}
|
||||||
|
|
||||||
|
out.resize(count);
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Foam::fileName::equals(const std::string& s1, const std::string& s2)
|
||||||
|
{
|
||||||
|
// Do not use (s1 == s2) or s1.compare(s2) first since this would
|
||||||
|
// potentially be doing the comparison twice.
|
||||||
|
|
||||||
|
std::string::size_type i1 = 0;
|
||||||
|
std::string::size_type i2 = 0;
|
||||||
|
|
||||||
|
const auto n1 = s1.size();
|
||||||
|
const auto n2 = s2.size();
|
||||||
|
|
||||||
|
//Info<< "compare " << s1 << " == " << s2 << endl;
|
||||||
|
while (i1 < n1 && i2 < n2)
|
||||||
|
{
|
||||||
|
//Info<< "check '" << s1[i1] << "' vs '" << s2[i2] << "'" << endl;
|
||||||
|
|
||||||
|
if (s1[i1] != s2[i2])
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Increment to next positions and also skip repeated slashes
|
||||||
|
do
|
||||||
|
{
|
||||||
|
++i1;
|
||||||
|
}
|
||||||
|
while (s1[i1] == '/');
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
++i2;
|
||||||
|
}
|
||||||
|
while (s2[i2] == '/');
|
||||||
|
}
|
||||||
|
//Info<< "return: " << Switch(i1 == n1 && i2 == n2) << endl;
|
||||||
|
|
||||||
|
// Equal if it made it all the way through both strings
|
||||||
|
return (i1 == n1 && i2 == n2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
Foam::fileName::fileName(const UList<word>& lst)
|
Foam::fileName::fileName(const UList<word>& lst)
|
||||||
{
|
{
|
||||||
// Estimate overall size
|
// Estimate overall size
|
||||||
size_type sz = lst.size(); // Approx number of '/' needed
|
size_type sz = lst.size(); // Approx number of '/' needed
|
||||||
for (const auto& item : lst)
|
for (const word& item : lst)
|
||||||
{
|
{
|
||||||
sz += item.size();
|
sz += item.size();
|
||||||
}
|
}
|
||||||
reserve(sz);
|
reserve(sz);
|
||||||
|
|
||||||
sz = 0;
|
sz = 0;
|
||||||
for (const auto& item : lst)
|
for (const word& item : lst)
|
||||||
{
|
{
|
||||||
if (item.size())
|
if (item.size())
|
||||||
{
|
{
|
||||||
@ -65,14 +150,14 @@ Foam::fileName::fileName(std::initializer_list<word> lst)
|
|||||||
{
|
{
|
||||||
// Estimate overall size
|
// Estimate overall size
|
||||||
size_type sz = lst.size(); // Approx number of '/' needed
|
size_type sz = lst.size(); // Approx number of '/' needed
|
||||||
for (const auto& item : lst)
|
for (const word& item : lst)
|
||||||
{
|
{
|
||||||
sz += item.size();
|
sz += item.size();
|
||||||
}
|
}
|
||||||
reserve(sz);
|
reserve(sz);
|
||||||
|
|
||||||
sz = 0;
|
sz = 0;
|
||||||
for (const auto& item : lst)
|
for (const word& item : lst)
|
||||||
{
|
{
|
||||||
if (item.size())
|
if (item.size())
|
||||||
{
|
{
|
||||||
@ -217,10 +302,8 @@ std::string Foam::fileName::name(const std::string& str)
|
|||||||
{
|
{
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
return str.substr(beg+1);
|
||||||
return str.substr(beg+1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -253,10 +336,8 @@ std::string Foam::fileName::nameLessExt(const std::string& str)
|
|||||||
{
|
{
|
||||||
return str.substr(beg);
|
return str.substr(beg);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
return str.substr(beg, dot - beg);
|
||||||
return str.substr(beg, dot - beg);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -299,10 +380,8 @@ Foam::fileName Foam::fileName::lessExt() const
|
|||||||
{
|
{
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
return substr(0, i);
|
||||||
return substr(0, i);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -407,28 +486,26 @@ void Foam::fileName::operator=(const char* str)
|
|||||||
|
|
||||||
Foam::fileName Foam::operator/(const string& a, const string& b)
|
Foam::fileName Foam::operator/(const string& a, const string& b)
|
||||||
{
|
{
|
||||||
if (a.size()) // First string non-null
|
if (a.size())
|
||||||
{
|
{
|
||||||
if (b.size()) // Second string non-null
|
if (b.size())
|
||||||
{
|
{
|
||||||
|
// Two non-empty strings: can concatenate
|
||||||
return fileName(a + '/' + b);
|
return fileName(a + '/' + b);
|
||||||
}
|
}
|
||||||
else // Second string null
|
|
||||||
{
|
return a;
|
||||||
return a;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else // First string null
|
|
||||||
|
// Or, if the first string is empty
|
||||||
|
|
||||||
|
if (b.size())
|
||||||
{
|
{
|
||||||
if (b.size()) // Second string non-null
|
return b;
|
||||||
{
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
else // Second string null
|
|
||||||
{
|
|
||||||
return fileName();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Both strings are empty
|
||||||
|
return fileName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -438,19 +515,19 @@ Foam::fileName Foam::search(const word& file, const fileName& directory)
|
|||||||
{
|
{
|
||||||
// Search the current directory for the file
|
// Search the current directory for the file
|
||||||
fileNameList files(fileHandler().readDir(directory));
|
fileNameList files(fileHandler().readDir(directory));
|
||||||
forAll(files, i)
|
for (const fileName& item : files)
|
||||||
{
|
{
|
||||||
if (files[i] == file)
|
if (item == file)
|
||||||
{
|
{
|
||||||
return directory/file;
|
return directory/item;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If not found search each of the sub-directories
|
// If not found search each of the sub-directories
|
||||||
fileNameList dirs(fileHandler().readDir(directory, fileName::DIRECTORY));
|
fileNameList dirs(fileHandler().readDir(directory, fileName::DIRECTORY));
|
||||||
forAll(dirs, i)
|
for (const fileName& item : dirs)
|
||||||
{
|
{
|
||||||
fileName path = search(file, directory/dirs[i]);
|
fileName path = search(file, directory/item);
|
||||||
if (path != fileName::null)
|
if (path != fileName::null)
|
||||||
{
|
{
|
||||||
return path;
|
return path;
|
||||||
|
|||||||
@ -135,6 +135,20 @@ public:
|
|||||||
//- Is this character valid for a fileName?
|
//- Is this character valid for a fileName?
|
||||||
inline static bool valid(char c);
|
inline static bool valid(char c);
|
||||||
|
|
||||||
|
//- Construct validated fileName (no invalid characters).
|
||||||
|
// Optionally perform some additional cleanup such as removing
|
||||||
|
// duplicate or trailing slashes.
|
||||||
|
static fileName validate
|
||||||
|
(
|
||||||
|
const std::string& s,
|
||||||
|
const bool doClean=false
|
||||||
|
);
|
||||||
|
|
||||||
|
//- This is a specialized (possibly slower) version of compare()
|
||||||
|
// that ignores duplicate or trailing slashes.
|
||||||
|
static bool equals(const std::string& s1, const std::string& s2);
|
||||||
|
|
||||||
|
|
||||||
//- Cleanup filename
|
//- Cleanup filename
|
||||||
//
|
//
|
||||||
// Removes trailing \c /
|
// Removes trailing \c /
|
||||||
|
|||||||
Reference in New Issue
Block a user