//# Directory.cc: Class to define a Directory //# Copyright (C) 1996,1997,1999,2000,2001,2002 //# Associated Universities, Inc. Washington DC, USA. //# //# This library is free software; you can redistribute it and/or modify it //# under the terms of the GNU Library General Public License as published by //# the Free Software Foundation; either version 2 of the License, or (at your //# option) any later version. //# //# This library 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 Library General Public //# License for more details. //# //# You should have received a copy of the GNU Library General Public License //# along with this library; if not, write to the Free Software Foundation, //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA. //# //# Correspondence concerning AIPS++ should be addressed as follows: //# Internet email: aips2-request@nrao.edu. //# Postal address: AIPS++ Project Office //# National Radio Astronomy Observatory //# 520 Edgemont Road //# Charlottesville, VA 22903-2475 USA //# //# $Id$ // we NEED to include aips(env).h before using any AIPS_xyz defines #include #if defined(AIPS_SOLARIS) || defined(AIPS_OSF) # if defined(AIPS_OSF) extern "C" { // missing in system include file # endif # if defined(AIPS_SOLARIS) # undef _FILE_OFFSET_BITS # undef _LARGEFILE_SOURCE # endif # include // needed for statvfs # if defined(AIPS_OSF) } # endif # define statfs statvfs #elif defined(AIPS_DARWIN) || defined(AIPS_BSD) #include #include #else # include # if defined(AIPS_IRIX) # include # define f_bavail f_bfree # endif #endif #include #include #include #include #include #include #include #include #include #include // needed for rmdir, unlink #include // needed for mkdir #include // needed for errno #include // needed for strerror // Shouldn't be needed, but is needed to get rename under linux. The // man page claims it's in unistd.h. #include namespace casacore { //# NAMESPACE CASACORE - BEGIN Directory::Directory() : File() // sets to working directory {} Directory::Directory (const Path& name) : File(name) { checkPath(); } Directory::Directory (const String& name) : File(name) { checkPath(); } Directory::Directory (const File& name) : File(name) { checkPath(); } Directory::Directory (const Directory& directory) : File (directory), itsFile (directory.itsFile) {} Directory::~Directory() {} Directory& Directory::operator= (const Directory& directory) { if (this != &directory) { File::operator= (directory); itsFile = directory.itsFile; } return *this; } void Directory::checkPath() { itsFile = *this; // If exists, check if it is a directory. // If the file is a symlink, resolve the entire symlink chain. // Otherwise check if it can be created. if (exists()) { if (isSymLink()) { itsFile = SymLink(*this).followSymLink(); // Error if no directory and exists or cannot be created. if (!itsFile.isDirectory()) { if (itsFile.exists() || !itsFile.canCreate()) { throw (AipsError ("Directory: " + path().expandedName() + " is a symbolic link not" " pointing to a valid directory")); } } } else if (!isDirectory()) { throw (AipsError ("Directory: " + path().expandedName() + " exists, but is no directory")); } } else { if (!canCreate()) { throw (AipsError ("Directory: " + path().expandedName() + " does not exist and cannot be created")); } } } uInt Directory::nEntries() const { uInt nentries = 0; DirectoryIterator iter(*this); while (! iter.pastEnd()) { nentries++; iter++; } return nentries; } Bool Directory::isEmpty() const { DirectoryIterator iter(*this); while (! iter.pastEnd()) { String nm (iter.name()); if (nm.size() < 5 || nm.before(4) != ".nfs") { /// cout <<"iter at "< 0) { bsize = buf.f_frsize; } #endif return bsize * buf.f_bavail; #endif } void Directory::create (Bool overwrite) { // If overwrite is False the directory will not be overwritten. if (exists()) { if (!itsFile.isDirectory()) { throw (AipsError ("Directory::create: " + itsFile.path().expandedName() + " already exists as a non-directory")); } if (!overwrite) { throw (AipsError ("Directory::create: " + itsFile.path().expandedName() + " already exists")); } // Keep the directory, so special allocation on Lustre is preserved. Directory(itsFile).removeRecursive(True); } else { if (mkdir (itsFile.path().expandedName().chars(), 0777) < 0) { throw (AipsError ("Directory::create error on " + itsFile.path().expandedName() + ": " + strerror(errno))); } } } void Directory::remove() { // If the directory is not empty it cannot be removed. if (! isEmpty()) { throw (AipsError ("Directory::remove: " + path().expandedName() + " is not empty")); } if (isSymLink()) { removeSymLinks(); } rmdir (itsFile.path().absoluteName().chars()); } void Directory::removeFiles() { DirectoryIterator iter(*this); while (! iter.pastEnd()) { File file = iter.file(); if (! file.isDirectory (False)) { unlink (file.path().originalName().chars()); } iter++; } } void Directory::removeRecursive (Bool keepDir) { DirectoryIterator iter(*this); while (! iter.pastEnd()) { File file = iter.file(); if (file.isDirectory (False)) { Directory(file).removeRecursive(); } else { unlink (file.path().originalName().chars()); } iter++; } if (!keepDir) { remove(); } } Int64 Directory::size() const { Int64 totSize=0; DirectoryIterator iter(*this); while (! iter.pastEnd()) { File file = iter.file(); if (file.isDirectory ()) { totSize+=Directory(file).size(); } else { totSize+=file.size(); } iter++; } return totSize; } void Directory::copy (const Path& target, Bool overwrite, Bool setUserWritePermission) const { Path targetName(target); checkTarget (targetName, overwrite, True); // Remove the target if it already exists. File targetFile(targetName); if (targetFile.isRegular (False)) { RegularFile(targetFile).remove(); } else if (targetFile.isDirectory (False)) { Directory(targetFile).removeRecursive(); } else { SymLink(targetFile).remove(); } // Copy the entire directory recursively using the system function cp. #if defined(AIPS_CRAY_PGI) // On the Cray XT3 the system call is not supported, so we have to // do it ourselves. copyRecursive (targetName.expandedName()); #else String command("cp -r '"); command += itsFile.path().expandedName() + "' '" + targetName.expandedName() + "'"; int result = system(command.chars()); if(result != 0) { throw AipsError("Executing cp command returned an error. Command was: " + command); } // Give write permission to user if needed. if (setUserWritePermission) { #if defined(__hpux__) || defined(AIPS_IRIX) command = "chmod -R u+w '"; #else command = "chmod -Rf u+w '"; #endif command += targetName.expandedName() + "'"; int result = system(command.chars()); if(result != 0) throw AipsError("Executing chmod command returned an error. Command was: " + command); } #endif } void Directory::copyRecursive (const String& target) const { // First create the directory. Directory dir(target); dir.create (True); // Now loop over all files and copy. DirectoryIterator iter(*this); while (! iter.pastEnd()) { File file = iter.file(); String outName = target + '/' + file.path().baseName(); if (file.isDirectory (False)) { Directory(file).copyRecursive (outName); } else { RegularFile::manualCopy (file.path().originalName(), outName); } iter++; } } void Directory::move (const Path& target, Bool overwrite) { Path targetPath(target); checkTarget (targetPath, overwrite, True); // Start trying to rename. // If source and target are the same directory, rename does nothing // and returns a success status. if (rename (path().expandedName().chars(), targetPath.expandedName().chars()) == 0) { return; } // The rename failed for one reason or another. // Remove the target if it already exists. Bool alrExist = False; if (errno == EEXIST) { alrExist = True; } #if defined(ENOTEMPTY) if (errno == ENOTEMPTY) { alrExist = True; } #endif #if defined(EBUSY) if (errno == EBUSY) { alrExist = True; } #endif if (alrExist) { Directory(targetPath).removeRecursive(); } else if (errno == ENOTDIR) { unlink (targetPath.expandedName().chars()); } // Try again. if (rename (path().expandedName().chars(), targetPath.expandedName().chars()) == 0) { return; } // Throw an exception if not "different file systems" error. if (errno != EXDEV) { throw (AipsError ("Directory::move error on " + path().expandedName() + " to " + targetPath.expandedName() + ": " + strerror(errno))); } // Copy the directory and remove it thereafter. copy (targetPath, overwrite, False); removeRecursive(); } // Vector Directory::find (const String& fileName, // Bool followSymLinks) const // { // //#// return find ('^' + Regex::fromString (fileName) + '$', followSymLinks); // return find (Regex (Regex::fromString (fileName)), followSymLinks); // } Vector Directory::find (const Regex& regexp, Bool followSymLinks, Bool recursive) const { DirectoryIterator iter(*this); Vector myentries(10); uInt count=0; while (!iter.pastEnd()) { //#// if (iter.name().contains (regexp)) { if (iter.name().matches (regexp)) { if (count + 1 >= myentries.nelements()) { // More entries have been added - have to resize myentries.resize (2*myentries.nelements(), True); } myentries(count) = iter.name(); count++; } iter++; } myentries.resize (count, True); // Trim the trailing entries // Now recursively add all the ones we find in subdirectories, prepending // the pathname. if (recursive) { iter.reset(); while (!iter.pastEnd()) { File file = iter.file(); if (file.isDirectory (followSymLinks)) { Directory subdir = file; Vector subentries = subdir.find (regexp); String basename = iter.name() + "/"; subentries = basename + subentries; uInt oldsize = myentries.nelements(); myentries.resize (oldsize + subentries.nelements(), True); myentries(Slice(oldsize, subentries.nelements())) = subentries; } iter++; } } return myentries; } Vector Directory::shellExpand (const Vector& files, Bool stripPath) // // Take a list of potentially wild-carded file names, and expand // them into (optional) absolute path and name. Some more development // needed to expand the path as well, if there are any wild cards in that. // { Vector expInNames; uInt nExpInNames = 0; uInt k = 0; Regex exp; // for (uInt i=0; i expFiles = dir.find(exp, True, False); nExpInNames += expFiles.nelements(); expInNames.resize(nExpInNames, True); // Add the path back on to each name if (stripPath) { for (uInt j=0; j #include #else #include #include #include #endif Bool Directory::isNFSMounted() const { struct statfs buf; if (statfs (itsFile.path().expandedName().chars(), &buf) < 0) { throw (AipsError ("Directory::isNFSMounted error on " + itsFile.path().expandedName() + ": " + strerror(errno))); } #ifndef __APPLE__ return buf.f_type == NFS_SUPER_MAGIC; #else return buf.f_type == VT_NFS; #endif } } //# NAMESPACE CASACORE - END