/// @name Data
/// @{
private:
- sys::Path path_; ///< Path to the file.
+ sys::PathWithStatus path_; ///< Path to the file.
int options_; ///< Options used to create the mapping
void* base_; ///< Pointer to the base memory address
mutable MappedFileInfo* info_; ///< Platform specific info for the mapping
/// platform independent and eliminates many of the unix-specific fields.
/// However, to support llvm-ar, the mode, user, and group fields are
/// retained. These pertain to unix security and may not have a meaningful
- /// value on non-Unix platforms. However, the fileSize and modTime fields
- /// should always be applicable on all platforms. The structure is
- /// filled in by the Path::getFileStatus method.
+ /// value on non-Unix platforms. However, the other fields fields should
+ /// always be applicable on all platforms. The structure is filled in by
+ /// the PathWithStatus class.
/// @brief File status structure
class FileStatus {
public:
/// provided so that they can be used to indicate null or error results in
/// other lib/System functionality.
/// @brief Construct an empty (and invalid) path.
- Path() : path(), status(0) {}
- ~Path() { delete status; }
- Path(const Path &that) : path(that.path), status(0) {}
+ Path() : path() {}
+ Path(const Path &that) : path(that.path) {}
/// This constructor will accept a std::string as a path. No checking is
/// done on this path to determine if it is valid. To determine validity
/// of the path, use the isValid method.
/// @param p The path to assign.
/// @brief Construct a Path from a string.
- explicit Path(const std::string& p) : path(p), status(0) {}
+ explicit Path(const std::string& p) : path(p) {}
/// @}
/// @name Operators
/// @brief Assignment Operator
Path &operator=(const Path &that) {
path = that.path;
- if (status)
- delete status;
- status = 0;
return *this;
}
/// This function determines if the contents of the path name are empty.
/// That is, the path name has a zero length. This does NOT determine if
/// if the file is empty. To get the length of the file itself, Use the
- /// getFileStatus() method and then the getSize() on the returned
- /// FileStatus object
+ /// PathWithStatus::getFileStatus() method and then the getSize() method
+ /// on the returned FileStatus object.
/// @returns true iff the path is empty.
/// @brief Determines if the path name is empty (invalid).
bool isEmpty() const { return path.empty(); }
std::string* ErrMsg ///< Optional place to return an error message.
) const;
- /// This function returns status information about the file. The type of
- /// path (file or directory) is updated to reflect the actual contents
- /// of the file system.
- /// @returns 0 on failure, with Error explaining why (if non-zero)
- /// @returns a pointer to a FileStatus structure on success.
- /// @brief Get file status.
- const FileStatus *getFileStatus(
- bool forceUpdate = false, ///< Force an update from the file system
- std::string *Error = 0 ///< Optional place to return an error msg.
- ) const;
-
/// @}
/// @name Path Mutators
/// @{
/// @}
/// @name Data
/// @{
- private:
+ protected:
mutable std::string path; ///< Storage for the path name.
- mutable FileStatus *status; ///< Status information.
+
+ /// @}
+ };
+
+ /// This class is identical to Path class except it allows you to obtain the
+ /// file status of the Path as well. The reason for the distinction is one of
+ /// efficiency. First, the file status requires additional space and the space
+ /// is incorporated directly into PathWithStatus without an additional malloc.
+ /// Second, obtaining status information is an expensive operation on most
+ /// operating systems so we want to be careful and explicity about where we
+ /// allow this operation in LLVM.
+ /// @brief Path with file status class.
+ class PathWithStatus : public Path {
+ /// @name Constructors
+ /// @{
+ public:
+ /// @brief Default constructor
+ PathWithStatus() : Path(), status(), fsIsValid(false) {}
+
+ /// @brief Copy constructor
+ PathWithStatus(const PathWithStatus &that)
+ : Path(static_cast<const Path&>(that)), status(that.status),
+ fsIsValid(that.fsIsValid) {}
+
+ /// This constructor allows construction from a Path object
+ /// @brief Path constructor
+ PathWithStatus(const Path &other)
+ : Path(other), status(), fsIsValid(false) {}
+
+ /// This constructor will accept a std::string as a path. No checking is
+ /// done on this path to determine if it is valid. To determine validity
+ /// of the path, use the isValid method.
+ /// @param p The path to assign.
+ /// @brief Construct a Path from a string.
+ explicit PathWithStatus(const std::string& p)
+ : Path(p), status(), fsIsValid(false) {}
+
+ /// Makes a copy of \p that to \p this.
+ /// @returns \p this
+ /// @brief Assignment Operator
+ PathWithStatus &operator=(const PathWithStatus &that) {
+ static_cast<Path&>(*this) = static_cast<const Path&>(that);
+ status = that.status;
+ fsIsValid = that.fsIsValid;
+ return *this;
+ }
+
+ /// Makes a copy of \p that to \p this.
+ /// @returns \p this
+ /// @brief Assignment Operator
+ PathWithStatus &operator=(const Path &that) {
+ static_cast<Path&>(*this) = static_cast<const Path&>(that);
+ fsIsValid = false;
+ return *this;
+ }
+
+ /// @}
+ /// @name Methods
+ /// @{
+ public:
+ /// This function returns status information about the file. The type of
+ /// path (file or directory) is updated to reflect the actual contents
+ /// of the file system.
+ /// @returns 0 on failure, with Error explaining why (if non-zero)
+ /// @returns a pointer to a FileStatus structure on success.
+ /// @brief Get file status.
+ const FileStatus *getFileStatus(
+ bool forceUpdate = false, ///< Force an update from the file system
+ std::string *Error = 0 ///< Optional place to return an error msg.
+ ) const;
+
+ /// @}
+ /// @name Data
+ /// @{
+ private:
+ mutable FileStatus status; ///< Status information.
+ mutable bool fsIsValid; ///< Whether we've obtained it or not
/// @}
};
bool CopyFile(const Path& Dest, const Path& Src, std::string* ErrMsg);
}
+
std::ostream& operator<<(std::ostream& strm, const sys::Path& aPath);
+std::ostream& operator<<(std::ostream& strm, const sys::PathWithStatus& aPath);
}
Path::canExecute() const {
if (0 != access(path.c_str(), R_OK | X_OK ))
return false;
- if (const FileStatus *fs = getFileStatus(true, 0)) {
- if (!S_ISREG(fs->mode))
- return false;
- } else
+ struct stat buf;
+ if (0 != stat(path.c_str(), &buf))
+ return false;
+ if (!S_ISREG(buf.st_mode))
return false;
return true;
}
return path.substr(pos+1);
}
-const FileStatus*
-Path::getFileStatus(bool update, std::string *ErrStr) const {
- if (status == 0 || update) {
+const FileStatus *
+PathWithStatus::getFileStatus(bool update, std::string *ErrStr) const {
+ if (!fsIsValid || update) {
struct stat buf;
if (0 != stat(path.c_str(), &buf)) {
MakeErrMsg(ErrStr, path + ": can't get status of file");
return 0;
}
- if (status == 0)
- status = new FileStatus;
- status->fileSize = buf.st_size;
- status->modTime.fromEpochTime(buf.st_mtime);
- status->mode = buf.st_mode;
- status->user = buf.st_uid;
- status->group = buf.st_gid;
- status->uniqueID = uint64_t(buf.st_ino);
- status->isDir = S_ISDIR(buf.st_mode);
- status->isFile = S_ISREG(buf.st_mode);
+ status.fileSize = buf.st_size;
+ status.modTime.fromEpochTime(buf.st_mtime);
+ status.mode = buf.st_mode;
+ status.user = buf.st_uid;
+ status.group = buf.st_gid;
+ status.uniqueID = uint64_t(buf.st_ino);
+ status.isDir = S_ISDIR(buf.st_mode);
+ status.isFile = S_ISREG(buf.st_mode);
+ fsIsValid = true;
}
- return status;
+ return &status;
}
static bool AddPermissionBits(const Path &File, int bits) {
umask(mask); // Restore the umask.
// Get the file's current mode.
- if (const FileStatus *fs = File.getFileStatus()) {
- // Change the file to have whichever permissions bits from 'bits'
- // that the umask would not disable.
- if ((chmod(File.c_str(), (fs->getMode() | (bits & ~mask)))) == -1)
- return false;
- } else
+ struct stat buf;
+ if (0 != stat(File.toString().c_str(), &buf))
return false;
-
+ // Change the file to have whichever permissions bits from 'bits'
+ // that the umask would not disable.
+ if ((chmod(File.c_str(), (buf.st_mode | (bits & ~mask)))) == -1)
+ return false;
return true;
}
bool
Path::eraseFromDisk(bool remove_contents, std::string *ErrStr) const {
- FileStatus Status;
- if (const FileStatus *Status = getFileStatus(false, ErrStr)) {
- // Note: this check catches strange situations. In all cases, LLVM should
- // only be involved in the creation and deletion of regular files. This
- // check ensures that what we're trying to erase is a regular file. It
- // effectively prevents LLVM from erasing things like /dev/null, any block
- // special file, or other things that aren't "regular" files.
- if (Status->isFile) {
- if (unlink(path.c_str()) != 0)
- return MakeErrMsg(ErrStr, path + ": can't destroy file");
- return false;
- }
-
- if (!Status->isDir) {
- if (ErrStr) *ErrStr = "not a file or directory";
- return true;
- }
- } else
+ // Get the status so we can determin if its a file or directory
+ struct stat buf;
+ if (0 != stat(path.c_str(), &buf)) {
+ MakeErrMsg(ErrStr, path + ": can't get status of file");
return true;
+ }
+
+ // Note: this check catches strange situations. In all cases, LLVM should
+ // only be involved in the creation and deletion of regular files. This
+ // check ensures that what we're trying to erase is a regular file. It
+ // effectively prevents LLVM from erasing things like /dev/null, any block
+ // special file, or other things that aren't "regular" files.
+ if (S_ISREG(buf.st_mode)) {
+ if (unlink(path.c_str()) != 0)
+ return MakeErrMsg(ErrStr, path + ": can't destroy file");
+ return false;
+ }
+
+ if (!S_ISDIR(buf.st_mode)) {
+ if (ErrStr) *ErrStr = "not a file or directory";
+ return true;
+ }
if (remove_contents) {
// Recursively descend the directory to remove its contents.
return false;
}
-bool
+bool
Path::setStatusInfoOnDisk(const FileStatus &si, std::string *ErrStr) const {
struct utimbuf utb;
utb.actime = si.modTime.toPosixTime();
#if HAVE_SIGNAL_H
#include <signal.h>
#endif
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
using namespace llvm;
namespace {
// RemoveDirectoryOnSignal - The public API
bool sys::RemoveDirectoryOnSignal(const sys::Path& path, std::string* ErrMsg) {
// Not a directory?
- const sys::FileStatus *Status = path.getFileStatus(false, ErrMsg);
- if (!Status)
+ struct stat buf;
+ if (0 != stat(path.c_str(), &buf)) {
+ MakeErrMsg(ErrMsg, path.toString() + ": can't get status of file");
return true;
- if (!Status->isDir) {
+ }
+
+ if (!S_ISDIR(buf.st_mode)) {
if (ErrMsg)
*ErrMsg = path.toString() + " is not a directory";
return true;
}
const FileStatus *
-Path::getFileStatus(bool update, std::string *ErrStr) const {
- if (status == 0 || update) {
+PathWithStatus::getFileStatus(bool update, std::string *ErrStr) const {
+ if (!fsIsValid || update) {
WIN32_FILE_ATTRIBUTE_DATA fi;
if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi)) {
MakeErrMsg(ErrStr, "getStatusInfo():" + std::string(path) +
return 0;
}
- if (status == 0)
- status = new FileStatus;
+ status.fileSize = fi.nFileSizeHigh;
+ status.fileSize <<= sizeof(fi.nFileSizeHigh)*8;
+ status.fileSize += fi.nFileSizeLow;
- status->fileSize = fi.nFileSizeHigh;
- status->fileSize <<= sizeof(fi.nFileSizeHigh)*8;
- status->fileSize += fi.nFileSizeLow;
-
- status->mode = fi.dwFileAttributes & FILE_ATTRIBUTE_READONLY ? 0555 : 0777;
- status->user = 9999; // Not applicable to Windows, so...
- status->group = 9999; // Not applicable to Windows, so...
+ status.mode = fi.dwFileAttributes & FILE_ATTRIBUTE_READONLY ? 0555 : 0777;
+ status.user = 9999; // Not applicable to Windows, so...
+ status.group = 9999; // Not applicable to Windows, so...
// FIXME: this is only unique if the file is accessed by the same file path.
// How do we do this for C:\dir\file and ..\dir\file ? Unix has inode
// numbers, but the concept doesn't exist in Windows.
- status->uniqueID = 0;
+ status.uniqueID = 0;
for (unsigned i = 0; i < path.length(); ++i)
- status->uniqueID += path[i];
+ status.uniqueID += path[i];
__int64 ft = *reinterpret_cast<__int64*>(&fi.ftLastWriteTime);
- status->modTime.fromWin32Time(ft);
+ status.modTime.fromWin32Time(ft);
- status->isDir = fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
+ status.isDir = fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
+ fsIsValid = true;
}
- return status;
+ return &status;
}
bool Path::makeReadableOnDisk(std::string* ErrMsg) {