ENH: Foam::readLink(..)

- recover the target of symbolic links.
  This is needed when re-creating a file tree on another rank.

ENH: handle checkGzip, followLink flags in fileHander filePath()

- previously just relied on the backend defaults, now pass through
- separate init(...) for common constructor init steps
This commit is contained in:
mattijs 2022-11-24 09:00:00 +00:00 committed by Mark Olesen
parent 478c1b2312
commit 286c6ce7d8
18 changed files with 296 additions and 135 deletions

View File

@ -940,13 +940,24 @@ bool Foam::ln(const fileName& src, const fileName& dst)
if (MSwindows::debug) if (MSwindows::debug)
{ {
Info<< "MSwindows does not support ln - softlinking" << endl; Info<< "MSwindows does not support softlinks" << endl;
} }
return false; return false;
} }
Foam::fileName Foam::readLink(const fileName& link)
{
if (MSwindows::debug)
{
Info<< "MSwindows does not support softlinks" << endl;
}
return fileName();
}
bool Foam::mv(const fileName& src, const fileName& dst, const bool followLink) bool Foam::mv(const fileName& src, const fileName& dst, const bool followLink)
{ {
if (MSwindows::debug) if (MSwindows::debug)
@ -954,7 +965,7 @@ bool Foam::mv(const fileName& src, const fileName& dst, const bool followLink)
Info<< "Move : " << src << " to " << dst << endl; Info<< "Move : " << src << " to " << dst << endl;
} }
// Ignore an empty names => always false // Ignore empty names => always false
if (src.empty() || dst.empty()) if (src.empty() || dst.empty())
{ {
return false; return false;

View File

@ -1169,7 +1169,7 @@ bool Foam::ln(const fileName& src, const fileName& dst)
{ {
//InfoInFunction //InfoInFunction
Pout<< FUNCTION_NAME Pout<< FUNCTION_NAME
<< " : Create softlink from : " << src << " to " << dst << endl; << " : Create symlink from : " << src << " to " << dst << endl;
if ((POSIX::debug & 2) && !Pstream::master()) if ((POSIX::debug & 2) && !Pstream::master())
{ {
error::printStack(Pout); error::printStack(Pout);
@ -1216,6 +1216,40 @@ bool Foam::ln(const fileName& src, const fileName& dst)
} }
Foam::fileName Foam::readLink(const fileName& link)
{
if (POSIX::debug)
{
//InfoInFunction
Pout<< FUNCTION_NAME
<< " : Returning symlink destination for : " << link << endl;
if ((POSIX::debug & 2) && !Pstream::master())
{
error::printStack(Pout);
}
}
if (link.empty())
{
// Treat an empty path as a no-op.
return fileName();
}
fileName result;
result.resize(1024); // Should be large enough (mostly relative anyhow)
ssize_t len = ::readlink(link.c_str(), &(result.front()), result.size());
if (len > 0)
{
result.resize(len);
return result;
}
// Failure: return empty result
return fileName();
}
bool Foam::mv(const fileName& src, const fileName& dst, const bool followLink) bool Foam::mv(const fileName& src, const fileName& dst, const bool followLink)
{ {
if (POSIX::debug) if (POSIX::debug)
@ -1228,7 +1262,7 @@ bool Foam::mv(const fileName& src, const fileName& dst, const bool followLink)
} }
} }
// Ignore an empty names => always false // Ignore empty names => always false
if (src.empty() || dst.empty()) if (src.empty() || dst.empty())
{ {
return false; return false;

View File

@ -195,13 +195,14 @@ void Foam::Time::setControls()
// Check if time directory exists // Check if time directory exists
// If not increase time precision to see if it is formatted differently. // If not increase time precision to see if it is formatted differently.
// Note: do not use raw fileHandler().exists(...) since does not check // Note: - do not use raw fileHandler().exists(...) since does not check
// alternative processorsDDD directories naming // alternative processorsDDD directories naming
if (fileHandler().filePath(timePath()).empty()) // - do not look for compressed (is directory)
if (fileHandler().filePath(timePath(), false).empty())
{ {
int oldPrecision = precision_; const int oldPrecision = precision_;
int requiredPrecision = -1; int requiredPrecision = -1;
bool found = false;
word oldTime(timeName()); word oldTime(timeName());
for for
( (
@ -218,14 +219,10 @@ void Foam::Time::setControls()
{ {
break; break;
} }
oldTime = newTime; oldTime = std::move(newTime);
// Check the existence of the time directory with the new format // Does a time directory exist with the new format?
//found = fileHandler().exists(timePath(), false); if (!fileHandler().filePath(timePath(), false).empty())
const fileName dirName(fileHandler().filePath(timePath()));
found = !dirName.empty();
if (found)
{ {
requiredPrecision = precision_; requiredPrecision = precision_;
} }

View File

@ -414,6 +414,15 @@ public:
return runTimeModifiable_; return runTimeModifiable_;
} }
//- Set re-reading support on/off (use with caution).
// \return the previous value
Switch runTimeModifiable(const Switch sw) noexcept
{
Switch old(runTimeModifiable_);
runTimeModifiable_ = sw;
return old;
}
//- Read control dictionary, update controls and time //- Read control dictionary, update controls and time
virtual bool read(); virtual bool read();

View File

@ -579,7 +579,8 @@ bool Foam::Time::writeObject
( (
fileHandler().filePath fileHandler().filePath
( (
objectRegistry::path(previousWriteTimes_.pop()) objectRegistry::path(previousWriteTimes_.pop()),
false // No .gz check (is directory)
) )
); );
} }

View File

@ -241,6 +241,51 @@ static void printHostsSubscription(const UList<string>& hostProcs)
Info<< ')' << nl; Info<< ')' << nl;
} }
static bool printRootsSubscription
(
const UList<string>& hostProcs,
const UList<fileName>& roots
)
{
if (hostProcs.size() == roots.size()+1)
{
// Sort roots according to hostProc
DynamicList<string> sortedProcs;
DynamicList<label> sortedRoots;
forAll(roots, i)
{
const fileName& root = roots[i];
const string& host = hostProcs[i+1];
const label index = sortedProcs.find(host);
if (index == -1)
{
sortedProcs.append(host);
sortedRoots.append(i);
}
else if (roots[sortedRoots[index]] != root)
{
// Not properly sorted...
return false;
}
}
Info<< "Roots :\n(" << nl;
forAll(sortedProcs, i)
{
Info<< " (" << sortedProcs[i].c_str() << ' '
<< roots[sortedRoots[i]] << ')' << nl;
}
Info<< ')' << nl;
return true;
}
return false;
}
} // End namespace Foam } // End namespace Foam
@ -1184,6 +1229,7 @@ void Foam::argList::parse
stringList hostMachine; stringList hostMachine;
stringList hostProcs; stringList hostProcs;
const int writeHostsSwitch = Foam::debug::infoSwitch("writeHosts", 1); const int writeHostsSwitch = Foam::debug::infoSwitch("writeHosts", 1);
const int writeRootsSwitch = Foam::debug::infoSwitch("writeRoots", 1);
// Collect machine/pid, and check that the build is identical // Collect machine/pid, and check that the build is identical
if (runControl_.parRun()) if (runControl_.parRun())
@ -1615,7 +1661,7 @@ void Foam::argList::parse
// Clear here to ensures it doesn't show in the jobInfo // Clear here to ensures it doesn't show in the jobInfo
hostProcs.clear(); hostProcs.clear();
} }
if (!debug::infoSwitch("writeRoots", 1)) if (!writeRootsSwitch)
{ {
roots.clear(); roots.clear();
} }
@ -1654,7 +1700,17 @@ void Foam::argList::parse
} }
if (roots.size()) if (roots.size())
{ {
Info<< "Roots : " << roots << nl; bool hasPrinted = false;
if (writeRootsSwitch == 1)
{
// Compact output
hasPrinted = printRootsSubscription(hostProcs, roots);
}
if (writeRootsSwitch && !hasPrinted)
{
// Full output
Info<< "Roots : " << roots << nl;
}
} }
Info<< "Pstream initialized with:" << nl Info<< "Pstream initialized with:" << nl
<< " floatTransfer : " << Pstream::floatTransfer << nl << " floatTransfer : " << Pstream::floatTransfer << nl
@ -2000,7 +2056,7 @@ bool Foam::argList::checkRootCase() const
return false; return false;
} }
const fileName pathDir(fileHandler().filePath(path())); const fileName pathDir(fileHandler().filePath(path(), false));
if (checkProcessorDirectories_ && pathDir.empty() && Pstream::master()) if (checkProcessorDirectories_ && pathDir.empty() && Pstream::master())
{ {

View File

@ -258,6 +258,17 @@ bool Foam::fileOperations::collatedFileOperation::appendObject
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
void Foam::fileOperations::collatedFileOperation::init(bool verbose)
{
verbose = (verbose && Foam::infoDetailLevel > 0);
if (verbose)
{
this->printBanner(ioRanks_.size());
}
}
Foam::fileOperations::collatedFileOperation::collatedFileOperation Foam::fileOperations::collatedFileOperation::collatedFileOperation
( (
bool verbose bool verbose
@ -281,10 +292,7 @@ Foam::fileOperations::collatedFileOperation::collatedFileOperation
nProcs_(Pstream::nProcs()), nProcs_(Pstream::nProcs()),
ioRanks_(ioRanks()) ioRanks_(ioRanks())
{ {
if (verbose && Foam::infoDetailLevel > 0) init(verbose);
{
this->printBanner(ioRanks_.size());
}
} }
@ -302,10 +310,7 @@ Foam::fileOperations::collatedFileOperation::collatedFileOperation
nProcs_(Pstream::nProcs()), nProcs_(Pstream::nProcs()),
ioRanks_(ioRanks) ioRanks_(ioRanks)
{ {
if (verbose && Foam::infoDetailLevel > 0) init(verbose);
{
this->printBanner(ioRanks_.size());
}
} }

View File

@ -67,6 +67,11 @@ class collatedFileOperation
: :
public masterUncollatedFileOperation public masterUncollatedFileOperation
{ {
// Private Member Functions
//- Any initialisation steps after constructing
void init(bool verbose);
protected: protected:
// Protected Data // Protected Data

View File

@ -123,6 +123,17 @@ Foam::labelList Foam::fileOperations::hostCollatedFileOperation::subRanks
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
void Foam::fileOperations::hostCollatedFileOperation::init(bool verbose)
{
verbose = (verbose && Foam::infoDetailLevel > 0);
if (verbose)
{
this->printBanner(ioRanks_.size());
}
}
Foam::fileOperations::hostCollatedFileOperation::hostCollatedFileOperation Foam::fileOperations::hostCollatedFileOperation::hostCollatedFileOperation
( (
bool verbose bool verbose
@ -140,10 +151,7 @@ Foam::fileOperations::hostCollatedFileOperation::hostCollatedFileOperation
false // verbose false // verbose
) )
{ {
if (verbose && Foam::infoDetailLevel > 0) init(verbose);
{
this->printBanner(ioRanks_.size());
}
} }

View File

@ -77,12 +77,14 @@ class hostCollatedFileOperation
: :
public collatedFileOperation public collatedFileOperation
{ {
// Private Member Functions // Private Member Functions
//- Any initialisation steps after constructing
void init(bool verbose);
//- Get the list of processors part of this set //- Get the list of processors part of this set
static labelList subRanks(const label n); static labelList subRanks(const label n);
public: public:
//- Runtime type information //- Runtime type information

View File

@ -59,6 +59,8 @@ namespace Foam
); );
} }
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
const Foam::Enum<Foam::fileOperation::pathType> const Foam::Enum<Foam::fileOperation::pathType>
Foam::fileOperation::pathTypeNames_ Foam::fileOperation::pathTypeNames_
({ ({
@ -792,7 +794,12 @@ bool Foam::fileOperation::writeObject
} }
Foam::fileName Foam::fileOperation::filePath(const fileName& fName) const Foam::fileName Foam::fileOperation::filePath
(
const fileName& fName,
const bool checkGzip,
const bool followLink
) const
{ {
if (debug) if (debug)
{ {
@ -820,7 +827,7 @@ Foam::fileName Foam::fileOperation::filePath(const fileName& fName) const
const fileName& procDir = dirIdx.first(); const fileName& procDir = dirIdx.first();
fileName collatedName(path/procDir/local); fileName collatedName(path/procDir/local);
if (exists(collatedName)) if (exists(collatedName, checkGzip, followLink))
{ {
if (debug) if (debug)
{ {
@ -831,7 +838,7 @@ Foam::fileName Foam::fileOperation::filePath(const fileName& fName) const
} }
} }
if (exists(fName)) if (exists(fName, checkGzip, followLink))
{ {
if (debug) if (debug)
{ {
@ -844,7 +851,8 @@ Foam::fileName Foam::fileOperation::filePath(const fileName& fName) const
{ {
Pout<< "fileOperation::filePath : Not found" << endl; Pout<< "fileOperation::filePath : Not found" << endl;
} }
return fileName::null;
return fileName();
} }
@ -992,7 +1000,8 @@ Foam::instantList Foam::fileOperation::findTimes
if (debug) if (debug)
{ {
Pout<< "fileOperation::findTimes : Found times:" << times << endl; Pout<< "fileOperation::findTimes : Found times:" << flatOutput(times)
<< endl;
} }
return times; return times;
} }
@ -1177,7 +1186,7 @@ Foam::fileNameList Foam::fileOperation::readObjects
fileName path(db.path(instance, db.dbDir()/local)); fileName path(db.path(instance, db.dbDir()/local));
newInstance = word::null; newInstance.clear();
fileNameList objectNames; fileNameList objectNames;
if (Foam::isDir(path)) if (Foam::isDir(path))
@ -1311,7 +1320,7 @@ Foam::fileName Foam::fileOperation::processorsPath
return dir.path()/procsDir; return dir.path()/procsDir;
} }
return fileName::null; return fileName();
} }
@ -1502,7 +1511,7 @@ const Foam::fileOperation& Foam::fileHandler()
{ {
if (!fileOperation::fileHandlerPtr_) if (!fileOperation::fileHandlerPtr_)
{ {
word handler(getEnv("FOAM_FILEHANDLER")); word handler(Foam::getEnv("FOAM_FILEHANDLER"));
if (handler.empty()) if (handler.empty())
{ {

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2017 OpenFOAM Foundation Copyright (C) 2017 OpenFOAM Foundation
Copyright (C) 2020-2021 OpenCFD Ltd. Copyright (C) 2020-2022 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -70,6 +70,8 @@ class fileOperation
{ {
public: public:
// Public Data Types
//- Enumeration for the location of an IOobject //- Enumeration for the location of an IOobject
enum pathType : int enum pathType : int
{ {
@ -274,7 +276,7 @@ public:
virtual bool exists virtual bool exists
( (
const fileName&, const fileName&,
const bool checkGzip=true, const bool checkGzip = true,
const bool followLink = true const bool followLink = true
) const = 0; ) const = 0;
@ -290,7 +292,7 @@ public:
virtual bool isFile virtual bool isFile
( (
const fileName&, const fileName&,
const bool checkGzip=true, const bool checkGzip = true,
const bool followLink = true const bool followLink = true
) const = 0; ) const = 0;
@ -367,14 +369,6 @@ public:
const bool emptyOnly = false const bool emptyOnly = false
) const = 0; ) const = 0;
// //- Open a shared library. Return handle to library. Print error
// // message if library cannot be loaded (check = true)
// virtual void* dlOpen
// (
// const fileName& lib,
// const bool check = true
// ) const = 0;
// (reg)IOobject functionality // (reg)IOobject functionality
@ -456,9 +450,14 @@ public:
// Filename (not IOobject) operations // Filename (not IOobject) operations
//- Search for a file or directory. Use IOobject version in //- Search for a file or directory.
// preference //- Use IOobject version in preference
virtual fileName filePath(const fileName&) const; virtual fileName filePath
(
const fileName&,
const bool checkGzip = true,
const bool followLink = true
) const;
//- Generate an ISstream that reads a file //- Generate an ISstream that reads a file
virtual autoPtr<ISstream> NewIFstream(const fileName&) const = 0; virtual autoPtr<ISstream> NewIFstream(const fileName&) const = 0;
@ -607,6 +606,24 @@ public:
}; };
//- Read pathType as an integer value
inline Istream& operator>>(Istream& is, fileOperation::pathType& b)
{
int val(0);
is >> val;
b = static_cast<fileOperation::pathType>(val);
return is;
}
//- Write pathType as an integer value
inline Ostream& operator<<(Ostream& os, const fileOperation::pathType b)
{
os << static_cast<int>(b);
return os;
}
// * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * //
// Note: defined in fileOperation.C // Note: defined in fileOperation.C

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2017-2018 OpenFOAM Foundation Copyright (C) 2017-2018 OpenFOAM Foundation
Copyright (C) 2019-2021 OpenCFD Ltd. Copyright (C) 2019-2022 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -50,17 +50,37 @@ Foam::fileOperations::fileOperationInitialise::fileOperationInitialise
char**& argv char**& argv
) )
{ {
// Filter out commonly known arguments // Check for -ioRanks, which requires an argument
const string s("-ioRanks");
int index = -1; int index = -1;
for (int i=1; i<argc-1; i++) for (int argi = 1; argi < argc; ++argi)
{ {
if (argv[i] == s) if (argv[argi][0] == '-')
{ {
index = i; const char *optName = &argv[argi][1];
Foam::setEnv("FOAM_IORANKS", argv[i+1], true);
break; if (strcmp(optName, "ioRanks") == 0)
{
if (argi < argc-1)
{
index = argi;
Foam::setEnv("FOAM_IORANKS", argv[argi+1], true);
break;
}
else
{
// No argument to -ioRanks.
// Give error message as in argList.
// Slight problem: Pstream not yet initialised so
// - no master-only output
// - no early exit
Info<< nl
<< "Error: option '-ioRanks' requires a list of"
" IO ranks as argument" << nl << nl;
//Pstream::exit(1); // works for serial and parallel
}
}
} }
} }

View File

@ -715,21 +715,7 @@ Foam::fileOperations::masterUncollatedFileOperation::read
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::fileOperations::masterUncollatedFileOperation:: void Foam::fileOperations::masterUncollatedFileOperation::init(bool verbose)
masterUncollatedFileOperation
(
bool verbose
)
:
fileOperation
(
UPstream::allocateCommunicator
(
UPstream::worldComm,
subRanks(Pstream::nProcs())
)
),
myComm_(comm_)
{ {
verbose = (verbose && Foam::infoDetailLevel > 0); verbose = (verbose && Foam::infoDetailLevel > 0);
@ -763,6 +749,26 @@ masterUncollatedFileOperation
} }
Foam::fileOperations::masterUncollatedFileOperation::
masterUncollatedFileOperation
(
bool verbose
)
:
fileOperation
(
UPstream::allocateCommunicator
(
UPstream::worldComm,
subRanks(Pstream::nProcs())
)
),
myComm_(comm_)
{
init(verbose);
}
Foam::fileOperations::masterUncollatedFileOperation:: Foam::fileOperations::masterUncollatedFileOperation::
masterUncollatedFileOperation masterUncollatedFileOperation
( (
@ -773,35 +779,7 @@ masterUncollatedFileOperation
fileOperation(comm), fileOperation(comm),
myComm_(-1) myComm_(-1)
{ {
verbose = (verbose && Foam::infoDetailLevel > 0); init(verbose);
if (verbose)
{
DetailInfo
<< "I/O : " << typeName
<< " (maxMasterFileBufferSize " << maxMasterFileBufferSize << ')'
<< endl;
}
if (IOobject::fileModificationChecking == IOobject::timeStampMaster)
{
if (verbose)
{
WarningInFunction
<< "Resetting fileModificationChecking to timeStamp" << endl;
}
IOobject::fileModificationChecking = IOobject::timeStamp;
}
else if (IOobject::fileModificationChecking == IOobject::inotifyMaster)
{
if (verbose)
{
WarningInFunction
<< "Resetting fileModificationChecking to inotify"
<< endl;
}
IOobject::fileModificationChecking = IOobject::inotify;
}
} }

View File

@ -88,6 +88,11 @@ class masterUncollatedFileOperation
: :
public fileOperation public fileOperation
{ {
// Private Member Functions
//- Any initialisation steps after constructing
void init(bool verbose);
protected: protected:
// Protected Data // Protected Data
@ -351,7 +356,7 @@ protected:
( (
(isFile_ ? Foam::isFile(f) : Foam::isDir(f)) (isFile_ ? Foam::isFile(f) : Foam::isDir(f))
? f ? f
: fileName::null : fileName::null // const reference, not temporary
); );
} }
}; };
@ -426,7 +431,7 @@ protected:
( (
const bool checkGlobal, const bool checkGlobal,
const bool isFile, const bool isFile,
const IOobject&, const IOobject& io,
const bool search, const bool search,
pathType& searchType, pathType& searchType,
word& processorsDir, word& processorsDir,
@ -615,14 +620,6 @@ public:
const bool emptyOnly = false const bool emptyOnly = false
) const; ) const;
// //- Open a shared library. Return handle to library. Print error
// // message if library cannot be loaded (check = true)
// virtual void* dlOpen
// (
// const fileName& lib,
// const bool check = true
// ) const;
// (reg)IOobject functinality // (reg)IOobject functinality

View File

@ -176,6 +176,18 @@ Foam::fileOperations::uncollatedFileOperation::lookupProcessorsPath
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
void Foam::fileOperations::uncollatedFileOperation::init(bool verbose)
{
verbose = (verbose && Foam::infoDetailLevel > 0);
if (verbose)
{
DetailInfo
<< "I/O : " << typeName << endl;
}
}
Foam::fileOperations::uncollatedFileOperation::uncollatedFileOperation Foam::fileOperations::uncollatedFileOperation::uncollatedFileOperation
( (
bool verbose bool verbose
@ -183,11 +195,7 @@ Foam::fileOperations::uncollatedFileOperation::uncollatedFileOperation
: :
fileOperation(Pstream::worldComm) fileOperation(Pstream::worldComm)
{ {
if (verbose) init(verbose);
{
DetailInfo
<< "I/O : " << typeName << endl;
}
} }

View File

@ -53,6 +53,11 @@ class uncollatedFileOperation
: :
public fileOperation public fileOperation
{ {
// Private Member Functions
//- Any initialisation steps after constructing
void init(bool verbose);
protected: protected:
// Protected Member Functions // Protected Member Functions
@ -215,14 +220,6 @@ public:
const bool emptyOnly = false const bool emptyOnly = false
) const; ) const;
// //- Open a shared library. Return handle to library. Print error
// // message if library cannot be loaded (check = true)
// virtual void* dlOpen
// (
// const fileName& lib,
// const bool check = true
// ) const;
// (reg)IOobject functionality // (reg)IOobject functionality

View File

@ -144,8 +144,8 @@ fileName::Type type(const fileName& name, const bool followLink=true);
bool exists bool exists
( (
const fileName& name, const fileName& name,
const bool checkGzip=true, const bool checkGzip = true,
const bool followLink=true const bool followLink = true
); );
//- Does the name exist as a DIRECTORY in the file system? //- Does the name exist as a DIRECTORY in the file system?
@ -158,8 +158,8 @@ bool isDir(const fileName& name, const bool followLink=true);
bool isFile bool isFile
( (
const fileName& name, const fileName& name,
const bool checkGzip=true, const bool checkGzip = true,
const bool followLink=true const bool followLink = true
); );
//- Return size of file or -1 on failure (normally follows symbolic links). //- Return size of file or -1 on failure (normally follows symbolic links).
@ -197,6 +197,13 @@ bool cp(const fileName& src, const fileName& dst, const bool followLink=true);
// but also produces a warning. // but also produces a warning.
bool ln(const fileName& src, const fileName& dst); bool ln(const fileName& src, const fileName& dst);
//- Return the contents (target) of a symlink.
// For example, returns \c target for <code>ln -s target linkName</code>
//
// An empty link name is a no-op that always returns an empty string.
// Following a non-link is an error that returns an empty string.
fileName readLink(const fileName& link);
//- Rename src to dst. //- Rename src to dst.
// An empty source or destination name is a no-op that always returns false. // An empty source or destination name is a no-op that always returns false.
bool mv bool mv