forked from OSchip/llvm-project
PathV1 is deprecated since the 18th of Dec 2010. Remove it.
llvm-svn: 184960
This commit is contained in:
parent
b6d9c0001a
commit
b0f2eba499
|
@ -1,407 +0,0 @@
|
|||
//===- llvm/Support/PathV1.h - Path Operating System Concept ----*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file declares the llvm::sys::Path class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_SUPPORT_PATHV1_H
|
||||
#define LLVM_SUPPORT_PATHV1_H
|
||||
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/TimeValue.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#define LLVM_PATH_DEPRECATED_MSG(replacement) \
|
||||
"PathV1 has been deprecated and will be removed as soon as all LLVM and" \
|
||||
" Clang clients have been moved over to PathV2. Please use `" #replacement \
|
||||
"` from PathV2 instead."
|
||||
|
||||
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 other fields should
|
||||
/// always be applicable on all platforms. The structure is filled in by
|
||||
/// the PathWithStatus class.
|
||||
/// @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), isFile(false) { }
|
||||
|
||||
TimeValue getTimestamp() const { return modTime; }
|
||||
uint64_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
|
||||
/// or directory which may or may not be valid for a given machine's file
|
||||
/// system. The class is patterned after the java.io.File class with various
|
||||
/// extensions and several omissions (not relevant to LLVM). A Path object
|
||||
/// ensures that the path it encapsulates is syntactically valid for the
|
||||
/// operating system it is running on but does not ensure correctness for
|
||||
/// any particular file system. That is, a syntactically valid path might
|
||||
/// specify path components that do not exist in the file system and using
|
||||
/// such a Path to act on the file system could produce errors. There is one
|
||||
/// invalid Path value which is permitted: the empty path. The class should
|
||||
/// never allow a syntactically invalid non-empty path name to be assigned.
|
||||
/// Empty paths are required in order to indicate an error result in some
|
||||
/// situations. If the path is empty, the isValid operation will return
|
||||
/// false. All operations will fail if isValid is false. Operations that
|
||||
/// change the path will either return false if it would cause a syntactically
|
||||
/// invalid path name (in which case the Path object is left unchanged) or
|
||||
/// throw an std::string exception indicating the error. The methods are
|
||||
/// grouped into four basic categories: Path Accessors (provide information
|
||||
/// about the path without accessing disk), Disk Accessors (provide
|
||||
/// information about the underlying file or directory), Path Mutators
|
||||
/// (change the path information, not the disk), and Disk Mutators (change
|
||||
/// the disk file/directory referenced by the path). The Disk Mutator methods
|
||||
/// all have the word "disk" embedded in their method name to reinforce the
|
||||
/// notion that the operation modifies the file system.
|
||||
/// @since 1.4
|
||||
/// @brief An abstraction for operating system paths.
|
||||
class Path {
|
||||
/// @name Constructors
|
||||
/// @{
|
||||
public:
|
||||
/// Construct a path to a unique temporary directory that is created in
|
||||
/// a "standard" place for the operating system. The directory is
|
||||
/// guaranteed to be created on exit from this function. If the directory
|
||||
/// cannot be created, the function will throw an exception.
|
||||
/// @returns an invalid path (empty) on error
|
||||
/// @param ErrMsg Optional place for an error message if an error occurs
|
||||
/// @brief Construct a path to an new, unique, existing temporary
|
||||
/// directory.
|
||||
static Path GetTemporaryDirectory(std::string* ErrMsg = 0);
|
||||
|
||||
/// Construct a path to the current directory for the current process.
|
||||
/// @returns The current working directory.
|
||||
/// @brief Returns the current working directory.
|
||||
static Path GetCurrentDirectory();
|
||||
|
||||
/// This is one of the very few ways in which a path can be constructed
|
||||
/// with a syntactically invalid name. The only *legal* invalid name is an
|
||||
/// empty one. Other invalid names are not permitted. Empty paths are
|
||||
/// 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() {}
|
||||
Path(const Path &that) : path(that.path) {}
|
||||
|
||||
/// This constructor will accept a char* or 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(StringRef p);
|
||||
|
||||
/// This constructor will accept a character range 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 StrStart A pointer to the first character of the path name
|
||||
/// @param StrLen The length of the path name at StrStart
|
||||
/// @brief Construct a Path from a string.
|
||||
Path(const char *StrStart, unsigned StrLen);
|
||||
|
||||
/// @}
|
||||
/// @name Operators
|
||||
/// @{
|
||||
public:
|
||||
/// Makes a copy of \p that to \p this.
|
||||
/// @returns \p this
|
||||
/// @brief Assignment Operator
|
||||
Path &operator=(const Path &that) {
|
||||
path = that.path;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Makes a copy of \p that to \p this.
|
||||
/// @param that A StringRef denoting the path
|
||||
/// @returns \p this
|
||||
/// @brief Assignment Operator
|
||||
Path &operator=(StringRef that);
|
||||
|
||||
/// 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;
|
||||
|
||||
/// 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 !(*this == that); }
|
||||
|
||||
/// Determines if \p this Path is less than \p that Path. This is required
|
||||
/// so that Path objects can be placed into ordered collections (e.g.
|
||||
/// std::map). The comparison is done lexicographically as defined by
|
||||
/// 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;
|
||||
|
||||
/// @}
|
||||
/// @name Path Accessors
|
||||
/// @{
|
||||
public:
|
||||
/// This function will use an operating system specific algorithm to
|
||||
/// determine if the current value of \p this is a syntactically valid
|
||||
/// path name for the operating system. The path name does not need to
|
||||
/// exist, validity is simply syntactical. Empty paths are always invalid.
|
||||
/// @returns true iff the path name is syntactically legal for the
|
||||
/// host operating system.
|
||||
/// @brief Determine if a path is syntactically valid or not.
|
||||
bool isValid() const;
|
||||
|
||||
/// 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
|
||||
/// 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(); }
|
||||
|
||||
|
||||
|
||||
/// 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 *c_str() const { return path.c_str(); }
|
||||
const std::string &str() const { return path; }
|
||||
|
||||
|
||||
/// size - Return the length in bytes of this path name.
|
||||
size_t size() const { return path.size(); }
|
||||
|
||||
/// empty - Returns true if the path is empty.
|
||||
unsigned empty() const { return path.empty(); }
|
||||
|
||||
/// @}
|
||||
/// @name Disk Accessors
|
||||
/// @{
|
||||
public:
|
||||
/// This function determines if the path name in the object references an
|
||||
/// archive file by looking at its magic number.
|
||||
/// @returns true if the file starts with the magic number for an archive
|
||||
/// file.
|
||||
/// @brief Determine if the path references an archive file.
|
||||
bool isArchive() const;
|
||||
|
||||
/// This function determines if the path name in the object references a
|
||||
/// native Dynamic Library (shared library, shared object) by looking at
|
||||
/// the file's magic number. The Path object must reference a file, not a
|
||||
/// directory.
|
||||
/// @returns true if the file starts with the magic number for a native
|
||||
/// shared library.
|
||||
/// @brief Determine if the path references a dynamic library.
|
||||
bool isDynamicLibrary() const;
|
||||
|
||||
/// This function determines if the path name references an existing file
|
||||
/// or directory in the file system.
|
||||
/// @returns true if the pathname references an existing file or
|
||||
/// directory.
|
||||
/// @brief Determines if the path is a file or directory in
|
||||
/// the file system.
|
||||
LLVM_ATTRIBUTE_DEPRECATED(bool exists() const,
|
||||
LLVM_PATH_DEPRECATED_MSG(fs::exists));
|
||||
|
||||
/// This function determines if the path name references an
|
||||
/// existing directory.
|
||||
/// @returns true if the pathname references an existing directory.
|
||||
/// @brief Determines if the path is a directory in the file system.
|
||||
LLVM_ATTRIBUTE_DEPRECATED(bool isDirectory() const,
|
||||
LLVM_PATH_DEPRECATED_MSG(fs::is_directory));
|
||||
|
||||
/// This function determines if the path name references an
|
||||
/// existing symbolic link.
|
||||
/// @returns true if the pathname references an existing symlink.
|
||||
/// @brief Determines if the path is a symlink in the file system.
|
||||
LLVM_ATTRIBUTE_DEPRECATED(bool isSymLink() const,
|
||||
LLVM_PATH_DEPRECATED_MSG(fs::is_symlink));
|
||||
|
||||
/// This function checks that what we're trying to work only on a regular
|
||||
/// file. Check for things like /dev/null, any block special file, or
|
||||
/// other things that aren't "regular" regular files.
|
||||
/// @returns true if the file is S_ISREG.
|
||||
/// @brief Determines if the file is a regular file
|
||||
bool isRegularFile() const;
|
||||
|
||||
/// @}
|
||||
/// @name Path Mutators
|
||||
/// @{
|
||||
public:
|
||||
/// The path name is cleared and becomes empty. This is an invalid
|
||||
/// path name but is the *only* invalid path name. This is provided
|
||||
/// so that path objects can be used to indicate the lack of a
|
||||
/// valid path being found.
|
||||
/// @brief Make the path empty.
|
||||
void clear() { path.clear(); }
|
||||
|
||||
/// This method sets the Path object to \p unverified_path. This can fail
|
||||
/// if the \p unverified_path does not pass the syntactic checks of the
|
||||
/// isValid() method. If verification fails, the Path object remains
|
||||
/// unchanged and false is returned. Otherwise true is returned and the
|
||||
/// Path object takes on the path value of \p unverified_path
|
||||
/// @returns true if the path was set, false otherwise.
|
||||
/// @param unverified_path The path to be set in Path object.
|
||||
/// @brief Set a full path from a StringRef
|
||||
bool set(StringRef unverified_path);
|
||||
|
||||
/// One path component is removed from the Path. If only one component is
|
||||
/// present in the path, the Path object becomes empty. If the Path object
|
||||
/// is empty, no change is made.
|
||||
/// @returns false if the path component could not be removed.
|
||||
/// @brief Removes the last directory component of the Path.
|
||||
bool eraseComponent();
|
||||
|
||||
/// The \p component is added to the end of the Path if it is a legal
|
||||
/// name for the operating system. A directory separator will be added if
|
||||
/// needed.
|
||||
/// @returns false if the path component could not be added.
|
||||
/// @brief Appends one path component to the Path.
|
||||
bool appendComponent(StringRef component);
|
||||
|
||||
/// A period and the \p suffix are appended to the end of the pathname.
|
||||
/// When the \p suffix is empty, no action is performed.
|
||||
/// @brief Adds a period and the \p suffix to the end of the pathname.
|
||||
void appendSuffix(StringRef suffix);
|
||||
|
||||
/// The suffix of the filename is erased. The suffix begins with and
|
||||
/// includes the last . character in the filename after the last directory
|
||||
/// separator and extends until the end of the name. If no . character is
|
||||
/// after the last directory separator, then the file name is left
|
||||
/// unchanged (i.e. it was already without a suffix) but the function
|
||||
/// returns false.
|
||||
/// @returns false if there was no suffix to remove, true otherwise.
|
||||
/// @brief Remove the suffix from a path name.
|
||||
bool eraseSuffix();
|
||||
|
||||
/// The current Path name is made unique in the file system. Upon return,
|
||||
/// the Path will have been changed to make a unique file in the file
|
||||
/// system or it will not have been changed if the current path name is
|
||||
/// already unique.
|
||||
/// @throws std::string if an unrecoverable error occurs.
|
||||
/// @brief Make the current path name unique in the file system.
|
||||
bool makeUnique( bool reuse_current /*= true*/, std::string* ErrMsg );
|
||||
|
||||
/// The current Path name is made absolute by prepending the
|
||||
/// current working directory if necessary.
|
||||
LLVM_ATTRIBUTE_DEPRECATED(
|
||||
void makeAbsolute(),
|
||||
LLVM_PATH_DEPRECATED_MSG(fs::make_absolute));
|
||||
|
||||
/// @}
|
||||
/// @name Disk Mutators
|
||||
/// @{
|
||||
public:
|
||||
/// This method attempts to make the file referenced by the Path object
|
||||
/// available for reading so that the canRead() method will return true.
|
||||
/// @brief Make the file readable;
|
||||
bool makeReadableOnDisk(std::string* ErrMsg = 0);
|
||||
|
||||
/// This method attempts to make the file referenced by the Path object
|
||||
/// available for writing so that the canWrite() method will return true.
|
||||
/// @brief Make the file writable;
|
||||
bool makeWriteableOnDisk(std::string* ErrMsg = 0);
|
||||
|
||||
/// This method allows the last modified time stamp and permission bits
|
||||
/// to be set on the disk object referenced by the Path.
|
||||
/// @throws std::string if an error occurs.
|
||||
/// @returns true on error.
|
||||
/// @brief Set the status information.
|
||||
bool setStatusInfoOnDisk(const FileStatus &SI,
|
||||
std::string *ErrStr = 0) 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
|
||||
/// whether intermediate directories are created or not. if \p
|
||||
/// create_parents is true, then an attempt will be made to create all
|
||||
/// intermediate directories, as needed. If \p create_parents is false,
|
||||
/// then only the final directory component of the Path name will be
|
||||
/// created. The created directory will have no entries.
|
||||
/// @returns true if the directory could not be created, false otherwise
|
||||
/// @brief Create the directory this Path refers to.
|
||||
bool createDirectoryOnDisk(
|
||||
bool create_parents = false, ///< Determines whether non-existent
|
||||
///< directory components other than the last one (the "parents")
|
||||
///< are created or not.
|
||||
std::string* ErrMsg = 0 ///< Optional place to put error messages.
|
||||
);
|
||||
|
||||
/// This is like createFile except that it creates a temporary file. A
|
||||
/// unique temporary file name is generated based on the contents of
|
||||
/// \p this before the call. The new name is assigned to \p this and the
|
||||
/// file is created. Note that this will both change the Path object
|
||||
/// *and* create the corresponding file. This function will ensure that
|
||||
/// the newly generated temporary file name is unique in the file system.
|
||||
/// @returns true if the file couldn't be created, false otherwise.
|
||||
/// @brief Create a unique temporary file
|
||||
bool createTemporaryFileOnDisk(
|
||||
bool reuse_current = false, ///< When set to true, this parameter
|
||||
///< indicates that if the current file name does not exist then
|
||||
///< it will be used without modification.
|
||||
std::string* ErrMsg = 0 ///< Optional place to put error messages
|
||||
);
|
||||
|
||||
/// This method renames the file referenced by \p this as \p newName. The
|
||||
/// file referenced by \p this must exist. The file referenced by
|
||||
/// \p newName does not need to exist.
|
||||
/// @returns true on error, false otherwise
|
||||
/// @brief Rename one file as another.
|
||||
bool renamePathOnDisk(const Path& newName, std::string* ErrMsg);
|
||||
|
||||
/// This method attempts to destroy the file or directory named by the
|
||||
/// last component of the Path. If the Path refers to a directory and the
|
||||
/// \p destroy_contents is false, an attempt will be made to remove just
|
||||
/// the directory (the final Path component). If \p destroy_contents is
|
||||
/// true, an attempt will be made to remove the entire contents of the
|
||||
/// directory, recursively. If the Path refers to a file, the
|
||||
/// \p destroy_contents parameter is ignored.
|
||||
/// @param destroy_contents Indicates whether the contents of a destroyed
|
||||
/// @param Err An optional string to receive an error message.
|
||||
/// directory should also be destroyed (recursively).
|
||||
/// @returns false if the file/directory was destroyed, true on error.
|
||||
/// @brief Removes the file or directory from the filesystem.
|
||||
bool eraseFromDisk(bool destroy_contents = false,
|
||||
std::string *Err = 0) const;
|
||||
|
||||
/// @}
|
||||
/// @name Data
|
||||
/// @{
|
||||
protected:
|
||||
// Our win32 implementation relies on this string being mutable.
|
||||
mutable std::string path; ///< Storage for the path name.
|
||||
|
||||
|
||||
/// @}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -73,7 +73,6 @@ add_llvm_library(LLVMSupport
|
|||
IncludeFile.cpp
|
||||
Memory.cpp
|
||||
Mutex.cpp
|
||||
Path.cpp
|
||||
PathV2.cpp
|
||||
Process.cpp
|
||||
Program.cpp
|
||||
|
@ -90,7 +89,6 @@ add_llvm_library(LLVMSupport
|
|||
Unix/Host.inc
|
||||
Unix/Memory.inc
|
||||
Unix/Mutex.inc
|
||||
Unix/Path.inc
|
||||
Unix/PathV2.inc
|
||||
Unix/Process.inc
|
||||
Unix/Program.inc
|
||||
|
@ -104,7 +102,6 @@ add_llvm_library(LLVMSupport
|
|||
Windows/Host.inc
|
||||
Windows/Memory.inc
|
||||
Windows/Mutex.inc
|
||||
Windows/Path.inc
|
||||
Windows/PathV2.inc
|
||||
Windows/Process.inc
|
||||
Windows/Program.inc
|
||||
|
|
|
@ -1,78 +0,0 @@
|
|||
//===-- Path.cpp - Implement OS Path Concept --------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This header file implements the operating system Path concept.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Support/Path.h"
|
||||
#include "llvm/Config/config.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
#include "llvm/Support/PathV1.h"
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <ostream>
|
||||
using namespace llvm;
|
||||
using namespace sys;
|
||||
namespace {
|
||||
using support::ulittle32_t;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
//=== WARNING: Implementation here must contain only TRULY operating system
|
||||
//=== independent code.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
bool Path::operator==(const Path &that) const {
|
||||
return path == that.path;
|
||||
}
|
||||
|
||||
bool Path::operator<(const Path& that) const {
|
||||
return path < that.path;
|
||||
}
|
||||
|
||||
bool
|
||||
Path::isArchive() const {
|
||||
fs::file_magic type;
|
||||
if (fs::identify_magic(str(), type))
|
||||
return false;
|
||||
return type == fs::file_magic::archive;
|
||||
}
|
||||
|
||||
bool
|
||||
Path::isDynamicLibrary() const {
|
||||
fs::file_magic type;
|
||||
if (fs::identify_magic(str(), type))
|
||||
return false;
|
||||
switch (type) {
|
||||
default: return false;
|
||||
case fs::file_magic::macho_fixed_virtual_memory_shared_lib:
|
||||
case fs::file_magic::macho_dynamically_linked_shared_lib:
|
||||
case fs::file_magic::macho_dynamically_linked_shared_lib_stub:
|
||||
case fs::file_magic::elf_shared_object:
|
||||
case fs::file_magic::pecoff_executable: return true;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Path::appendSuffix(StringRef suffix) {
|
||||
if (!suffix.empty()) {
|
||||
path.append(".");
|
||||
path.append(suffix);
|
||||
}
|
||||
}
|
||||
|
||||
// Include the truly platform-specific parts of this class.
|
||||
#if defined(LLVM_ON_UNIX)
|
||||
#include "Unix/Path.inc"
|
||||
#endif
|
||||
#if defined(LLVM_ON_WIN32)
|
||||
#include "Windows/Path.inc"
|
||||
#endif
|
|
@ -1,496 +0,0 @@
|
|||
//===- llvm/Support/Unix/Path.cpp - Unix Path Implementation -----*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the Unix specific portion of the Path class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
//=== WARNING: Implementation here must contain only generic UNIX code that
|
||||
//=== is guaranteed to work on *all* UNIX variants.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "Unix.h"
|
||||
#if HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#if HAVE_FCNTL_H
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_MMAN_H
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#if HAVE_UTIME_H
|
||||
#include <utime.h>
|
||||
#endif
|
||||
#if HAVE_TIME_H
|
||||
#include <time.h>
|
||||
#endif
|
||||
#if HAVE_DIRENT_H
|
||||
# include <dirent.h>
|
||||
# define NAMLEN(dirent) strlen((dirent)->d_name)
|
||||
#else
|
||||
# define dirent direct
|
||||
# define NAMLEN(dirent) (dirent)->d_namlen
|
||||
# if HAVE_SYS_NDIR_H
|
||||
# include <sys/ndir.h>
|
||||
# endif
|
||||
# if HAVE_SYS_DIR_H
|
||||
# include <sys/dir.h>
|
||||
# endif
|
||||
# if HAVE_NDIR_H
|
||||
# include <ndir.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if HAVE_DLFCN_H
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <mach-o/dyld.h>
|
||||
#endif
|
||||
|
||||
// For GNU Hurd
|
||||
#if defined(__GNU__) && !defined(MAXPATHLEN)
|
||||
# define MAXPATHLEN 4096
|
||||
#endif
|
||||
|
||||
// Put in a hack for Cygwin which falsely reports that the mkdtemp function
|
||||
// is available when it is not.
|
||||
#ifdef __CYGWIN__
|
||||
# undef HAVE_MKDTEMP
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
inline bool lastIsSlash(const std::string& path) {
|
||||
return !path.empty() && path[path.length() - 1] == '/';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace llvm {
|
||||
using namespace sys;
|
||||
|
||||
Path::Path(StringRef p)
|
||||
: path(p) {}
|
||||
|
||||
Path::Path(const char *StrStart, unsigned StrLen)
|
||||
: path(StrStart, StrLen) {}
|
||||
|
||||
Path&
|
||||
Path::operator=(StringRef that) {
|
||||
path.assign(that.data(), that.size());
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool
|
||||
Path::isValid() const {
|
||||
// Empty paths are considered invalid here.
|
||||
// This code doesn't check MAXPATHLEN because there's no need. Nothing in
|
||||
// LLVM manipulates Paths with fixed-sizes arrays, and if the OS can't
|
||||
// handle names longer than some limit, it'll report this on demand using
|
||||
// ENAMETOLONG.
|
||||
return !path.empty();
|
||||
}
|
||||
|
||||
Path
|
||||
Path::GetTemporaryDirectory(std::string *ErrMsg) {
|
||||
#if defined(HAVE_MKDTEMP)
|
||||
// The best way is with mkdtemp but that's not available on many systems,
|
||||
// Linux and FreeBSD have it. Others probably won't.
|
||||
char pathname[] = "/tmp/llvm_XXXXXX";
|
||||
if (0 == mkdtemp(pathname)) {
|
||||
MakeErrMsg(ErrMsg,
|
||||
std::string(pathname) + ": can't create temporary directory");
|
||||
return Path();
|
||||
}
|
||||
return Path(pathname);
|
||||
#elif defined(HAVE_MKSTEMP)
|
||||
// If no mkdtemp is available, mkstemp can be used to create a temporary file
|
||||
// which is then removed and created as a directory. We prefer this over
|
||||
// mktemp because of mktemp's inherent security and threading risks. We still
|
||||
// have a slight race condition from the time the temporary file is created to
|
||||
// the time it is re-created as a directoy.
|
||||
char pathname[] = "/tmp/llvm_XXXXXX";
|
||||
int fd = 0;
|
||||
if (-1 == (fd = mkstemp(pathname))) {
|
||||
MakeErrMsg(ErrMsg,
|
||||
std::string(pathname) + ": can't create temporary directory");
|
||||
return Path();
|
||||
}
|
||||
::close(fd);
|
||||
::unlink(pathname); // start race condition, ignore errors
|
||||
if (-1 == ::mkdir(pathname, S_IRWXU)) { // end race condition
|
||||
MakeErrMsg(ErrMsg,
|
||||
std::string(pathname) + ": can't create temporary directory");
|
||||
return Path();
|
||||
}
|
||||
return Path(pathname);
|
||||
#elif defined(HAVE_MKTEMP)
|
||||
// If a system doesn't have mkdtemp(3) or mkstemp(3) but it does have
|
||||
// mktemp(3) then we'll assume that system (e.g. AIX) has a reasonable
|
||||
// implementation of mktemp(3) and doesn't follow BSD 4.3's lead of replacing
|
||||
// the XXXXXX with the pid of the process and a letter. That leads to only
|
||||
// twenty six temporary files that can be generated.
|
||||
char pathname[] = "/tmp/llvm_XXXXXX";
|
||||
char *TmpName = ::mktemp(pathname);
|
||||
if (TmpName == 0) {
|
||||
MakeErrMsg(ErrMsg,
|
||||
std::string(TmpName) + ": can't create unique directory name");
|
||||
return Path();
|
||||
}
|
||||
if (-1 == ::mkdir(TmpName, S_IRWXU)) {
|
||||
MakeErrMsg(ErrMsg,
|
||||
std::string(TmpName) + ": can't create temporary directory");
|
||||
return Path();
|
||||
}
|
||||
return Path(TmpName);
|
||||
#else
|
||||
// This is the worst case implementation. tempnam(3) leaks memory unless its
|
||||
// on an SVID2 (or later) system. On BSD 4.3 it leaks. tmpnam(3) has thread
|
||||
// issues. The mktemp(3) function doesn't have enough variability in the
|
||||
// temporary name generated. So, we provide our own implementation that
|
||||
// increments an integer from a random number seeded by the current time. This
|
||||
// should be sufficiently unique that we don't have many collisions between
|
||||
// processes. Generally LLVM processes don't run very long and don't use very
|
||||
// many temporary files so this shouldn't be a big issue for LLVM.
|
||||
static time_t num = ::time(0);
|
||||
char pathname[MAXPATHLEN];
|
||||
do {
|
||||
num++;
|
||||
sprintf(pathname, "/tmp/llvm_%010u", unsigned(num));
|
||||
} while ( 0 == access(pathname, F_OK ) );
|
||||
if (-1 == ::mkdir(pathname, S_IRWXU)) {
|
||||
MakeErrMsg(ErrMsg,
|
||||
std::string(pathname) + ": can't create temporary directory");
|
||||
return Path();
|
||||
}
|
||||
return Path(pathname);
|
||||
#endif
|
||||
}
|
||||
|
||||
Path
|
||||
Path::GetCurrentDirectory() {
|
||||
char pathname[MAXPATHLEN];
|
||||
if (!getcwd(pathname, MAXPATHLEN)) {
|
||||
assert(false && "Could not query current working directory.");
|
||||
return Path();
|
||||
}
|
||||
|
||||
return Path(pathname);
|
||||
}
|
||||
|
||||
bool
|
||||
Path::exists() const {
|
||||
return 0 == access(path.c_str(), F_OK );
|
||||
}
|
||||
|
||||
bool
|
||||
Path::isDirectory() const {
|
||||
struct stat buf;
|
||||
if (0 != stat(path.c_str(), &buf))
|
||||
return false;
|
||||
return ((buf.st_mode & S_IFMT) == S_IFDIR) ? true : false;
|
||||
}
|
||||
|
||||
bool
|
||||
Path::isSymLink() const {
|
||||
struct stat buf;
|
||||
if (0 != lstat(path.c_str(), &buf))
|
||||
return false;
|
||||
return S_ISLNK(buf.st_mode);
|
||||
}
|
||||
|
||||
bool
|
||||
Path::isRegularFile() const {
|
||||
// Get the status so we can determine if it's a file or directory
|
||||
struct stat buf;
|
||||
|
||||
if (0 != stat(path.c_str(), &buf))
|
||||
return false;
|
||||
|
||||
if (S_ISREG(buf.st_mode))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
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
|
||||
// time to reset it to the user's preference.
|
||||
int mask = umask(0777); // The arg. to umask is arbitrary.
|
||||
umask(mask); // Restore the umask.
|
||||
|
||||
// Get the file's current mode.
|
||||
struct stat buf;
|
||||
if (0 != stat(File.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::makeReadableOnDisk(std::string* ErrMsg) {
|
||||
if (!AddPermissionBits(*this, 0444))
|
||||
return MakeErrMsg(ErrMsg, path + ": can't make file readable");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Path::makeWriteableOnDisk(std::string* ErrMsg) {
|
||||
if (!AddPermissionBits(*this, 0222))
|
||||
return MakeErrMsg(ErrMsg, path + ": can't make file writable");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
Path::set(StringRef a_path) {
|
||||
if (a_path.empty())
|
||||
return false;
|
||||
path = a_path;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Path::appendComponent(StringRef name) {
|
||||
if (name.empty())
|
||||
return false;
|
||||
if (!lastIsSlash(path))
|
||||
path += '/';
|
||||
path += name;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Path::eraseComponent() {
|
||||
size_t slashpos = path.rfind('/',path.size());
|
||||
if (slashpos == 0 || slashpos == std::string::npos) {
|
||||
path.erase();
|
||||
return true;
|
||||
}
|
||||
if (slashpos == path.size() - 1)
|
||||
slashpos = path.rfind('/',slashpos-1);
|
||||
if (slashpos == std::string::npos) {
|
||||
path.erase();
|
||||
return true;
|
||||
}
|
||||
path.erase(slashpos);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Path::eraseSuffix() {
|
||||
size_t dotpos = path.rfind('.',path.size());
|
||||
size_t slashpos = path.rfind('/',path.size());
|
||||
if (dotpos != std::string::npos) {
|
||||
if (slashpos == std::string::npos || dotpos > slashpos+1) {
|
||||
path.erase(dotpos, path.size()-dotpos);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool createDirectoryHelper(char* beg, char* end, bool create_parents) {
|
||||
|
||||
if (access(beg, R_OK | W_OK) == 0)
|
||||
return false;
|
||||
|
||||
if (create_parents) {
|
||||
|
||||
char* c = end;
|
||||
|
||||
for (; c != beg; --c)
|
||||
if (*c == '/') {
|
||||
|
||||
// Recurse to handling the parent directory.
|
||||
*c = '\0';
|
||||
bool x = createDirectoryHelper(beg, c, create_parents);
|
||||
*c = '/';
|
||||
|
||||
// Return if we encountered an error.
|
||||
if (x)
|
||||
return true;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return mkdir(beg, S_IRWXU | S_IRWXG) != 0;
|
||||
}
|
||||
|
||||
bool
|
||||
Path::createDirectoryOnDisk( bool create_parents, std::string* ErrMsg ) {
|
||||
// Get a writeable copy of the path name
|
||||
std::string pathname(path);
|
||||
|
||||
// Null-terminate the last component
|
||||
size_t lastchar = path.length() - 1 ;
|
||||
|
||||
if (pathname[lastchar] != '/')
|
||||
++lastchar;
|
||||
|
||||
pathname[lastchar] = '\0';
|
||||
|
||||
if (createDirectoryHelper(&pathname[0], &pathname[lastchar], create_parents))
|
||||
return MakeErrMsg(ErrMsg, pathname + ": can't create directory");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
Path::createTemporaryFileOnDisk(bool reuse_current, std::string* ErrMsg) {
|
||||
// Make this into a unique file name
|
||||
if (makeUnique( reuse_current, ErrMsg ))
|
||||
return true;
|
||||
|
||||
// create the file
|
||||
int fd = ::open(path.c_str(), O_WRONLY|O_CREAT|O_TRUNC, 0666);
|
||||
if (fd < 0)
|
||||
return MakeErrMsg(ErrMsg, path + ": can't create temporary file");
|
||||
::close(fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
Path::eraseFromDisk(bool remove_contents, std::string *ErrStr) const {
|
||||
// Get the status so we can determine if it's 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.
|
||||
std::string cmd = "/bin/rm -rf " + path;
|
||||
if (system(cmd.c_str()) != 0) {
|
||||
MakeErrMsg(ErrStr, path + ": failed to recursively remove directory.");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Otherwise, try to just remove the one directory.
|
||||
std::string pathname(path);
|
||||
size_t lastchar = path.length() - 1;
|
||||
if (pathname[lastchar] == '/')
|
||||
pathname[lastchar] = '\0';
|
||||
else
|
||||
pathname[lastchar+1] = '\0';
|
||||
|
||||
if (rmdir(pathname.c_str()) != 0)
|
||||
return MakeErrMsg(ErrStr, pathname + ": can't erase directory");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
Path::renamePathOnDisk(const Path& newName, std::string* ErrMsg) {
|
||||
if (0 != ::rename(path.c_str(), newName.c_str()))
|
||||
return MakeErrMsg(ErrMsg, std::string("can't rename '") + path + "' as '" +
|
||||
newName.str() + "'");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
Path::setStatusInfoOnDisk(const FileStatus &si, std::string *ErrStr) const {
|
||||
struct utimbuf utb;
|
||||
utb.actime = si.modTime.toPosixTime();
|
||||
utb.modtime = utb.actime;
|
||||
if (0 != ::utime(path.c_str(),&utb))
|
||||
return MakeErrMsg(ErrStr, path + ": can't set file modification time");
|
||||
if (0 != ::chmod(path.c_str(),si.mode))
|
||||
return MakeErrMsg(ErrStr, path + ": can't set mode");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
Path::makeUnique(bool reuse_current, std::string* ErrMsg) {
|
||||
bool Exists;
|
||||
if (reuse_current && (fs::exists(path, Exists) || !Exists))
|
||||
return false; // File doesn't exist already, just use it!
|
||||
|
||||
// Append an XXXXXX pattern to the end of the file for use with mkstemp,
|
||||
// mktemp or our own implementation.
|
||||
// This uses std::vector instead of SmallVector to avoid a dependence on
|
||||
// libSupport. And performance isn't critical here.
|
||||
std::vector<char> Buf;
|
||||
Buf.resize(path.size()+8);
|
||||
char *FNBuffer = &Buf[0];
|
||||
path.copy(FNBuffer,path.size());
|
||||
bool isdir;
|
||||
if (!fs::is_directory(path, isdir) && isdir)
|
||||
strcpy(FNBuffer+path.size(), "/XXXXXX");
|
||||
else
|
||||
strcpy(FNBuffer+path.size(), "-XXXXXX");
|
||||
|
||||
#if defined(HAVE_MKSTEMP)
|
||||
int TempFD;
|
||||
if ((TempFD = mkstemp(FNBuffer)) == -1)
|
||||
return MakeErrMsg(ErrMsg, path + ": can't make unique filename");
|
||||
|
||||
// We don't need to hold the temp file descriptor... we will trust that no one
|
||||
// will overwrite/delete the file before we can open it again.
|
||||
close(TempFD);
|
||||
|
||||
// Save the name
|
||||
path = FNBuffer;
|
||||
|
||||
// By default mkstemp sets the mode to 0600, so update mode bits now.
|
||||
AddPermissionBits (*this, 0666);
|
||||
#elif defined(HAVE_MKTEMP)
|
||||
// If we don't have mkstemp, use the old and obsolete mktemp function.
|
||||
if (mktemp(FNBuffer) == 0)
|
||||
return MakeErrMsg(ErrMsg, path + ": can't make unique filename");
|
||||
|
||||
// Save the name
|
||||
path = FNBuffer;
|
||||
#else
|
||||
// Okay, looks like we have to do it all by our lonesome.
|
||||
static unsigned FCounter = 0;
|
||||
// Try to initialize with unique value.
|
||||
if (FCounter == 0) FCounter = ((unsigned)getpid() & 0xFFFF) << 8;
|
||||
char* pos = strstr(FNBuffer, "XXXXXX");
|
||||
do {
|
||||
if (++FCounter > 0xFFFFFF) {
|
||||
return MakeErrMsg(ErrMsg,
|
||||
path + ": can't make unique filename: too many files");
|
||||
}
|
||||
sprintf(pos, "%06X", FCounter);
|
||||
path = FNBuffer;
|
||||
} while (exists());
|
||||
// POSSIBLE SECURITY BUG: An attacker can easily guess the name and exploit
|
||||
// LLVM.
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
} // end llvm namespace
|
|
@ -1,587 +0,0 @@
|
|||
//===- llvm/Support/Win32/Path.cpp - Win32 Path Implementation ---*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file provides the Win32 specific implementation of the Path class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
//=== WARNING: Implementation here must contain only generic Win32 code that
|
||||
//=== is guaranteed to work on *all* Win32 variants.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "Windows.h"
|
||||
#include <cstdio>
|
||||
#include <malloc.h>
|
||||
|
||||
// We need to undo a macro defined in Windows.h, otherwise we won't compile:
|
||||
#undef GetCurrentDirectory
|
||||
|
||||
// Windows happily accepts either forward or backward slashes, though any path
|
||||
// returned by a Win32 API will have backward slashes. As LLVM code basically
|
||||
// assumes forward slashes are used, backward slashs are converted where they
|
||||
// can be introduced into a path.
|
||||
//
|
||||
// Another invariant is that a path ends with a slash if and only if the path
|
||||
// is a root directory. Any other use of a trailing slash is stripped. Unlike
|
||||
// in Unix, Windows has a rather complicated notion of a root path and this
|
||||
// invariant helps simply the code.
|
||||
|
||||
static void FlipBackSlashes(std::string& s) {
|
||||
for (size_t i = 0; i < s.size(); i++)
|
||||
if (s[i] == '\\')
|
||||
s[i] = '/';
|
||||
}
|
||||
|
||||
namespace llvm {
|
||||
namespace sys {
|
||||
|
||||
Path::Path(llvm::StringRef p)
|
||||
: path(p) {
|
||||
FlipBackSlashes(path);
|
||||
}
|
||||
|
||||
Path::Path(const char *StrStart, unsigned StrLen)
|
||||
: path(StrStart, StrLen) {
|
||||
FlipBackSlashes(path);
|
||||
}
|
||||
|
||||
Path&
|
||||
Path::operator=(StringRef that) {
|
||||
path.assign(that.data(), that.size());
|
||||
FlipBackSlashes(path);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool
|
||||
Path::isValid() const {
|
||||
if (path.empty())
|
||||
return false;
|
||||
|
||||
size_t len = path.size();
|
||||
// If there is a null character, it and all its successors are ignored.
|
||||
size_t pos = path.find_first_of('\0');
|
||||
if (pos != std::string::npos)
|
||||
len = pos;
|
||||
|
||||
// If there is a colon, it must be the second character, preceded by a letter
|
||||
// and followed by something.
|
||||
pos = path.rfind(':',len);
|
||||
size_t rootslash = 0;
|
||||
if (pos != std::string::npos) {
|
||||
if (pos != 1 || !isalpha(static_cast<unsigned char>(path[0])) || len < 3)
|
||||
return false;
|
||||
rootslash = 2;
|
||||
}
|
||||
|
||||
// Look for a UNC path, and if found adjust our notion of the root slash.
|
||||
if (len > 3 && path[0] == '/' && path[1] == '/') {
|
||||
rootslash = path.find('/', 2);
|
||||
if (rootslash == std::string::npos)
|
||||
rootslash = 0;
|
||||
}
|
||||
|
||||
// Check for illegal characters.
|
||||
if (path.find_first_of("\\<>\"|\001\002\003\004\005\006\007\010\011\012"
|
||||
"\013\014\015\016\017\020\021\022\023\024\025\026"
|
||||
"\027\030\031\032\033\034\035\036\037")
|
||||
!= std::string::npos)
|
||||
return false;
|
||||
|
||||
// Remove trailing slash, unless it's a root slash.
|
||||
if (len > rootslash+1 && path[len-1] == '/')
|
||||
path.erase(--len);
|
||||
|
||||
// Check each component for legality.
|
||||
for (pos = 0; pos < len; ++pos) {
|
||||
// A component may not end in a space.
|
||||
if (path[pos] == ' ') {
|
||||
if (pos+1 == len || path[pos+1] == '/' || path[pos+1] == '\0')
|
||||
return false;
|
||||
}
|
||||
|
||||
// A component may not end in a period.
|
||||
if (path[pos] == '.') {
|
||||
if (pos+1 == len || path[pos+1] == '/') {
|
||||
// Unless it is the pseudo-directory "."...
|
||||
if (pos == 0 || path[pos-1] == '/' || path[pos-1] == ':')
|
||||
return true;
|
||||
// or "..".
|
||||
if (pos > 0 && path[pos-1] == '.') {
|
||||
if (pos == 1 || path[pos-2] == '/' || path[pos-2] == ':')
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Path::makeAbsolute() {
|
||||
TCHAR FullPath[MAX_PATH + 1] = {0};
|
||||
LPTSTR FilePart = NULL;
|
||||
|
||||
DWORD RetLength = ::GetFullPathNameA(path.c_str(),
|
||||
sizeof(FullPath)/sizeof(FullPath[0]),
|
||||
FullPath, &FilePart);
|
||||
|
||||
if (0 == RetLength) {
|
||||
// FIXME: Report the error GetLastError()
|
||||
assert(0 && "Unable to make absolute path!");
|
||||
} else if (RetLength > MAX_PATH) {
|
||||
// FIXME: Report too small buffer (needed RetLength bytes).
|
||||
assert(0 && "Unable to make absolute path!");
|
||||
} else {
|
||||
path = FullPath;
|
||||
}
|
||||
}
|
||||
|
||||
static Path *TempDirectory;
|
||||
|
||||
Path
|
||||
Path::GetTemporaryDirectory(std::string* ErrMsg) {
|
||||
if (TempDirectory) {
|
||||
#if defined(_MSC_VER)
|
||||
// Visual Studio gets confused and emits a diagnostic about calling exists,
|
||||
// even though this is the implementation for PathV1. Temporarily
|
||||
// disable the deprecated warning message
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4996)
|
||||
#endif
|
||||
assert(TempDirectory->exists() && "Who has removed TempDirectory?");
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
return *TempDirectory;
|
||||
}
|
||||
|
||||
char pathname[MAX_PATH];
|
||||
if (!GetTempPath(MAX_PATH, pathname)) {
|
||||
if (ErrMsg)
|
||||
*ErrMsg = "Can't determine temporary directory";
|
||||
return Path();
|
||||
}
|
||||
|
||||
Path result;
|
||||
result.set(pathname);
|
||||
|
||||
// Append a subdirectory based on our process id so multiple LLVMs don't
|
||||
// step on each other's toes.
|
||||
#ifdef __MINGW32__
|
||||
// Mingw's Win32 header files are broken.
|
||||
sprintf(pathname, "LLVM_%u", unsigned(GetCurrentProcessId()));
|
||||
#else
|
||||
sprintf(pathname, "LLVM_%u", GetCurrentProcessId());
|
||||
#endif
|
||||
result.appendComponent(pathname);
|
||||
|
||||
// If there's a directory left over from a previous LLVM execution that
|
||||
// happened to have the same process id, get rid of it.
|
||||
result.eraseFromDisk(true);
|
||||
|
||||
// And finally (re-)create the empty directory.
|
||||
result.createDirectoryOnDisk(false);
|
||||
TempDirectory = new Path(result);
|
||||
return *TempDirectory;
|
||||
}
|
||||
|
||||
Path
|
||||
Path::GetCurrentDirectory() {
|
||||
char pathname[MAX_PATH];
|
||||
::GetCurrentDirectoryA(MAX_PATH,pathname);
|
||||
return Path(pathname);
|
||||
}
|
||||
|
||||
// FIXME: the above set of functions don't map to Windows very well.
|
||||
|
||||
bool
|
||||
Path::exists() const {
|
||||
DWORD attr = GetFileAttributes(path.c_str());
|
||||
return attr != INVALID_FILE_ATTRIBUTES;
|
||||
}
|
||||
|
||||
bool
|
||||
Path::isDirectory() const {
|
||||
DWORD attr = GetFileAttributes(path.c_str());
|
||||
return (attr != INVALID_FILE_ATTRIBUTES) &&
|
||||
(attr & FILE_ATTRIBUTE_DIRECTORY);
|
||||
}
|
||||
|
||||
bool
|
||||
Path::isSymLink() const {
|
||||
DWORD attributes = GetFileAttributes(path.c_str());
|
||||
|
||||
if (attributes == INVALID_FILE_ATTRIBUTES)
|
||||
// There's no sane way to report this :(.
|
||||
assert(0 && "GetFileAttributes returned INVALID_FILE_ATTRIBUTES");
|
||||
|
||||
// This isn't exactly what defines a NTFS symlink, but it is only true for
|
||||
// paths that act like a symlink.
|
||||
return attributes & FILE_ATTRIBUTE_REPARSE_POINT;
|
||||
}
|
||||
|
||||
bool
|
||||
Path::isRegularFile() const {
|
||||
bool res;
|
||||
if (fs::is_regular_file(path, res))
|
||||
return false;
|
||||
return res;
|
||||
}
|
||||
|
||||
bool Path::makeReadableOnDisk(std::string* ErrMsg) {
|
||||
// All files are readable on Windows (ignoring security attributes).
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Path::makeWriteableOnDisk(std::string* ErrMsg) {
|
||||
DWORD attr = GetFileAttributes(path.c_str());
|
||||
|
||||
// If it doesn't exist, we're done.
|
||||
if (attr == INVALID_FILE_ATTRIBUTES)
|
||||
return false;
|
||||
|
||||
if (attr & FILE_ATTRIBUTE_READONLY) {
|
||||
if (!SetFileAttributes(path.c_str(), attr & ~FILE_ATTRIBUTE_READONLY)) {
|
||||
MakeErrMsg(ErrMsg, std::string(path) + ": Can't make file writable: ");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
Path::set(StringRef a_path) {
|
||||
if (a_path.empty())
|
||||
return false;
|
||||
std::string save(path);
|
||||
path = a_path;
|
||||
FlipBackSlashes(path);
|
||||
if (!isValid()) {
|
||||
path = save;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Path::appendComponent(StringRef name) {
|
||||
if (name.empty())
|
||||
return false;
|
||||
std::string save(path);
|
||||
if (!path.empty()) {
|
||||
size_t last = path.size() - 1;
|
||||
if (path[last] != '/')
|
||||
path += '/';
|
||||
}
|
||||
path += name;
|
||||
if (!isValid()) {
|
||||
path = save;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Path::eraseComponent() {
|
||||
size_t slashpos = path.rfind('/',path.size());
|
||||
if (slashpos == path.size() - 1 || slashpos == std::string::npos)
|
||||
return false;
|
||||
std::string save(path);
|
||||
path.erase(slashpos);
|
||||
if (!isValid()) {
|
||||
path = save;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Path::eraseSuffix() {
|
||||
size_t dotpos = path.rfind('.',path.size());
|
||||
size_t slashpos = path.rfind('/',path.size());
|
||||
if (dotpos != std::string::npos) {
|
||||
if (slashpos == std::string::npos || dotpos > slashpos+1) {
|
||||
std::string save(path);
|
||||
path.erase(dotpos, path.size()-dotpos);
|
||||
if (!isValid()) {
|
||||
path = save;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool PathMsg(std::string* ErrMsg, const char* pathname, const char*msg) {
|
||||
if (ErrMsg)
|
||||
*ErrMsg = std::string(pathname) + ": " + std::string(msg);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Path::createDirectoryOnDisk(bool create_parents, std::string* ErrMsg) {
|
||||
// Get a writeable copy of the path name
|
||||
size_t len = path.length();
|
||||
char *pathname = reinterpret_cast<char *>(_alloca(len+2));
|
||||
path.copy(pathname, len);
|
||||
pathname[len] = 0;
|
||||
|
||||
// Make sure it ends with a slash.
|
||||
if (len == 0 || pathname[len - 1] != '/') {
|
||||
pathname[len] = '/';
|
||||
pathname[++len] = 0;
|
||||
}
|
||||
|
||||
// Determine starting point for initial / search.
|
||||
char *next = pathname;
|
||||
if (pathname[0] == '/' && pathname[1] == '/') {
|
||||
// Skip host name.
|
||||
next = strchr(pathname+2, '/');
|
||||
if (next == NULL)
|
||||
return PathMsg(ErrMsg, pathname, "badly formed remote directory");
|
||||
|
||||
// Skip share name.
|
||||
next = strchr(next+1, '/');
|
||||
if (next == NULL)
|
||||
return PathMsg(ErrMsg, pathname,"badly formed remote directory");
|
||||
|
||||
next++;
|
||||
if (*next == 0)
|
||||
return PathMsg(ErrMsg, pathname, "badly formed remote directory");
|
||||
|
||||
} else {
|
||||
if (pathname[1] == ':')
|
||||
next += 2; // skip drive letter
|
||||
if (*next == '/')
|
||||
next++; // skip root directory
|
||||
}
|
||||
|
||||
// If we're supposed to create intermediate directories
|
||||
if (create_parents) {
|
||||
// Loop through the directory components until we're done
|
||||
while (*next) {
|
||||
next = strchr(next, '/');
|
||||
*next = 0;
|
||||
if (!CreateDirectory(pathname, NULL) &&
|
||||
GetLastError() != ERROR_ALREADY_EXISTS)
|
||||
return MakeErrMsg(ErrMsg,
|
||||
std::string(pathname) + ": Can't create directory: ");
|
||||
*next++ = '/';
|
||||
}
|
||||
} else {
|
||||
// Drop trailing slash.
|
||||
pathname[len-1] = 0;
|
||||
if (!CreateDirectory(pathname, NULL) &&
|
||||
GetLastError() != ERROR_ALREADY_EXISTS) {
|
||||
return MakeErrMsg(ErrMsg, std::string(pathname) +
|
||||
": Can't create directory: ");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
Path::eraseFromDisk(bool remove_contents, std::string *ErrStr) const {
|
||||
WIN32_FILE_ATTRIBUTE_DATA fi;
|
||||
if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi))
|
||||
return true;
|
||||
|
||||
if (fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
// If it doesn't exist, we're done.
|
||||
bool Exists;
|
||||
if (fs::exists(path, Exists) || !Exists)
|
||||
return false;
|
||||
|
||||
char *pathname = reinterpret_cast<char *>(_alloca(path.length()+3));
|
||||
int lastchar = path.length() - 1 ;
|
||||
path.copy(pathname, lastchar+1);
|
||||
|
||||
// Make path end with '/*'.
|
||||
if (pathname[lastchar] != '/')
|
||||
pathname[++lastchar] = '/';
|
||||
pathname[lastchar+1] = '*';
|
||||
pathname[lastchar+2] = 0;
|
||||
|
||||
if (remove_contents) {
|
||||
WIN32_FIND_DATA fd;
|
||||
HANDLE h = FindFirstFile(pathname, &fd);
|
||||
|
||||
// It's a bad idea to alter the contents of a directory while enumerating
|
||||
// its contents. So build a list of its contents first, then destroy them.
|
||||
|
||||
if (h != INVALID_HANDLE_VALUE) {
|
||||
std::vector<Path> list;
|
||||
|
||||
do {
|
||||
if (strcmp(fd.cFileName, ".") == 0)
|
||||
continue;
|
||||
if (strcmp(fd.cFileName, "..") == 0)
|
||||
continue;
|
||||
|
||||
Path aPath(path);
|
||||
aPath.appendComponent(&fd.cFileName[0]);
|
||||
list.push_back(aPath);
|
||||
} while (FindNextFile(h, &fd));
|
||||
|
||||
DWORD err = GetLastError();
|
||||
FindClose(h);
|
||||
if (err != ERROR_NO_MORE_FILES) {
|
||||
SetLastError(err);
|
||||
return MakeErrMsg(ErrStr, path + ": Can't read directory: ");
|
||||
}
|
||||
|
||||
for (std::vector<Path>::iterator I = list.begin(); I != list.end();
|
||||
++I) {
|
||||
Path &aPath = *I;
|
||||
aPath.eraseFromDisk(true);
|
||||
}
|
||||
} else {
|
||||
if (GetLastError() != ERROR_FILE_NOT_FOUND)
|
||||
return MakeErrMsg(ErrStr, path + ": Can't read directory: ");
|
||||
}
|
||||
}
|
||||
|
||||
pathname[lastchar] = 0;
|
||||
if (!RemoveDirectory(pathname))
|
||||
return MakeErrMsg(ErrStr,
|
||||
std::string(pathname) + ": Can't destroy directory: ");
|
||||
return false;
|
||||
} else {
|
||||
// Read-only files cannot be deleted on Windows. Must remove the read-only
|
||||
// attribute first.
|
||||
if (fi.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
|
||||
if (!SetFileAttributes(path.c_str(),
|
||||
fi.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY))
|
||||
return MakeErrMsg(ErrStr, path + ": Can't destroy file: ");
|
||||
}
|
||||
|
||||
if (!DeleteFile(path.c_str()))
|
||||
return MakeErrMsg(ErrStr, path + ": Can't destroy file: ");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Path::renamePathOnDisk(const Path& newName, std::string* ErrMsg) {
|
||||
if (!MoveFileEx(path.c_str(), newName.c_str(), MOVEFILE_REPLACE_EXISTING))
|
||||
return MakeErrMsg(ErrMsg, "Can't move '" + path + "' to '" + newName.path
|
||||
+ "': ");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
Path::setStatusInfoOnDisk(const FileStatus &si, std::string *ErrMsg) const {
|
||||
// FIXME: should work on directories also.
|
||||
if (!si.isFile) {
|
||||
return true;
|
||||
}
|
||||
|
||||
HANDLE h = CreateFile(path.c_str(),
|
||||
FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
NULL);
|
||||
if (h == INVALID_HANDLE_VALUE)
|
||||
return true;
|
||||
|
||||
BY_HANDLE_FILE_INFORMATION bhfi;
|
||||
if (!GetFileInformationByHandle(h, &bhfi)) {
|
||||
DWORD err = GetLastError();
|
||||
CloseHandle(h);
|
||||
SetLastError(err);
|
||||
return MakeErrMsg(ErrMsg, path + ": GetFileInformationByHandle: ");
|
||||
}
|
||||
|
||||
ULARGE_INTEGER ui;
|
||||
ui.QuadPart = si.modTime.toWin32Time();
|
||||
FILETIME ft;
|
||||
ft.dwLowDateTime = ui.LowPart;
|
||||
ft.dwHighDateTime = ui.HighPart;
|
||||
BOOL ret = SetFileTime(h, NULL, &ft, &ft);
|
||||
DWORD err = GetLastError();
|
||||
CloseHandle(h);
|
||||
if (!ret) {
|
||||
SetLastError(err);
|
||||
return MakeErrMsg(ErrMsg, path + ": SetFileTime: ");
|
||||
}
|
||||
|
||||
// Best we can do with Unix permission bits is to interpret the owner
|
||||
// writable bit.
|
||||
if (si.mode & 0200) {
|
||||
if (bhfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
|
||||
if (!SetFileAttributes(path.c_str(),
|
||||
bhfi.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY))
|
||||
return MakeErrMsg(ErrMsg, path + ": SetFileAttributes: ");
|
||||
}
|
||||
} else {
|
||||
if (!(bhfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) {
|
||||
if (!SetFileAttributes(path.c_str(),
|
||||
bhfi.dwFileAttributes | FILE_ATTRIBUTE_READONLY))
|
||||
return MakeErrMsg(ErrMsg, path + ": SetFileAttributes: ");
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
Path::makeUnique(bool reuse_current, std::string* ErrMsg) {
|
||||
bool Exists;
|
||||
if (reuse_current && (fs::exists(path, Exists) || !Exists))
|
||||
return false; // File doesn't exist already, just use it!
|
||||
|
||||
// Reserve space for -XXXXXX at the end.
|
||||
char *FNBuffer = (char*) alloca(path.size()+8);
|
||||
unsigned offset = path.size();
|
||||
path.copy(FNBuffer, offset);
|
||||
|
||||
// Find a numeric suffix that isn't used by an existing file. Assume there
|
||||
// won't be more than 1 million files with the same prefix. Probably a safe
|
||||
// bet.
|
||||
static int FCounter = -1;
|
||||
if (FCounter < 0) {
|
||||
// Give arbitrary initial seed.
|
||||
// FIXME: We should use sys::fs::unique_file() in future.
|
||||
LARGE_INTEGER cnt64;
|
||||
DWORD x = GetCurrentProcessId();
|
||||
x = (x << 16) | (x >> 16);
|
||||
if (QueryPerformanceCounter(&cnt64)) // RDTSC
|
||||
x ^= cnt64.HighPart ^ cnt64.LowPart;
|
||||
FCounter = x % 1000000;
|
||||
}
|
||||
do {
|
||||
sprintf(FNBuffer+offset, "-%06u", FCounter);
|
||||
if (++FCounter > 999999)
|
||||
FCounter = 0;
|
||||
path = FNBuffer;
|
||||
} while (!fs::exists(path, Exists) && Exists);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
Path::createTemporaryFileOnDisk(bool reuse_current, std::string* ErrMsg) {
|
||||
// Make this into a unique file name
|
||||
makeUnique(reuse_current, ErrMsg);
|
||||
|
||||
// Now go and create it
|
||||
HANDLE h = CreateFile(path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW,
|
||||
FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (h == INVALID_HANDLE_VALUE)
|
||||
return MakeErrMsg(ErrMsg, path + ": can't create file");
|
||||
|
||||
CloseHandle(h);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue