Change Path::getStatusInfo to return a boolean and error string on an error

instead of throwing an exception.  This reduces the amount of code that is
exposed to exceptions (e.g. FileUtilities), though it is clearly only one step
along the way.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@29395 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Chris Lattner 2006-07-28 22:03:44 +00:00
parent 3236ced25f
commit 252ad03d7d
11 changed files with 116 additions and 108 deletions

View File

@ -40,7 +40,6 @@ class ArchiveMemberHeader; // Internal implementation class
/// of the Archive class instead.
/// @brief This class represents a single archive member.
class ArchiveMember {
/// @name Types
/// @{
public:
@ -75,28 +74,28 @@ class ArchiveMember {
/// have any applicability on non-Unix systems but is a required component
/// of the "ar" file format.
/// @brief Get the user associated with this archive member.
unsigned getUser() const { return info.user; }
unsigned getUser() const { return info.getUser(); }
/// The "group" is the owning group of the file per Unix security. This
/// may not have any applicability on non-Unix systems but is a required
/// component of the "ar" file format.
/// @brief Get the group associated with this archive member.
unsigned getGroup() const { return info.group; }
unsigned getGroup() const { return info.getGroup(); }
/// The "mode" specifies the access permissions for the file per Unix
/// security. This may not have any applicabiity on non-Unix systems but is
/// a required component of the "ar" file format.
/// @brief Get the permission mode associated with this archive member.
unsigned getMode() const { return info.mode; }
unsigned getMode() const { return info.getMode(); }
/// This method returns the time at which the archive member was last
/// modified when it was not in the archive.
/// @brief Get the time of last modification of the archive member.
sys::TimeValue getModTime() const { return info.modTime; }
sys::TimeValue getModTime() const { return info.getTimestamp(); }
/// @returns the size of the archive member in bytes.
/// @brief Get the size of the archive member.
unsigned getSize() const { return info.fileSize; }
unsigned getSize() const { return info.getSize(); }
/// This method returns the total size of the archive member as it
/// appears on disk. This includes the file content, the header, the
@ -162,14 +161,14 @@ class ArchiveMember {
/// systems.
/// @returns the status info for the archive member
/// @brief Obtain the status info for the archive member
const sys::Path::StatusInfo& getStatusInfo() const { return info; }
const sys::FileStatus &getFileStatus() const { return info; }
/// This method causes the archive member to be replaced with the contents
/// of the file specified by \p File. The contents of \p this will be
/// updated to reflect the new data from \p File. The \p File must exist and
/// be readable on entry to this method.
/// @brief Replace contents of archive member with a new file.
void replaceWith(const sys::Path& aFile);
void replaceWith(const sys::Path &aFile);
/// @}
/// @name ilist methods - do not use
@ -190,7 +189,7 @@ class ArchiveMember {
ArchiveMember* prev; ///< Pointer to previous archive member
Archive* parent; ///< Pointer to parent archive
sys::Path path; ///< Path of file containing the member
sys::Path::StatusInfo info; ///< Status info (size,mode,date)
sys::FileStatus info; ///< Status info (size,mode,date)
unsigned flags; ///< Flags about the archive member
const void* data; ///< Data for the member
@ -205,7 +204,7 @@ class ArchiveMember {
private:
/// Used internally by the Archive class to construct an ArchiveMember.
/// The contents of the ArchiveMember are filled out by the Archive class.
ArchiveMember( Archive* PAR );
ArchiveMember(Archive *PAR);
// So Archive can construct an ArchiveMember
friend class llvm::Archive;

View File

@ -24,6 +24,35 @@
namespace llvm {
namespace sys {
/// This structure provides basic file system information about a file. It
/// is patterned after the stat(2) Unix operating system call but made
/// 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.
/// @brief File status structure
class FileStatus {
public:
uint64_t fileSize; ///< Size of the file in bytes
TimeValue modTime; ///< Time of file's modification
uint32_t mode; ///< Mode of the file, if applicable
uint32_t user; ///< User ID of owner, if applicable
uint32_t group; ///< Group ID of owner, if applicable
bool isDir : 1; ///< True if this is a directory.
bool isFile : 1; ///< True if this is a file.
FileStatus() : fileSize(0), modTime(0,0), mode(0777), user(999),
group(999), isDir(false) { }
TimeValue getTimestamp() const { return modTime; }
size_t getSize() const { return fileSize; }
uint32_t getMode() const { return mode; }
uint32_t getUser() const { return user; }
uint32_t getGroup() const { return group; }
};
/// This class provides an abstraction for the path to a file or directory
/// in the operating system's filesystem and provides various basic operations
/// on it. Note that this class only represents the name of a path to a file
@ -53,30 +82,6 @@ namespace sys {
/// @since 1.4
/// @brief An abstraction for operating system paths.
class Path {
/// @name Types
/// @{
public:
/// This structure provides basic file system information about a file. It
/// is patterned after the stat(2) Unix operating system call but made
/// 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 applicabe on all platforms. The structure is
/// filled in by the getStatusInfo method.
/// @brief File status structure
struct StatusInfo {
StatusInfo() : fileSize(0), modTime(0,0), mode(0777), user(999),
group(999), isDir(false) { }
uint64_t fileSize; ///< Size of the file in bytes
TimeValue modTime; ///< Time of file's modification
uint32_t mode; ///< Mode of the file, if applicable
uint32_t user; ///< User ID of owner, if applicable
uint32_t group; ///< Group ID of owner, if applicable
bool isDir; ///< True if this is a directory.
};
/// @}
/// @name Constructors
/// @{
public:
@ -175,7 +180,7 @@ namespace sys {
/// Makes a copy of \p that to \p this.
/// @returns \p this
/// @brief Assignment Operator
Path & operator = ( const Path & that ) {
Path &operator=(const Path &that) {
path = that.path;
return *this;
}
@ -183,15 +188,15 @@ namespace sys {
/// Compares \p this Path with \p that Path for equality.
/// @returns true if \p this and \p that refer to the same thing.
/// @brief Equality Operator
bool operator == (const Path& that) const {
return 0 == path.compare(that.path) ;
bool operator==(const Path &that) const {
return 0 == path.compare(that.path);
}
/// Compares \p this Path with \p that Path for inequality.
/// @returns true if \p this and \p that refer to different things.
/// @brief Inequality Operator
bool operator !=( const Path & that ) const {
return 0 != path.compare( that.path );
bool operator!=(const Path &that) const {
return 0 != path.compare(that.path);
}
/// Determines if \p this Path is less than \p that Path. This is required
@ -200,8 +205,8 @@ namespace sys {
/// the std::string::compare method.
/// @returns true if \p this path is lexicographically less than \p that.
/// @brief Less Than Operator
bool operator< (const Path& that) const {
return 0 > path.compare( that.path );
bool operator<(const Path& that) const {
return 0 > path.compare(that.path);
}
/// @}
@ -228,7 +233,7 @@ namespace sys {
/// std::string. This allows the underlying path string to be manipulated.
/// @returns std::string containing the path name.
/// @brief Returns the path as a std::string.
const std::string& toString() const { return path; }
const std::string &toString() const { return path; }
/// This function returns the last component of the path name. The last
/// component is the file or directory name occuring after the last
@ -248,7 +253,7 @@ namespace sys {
/// Obtain a 'C' string for the path name.
/// @returns a 'C' string containing the path name.
/// @brief Returns the path as a C string.
const char* const c_str() const { return path.c_str(); }
const char *const c_str() const { return path.c_str(); }
/// @}
/// @name Disk Accessors
@ -362,31 +367,14 @@ namespace sys {
/// @returns false if \p this is not a directory, true otherwise
/// @throws std::string if the directory cannot be searched
/// @brief Build a list of directory's contents.
bool getDirectoryContents(std::set<Path>& paths) const;
bool getDirectoryContents(std::set<Path> &paths) 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. If the file does not exist, false is returned.
/// For other (hard I/O) errors, a std::string is thrown indicating the
/// problem.
/// @throws std::string if an error occurs.
/// of the file system. This returns false on success, or true on error
/// and fills in the specified error string if specified.
/// @brief Get file status.
void getStatusInfo(StatusInfo& info) const;
/// This function returns the last modified time stamp for the file
/// referenced by this path. The Path may reference a file or a directory.
/// If the file does not exist, a ZeroTime timestamp is returned.
/// @returns last modified timestamp of the file/directory or ZeroTime
/// @brief Get file timestamp.
inline TimeValue getTimestamp() const {
StatusInfo info; getStatusInfo(info); return info.modTime;
}
/// This function returns the size of the file referenced by this path.
/// @brief Get file size.
inline size_t getSize() const {
StatusInfo info; getStatusInfo(info); return info.fileSize;
}
bool getFileStatus(FileStatus &Status, std::string *Error = 0) const;
/// @}
/// @name Path Mutators
@ -475,7 +463,7 @@ namespace sys {
/// @throws std::string if an error occurs.
/// @returns true
/// @brief Set the status information.
bool setStatusInfoOnDisk(const StatusInfo& si) const;
bool setStatusInfoOnDisk(const FileStatus &SI) const;
/// This method attempts to create a directory in the file system with the
/// same name as the Path object. The \p create_parents parameter controls
@ -538,7 +526,7 @@ namespace sys {
/// refers to something that is neither a file nor a directory.
/// @throws std::string if there is an error.
/// @brief Removes the file or directory from the filesystem.
bool eraseFromDisk( bool destroy_contents = false ) const;
bool eraseFromDisk(bool destroy_contents = false) const;
/// @}
/// @name Data

View File

@ -104,12 +104,14 @@ void ArchiveMember::replaceWith(const sys::Path& newFile) {
flags &= ~HasLongFilenameFlag;
// Get the signature and status info
std::string magic;
const char* signature = (const char*) data;
std::string magic;
if (!signature) {
path.getMagicNumber(magic,4);
signature = magic.c_str();
path.getStatusInfo(info);
std::string err;
if (path.getFileStatus(info, &err))
throw err;
}
// Determine what kind of file it is

View File

@ -159,7 +159,9 @@ Archive::addFileBefore(const sys::Path& filePath, iterator where) {
mbr->data = 0;
mbr->path = filePath;
mbr->path.getStatusInfo(mbr->info);
std::string err;
if (mbr->path.getFileStatus(mbr->info, &err))
throw err;
unsigned flags = 0;
bool hasSlash = filePath.toString().find('/') != std::string::npos;

View File

@ -104,12 +104,14 @@ void ArchiveMember::replaceWith(const sys::Path& newFile) {
flags &= ~HasLongFilenameFlag;
// Get the signature and status info
std::string magic;
const char* signature = (const char*) data;
std::string magic;
if (!signature) {
path.getMagicNumber(magic,4);
signature = magic.c_str();
path.getStatusInfo(info);
std::string err;
if (path.getFileStatus(info, &err))
throw err;
}
// Determine what kind of file it is

View File

@ -159,7 +159,9 @@ Archive::addFileBefore(const sys::Path& filePath, iterator where) {
mbr->data = 0;
mbr->path = filePath;
mbr->path.getStatusInfo(mbr->info);
std::string err;
if (mbr->path.getFileStatus(mbr->info, &err))
throw err;
unsigned flags = 0;
bool hasSlash = filePath.toString().find('/') != std::string::npos;

View File

@ -196,8 +196,9 @@ void SourceFunctionInfo::getSourceLocation(unsigned &RetLineNo,
ProgramInfo::ProgramInfo(Module *m) : M(m), ProgramTimeStamp(0,0) {
assert(M && "Cannot create program information with a null module!");
sys::Path modulePath(M->getModuleIdentifier());
ProgramTimeStamp = modulePath.getTimestamp();
sys::FileStatus Stat;
if (!sys::Path(M->getModuleIdentifier()).getFileStatus(Stat))
ProgramTimeStamp = Stat.getTimestamp();
SourceFilesIsComplete = false;
SourceFunctionsIsComplete = false;

View File

@ -146,19 +146,23 @@ int llvm::DiffFilesWithTolerance(const sys::Path &FileA,
const sys::Path &FileB,
double AbsTol, double RelTol,
std::string *Error) {
sys::FileStatus FileAStat, FileBStat;
if (FileA.getFileStatus(FileAStat, Error) ||
FileB.getFileStatus(FileBStat, Error))
return 2;
// Check for zero length files because some systems croak when you try to
// mmap an empty file.
size_t A_size = FileAStat.getSize();
size_t B_size = FileBStat.getSize();
// If they are both zero sized then they're the same
if (A_size == 0 && B_size == 0)
return 0;
// If only one of them is zero sized then they can't be the same
if ((A_size == 0 || B_size == 0))
return 1;
try {
// Check for zero length files because some systems croak when you try to
// mmap an empty file.
size_t A_size = FileA.getSize();
size_t B_size = FileB.getSize();
// If they are both zero sized then they're the same
if (A_size == 0 && B_size == 0)
return 0;
// If only one of them is zero sized then they can't be the same
if ((A_size == 0 || B_size == 0))
return 1;
// Now its safe to mmap the files into memory becasue both files
// have a non-zero size.
sys::MappedFile F1(FileA);

View File

@ -386,21 +386,22 @@ Path::getLast() const {
return path.substr(pos+1);
}
void
Path::getStatusInfo(StatusInfo& info) const {
bool
Path::getFileStatus(FileStatus &info, std::string *ErrStr) const {
struct stat buf;
if (0 != stat(path.c_str(), &buf)) {
ThrowErrno(path + ": can't determine type of path object: ");
}
if (0 != stat(path.c_str(), &buf))
return GetErrno(path + ": can't determine type of path object: ", ErrStr);
info.fileSize = buf.st_size;
info.modTime.fromEpochTime(buf.st_mtime);
info.mode = buf.st_mode;
info.user = buf.st_uid;
info.group = buf.st_gid;
info.isDir = S_ISDIR(buf.st_mode);
info.isDir = S_ISDIR(buf.st_mode);
info.isFile = S_ISREG(buf.st_mode);
return false;
}
static bool AddPermissionBits(const std::string& Filename, int bits) {
static bool AddPermissionBits(const Path &File, int bits) {
// Get the umask value from the operating system. We want to use it
// when changing the file's permissions. Since calling umask() sets
// the umask and returns its old value, we must call it a second
@ -409,30 +410,29 @@ static bool AddPermissionBits(const std::string& Filename, int bits) {
umask(mask); // Restore the umask.
// Get the file's current mode.
struct stat st;
if ((stat(Filename.c_str(), &st)) == -1)
return false;
FileStatus Stat;
if (File.getFileStatus(Stat)) return false;
// Change the file to have whichever permissions bits from 'bits'
// that the umask would not disable.
if ((chmod(Filename.c_str(), (st.st_mode | (bits & ~mask)))) == -1)
if ((chmod(File.c_str(), (Stat.getMode() | (bits & ~mask)))) == -1)
return false;
return true;
}
void Path::makeReadableOnDisk() {
if (!AddPermissionBits(path,0444))
if (!AddPermissionBits(*this, 0444))
ThrowErrno(path + ": can't make file readable");
}
void Path::makeWriteableOnDisk() {
if (!AddPermissionBits(path,0222))
if (!AddPermissionBits(*this, 0222))
ThrowErrno(path + ": can't make file writable");
}
void Path::makeExecutableOnDisk() {
if (!AddPermissionBits(path,0111))
if (!AddPermissionBits(*this, 0111))
ThrowErrno(path + ": can't make file executable");
}
@ -642,7 +642,7 @@ Path::renamePathOnDisk(const Path& newName) {
}
bool
Path::setStatusInfoOnDisk(const StatusInfo& si) const {
Path::setStatusInfoOnDisk(const FileStatus &si) const {
struct utimbuf utb;
utb.actime = si.modTime.toPosixTime();
utb.modtime = utb.actime;

View File

@ -299,8 +299,10 @@ void buildPaths(bool checkExistence = true) {
if (checkExistence) {
if (!aPath.exists())
throw std::string("File does not exist: ") + Members[i];
sys::Path::StatusInfo si;
aPath.getStatusInfo(si);
sys::FileStatus si;
std::string Err;
if (aPath.getFileStatus(si, &Err))
throw Err;
if (si.isDir) {
std::set<sys::Path> dirpaths = recurseDirectories(aPath);
Paths.insert(dirpaths.begin(),dirpaths.end());
@ -456,7 +458,7 @@ void doExtract() {
// If we're supposed to retain the original modification times, etc. do so
// now.
if (OriginalDates)
I->getPath().setStatusInfoOnDisk(I->getStatusInfo());
I->getPath().setStatusInfoOnDisk(I->getFileStatus());
}
}
}
@ -610,8 +612,10 @@ void doReplaceOrInsert() {
}
if (found != remaining.end()) {
sys::Path::StatusInfo si;
found->getStatusInfo(si);
sys::FileStatus si;
std::string Err;
if (found->getFileStatus(si, &Err))
throw Err;
if (si.isDir) {
if (OnlyUpdate) {
// Replace the item only if it is newer.

View File

@ -49,8 +49,12 @@ void CLIDebugger::startProgramRunning() {
eliminateRunInfo();
// If the program has been modified, reload it!
sys::Path Program (Dbg.getProgramPath());
if (TheProgramInfo->getProgramTimeStamp() != Program.getTimestamp()) {
sys::Path Program(Dbg.getProgramPath());
sys::FileStatus Status;
std::string Err;
if (Program.getFileStatus(Status, &Err))
throw Err;
if (TheProgramInfo->getProgramTimeStamp() != Status.getTimestamp()) {
std::cout << "'" << Program << "' has changed; re-reading program.\n";
// Unload an existing program. This kills the program if necessary.