1218885Sdim//===- llvm/Support/FileSystem.h - File System OS Concept -------*- C++ -*-===// 2218885Sdim// 3218885Sdim// The LLVM Compiler Infrastructure 4218885Sdim// 5218885Sdim// This file is distributed under the University of Illinois Open Source 6218885Sdim// License. See LICENSE.TXT for details. 7218885Sdim// 8218885Sdim//===----------------------------------------------------------------------===// 9218885Sdim// 10218885Sdim// This file declares the llvm::sys::fs namespace. It is designed after 11218885Sdim// TR2/boost filesystem (v3), but modified to remove exception handling and the 12218885Sdim// path class. 13218885Sdim// 14218885Sdim// All functions return an error_code and their actual work via the last out 15218885Sdim// argument. The out argument is defined if and only if errc::success is 16218885Sdim// returned. A function may return any error code in the generic or system 17218885Sdim// category. However, they shall be equivalent to any error conditions listed 18218885Sdim// in each functions respective documentation if the condition applies. [ note: 19218885Sdim// this does not guarantee that error_code will be in the set of explicitly 20218885Sdim// listed codes, but it does guarantee that if any of the explicitly listed 21218885Sdim// errors occur, the correct error_code will be used ]. All functions may 22218885Sdim// return errc::not_enough_memory if there is not enough memory to complete the 23218885Sdim// operation. 24218885Sdim// 25218885Sdim//===----------------------------------------------------------------------===// 26218885Sdim 27252723Sdim#ifndef LLVM_SUPPORT_FILESYSTEM_H 28252723Sdim#define LLVM_SUPPORT_FILESYSTEM_H 29218885Sdim 30235633Sdim#include "llvm/ADT/IntrusiveRefCntPtr.h" 31245431Sdim#include "llvm/ADT/OwningPtr.h" 32218885Sdim#include "llvm/ADT/SmallString.h" 33218885Sdim#include "llvm/ADT/Twine.h" 34218885Sdim#include "llvm/Support/DataTypes.h" 35235633Sdim#include "llvm/Support/ErrorHandling.h" 36263509Sdim#include "llvm/Support/TimeValue.h" 37218885Sdim#include "llvm/Support/system_error.h" 38218885Sdim#include <ctime> 39218885Sdim#include <iterator> 40235633Sdim#include <stack> 41218885Sdim#include <string> 42235633Sdim#include <vector> 43218885Sdim 44245431Sdim#ifdef HAVE_SYS_STAT_H 45235633Sdim#include <sys/stat.h> 46235633Sdim#endif 47235633Sdim 48218885Sdimnamespace llvm { 49218885Sdimnamespace sys { 50218885Sdimnamespace fs { 51218885Sdim 52218885Sdim/// file_type - An "enum class" enumeration for the file system's view of the 53218885Sdim/// type. 54218885Sdimstruct file_type { 55218885Sdim enum _ { 56218885Sdim status_error, 57218885Sdim file_not_found, 58218885Sdim regular_file, 59218885Sdim directory_file, 60218885Sdim symlink_file, 61218885Sdim block_file, 62218885Sdim character_file, 63218885Sdim fifo_file, 64218885Sdim socket_file, 65218885Sdim type_unknown 66218885Sdim }; 67218885Sdim 68218885Sdim file_type(_ v) : v_(v) {} 69218885Sdim explicit file_type(int v) : v_(_(v)) {} 70218885Sdim operator int() const {return v_;} 71218885Sdim 72218885Sdimprivate: 73218885Sdim int v_; 74218885Sdim}; 75218885Sdim 76218885Sdim/// space_info - Self explanatory. 77218885Sdimstruct space_info { 78218885Sdim uint64_t capacity; 79218885Sdim uint64_t free; 80218885Sdim uint64_t available; 81218885Sdim}; 82218885Sdim 83245431Sdimenum perms { 84263509Sdim no_perms = 0, 85263509Sdim owner_read = 0400, 86263509Sdim owner_write = 0200, 87263509Sdim owner_exe = 0100, 88263509Sdim owner_all = owner_read | owner_write | owner_exe, 89263509Sdim group_read = 040, 90263509Sdim group_write = 020, 91263509Sdim group_exe = 010, 92263509Sdim group_all = group_read | group_write | group_exe, 93263509Sdim others_read = 04, 94263509Sdim others_write = 02, 95263509Sdim others_exe = 01, 96263509Sdim others_all = others_read | others_write | others_exe, 97263509Sdim all_read = owner_read | group_read | others_read, 98263509Sdim all_write = owner_write | group_write | others_write, 99263509Sdim all_exe = owner_exe | group_exe | others_exe, 100263509Sdim all_all = owner_all | group_all | others_all, 101263509Sdim set_uid_on_exe = 04000, 102263509Sdim set_gid_on_exe = 02000, 103263509Sdim sticky_bit = 01000, 104263509Sdim perms_not_known = 0xFFFF 105245431Sdim}; 106245431Sdim 107245431Sdim// Helper functions so that you can use & and | to manipulate perms bits: 108245431Sdiminline perms operator|(perms l , perms r) { 109245431Sdim return static_cast<perms>( 110245431Sdim static_cast<unsigned short>(l) | static_cast<unsigned short>(r)); 111245431Sdim} 112245431Sdiminline perms operator&(perms l , perms r) { 113245431Sdim return static_cast<perms>( 114245431Sdim static_cast<unsigned short>(l) & static_cast<unsigned short>(r)); 115245431Sdim} 116245431Sdiminline perms &operator|=(perms &l, perms r) { 117245431Sdim l = l | r; 118245431Sdim return l; 119245431Sdim} 120245431Sdiminline perms &operator&=(perms &l, perms r) { 121245431Sdim l = l & r; 122245431Sdim return l; 123245431Sdim} 124245431Sdiminline perms operator~(perms x) { 125245431Sdim return static_cast<perms>(~static_cast<unsigned short>(x)); 126245431Sdim} 127245431Sdim 128263509Sdimclass UniqueID { 129263509Sdim uint64_t Device; 130263509Sdim uint64_t File; 131245431Sdim 132263509Sdimpublic: 133263509Sdim UniqueID() {} 134263509Sdim UniqueID(uint64_t Device, uint64_t File) : Device(Device), File(File) {} 135263509Sdim bool operator==(const UniqueID &Other) const { 136263509Sdim return Device == Other.Device && File == Other.File; 137263509Sdim } 138263509Sdim bool operator!=(const UniqueID &Other) const { return !(*this == Other); } 139263509Sdim bool operator<(const UniqueID &Other) const { 140263509Sdim return Device < Other.Device || 141263509Sdim (Device == Other.Device && File < Other.File); 142263509Sdim } 143263509Sdim uint64_t getDevice() const { return Device; } 144263509Sdim uint64_t getFile() const { return File; } 145263509Sdim}; 146263509Sdim 147218885Sdim/// file_status - Represents the result of a call to stat and friends. It has 148218885Sdim/// a platform specific member to store the result. 149218885Sdimclass file_status 150218885Sdim{ 151235633Sdim #if defined(LLVM_ON_UNIX) 152245431Sdim dev_t fs_st_dev; 153245431Sdim ino_t fs_st_ino; 154263509Sdim time_t fs_st_mtime; 155263509Sdim uid_t fs_st_uid; 156263509Sdim gid_t fs_st_gid; 157263509Sdim off_t fs_st_size; 158235633Sdim #elif defined (LLVM_ON_WIN32) 159235633Sdim uint32_t LastWriteTimeHigh; 160235633Sdim uint32_t LastWriteTimeLow; 161235633Sdim uint32_t VolumeSerialNumber; 162235633Sdim uint32_t FileSizeHigh; 163235633Sdim uint32_t FileSizeLow; 164235633Sdim uint32_t FileIndexHigh; 165235633Sdim uint32_t FileIndexLow; 166235633Sdim #endif 167235633Sdim friend bool equivalent(file_status A, file_status B); 168218885Sdim file_type Type; 169245431Sdim perms Perms; 170218885Sdimpublic: 171263509Sdim file_status() : Type(file_type::status_error) {} 172263509Sdim file_status(file_type Type) : Type(Type) {} 173218885Sdim 174263509Sdim #if defined(LLVM_ON_UNIX) 175263509Sdim file_status(file_type Type, perms Perms, dev_t Dev, ino_t Ino, time_t MTime, 176263509Sdim uid_t UID, gid_t GID, off_t Size) 177263509Sdim : fs_st_dev(Dev), fs_st_ino(Ino), fs_st_mtime(MTime), fs_st_uid(UID), 178263509Sdim fs_st_gid(GID), fs_st_size(Size), Type(Type), Perms(Perms) {} 179263509Sdim #elif defined(LLVM_ON_WIN32) 180263509Sdim file_status(file_type Type, uint32_t LastWriteTimeHigh, 181263509Sdim uint32_t LastWriteTimeLow, uint32_t VolumeSerialNumber, 182263509Sdim uint32_t FileSizeHigh, uint32_t FileSizeLow, 183263509Sdim uint32_t FileIndexHigh, uint32_t FileIndexLow) 184263509Sdim : LastWriteTimeHigh(LastWriteTimeHigh), 185263509Sdim LastWriteTimeLow(LastWriteTimeLow), 186263509Sdim VolumeSerialNumber(VolumeSerialNumber), FileSizeHigh(FileSizeHigh), 187263509Sdim FileSizeLow(FileSizeLow), FileIndexHigh(FileIndexHigh), 188263509Sdim FileIndexLow(FileIndexLow), Type(Type), Perms(perms_not_known) {} 189263509Sdim #endif 190263509Sdim 191245431Sdim // getters 192218885Sdim file_type type() const { return Type; } 193245431Sdim perms permissions() const { return Perms; } 194263509Sdim TimeValue getLastModificationTime() const; 195263509Sdim UniqueID getUniqueID() const; 196263509Sdim 197263509Sdim #if defined(LLVM_ON_UNIX) 198263509Sdim uint32_t getUser() const { return fs_st_uid; } 199263509Sdim uint32_t getGroup() const { return fs_st_gid; } 200263509Sdim uint64_t getSize() const { return fs_st_size; } 201263509Sdim #elif defined (LLVM_ON_WIN32) 202263509Sdim uint32_t getUser() const { 203263509Sdim return 9999; // Not applicable to Windows, so... 204263509Sdim } 205263509Sdim uint32_t getGroup() const { 206263509Sdim return 9999; // Not applicable to Windows, so... 207263509Sdim } 208263509Sdim uint64_t getSize() const { 209263509Sdim return (uint64_t(FileSizeHigh) << 32) + FileSizeLow; 210263509Sdim } 211263509Sdim #endif 212263509Sdim 213245431Sdim // setters 214218885Sdim void type(file_type v) { Type = v; } 215245431Sdim void permissions(perms p) { Perms = p; } 216218885Sdim}; 217218885Sdim 218235633Sdim/// file_magic - An "enum class" enumeration of file types based on magic (the first 219235633Sdim/// N bytes of the file). 220235633Sdimstruct file_magic { 221263509Sdim enum Impl { 222235633Sdim unknown = 0, ///< Unrecognized file 223235633Sdim bitcode, ///< Bitcode file 224235633Sdim archive, ///< ar style archive file 225235633Sdim elf_relocatable, ///< ELF Relocatable object file 226235633Sdim elf_executable, ///< ELF Executable image 227235633Sdim elf_shared_object, ///< ELF dynamically linked shared lib 228235633Sdim elf_core, ///< ELF core image 229235633Sdim macho_object, ///< Mach-O Object file 230235633Sdim macho_executable, ///< Mach-O Executable 231235633Sdim macho_fixed_virtual_memory_shared_lib, ///< Mach-O Shared Lib, FVM 232235633Sdim macho_core, ///< Mach-O Core File 233263509Sdim macho_preload_executable, ///< Mach-O Preloaded Executable 234235633Sdim macho_dynamically_linked_shared_lib, ///< Mach-O dynlinked shared lib 235235633Sdim macho_dynamic_linker, ///< The Mach-O dynamic linker 236235633Sdim macho_bundle, ///< Mach-O Bundle file 237235633Sdim macho_dynamically_linked_shared_lib_stub, ///< Mach-O Shared lib stub 238235633Sdim macho_dsym_companion, ///< Mach-O dSYM companion file 239263509Sdim macho_universal_binary, ///< Mach-O universal binary 240235633Sdim coff_object, ///< COFF object file 241263509Sdim coff_import_library, ///< COFF import library 242263509Sdim pecoff_executable, ///< PECOFF executable file 243263509Sdim windows_resource ///< Windows compiled resource file (.rc) 244235633Sdim }; 245235633Sdim 246235633Sdim bool is_object() const { 247263509Sdim return V == unknown ? false : true; 248235633Sdim } 249235633Sdim 250263509Sdim file_magic() : V(unknown) {} 251263509Sdim file_magic(Impl V) : V(V) {} 252263509Sdim operator Impl() const { return V; } 253235633Sdim 254235633Sdimprivate: 255263509Sdim Impl V; 256235633Sdim}; 257235633Sdim 258218885Sdim/// @} 259218885Sdim/// @name Physical Operators 260218885Sdim/// @{ 261218885Sdim 262218885Sdim/// @brief Make \a path an absolute path. 263218885Sdim/// 264218885Sdim/// Makes \a path absolute using the current directory if it is not already. An 265218885Sdim/// empty \a path will result in the current directory. 266218885Sdim/// 267218885Sdim/// /absolute/path => /absolute/path 268218885Sdim/// relative/../path => <current-directory>/relative/../path 269218885Sdim/// 270218885Sdim/// @param path A path that is modified to be an absolute path. 271218885Sdim/// @returns errc::success if \a path has been made absolute, otherwise a 272218885Sdim/// platform specific error_code. 273218885Sdimerror_code make_absolute(SmallVectorImpl<char> &path); 274218885Sdim 275218885Sdim/// @brief Create all the non-existent directories in path. 276218885Sdim/// 277218885Sdim/// @param path Directories to create. 278218885Sdim/// @param existed Set to true if \a path already existed, false otherwise. 279218885Sdim/// @returns errc::success if is_directory(path) and existed have been set, 280218885Sdim/// otherwise a platform specific error_code. 281218885Sdimerror_code create_directories(const Twine &path, bool &existed); 282218885Sdim 283263509Sdim/// @brief Convenience function for clients that don't need to know if the 284263509Sdim/// directory existed or not. 285263509Sdiminline error_code create_directories(const Twine &Path) { 286263509Sdim bool Existed; 287263509Sdim return create_directories(Path, Existed); 288263509Sdim} 289263509Sdim 290218885Sdim/// @brief Create the directory in path. 291218885Sdim/// 292218885Sdim/// @param path Directory to create. 293218885Sdim/// @param existed Set to true if \a path already existed, false otherwise. 294218885Sdim/// @returns errc::success if is_directory(path) and existed have been set, 295218885Sdim/// otherwise a platform specific error_code. 296218885Sdimerror_code create_directory(const Twine &path, bool &existed); 297218885Sdim 298263509Sdim/// @brief Convenience function for clients that don't need to know if the 299263509Sdim/// directory existed or not. 300263509Sdiminline error_code create_directory(const Twine &Path) { 301263509Sdim bool Existed; 302263509Sdim return create_directory(Path, Existed); 303263509Sdim} 304263509Sdim 305218885Sdim/// @brief Create a hard link from \a from to \a to. 306218885Sdim/// 307218885Sdim/// @param to The path to hard link to. 308218885Sdim/// @param from The path to hard link from. This is created. 309218885Sdim/// @returns errc::success if exists(to) && exists(from) && equivalent(to, from) 310218885Sdim/// , otherwise a platform specific error_code. 311218885Sdimerror_code create_hard_link(const Twine &to, const Twine &from); 312218885Sdim 313218885Sdim/// @brief Create a symbolic link from \a from to \a to. 314218885Sdim/// 315218885Sdim/// @param to The path to symbolically link to. 316218885Sdim/// @param from The path to symbolically link from. This is created. 317218885Sdim/// @returns errc::success if exists(to) && exists(from) && is_symlink(from), 318218885Sdim/// otherwise a platform specific error_code. 319218885Sdimerror_code create_symlink(const Twine &to, const Twine &from); 320218885Sdim 321218885Sdim/// @brief Get the current path. 322218885Sdim/// 323218885Sdim/// @param result Holds the current path on return. 324245431Sdim/// @returns errc::success if the current path has been stored in result, 325218885Sdim/// otherwise a platform specific error_code. 326218885Sdimerror_code current_path(SmallVectorImpl<char> &result); 327218885Sdim 328218885Sdim/// @brief Remove path. Equivalent to POSIX remove(). 329218885Sdim/// 330218885Sdim/// @param path Input path. 331218885Sdim/// @param existed Set to true if \a path existed, false if it did not. 332218885Sdim/// undefined otherwise. 333245431Sdim/// @returns errc::success if path has been removed and existed has been 334218885Sdim/// successfully set, otherwise a platform specific error_code. 335218885Sdimerror_code remove(const Twine &path, bool &existed); 336218885Sdim 337263509Sdim/// @brief Convenience function for clients that don't need to know if the file 338263509Sdim/// existed or not. 339263509Sdiminline error_code remove(const Twine &Path) { 340263509Sdim bool Existed; 341263509Sdim return remove(Path, Existed); 342263509Sdim} 343263509Sdim 344218885Sdim/// @brief Recursively remove all files below \a path, then \a path. Files are 345218885Sdim/// removed as if by POSIX remove(). 346218885Sdim/// 347218885Sdim/// @param path Input path. 348218885Sdim/// @param num_removed Number of files removed. 349245431Sdim/// @returns errc::success if path has been removed and num_removed has been 350218885Sdim/// successfully set, otherwise a platform specific error_code. 351218885Sdimerror_code remove_all(const Twine &path, uint32_t &num_removed); 352218885Sdim 353263509Sdim/// @brief Convenience function for clients that don't need to know how many 354263509Sdim/// files were removed. 355263509Sdiminline error_code remove_all(const Twine &Path) { 356263509Sdim uint32_t Removed; 357263509Sdim return remove_all(Path, Removed); 358263509Sdim} 359263509Sdim 360218885Sdim/// @brief Rename \a from to \a to. Files are renamed as if by POSIX rename(). 361218885Sdim/// 362218885Sdim/// @param from The path to rename from. 363218885Sdim/// @param to The path to rename to. This is created. 364218885Sdimerror_code rename(const Twine &from, const Twine &to); 365218885Sdim 366218885Sdim/// @brief Resize path to size. File is resized as if by POSIX truncate(). 367218885Sdim/// 368218885Sdim/// @param path Input path. 369218885Sdim/// @param size Size to resize to. 370218885Sdim/// @returns errc::success if \a path has been resized to \a size, otherwise a 371218885Sdim/// platform specific error_code. 372218885Sdimerror_code resize_file(const Twine &path, uint64_t size); 373218885Sdim 374218885Sdim/// @} 375218885Sdim/// @name Physical Observers 376218885Sdim/// @{ 377218885Sdim 378218885Sdim/// @brief Does file exist? 379218885Sdim/// 380218885Sdim/// @param status A file_status previously returned from stat. 381245431Sdim/// @returns True if the file represented by status exists, false if it does 382218885Sdim/// not. 383218885Sdimbool exists(file_status status); 384218885Sdim 385218885Sdim/// @brief Does file exist? 386218885Sdim/// 387218885Sdim/// @param path Input path. 388218885Sdim/// @param result Set to true if the file represented by status exists, false if 389218885Sdim/// it does not. Undefined otherwise. 390245431Sdim/// @returns errc::success if result has been successfully set, otherwise a 391218885Sdim/// platform specific error_code. 392218885Sdimerror_code exists(const Twine &path, bool &result); 393218885Sdim 394226890Sdim/// @brief Simpler version of exists for clients that don't need to 395226890Sdim/// differentiate between an error and false. 396226890Sdiminline bool exists(const Twine &path) { 397226890Sdim bool result; 398226890Sdim return !exists(path, result) && result; 399226890Sdim} 400226890Sdim 401263509Sdim/// @brief Can we execute this file? 402263509Sdim/// 403263509Sdim/// @param Path Input path. 404263509Sdim/// @returns True if we can execute it, false otherwise. 405263509Sdimbool can_execute(const Twine &Path); 406263509Sdim 407263509Sdim/// @brief Can we write this file? 408263509Sdim/// 409263509Sdim/// @param Path Input path. 410263509Sdim/// @returns True if we can write to it, false otherwise. 411263509Sdimbool can_write(const Twine &Path); 412263509Sdim 413218885Sdim/// @brief Do file_status's represent the same thing? 414218885Sdim/// 415218885Sdim/// @param A Input file_status. 416218885Sdim/// @param B Input file_status. 417218885Sdim/// 418218885Sdim/// assert(status_known(A) || status_known(B)); 419218885Sdim/// 420245431Sdim/// @returns True if A and B both represent the same file system entity, false 421218885Sdim/// otherwise. 422218885Sdimbool equivalent(file_status A, file_status B); 423218885Sdim 424218885Sdim/// @brief Do paths represent the same thing? 425218885Sdim/// 426235633Sdim/// assert(status_known(A) || status_known(B)); 427235633Sdim/// 428218885Sdim/// @param A Input path A. 429218885Sdim/// @param B Input path B. 430218885Sdim/// @param result Set to true if stat(A) and stat(B) have the same device and 431218885Sdim/// inode (or equivalent). 432245431Sdim/// @returns errc::success if result has been successfully set, otherwise a 433218885Sdim/// platform specific error_code. 434218885Sdimerror_code equivalent(const Twine &A, const Twine &B, bool &result); 435218885Sdim 436245431Sdim/// @brief Simpler version of equivalent for clients that don't need to 437245431Sdim/// differentiate between an error and false. 438245431Sdiminline bool equivalent(const Twine &A, const Twine &B) { 439245431Sdim bool result; 440245431Sdim return !equivalent(A, B, result) && result; 441245431Sdim} 442245431Sdim 443218885Sdim/// @brief Does status represent a directory? 444218885Sdim/// 445218885Sdim/// @param status A file_status previously returned from status. 446245431Sdim/// @returns status.type() == file_type::directory_file. 447218885Sdimbool is_directory(file_status status); 448218885Sdim 449218885Sdim/// @brief Is path a directory? 450218885Sdim/// 451218885Sdim/// @param path Input path. 452218885Sdim/// @param result Set to true if \a path is a directory, false if it is not. 453218885Sdim/// Undefined otherwise. 454245431Sdim/// @returns errc::success if result has been successfully set, otherwise a 455218885Sdim/// platform specific error_code. 456218885Sdimerror_code is_directory(const Twine &path, bool &result); 457218885Sdim 458263509Sdim/// @brief Simpler version of is_directory for clients that don't need to 459263509Sdim/// differentiate between an error and false. 460263509Sdiminline bool is_directory(const Twine &Path) { 461263509Sdim bool Result; 462263509Sdim return !is_directory(Path, Result) && Result; 463263509Sdim} 464263509Sdim 465218885Sdim/// @brief Does status represent a regular file? 466218885Sdim/// 467218885Sdim/// @param status A file_status previously returned from status. 468245431Sdim/// @returns status_known(status) && status.type() == file_type::regular_file. 469218885Sdimbool is_regular_file(file_status status); 470218885Sdim 471218885Sdim/// @brief Is path a regular file? 472218885Sdim/// 473218885Sdim/// @param path Input path. 474218885Sdim/// @param result Set to true if \a path is a regular file, false if it is not. 475218885Sdim/// Undefined otherwise. 476245431Sdim/// @returns errc::success if result has been successfully set, otherwise a 477218885Sdim/// platform specific error_code. 478218885Sdimerror_code is_regular_file(const Twine &path, bool &result); 479218885Sdim 480263509Sdim/// @brief Simpler version of is_regular_file for clients that don't need to 481263509Sdim/// differentiate between an error and false. 482263509Sdiminline bool is_regular_file(const Twine &Path) { 483263509Sdim bool Result; 484263509Sdim if (is_regular_file(Path, Result)) 485263509Sdim return false; 486263509Sdim return Result; 487263509Sdim} 488263509Sdim 489218885Sdim/// @brief Does this status represent something that exists but is not a 490218885Sdim/// directory, regular file, or symlink? 491218885Sdim/// 492218885Sdim/// @param status A file_status previously returned from status. 493245431Sdim/// @returns exists(s) && !is_regular_file(s) && !is_directory(s) && 494218885Sdim/// !is_symlink(s) 495218885Sdimbool is_other(file_status status); 496218885Sdim 497218885Sdim/// @brief Is path something that exists but is not a directory, 498218885Sdim/// regular file, or symlink? 499218885Sdim/// 500218885Sdim/// @param path Input path. 501218885Sdim/// @param result Set to true if \a path exists, but is not a directory, regular 502218885Sdim/// file, or a symlink, false if it does not. Undefined otherwise. 503245431Sdim/// @returns errc::success if result has been successfully set, otherwise a 504218885Sdim/// platform specific error_code. 505218885Sdimerror_code is_other(const Twine &path, bool &result); 506218885Sdim 507218885Sdim/// @brief Does status represent a symlink? 508218885Sdim/// 509218885Sdim/// @param status A file_status previously returned from stat. 510245431Sdim/// @returns status.type() == symlink_file. 511218885Sdimbool is_symlink(file_status status); 512218885Sdim 513218885Sdim/// @brief Is path a symlink? 514218885Sdim/// 515218885Sdim/// @param path Input path. 516218885Sdim/// @param result Set to true if \a path is a symlink, false if it is not. 517218885Sdim/// Undefined otherwise. 518245431Sdim/// @returns errc::success if result has been successfully set, otherwise a 519218885Sdim/// platform specific error_code. 520218885Sdimerror_code is_symlink(const Twine &path, bool &result); 521218885Sdim 522218885Sdim/// @brief Get file status as if by POSIX stat(). 523218885Sdim/// 524218885Sdim/// @param path Input path. 525218885Sdim/// @param result Set to the file status. 526245431Sdim/// @returns errc::success if result has been successfully set, otherwise a 527218885Sdim/// platform specific error_code. 528218885Sdimerror_code status(const Twine &path, file_status &result); 529218885Sdim 530263509Sdim/// @brief A version for when a file descriptor is already available. 531263509Sdimerror_code status(int FD, file_status &Result); 532263509Sdim 533263509Sdim/// @brief Get file size. 534245431Sdim/// 535263509Sdim/// @param Path Input path. 536263509Sdim/// @param Result Set to the size of the file in \a Path. 537263509Sdim/// @returns errc::success if result has been successfully set, otherwise a 538245431Sdim/// platform specific error_code. 539263509Sdiminline error_code file_size(const Twine &Path, uint64_t &Result) { 540263509Sdim file_status Status; 541263509Sdim error_code EC = status(Path, Status); 542263509Sdim if (EC) 543263509Sdim return EC; 544263509Sdim Result = Status.getSize(); 545263509Sdim return error_code::success(); 546263509Sdim} 547245431Sdim 548263509Sdimerror_code setLastModificationAndAccessTime(int FD, TimeValue Time); 549263509Sdim 550218885Sdim/// @brief Is status available? 551218885Sdim/// 552245431Sdim/// @param s Input file status. 553245431Sdim/// @returns True if status() != status_error. 554218885Sdimbool status_known(file_status s); 555218885Sdim 556218885Sdim/// @brief Is status available? 557218885Sdim/// 558218885Sdim/// @param path Input path. 559218885Sdim/// @param result Set to true if status() != status_error. 560245431Sdim/// @returns errc::success if result has been successfully set, otherwise a 561218885Sdim/// platform specific error_code. 562218885Sdimerror_code status_known(const Twine &path, bool &result); 563218885Sdim 564263509Sdim/// @brief Create a uniquely named file. 565218885Sdim/// 566218885Sdim/// Generates a unique path suitable for a temporary file and then opens it as a 567218885Sdim/// file. The name is based on \a model with '%' replaced by a random char in 568218885Sdim/// [0-9a-f]. If \a model is not an absolute path, a suitable temporary 569218885Sdim/// directory will be prepended. 570218885Sdim/// 571263509Sdim/// Example: clang-%%-%%-%%-%%-%%.s => clang-a0-b1-c2-d3-e4.s 572263509Sdim/// 573218885Sdim/// This is an atomic operation. Either the file is created and opened, or the 574218885Sdim/// file system is left untouched. 575218885Sdim/// 576263509Sdim/// The intendend use is for files that are to be kept, possibly after 577263509Sdim/// renaming them. For example, when running 'clang -c foo.o', the file can 578263509Sdim/// be first created as foo-abc123.o and then renamed. 579218885Sdim/// 580263509Sdim/// @param Model Name to base unique path off of. 581263509Sdim/// @param ResultFD Set to the opened file's file descriptor. 582263509Sdim/// @param ResultPath Set to the opened file's absolute path. 583263509Sdim/// @returns errc::success if Result{FD,Path} have been successfully set, 584218885Sdim/// otherwise a platform specific error_code. 585263509Sdimerror_code createUniqueFile(const Twine &Model, int &ResultFD, 586263509Sdim SmallVectorImpl<char> &ResultPath, 587263509Sdim unsigned Mode = all_read | all_write); 588218885Sdim 589263509Sdim/// @brief Simpler version for clients that don't want an open file. 590263509Sdimerror_code createUniqueFile(const Twine &Model, 591263509Sdim SmallVectorImpl<char> &ResultPath); 592263509Sdim 593263509Sdim/// @brief Create a file in the system temporary directory. 594218885Sdim/// 595263509Sdim/// The filename is of the form prefix-random_chars.suffix. Since the directory 596263509Sdim/// is not know to the caller, Prefix and Suffix cannot have path separators. 597263509Sdim/// The files are created with mode 0600. 598218885Sdim/// 599263509Sdim/// This should be used for things like a temporary .s that is removed after 600263509Sdim/// running the assembler. 601263509Sdimerror_code createTemporaryFile(const Twine &Prefix, StringRef Suffix, 602263509Sdim int &ResultFD, 603263509Sdim SmallVectorImpl<char> &ResultPath); 604218885Sdim 605263509Sdim/// @brief Simpler version for clients that don't want an open file. 606263509Sdimerror_code createTemporaryFile(const Twine &Prefix, StringRef Suffix, 607263509Sdim SmallVectorImpl<char> &ResultPath); 608263509Sdim 609263509Sdimerror_code createUniqueDirectory(const Twine &Prefix, 610263509Sdim SmallVectorImpl<char> &ResultPath); 611263509Sdim 612263509Sdimenum OpenFlags { 613263509Sdim F_None = 0, 614263509Sdim 615263509Sdim /// F_Excl - When opening a file, this flag makes raw_fd_ostream 616263509Sdim /// report an error if the file already exists. 617263509Sdim F_Excl = 1, 618263509Sdim 619263509Sdim /// F_Append - When opening a file, if it already exists append to the 620263509Sdim /// existing file instead of returning an error. This may not be specified 621263509Sdim /// with F_Excl. 622263509Sdim F_Append = 2, 623263509Sdim 624263509Sdim /// F_Binary - The file should be opened in binary mode on platforms that 625263509Sdim /// make this distinction. 626263509Sdim F_Binary = 4 627263509Sdim}; 628263509Sdim 629263509Sdiminline OpenFlags operator|(OpenFlags A, OpenFlags B) { 630263509Sdim return OpenFlags(unsigned(A) | unsigned(B)); 631263509Sdim} 632263509Sdim 633263509Sdiminline OpenFlags &operator|=(OpenFlags &A, OpenFlags B) { 634263509Sdim A = A | B; 635263509Sdim return A; 636263509Sdim} 637263509Sdim 638263509Sdimerror_code openFileForWrite(const Twine &Name, int &ResultFD, OpenFlags Flags, 639263509Sdim unsigned Mode = 0666); 640263509Sdim 641263509Sdimerror_code openFileForRead(const Twine &Name, int &ResultFD); 642263509Sdim 643218885Sdim/// @brief Are \a path's first bytes \a magic? 644218885Sdim/// 645218885Sdim/// @param path Input path. 646218885Sdim/// @param magic Byte sequence to compare \a path's first len(magic) bytes to. 647245431Sdim/// @returns errc::success if result has been successfully set, otherwise a 648218885Sdim/// platform specific error_code. 649218885Sdimerror_code has_magic(const Twine &path, const Twine &magic, bool &result); 650218885Sdim 651218885Sdim/// @brief Get \a path's first \a len bytes. 652218885Sdim/// 653218885Sdim/// @param path Input path. 654218885Sdim/// @param len Number of magic bytes to get. 655218885Sdim/// @param result Set to the first \a len bytes in the file pointed to by 656218885Sdim/// \a path. Or the entire file if file_size(path) < len, in which 657218885Sdim/// case result.size() returns the size of the file. 658245431Sdim/// @returns errc::success if result has been successfully set, 659218885Sdim/// errc::value_too_large if len is larger then the file pointed to by 660218885Sdim/// \a path, otherwise a platform specific error_code. 661218885Sdimerror_code get_magic(const Twine &path, uint32_t len, 662218885Sdim SmallVectorImpl<char> &result); 663218885Sdim 664235633Sdim/// @brief Identify the type of a binary file based on how magical it is. 665235633Sdimfile_magic identify_magic(StringRef magic); 666235633Sdim 667218885Sdim/// @brief Get and identify \a path's type based on its content. 668218885Sdim/// 669218885Sdim/// @param path Input path. 670263509Sdim/// @param result Set to the type of file, or file_magic::unknown. 671245431Sdim/// @returns errc::success if result has been successfully set, otherwise a 672218885Sdim/// platform specific error_code. 673235633Sdimerror_code identify_magic(const Twine &path, file_magic &result); 674218885Sdim 675263509Sdimerror_code getUniqueID(const Twine Path, UniqueID &Result); 676218885Sdim 677245431Sdim/// This class represents a memory mapped file. It is based on 678245431Sdim/// boost::iostreams::mapped_file. 679245431Sdimclass mapped_file_region { 680245431Sdim mapped_file_region() LLVM_DELETED_FUNCTION; 681245431Sdim mapped_file_region(mapped_file_region&) LLVM_DELETED_FUNCTION; 682245431Sdim mapped_file_region &operator =(mapped_file_region&) LLVM_DELETED_FUNCTION; 683245431Sdim 684245431Sdimpublic: 685245431Sdim enum mapmode { 686245431Sdim readonly, ///< May only access map via const_data as read only. 687245431Sdim readwrite, ///< May access map via data and modify it. Written to path. 688245431Sdim priv ///< May modify via data, but changes are lost on destruction. 689245431Sdim }; 690245431Sdim 691245431Sdimprivate: 692245431Sdim /// Platform specific mapping state. 693245431Sdim mapmode Mode; 694245431Sdim uint64_t Size; 695245431Sdim void *Mapping; 696245431Sdim#ifdef LLVM_ON_WIN32 697245431Sdim int FileDescriptor; 698245431Sdim void *FileHandle; 699245431Sdim void *FileMappingHandle; 700245431Sdim#endif 701245431Sdim 702252723Sdim error_code init(int FD, bool CloseFD, uint64_t Offset); 703245431Sdim 704245431Sdimpublic: 705245431Sdim typedef char char_type; 706245431Sdim 707252723Sdim#if LLVM_HAS_RVALUE_REFERENCES 708245431Sdim mapped_file_region(mapped_file_region&&); 709245431Sdim mapped_file_region &operator =(mapped_file_region&&); 710245431Sdim#endif 711245431Sdim 712245431Sdim /// Construct a mapped_file_region at \a path starting at \a offset of length 713245431Sdim /// \a length and with access \a mode. 714245431Sdim /// 715245431Sdim /// \param path Path to the file to map. If it does not exist it will be 716245431Sdim /// created. 717245431Sdim /// \param mode How to map the memory. 718245431Sdim /// \param length Number of bytes to map in starting at \a offset. If the file 719245431Sdim /// is shorter than this, it will be extended. If \a length is 720245431Sdim /// 0, the entire file will be mapped. 721245431Sdim /// \param offset Byte offset from the beginning of the file where the map 722245431Sdim /// should begin. Must be a multiple of 723245431Sdim /// mapped_file_region::alignment(). 724245431Sdim /// \param ec This is set to errc::success if the map was constructed 725263509Sdim /// successfully. Otherwise it is set to a platform dependent error. 726245431Sdim mapped_file_region(const Twine &path, 727245431Sdim mapmode mode, 728245431Sdim uint64_t length, 729245431Sdim uint64_t offset, 730245431Sdim error_code &ec); 731245431Sdim 732245431Sdim /// \param fd An open file descriptor to map. mapped_file_region takes 733252723Sdim /// ownership if closefd is true. It must have been opended in the correct 734252723Sdim /// mode. 735245431Sdim mapped_file_region(int fd, 736252723Sdim bool closefd, 737245431Sdim mapmode mode, 738245431Sdim uint64_t length, 739245431Sdim uint64_t offset, 740245431Sdim error_code &ec); 741245431Sdim 742245431Sdim ~mapped_file_region(); 743245431Sdim 744245431Sdim mapmode flags() const; 745245431Sdim uint64_t size() const; 746245431Sdim char *data() const; 747245431Sdim 748245431Sdim /// Get a const view of the data. Modifying this memory has undefined 749263509Sdim /// behavior. 750245431Sdim const char *const_data() const; 751245431Sdim 752245431Sdim /// \returns The minimum alignment offset must be. 753245431Sdim static int alignment(); 754245431Sdim}; 755245431Sdim 756245431Sdim/// @brief Memory maps the contents of a file 757245431Sdim/// 758245431Sdim/// @param path Path to file to map. 759245431Sdim/// @param file_offset Byte offset in file where mapping should begin. 760245431Sdim/// @param size Byte length of range of the file to map. 761245431Sdim/// @param map_writable If true, the file will be mapped in r/w such 762245431Sdim/// that changes to the mapped buffer will be flushed back 763245431Sdim/// to the file. If false, the file will be mapped read-only 764245431Sdim/// and the buffer will be read-only. 765245431Sdim/// @param result Set to the start address of the mapped buffer. 766245431Sdim/// @returns errc::success if result has been successfully set, otherwise a 767245431Sdim/// platform specific error_code. 768245431Sdimerror_code map_file_pages(const Twine &path, off_t file_offset, size_t size, 769245431Sdim bool map_writable, void *&result); 770245431Sdim 771245431Sdim 772245431Sdim/// @brief Memory unmaps the contents of a file 773245431Sdim/// 774245431Sdim/// @param base Pointer to the start of the buffer. 775245431Sdim/// @param size Byte length of the range to unmmap. 776245431Sdim/// @returns errc::success if result has been successfully set, otherwise a 777245431Sdim/// platform specific error_code. 778245431Sdimerror_code unmap_file_pages(void *base, size_t size); 779245431Sdim 780263509Sdim/// Return the path to the main executable, given the value of argv[0] from 781263509Sdim/// program startup and the address of main itself. In extremis, this function 782263509Sdim/// may fail and return an empty path. 783263509Sdimstd::string getMainExecutable(const char *argv0, void *MainExecAddr); 784245431Sdim 785218885Sdim/// @} 786218885Sdim/// @name Iterators 787218885Sdim/// @{ 788218885Sdim 789218885Sdim/// directory_entry - A single entry in a directory. Caches the status either 790226890Sdim/// from the result of the iteration syscall, or the first time status is 791226890Sdim/// called. 792218885Sdimclass directory_entry { 793218885Sdim std::string Path; 794218885Sdim mutable file_status Status; 795218885Sdim 796218885Sdimpublic: 797226890Sdim explicit directory_entry(const Twine &path, file_status st = file_status()) 798218885Sdim : Path(path.str()) 799226890Sdim , Status(st) {} 800218885Sdim 801218885Sdim directory_entry() {} 802218885Sdim 803226890Sdim void assign(const Twine &path, file_status st = file_status()) { 804218885Sdim Path = path.str(); 805218885Sdim Status = st; 806218885Sdim } 807218885Sdim 808226890Sdim void replace_filename(const Twine &filename, file_status st = file_status()); 809218885Sdim 810221345Sdim const std::string &path() const { return Path; } 811218885Sdim error_code status(file_status &result) const; 812218885Sdim 813218885Sdim bool operator==(const directory_entry& rhs) const { return Path == rhs.Path; } 814218885Sdim bool operator!=(const directory_entry& rhs) const { return !(*this == rhs); } 815218885Sdim bool operator< (const directory_entry& rhs) const; 816218885Sdim bool operator<=(const directory_entry& rhs) const; 817218885Sdim bool operator> (const directory_entry& rhs) const; 818218885Sdim bool operator>=(const directory_entry& rhs) const; 819218885Sdim}; 820218885Sdim 821235633Sdimnamespace detail { 822235633Sdim struct DirIterState; 823235633Sdim 824235633Sdim error_code directory_iterator_construct(DirIterState&, StringRef); 825235633Sdim error_code directory_iterator_increment(DirIterState&); 826235633Sdim error_code directory_iterator_destruct(DirIterState&); 827235633Sdim 828235633Sdim /// DirIterState - Keeps state for the directory_iterator. It is reference 829235633Sdim /// counted in order to preserve InputIterator semantics on copy. 830235633Sdim struct DirIterState : public RefCountedBase<DirIterState> { 831235633Sdim DirIterState() 832235633Sdim : IterationHandle(0) {} 833235633Sdim 834235633Sdim ~DirIterState() { 835235633Sdim directory_iterator_destruct(*this); 836235633Sdim } 837235633Sdim 838235633Sdim intptr_t IterationHandle; 839235633Sdim directory_entry CurrentEntry; 840235633Sdim }; 841235633Sdim} 842235633Sdim 843218885Sdim/// directory_iterator - Iterates through the entries in path. There is no 844218885Sdim/// operator++ because we need an error_code. If it's really needed we can make 845218885Sdim/// it call report_fatal_error on error. 846218885Sdimclass directory_iterator { 847235633Sdim IntrusiveRefCntPtr<detail::DirIterState> State; 848218885Sdim 849218885Sdimpublic: 850235633Sdim explicit directory_iterator(const Twine &path, error_code &ec) { 851235633Sdim State = new detail::DirIterState; 852218885Sdim SmallString<128> path_storage; 853235633Sdim ec = detail::directory_iterator_construct(*State, 854235633Sdim path.toStringRef(path_storage)); 855218885Sdim } 856218885Sdim 857235633Sdim explicit directory_iterator(const directory_entry &de, error_code &ec) { 858235633Sdim State = new detail::DirIterState; 859235633Sdim ec = detail::directory_iterator_construct(*State, de.path()); 860235633Sdim } 861235633Sdim 862218885Sdim /// Construct end iterator. 863263509Sdim directory_iterator() : State(0) {} 864218885Sdim 865218885Sdim // No operator++ because we need error_code. 866218885Sdim directory_iterator &increment(error_code &ec) { 867235633Sdim ec = directory_iterator_increment(*State); 868218885Sdim return *this; 869218885Sdim } 870218885Sdim 871235633Sdim const directory_entry &operator*() const { return State->CurrentEntry; } 872235633Sdim const directory_entry *operator->() const { return &State->CurrentEntry; } 873218885Sdim 874235633Sdim bool operator==(const directory_iterator &RHS) const { 875263509Sdim if (State == RHS.State) 876263509Sdim return true; 877263509Sdim if (RHS.State == 0) 878263509Sdim return State->CurrentEntry == directory_entry(); 879263509Sdim if (State == 0) 880263509Sdim return RHS.State->CurrentEntry == directory_entry(); 881235633Sdim return State->CurrentEntry == RHS.State->CurrentEntry; 882235633Sdim } 883235633Sdim 884218885Sdim bool operator!=(const directory_iterator &RHS) const { 885235633Sdim return !(*this == RHS); 886218885Sdim } 887218885Sdim // Other members as required by 888218885Sdim // C++ Std, 24.1.1 Input iterators [input.iterators] 889218885Sdim}; 890218885Sdim 891235633Sdimnamespace detail { 892235633Sdim /// RecDirIterState - Keeps state for the recursive_directory_iterator. It is 893235633Sdim /// reference counted in order to preserve InputIterator semantics on copy. 894235633Sdim struct RecDirIterState : public RefCountedBase<RecDirIterState> { 895235633Sdim RecDirIterState() 896235633Sdim : Level(0) 897235633Sdim , HasNoPushRequest(false) {} 898235633Sdim 899235633Sdim std::stack<directory_iterator, std::vector<directory_iterator> > Stack; 900235633Sdim uint16_t Level; 901235633Sdim bool HasNoPushRequest; 902235633Sdim }; 903235633Sdim} 904235633Sdim 905218885Sdim/// recursive_directory_iterator - Same as directory_iterator except for it 906218885Sdim/// recurses down into child directories. 907218885Sdimclass recursive_directory_iterator { 908235633Sdim IntrusiveRefCntPtr<detail::RecDirIterState> State; 909218885Sdim 910218885Sdimpublic: 911235633Sdim recursive_directory_iterator() {} 912235633Sdim explicit recursive_directory_iterator(const Twine &path, error_code &ec) 913235633Sdim : State(new detail::RecDirIterState) { 914235633Sdim State->Stack.push(directory_iterator(path, ec)); 915235633Sdim if (State->Stack.top() == directory_iterator()) 916235633Sdim State.reset(); 917235633Sdim } 918218885Sdim // No operator++ because we need error_code. 919235633Sdim recursive_directory_iterator &increment(error_code &ec) { 920263509Sdim const directory_iterator end_itr; 921218885Sdim 922235633Sdim if (State->HasNoPushRequest) 923235633Sdim State->HasNoPushRequest = false; 924235633Sdim else { 925235633Sdim file_status st; 926235633Sdim if ((ec = State->Stack.top()->status(st))) return *this; 927235633Sdim if (is_directory(st)) { 928235633Sdim State->Stack.push(directory_iterator(*State->Stack.top(), ec)); 929235633Sdim if (ec) return *this; 930235633Sdim if (State->Stack.top() != end_itr) { 931235633Sdim ++State->Level; 932235633Sdim return *this; 933235633Sdim } 934235633Sdim State->Stack.pop(); 935235633Sdim } 936235633Sdim } 937218885Sdim 938235633Sdim while (!State->Stack.empty() 939235633Sdim && State->Stack.top().increment(ec) == end_itr) { 940235633Sdim State->Stack.pop(); 941235633Sdim --State->Level; 942235633Sdim } 943235633Sdim 944235633Sdim // Check if we are done. If so, create an end iterator. 945235633Sdim if (State->Stack.empty()) 946235633Sdim State.reset(); 947235633Sdim 948235633Sdim return *this; 949235633Sdim } 950235633Sdim 951235633Sdim const directory_entry &operator*() const { return *State->Stack.top(); } 952235633Sdim const directory_entry *operator->() const { return &*State->Stack.top(); } 953235633Sdim 954218885Sdim // observers 955235633Sdim /// Gets the current level. Starting path is at level 0. 956235633Sdim int level() const { return State->Level; } 957235633Sdim 958218885Sdim /// Returns true if no_push has been called for this directory_entry. 959235633Sdim bool no_push_request() const { return State->HasNoPushRequest; } 960218885Sdim 961218885Sdim // modifiers 962218885Sdim /// Goes up one level if Level > 0. 963235633Sdim void pop() { 964263509Sdim assert(State && "Cannot pop an end iterator!"); 965235633Sdim assert(State->Level > 0 && "Cannot pop an iterator with level < 1"); 966235633Sdim 967263509Sdim const directory_iterator end_itr; 968235633Sdim error_code ec; 969235633Sdim do { 970235633Sdim if (ec) 971235633Sdim report_fatal_error("Error incrementing directory iterator."); 972235633Sdim State->Stack.pop(); 973235633Sdim --State->Level; 974235633Sdim } while (!State->Stack.empty() 975235633Sdim && State->Stack.top().increment(ec) == end_itr); 976235633Sdim 977235633Sdim // Check if we are done. If so, create an end iterator. 978235633Sdim if (State->Stack.empty()) 979235633Sdim State.reset(); 980235633Sdim } 981235633Sdim 982218885Sdim /// Does not go down into the current directory_entry. 983235633Sdim void no_push() { State->HasNoPushRequest = true; } 984218885Sdim 985235633Sdim bool operator==(const recursive_directory_iterator &RHS) const { 986235633Sdim return State == RHS.State; 987235633Sdim } 988235633Sdim 989235633Sdim bool operator!=(const recursive_directory_iterator &RHS) const { 990235633Sdim return !(*this == RHS); 991235633Sdim } 992218885Sdim // Other members as required by 993218885Sdim // C++ Std, 24.1.1 Input iterators [input.iterators] 994218885Sdim}; 995218885Sdim 996218885Sdim/// @} 997218885Sdim 998218885Sdim} // end namespace fs 999218885Sdim} // end namespace sys 1000218885Sdim} // end namespace llvm 1001218885Sdim 1002218885Sdim#endif 1003