mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-01-02 07:32:52 +00:00
For PR1291:
Implement the PathWithStatus class and its use throughout lib/System. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@35742 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
e9ed4452bc
commit
2ae9d11b7c
@ -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
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user