aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/llvm/System/MappedFile.h2
-rw-r--r--include/llvm/System/Path.h113
-rw-r--r--lib/System/Unix/Path.inc89
-rw-r--r--lib/System/Unix/Signals.inc12
-rw-r--r--lib/System/Win32/Path.inc30
5 files changed, 157 insertions, 89 deletions
diff --git a/include/llvm/System/MappedFile.h b/include/llvm/System/MappedFile.h
index f82d6fe..6276bc3 100644
--- a/include/llvm/System/MappedFile.h
+++ b/include/llvm/System/MappedFile.h
@@ -152,7 +152,7 @@ namespace sys {
/// @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
diff --git a/include/llvm/System/Path.h b/include/llvm/System/Path.h
index e251985..69c1b48 100644
--- a/include/llvm/System/Path.h
+++ b/include/llvm/System/Path.h
@@ -29,9 +29,9 @@ namespace sys {
/// 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:
@@ -164,16 +164,15 @@ namespace sys {
/// 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
@@ -184,9 +183,6 @@ namespace sys {
/// @brief Assignment Operator
Path &operator=(const Path &that) {
path = that.path;
- if (status)
- delete status;
- status = 0;
return *this;
}
@@ -230,8 +226,8 @@ namespace sys {
/// 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(); }
@@ -361,17 +357,6 @@ namespace sys {
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
/// @{
@@ -527,9 +512,85 @@ namespace sys {
/// @}
/// @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
/// @}
};
@@ -556,7 +617,9 @@ namespace sys {
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);
}
diff --git a/lib/System/Unix/Path.inc b/lib/System/Unix/Path.inc
index 6ceffcd..53906d9 100644
--- a/lib/System/Unix/Path.inc
+++ b/lib/System/Unix/Path.inc
@@ -333,10 +333,10 @@ bool
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;
}
@@ -363,26 +363,25 @@ Path::getLast() const {
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) {
@@ -394,14 +393,13 @@ 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;
}
@@ -594,25 +592,28 @@ Path::createTemporaryFileOnDisk(bool reuse_current, std::string* ErrMsg) {
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.
@@ -644,7 +645,7 @@ Path::renamePathOnDisk(const Path& newName, std::string* ErrMsg) {
return false;
}
-bool
+bool
Path::setStatusInfoOnDisk(const FileStatus &si, std::string *ErrStr) const {
struct utimbuf utb;
utb.actime = si.modTime.toPosixTime();
diff --git a/lib/System/Unix/Signals.inc b/lib/System/Unix/Signals.inc
index a471b95..d1493a2 100644
--- a/lib/System/Unix/Signals.inc
+++ b/lib/System/Unix/Signals.inc
@@ -21,6 +21,9 @@
#if HAVE_SIGNAL_H
#include <signal.h>
#endif
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
using namespace llvm;
namespace {
@@ -168,10 +171,13 @@ bool sys::RemoveFileOnSignal(const sys::Path &Filename, std::string* ErrMsg) {
// 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;
diff --git a/lib/System/Win32/Path.inc b/lib/System/Win32/Path.inc
index 57d7535..937bb51 100644
--- a/lib/System/Win32/Path.inc
+++ b/lib/System/Win32/Path.inc
@@ -307,8 +307,8 @@ Path::getLast() const {
}
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) +
@@ -316,30 +316,28 @@ Path::getFileStatus(bool update, std::string *ErrStr) const {
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) {