#ifndef LLVM_SUPPORT_FILESYSTEM_H
#define LLVM_SUPPORT_FILESYSTEM_H
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/DataTypes.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/TimeValue.h"
#include <ctime>
#include <iterator>
#include <stack>
#include <string>
#include <system_error>
#include <tuple>
#include <vector>
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
namespace llvm {
namespace sys {
namespace fs {
enum class file_type {
status_error,
file_not_found,
regular_file,
directory_file,
symlink_file,
block_file,
character_file,
fifo_file,
socket_file,
type_unknown
};
struct space_info {
uint64_t capacity;
uint64_t free;
uint64_t available;
};
enum perms {
no_perms = 0,
owner_read = 0400,
owner_write = 0200,
owner_exe = 0100,
owner_all = owner_read | owner_write | owner_exe,
group_read = 040,
group_write = 020,
group_exe = 010,
group_all = group_read | group_write | group_exe,
others_read = 04,
others_write = 02,
others_exe = 01,
others_all = others_read | others_write | others_exe,
all_read = owner_read | group_read | others_read,
all_write = owner_write | group_write | others_write,
all_exe = owner_exe | group_exe | others_exe,
all_all = owner_all | group_all | others_all,
set_uid_on_exe = 04000,
set_gid_on_exe = 02000,
sticky_bit = 01000,
perms_not_known = 0xFFFF
};
inline perms operator|(perms l , perms r) {
return static_cast<perms>(
static_cast<unsigned short>(l) | static_cast<unsigned short>(r));
}
inline perms operator&(perms l , perms r) {
return static_cast<perms>(
static_cast<unsigned short>(l) & static_cast<unsigned short>(r));
}
inline perms &operator|=(perms &l, perms r) {
l = l | r;
return l;
}
inline perms &operator&=(perms &l, perms r) {
l = l & r;
return l;
}
inline perms operator~(perms x) {
return static_cast<perms>(~static_cast<unsigned short>(x));
}
class UniqueID {
uint64_t Device;
uint64_t File;
public:
UniqueID() {}
UniqueID(uint64_t Device, uint64_t File) : Device(Device), File(File) {}
bool operator==(const UniqueID &Other) const {
return Device == Other.Device && File == Other.File;
}
bool operator!=(const UniqueID &Other) const { return !(*this == Other); }
bool operator<(const UniqueID &Other) const {
return std::tie(Device, File) < std::tie(Other.Device, Other.File);
}
uint64_t getDevice() const { return Device; }
uint64_t getFile() const { return File; }
};
class file_status
{
#if defined(LLVM_ON_UNIX)
dev_t fs_st_dev;
ino_t fs_st_ino;
time_t fs_st_mtime;
uid_t fs_st_uid;
gid_t fs_st_gid;
off_t fs_st_size;
#elif defined (LLVM_ON_WIN32)
uint32_t LastWriteTimeHigh;
uint32_t LastWriteTimeLow;
uint32_t VolumeSerialNumber;
uint32_t FileSizeHigh;
uint32_t FileSizeLow;
uint32_t FileIndexHigh;
uint32_t FileIndexLow;
#endif
friend bool equivalent(file_status A, file_status B);
file_type Type;
perms Perms;
public:
#if defined(LLVM_ON_UNIX)
file_status() : fs_st_dev(0), fs_st_ino(0), fs_st_mtime(0),
fs_st_uid(0), fs_st_gid(0), fs_st_size(0),
Type(file_type::status_error), Perms(perms_not_known) {}
file_status(file_type Type) : fs_st_dev(0), fs_st_ino(0), fs_st_mtime(0),
fs_st_uid(0), fs_st_gid(0), fs_st_size(0), Type(Type),
Perms(perms_not_known) {}
file_status(file_type Type, perms Perms, dev_t Dev, ino_t Ino, time_t MTime,
uid_t UID, gid_t GID, off_t Size)
: fs_st_dev(Dev), fs_st_ino(Ino), fs_st_mtime(MTime), fs_st_uid(UID),
fs_st_gid(GID), fs_st_size(Size), Type(Type), Perms(Perms) {}
#elif defined(LLVM_ON_WIN32)
file_status() : LastWriteTimeHigh(0), LastWriteTimeLow(0),
VolumeSerialNumber(0), FileSizeHigh(0), FileSizeLow(0),
FileIndexHigh(0), FileIndexLow(0), Type(file_type::status_error),
Perms(perms_not_known) {}
file_status(file_type Type) : LastWriteTimeHigh(0), LastWriteTimeLow(0),
VolumeSerialNumber(0), FileSizeHigh(0), FileSizeLow(0),
FileIndexHigh(0), FileIndexLow(0), Type(Type),
Perms(perms_not_known) {}
file_status(file_type Type, uint32_t LastWriteTimeHigh,
uint32_t LastWriteTimeLow, uint32_t VolumeSerialNumber,
uint32_t FileSizeHigh, uint32_t FileSizeLow,
uint32_t FileIndexHigh, uint32_t FileIndexLow)
: LastWriteTimeHigh(LastWriteTimeHigh),
LastWriteTimeLow(LastWriteTimeLow),
VolumeSerialNumber(VolumeSerialNumber), FileSizeHigh(FileSizeHigh),
FileSizeLow(FileSizeLow), FileIndexHigh(FileIndexHigh),
FileIndexLow(FileIndexLow), Type(Type), Perms(perms_not_known) {}
#endif
file_type type() const { return Type; }
perms permissions() const { return Perms; }
TimeValue getLastModificationTime() const;
UniqueID getUniqueID() const;
#if defined(LLVM_ON_UNIX)
uint32_t getUser() const { return fs_st_uid; }
uint32_t getGroup() const { return fs_st_gid; }
uint64_t getSize() const { return fs_st_size; }
#elif defined (LLVM_ON_WIN32)
uint32_t getUser() const {
return 9999; }
uint32_t getGroup() const {
return 9999; }
uint64_t getSize() const {
return (uint64_t(FileSizeHigh) << 32) + FileSizeLow;
}
#endif
void type(file_type v) { Type = v; }
void permissions(perms p) { Perms = p; }
};
struct file_magic {
enum Impl {
unknown = 0, bitcode, archive, elf, elf_relocatable, elf_executable, elf_shared_object, elf_core, macho_object, macho_executable, macho_fixed_virtual_memory_shared_lib, macho_core, macho_preload_executable, macho_dynamically_linked_shared_lib, macho_dynamic_linker, macho_bundle, macho_dynamically_linked_shared_lib_stub, macho_dsym_companion, macho_kext_bundle, macho_universal_binary, coff_object, coff_import_library, pecoff_executable, windows_resource };
bool is_object() const {
return V == unknown ? false : true;
}
file_magic() : V(unknown) {}
file_magic(Impl V) : V(V) {}
operator Impl() const { return V; }
private:
Impl V;
};
std::error_code make_absolute(SmallVectorImpl<char> &path);
std::error_code create_directories(const Twine &path,
bool IgnoreExisting = true);
std::error_code create_directory(const Twine &path, bool IgnoreExisting = true);
std::error_code create_link(const Twine &to, const Twine &from);
std::error_code current_path(SmallVectorImpl<char> &result);
std::error_code remove(const Twine &path, bool IgnoreNonExisting = true);
std::error_code rename(const Twine &from, const Twine &to);
std::error_code copy_file(const Twine &From, const Twine &To);
std::error_code resize_file(int FD, uint64_t Size);
bool exists(file_status status);
enum class AccessMode { Exist, Write, Execute };
std::error_code access(const Twine &Path, AccessMode Mode);
inline bool exists(const Twine &Path) {
return !access(Path, AccessMode::Exist);
}
inline bool can_execute(const Twine &Path) {
return !access(Path, AccessMode::Execute);
}
inline bool can_write(const Twine &Path) {
return !access(Path, AccessMode::Write);
}
bool equivalent(file_status A, file_status B);
std::error_code equivalent(const Twine &A, const Twine &B, bool &result);
inline bool equivalent(const Twine &A, const Twine &B) {
bool result;
return !equivalent(A, B, result) && result;
}
bool is_directory(file_status status);
std::error_code is_directory(const Twine &path, bool &result);
inline bool is_directory(const Twine &Path) {
bool Result;
return !is_directory(Path, Result) && Result;
}
bool is_regular_file(file_status status);
std::error_code is_regular_file(const Twine &path, bool &result);
inline bool is_regular_file(const Twine &Path) {
bool Result;
if (is_regular_file(Path, Result))
return false;
return Result;
}
bool is_other(file_status status);
std::error_code is_other(const Twine &path, bool &result);
std::error_code status(const Twine &path, file_status &result);
std::error_code status(int FD, file_status &Result);
inline std::error_code file_size(const Twine &Path, uint64_t &Result) {
file_status Status;
std::error_code EC = status(Path, Status);
if (EC)
return EC;
Result = Status.getSize();
return std::error_code();
}
std::error_code setLastModificationAndAccessTime(int FD, TimeValue Time);
bool status_known(file_status s);
std::error_code status_known(const Twine &path, bool &result);
std::error_code createUniqueFile(const Twine &Model, int &ResultFD,
SmallVectorImpl<char> &ResultPath,
unsigned Mode = all_read | all_write);
std::error_code createUniqueFile(const Twine &Model,
SmallVectorImpl<char> &ResultPath);
std::error_code createTemporaryFile(const Twine &Prefix, StringRef Suffix,
int &ResultFD,
SmallVectorImpl<char> &ResultPath);
std::error_code createTemporaryFile(const Twine &Prefix, StringRef Suffix,
SmallVectorImpl<char> &ResultPath);
std::error_code createUniqueDirectory(const Twine &Prefix,
SmallVectorImpl<char> &ResultPath);
enum OpenFlags : unsigned {
F_None = 0,
F_Excl = 1,
F_Append = 2,
F_Text = 4,
F_RW = 8
};
inline OpenFlags operator|(OpenFlags A, OpenFlags B) {
return OpenFlags(unsigned(A) | unsigned(B));
}
inline OpenFlags &operator|=(OpenFlags &A, OpenFlags B) {
A = A | B;
return A;
}
std::error_code openFileForWrite(const Twine &Name, int &ResultFD,
OpenFlags Flags, unsigned Mode = 0666);
std::error_code openFileForRead(const Twine &Name, int &ResultFD);
file_magic identify_magic(StringRef magic);
std::error_code identify_magic(const Twine &path, file_magic &result);
std::error_code getUniqueID(const Twine Path, UniqueID &Result);
class mapped_file_region {
mapped_file_region() LLVM_DELETED_FUNCTION;
mapped_file_region(mapped_file_region&) LLVM_DELETED_FUNCTION;
mapped_file_region &operator =(mapped_file_region&) LLVM_DELETED_FUNCTION;
public:
enum mapmode {
readonly, readwrite, priv };
private:
uint64_t Size;
void *Mapping;
std::error_code init(int FD, uint64_t Offset, mapmode Mode);
public:
mapped_file_region(int fd, mapmode mode, uint64_t length, uint64_t offset,
std::error_code &ec);
~mapped_file_region();
uint64_t size() const;
char *data() const;
const char *const_data() const;
static int alignment();
};
std::string getMainExecutable(const char *argv0, void *MainExecAddr);
class directory_entry {
std::string Path;
mutable file_status Status;
public:
explicit directory_entry(const Twine &path, file_status st = file_status())
: Path(path.str())
, Status(st) {}
directory_entry() {}
void assign(const Twine &path, file_status st = file_status()) {
Path = path.str();
Status = st;
}
void replace_filename(const Twine &filename, file_status st = file_status());
const std::string &path() const { return Path; }
std::error_code status(file_status &result) const;
bool operator==(const directory_entry& rhs) const { return Path == rhs.Path; }
bool operator!=(const directory_entry& rhs) const { return !(*this == rhs); }
bool operator< (const directory_entry& rhs) const;
bool operator<=(const directory_entry& rhs) const;
bool operator> (const directory_entry& rhs) const;
bool operator>=(const directory_entry& rhs) const;
};
namespace detail {
struct DirIterState;
std::error_code directory_iterator_construct(DirIterState &, StringRef);
std::error_code directory_iterator_increment(DirIterState &);
std::error_code directory_iterator_destruct(DirIterState &);
struct DirIterState : public RefCountedBase<DirIterState> {
DirIterState()
: IterationHandle(0) {}
~DirIterState() {
directory_iterator_destruct(*this);
}
intptr_t IterationHandle;
directory_entry CurrentEntry;
};
}
class directory_iterator {
IntrusiveRefCntPtr<detail::DirIterState> State;
public:
explicit directory_iterator(const Twine &path, std::error_code &ec) {
State = new detail::DirIterState;
SmallString<128> path_storage;
ec = detail::directory_iterator_construct(*State,
path.toStringRef(path_storage));
}
explicit directory_iterator(const directory_entry &de, std::error_code &ec) {
State = new detail::DirIterState;
ec = detail::directory_iterator_construct(*State, de.path());
}
directory_iterator() : State(nullptr) {}
directory_iterator &increment(std::error_code &ec) {
ec = directory_iterator_increment(*State);
return *this;
}
const directory_entry &operator*() const { return State->CurrentEntry; }
const directory_entry *operator->() const { return &State->CurrentEntry; }
bool operator==(const directory_iterator &RHS) const {
if (State == RHS.State)
return true;
if (!RHS.State)
return State->CurrentEntry == directory_entry();
if (!State)
return RHS.State->CurrentEntry == directory_entry();
return State->CurrentEntry == RHS.State->CurrentEntry;
}
bool operator!=(const directory_iterator &RHS) const {
return !(*this == RHS);
}
};
namespace detail {
struct RecDirIterState : public RefCountedBase<RecDirIterState> {
RecDirIterState()
: Level(0)
, HasNoPushRequest(false) {}
std::stack<directory_iterator, std::vector<directory_iterator> > Stack;
uint16_t Level;
bool HasNoPushRequest;
};
}
class recursive_directory_iterator {
IntrusiveRefCntPtr<detail::RecDirIterState> State;
public:
recursive_directory_iterator() {}
explicit recursive_directory_iterator(const Twine &path, std::error_code &ec)
: State(new detail::RecDirIterState) {
State->Stack.push(directory_iterator(path, ec));
if (State->Stack.top() == directory_iterator())
State.reset();
}
recursive_directory_iterator &increment(std::error_code &ec) {
const directory_iterator end_itr;
if (State->HasNoPushRequest)
State->HasNoPushRequest = false;
else {
file_status st;
if ((ec = State->Stack.top()->status(st))) return *this;
if (is_directory(st)) {
State->Stack.push(directory_iterator(*State->Stack.top(), ec));
if (ec) return *this;
if (State->Stack.top() != end_itr) {
++State->Level;
return *this;
}
State->Stack.pop();
}
}
while (!State->Stack.empty()
&& State->Stack.top().increment(ec) == end_itr) {
State->Stack.pop();
--State->Level;
}
if (State->Stack.empty())
State.reset();
return *this;
}
const directory_entry &operator*() const { return *State->Stack.top(); }
const directory_entry *operator->() const { return &*State->Stack.top(); }
int level() const { return State->Level; }
bool no_push_request() const { return State->HasNoPushRequest; }
void pop() {
assert(State && "Cannot pop an end iterator!");
assert(State->Level > 0 && "Cannot pop an iterator with level < 1");
const directory_iterator end_itr;
std::error_code ec;
do {
if (ec)
report_fatal_error("Error incrementing directory iterator.");
State->Stack.pop();
--State->Level;
} while (!State->Stack.empty()
&& State->Stack.top().increment(ec) == end_itr);
if (State->Stack.empty())
State.reset();
}
void no_push() { State->HasNoPushRequest = true; }
bool operator==(const recursive_directory_iterator &RHS) const {
return State == RHS.State;
}
bool operator!=(const recursive_directory_iterator &RHS) const {
return !(*this == RHS);
}
};
} } }
#endif