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 27249423Sdim#ifndef LLVM_SUPPORT_FILESYSTEM_H 28249423Sdim#define LLVM_SUPPORT_FILESYSTEM_H 29218885Sdim 30234353Sdim#include "llvm/ADT/IntrusiveRefCntPtr.h" 31239462Sdim#include "llvm/ADT/OwningPtr.h" 32218885Sdim#include "llvm/ADT/SmallString.h" 33218885Sdim#include "llvm/ADT/Twine.h" 34218885Sdim#include "llvm/Support/DataTypes.h" 35234353Sdim#include "llvm/Support/ErrorHandling.h" 36263508Sdim#include "llvm/Support/TimeValue.h" 37218885Sdim#include "llvm/Support/system_error.h" 38218885Sdim#include <ctime> 39218885Sdim#include <iterator> 40234353Sdim#include <stack> 41218885Sdim#include <string> 42234353Sdim#include <vector> 43218885Sdim 44243830Sdim#ifdef HAVE_SYS_STAT_H 45234353Sdim#include <sys/stat.h> 46234353Sdim#endif 47234353Sdim 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 83239462Sdimenum perms { 84263508Sdim no_perms = 0, 85263508Sdim owner_read = 0400, 86263508Sdim owner_write = 0200, 87263508Sdim owner_exe = 0100, 88263508Sdim owner_all = owner_read | owner_write | owner_exe, 89263508Sdim group_read = 040, 90263508Sdim group_write = 020, 91263508Sdim group_exe = 010, 92263508Sdim group_all = group_read | group_write | group_exe, 93263508Sdim others_read = 04, 94263508Sdim others_write = 02, 95263508Sdim others_exe = 01, 96263508Sdim others_all = others_read | others_write | others_exe, 97263508Sdim all_read = owner_read | group_read | others_read, 98263508Sdim all_write = owner_write | group_write | others_write, 99263508Sdim all_exe = owner_exe | group_exe | others_exe, 100263508Sdim all_all = owner_all | group_all | others_all, 101263508Sdim set_uid_on_exe = 04000, 102263508Sdim set_gid_on_exe = 02000, 103263508Sdim sticky_bit = 01000, 104263508Sdim perms_not_known = 0xFFFF 105239462Sdim}; 106239462Sdim 107239462Sdim// Helper functions so that you can use & and | to manipulate perms bits: 108239462Sdiminline perms operator|(perms l , perms r) { 109239462Sdim return static_cast<perms>( 110239462Sdim static_cast<unsigned short>(l) | static_cast<unsigned short>(r)); 111239462Sdim} 112239462Sdiminline perms operator&(perms l , perms r) { 113239462Sdim return static_cast<perms>( 114239462Sdim static_cast<unsigned short>(l) & static_cast<unsigned short>(r)); 115239462Sdim} 116239462Sdiminline perms &operator|=(perms &l, perms r) { 117239462Sdim l = l | r; 118239462Sdim return l; 119239462Sdim} 120239462Sdiminline perms &operator&=(perms &l, perms r) { 121239462Sdim l = l & r; 122239462Sdim return l; 123239462Sdim} 124239462Sdiminline perms operator~(perms x) { 125239462Sdim return static_cast<perms>(~static_cast<unsigned short>(x)); 126239462Sdim} 127239462Sdim 128263508Sdimclass UniqueID { 129263508Sdim uint64_t Device; 130263508Sdim uint64_t File; 131239462Sdim 132263508Sdimpublic: 133263508Sdim UniqueID() {} 134263508Sdim UniqueID(uint64_t Device, uint64_t File) : Device(Device), File(File) {} 135263508Sdim bool operator==(const UniqueID &Other) const { 136263508Sdim return Device == Other.Device && File == Other.File; 137263508Sdim } 138263508Sdim bool operator!=(const UniqueID &Other) const { return !(*this == Other); } 139263508Sdim bool operator<(const UniqueID &Other) const { 140263508Sdim return Device < Other.Device || 141263508Sdim (Device == Other.Device && File < Other.File); 142263508Sdim } 143263508Sdim uint64_t getDevice() const { return Device; } 144263508Sdim uint64_t getFile() const { return File; } 145263508Sdim}; 146263508Sdim 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{ 151234353Sdim #if defined(LLVM_ON_UNIX) 152239462Sdim dev_t fs_st_dev; 153239462Sdim ino_t fs_st_ino; 154263508Sdim time_t fs_st_mtime; 155263508Sdim uid_t fs_st_uid; 156263508Sdim gid_t fs_st_gid; 157263508Sdim off_t fs_st_size; 158234353Sdim #elif defined (LLVM_ON_WIN32) 159234353Sdim uint32_t LastWriteTimeHigh; 160234353Sdim uint32_t LastWriteTimeLow; 161234353Sdim uint32_t VolumeSerialNumber; 162234353Sdim uint32_t FileSizeHigh; 163234353Sdim uint32_t FileSizeLow; 164234353Sdim uint32_t FileIndexHigh; 165234353Sdim uint32_t FileIndexLow; 166234353Sdim #endif 167234353Sdim friend bool equivalent(file_status A, file_status B); 168218885Sdim file_type Type; 169239462Sdim perms Perms; 170218885Sdimpublic: 171263508Sdim file_status() : Type(file_type::status_error) {} 172263508Sdim file_status(file_type Type) : Type(Type) {} 173218885Sdim 174263508Sdim #if defined(LLVM_ON_UNIX) 175263508Sdim file_status(file_type Type, perms Perms, dev_t Dev, ino_t Ino, time_t MTime, 176263508Sdim uid_t UID, gid_t GID, off_t Size) 177263508Sdim : fs_st_dev(Dev), fs_st_ino(Ino), fs_st_mtime(MTime), fs_st_uid(UID), 178263508Sdim fs_st_gid(GID), fs_st_size(Size), Type(Type), Perms(Perms) {} 179263508Sdim #elif defined(LLVM_ON_WIN32) 180263508Sdim file_status(file_type Type, uint32_t LastWriteTimeHigh, 181263508Sdim uint32_t LastWriteTimeLow, uint32_t VolumeSerialNumber, 182263508Sdim uint32_t FileSizeHigh, uint32_t FileSizeLow, 183263508Sdim uint32_t FileIndexHigh, uint32_t FileIndexLow) 184263508Sdim : LastWriteTimeHigh(LastWriteTimeHigh), 185263508Sdim LastWriteTimeLow(LastWriteTimeLow), 186263508Sdim VolumeSerialNumber(VolumeSerialNumber), FileSizeHigh(FileSizeHigh), 187263508Sdim FileSizeLow(FileSizeLow), FileIndexHigh(FileIndexHigh), 188263508Sdim FileIndexLow(FileIndexLow), Type(Type), Perms(perms_not_known) {} 189263508Sdim #endif 190263508Sdim 191239462Sdim // getters 192218885Sdim file_type type() const { return Type; } 193239462Sdim perms permissions() const { return Perms; } 194263508Sdim TimeValue getLastModificationTime() const; 195263508Sdim UniqueID getUniqueID() const; 196263508Sdim 197263508Sdim #if defined(LLVM_ON_UNIX) 198263508Sdim uint32_t getUser() const { return fs_st_uid; } 199263508Sdim uint32_t getGroup() const { return fs_st_gid; } 200263508Sdim uint64_t getSize() const { return fs_st_size; } 201263508Sdim #elif defined (LLVM_ON_WIN32) 202263508Sdim uint32_t getUser() const { 203263508Sdim return 9999; // Not applicable to Windows, so... 204263508Sdim } 205263508Sdim uint32_t getGroup() const { 206263508Sdim return 9999; // Not applicable to Windows, so... 207263508Sdim } 208263508Sdim uint64_t getSize() const { 209263508Sdim return (uint64_t(FileSizeHigh) << 32) + FileSizeLow; 210263508Sdim } 211263508Sdim #endif 212263508Sdim 213239462Sdim // setters 214218885Sdim void type(file_type v) { Type = v; } 215239462Sdim void permissions(perms p) { Perms = p; } 216218885Sdim}; 217218885Sdim 218234353Sdim/// file_magic - An "enum class" enumeration of file types based on magic (the first 219234353Sdim/// N bytes of the file). 220234353Sdimstruct file_magic { 221263508Sdim enum Impl { 222234353Sdim unknown = 0, ///< Unrecognized file 223234353Sdim bitcode, ///< Bitcode file 224234353Sdim archive, ///< ar style archive file 225234353Sdim elf_relocatable, ///< ELF Relocatable object file 226234353Sdim elf_executable, ///< ELF Executable image 227234353Sdim elf_shared_object, ///< ELF dynamically linked shared lib 228234353Sdim elf_core, ///< ELF core image 229234353Sdim macho_object, ///< Mach-O Object file 230234353Sdim macho_executable, ///< Mach-O Executable 231234353Sdim macho_fixed_virtual_memory_shared_lib, ///< Mach-O Shared Lib, FVM 232234353Sdim macho_core, ///< Mach-O Core File 233263508Sdim macho_preload_executable, ///< Mach-O Preloaded Executable 234234353Sdim macho_dynamically_linked_shared_lib, ///< Mach-O dynlinked shared lib 235234353Sdim macho_dynamic_linker, ///< The Mach-O dynamic linker 236234353Sdim macho_bundle, ///< Mach-O Bundle file 237234353Sdim macho_dynamically_linked_shared_lib_stub, ///< Mach-O Shared lib stub 238234353Sdim macho_dsym_companion, ///< Mach-O dSYM companion file 239263508Sdim macho_universal_binary, ///< Mach-O universal binary 240234353Sdim coff_object, ///< COFF object file 241263508Sdim coff_import_library, ///< COFF import library 242263508Sdim pecoff_executable, ///< PECOFF executable file 243263508Sdim windows_resource ///< Windows compiled resource file (.rc) 244234353Sdim }; 245234353Sdim 246234353Sdim bool is_object() const { 247263508Sdim return V == unknown ? false : true; 248234353Sdim } 249234353Sdim 250263508Sdim file_magic() : V(unknown) {} 251263508Sdim file_magic(Impl V) : V(V) {} 252263508Sdim operator Impl() const { return V; } 253234353Sdim 254234353Sdimprivate: 255263508Sdim Impl V; 256234353Sdim}; 257234353Sdim 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 283263508Sdim/// @brief Convenience function for clients that don't need to know if the 284263508Sdim/// directory existed or not. 285263508Sdiminline error_code create_directories(const Twine &Path) { 286263508Sdim bool Existed; 287263508Sdim return create_directories(Path, Existed); 288263508Sdim} 289263508Sdim 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 298263508Sdim/// @brief Convenience function for clients that don't need to know if the 299263508Sdim/// directory existed or not. 300263508Sdiminline error_code create_directory(const Twine &Path) { 301263508Sdim bool Existed; 302263508Sdim return create_directory(Path, Existed); 303263508Sdim} 304263508Sdim 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. 324243830Sdim/// @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. 333243830Sdim/// @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 337263508Sdim/// @brief Convenience function for clients that don't need to know if the file 338263508Sdim/// existed or not. 339263508Sdiminline error_code remove(const Twine &Path) { 340263508Sdim bool Existed; 341263508Sdim return remove(Path, Existed); 342263508Sdim} 343263508Sdim 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. 349243830Sdim/// @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 353263508Sdim/// @brief Convenience function for clients that don't need to know how many 354263508Sdim/// files were removed. 355263508Sdiminline error_code remove_all(const Twine &Path) { 356263508Sdim uint32_t Removed; 357263508Sdim return remove_all(Path, Removed); 358263508Sdim} 359263508Sdim 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. 381243830Sdim/// @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. 390243830Sdim/// @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 394226633Sdim/// @brief Simpler version of exists for clients that don't need to 395226633Sdim/// differentiate between an error and false. 396226633Sdiminline bool exists(const Twine &path) { 397226633Sdim bool result; 398226633Sdim return !exists(path, result) && result; 399226633Sdim} 400226633Sdim 401263508Sdim/// @brief Can we execute this file? 402263508Sdim/// 403263508Sdim/// @param Path Input path. 404263508Sdim/// @returns True if we can execute it, false otherwise. 405263508Sdimbool can_execute(const Twine &Path); 406263508Sdim 407263508Sdim/// @brief Can we write this file? 408263508Sdim/// 409263508Sdim/// @param Path Input path. 410263508Sdim/// @returns True if we can write to it, false otherwise. 411263508Sdimbool can_write(const Twine &Path); 412263508Sdim 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/// 420243830Sdim/// @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/// 426234353Sdim/// assert(status_known(A) || status_known(B)); 427234353Sdim/// 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). 432243830Sdim/// @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 436239462Sdim/// @brief Simpler version of equivalent for clients that don't need to 437239462Sdim/// differentiate between an error and false. 438239462Sdiminline bool equivalent(const Twine &A, const Twine &B) { 439239462Sdim bool result; 440239462Sdim return !equivalent(A, B, result) && result; 441239462Sdim} 442239462Sdim 443218885Sdim/// @brief Does status represent a directory? 444218885Sdim/// 445218885Sdim/// @param status A file_status previously returned from status. 446243830Sdim/// @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. 454243830Sdim/// @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 458263508Sdim/// @brief Simpler version of is_directory for clients that don't need to 459263508Sdim/// differentiate between an error and false. 460263508Sdiminline bool is_directory(const Twine &Path) { 461263508Sdim bool Result; 462263508Sdim return !is_directory(Path, Result) && Result; 463263508Sdim} 464263508Sdim 465218885Sdim/// @brief Does status represent a regular file? 466218885Sdim/// 467218885Sdim/// @param status A file_status previously returned from status. 468243830Sdim/// @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. 476243830Sdim/// @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 480263508Sdim/// @brief Simpler version of is_regular_file for clients that don't need to 481263508Sdim/// differentiate between an error and false. 482263508Sdiminline bool is_regular_file(const Twine &Path) { 483263508Sdim bool Result; 484263508Sdim if (is_regular_file(Path, Result)) 485263508Sdim return false; 486263508Sdim return Result; 487263508Sdim} 488263508Sdim 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. 493243830Sdim/// @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. 503243830Sdim/// @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. 510243830Sdim/// @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. 518243830Sdim/// @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. 526243830Sdim/// @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 530263508Sdim/// @brief A version for when a file descriptor is already available. 531263508Sdimerror_code status(int FD, file_status &Result); 532263508Sdim 533263508Sdim/// @brief Get file size. 534239462Sdim/// 535263508Sdim/// @param Path Input path. 536263508Sdim/// @param Result Set to the size of the file in \a Path. 537263508Sdim/// @returns errc::success if result has been successfully set, otherwise a 538239462Sdim/// platform specific error_code. 539263508Sdiminline error_code file_size(const Twine &Path, uint64_t &Result) { 540263508Sdim file_status Status; 541263508Sdim error_code EC = status(Path, Status); 542263508Sdim if (EC) 543263508Sdim return EC; 544263508Sdim Result = Status.getSize(); 545263508Sdim return error_code::success(); 546263508Sdim} 547239462Sdim 548263508Sdimerror_code setLastModificationAndAccessTime(int FD, TimeValue Time); 549263508Sdim 550218885Sdim/// @brief Is status available? 551218885Sdim/// 552243830Sdim/// @param s Input file status. 553243830Sdim/// @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. 560243830Sdim/// @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 564263508Sdim/// @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/// 571263508Sdim/// Example: clang-%%-%%-%%-%%-%%.s => clang-a0-b1-c2-d3-e4.s 572263508Sdim/// 573218885Sdim/// This is an atomic operation. Either the file is created and opened, or the 574218885Sdim/// file system is left untouched. 575218885Sdim/// 576263508Sdim/// The intendend use is for files that are to be kept, possibly after 577263508Sdim/// renaming them. For example, when running 'clang -c foo.o', the file can 578263508Sdim/// be first created as foo-abc123.o and then renamed. 579218885Sdim/// 580263508Sdim/// @param Model Name to base unique path off of. 581263508Sdim/// @param ResultFD Set to the opened file's file descriptor. 582263508Sdim/// @param ResultPath Set to the opened file's absolute path. 583263508Sdim/// @returns errc::success if Result{FD,Path} have been successfully set, 584218885Sdim/// otherwise a platform specific error_code. 585263508Sdimerror_code createUniqueFile(const Twine &Model, int &ResultFD, 586263508Sdim SmallVectorImpl<char> &ResultPath, 587263508Sdim unsigned Mode = all_read | all_write); 588218885Sdim 589263508Sdim/// @brief Simpler version for clients that don't want an open file. 590263508Sdimerror_code createUniqueFile(const Twine &Model, 591263508Sdim SmallVectorImpl<char> &ResultPath); 592263508Sdim 593263508Sdim/// @brief Create a file in the system temporary directory. 594218885Sdim/// 595263508Sdim/// The filename is of the form prefix-random_chars.suffix. Since the directory 596263508Sdim/// is not know to the caller, Prefix and Suffix cannot have path separators. 597263508Sdim/// The files are created with mode 0600. 598218885Sdim/// 599263508Sdim/// This should be used for things like a temporary .s that is removed after 600263508Sdim/// running the assembler. 601263508Sdimerror_code createTemporaryFile(const Twine &Prefix, StringRef Suffix, 602263508Sdim int &ResultFD, 603263508Sdim SmallVectorImpl<char> &ResultPath); 604218885Sdim 605263508Sdim/// @brief Simpler version for clients that don't want an open file. 606263508Sdimerror_code createTemporaryFile(const Twine &Prefix, StringRef Suffix, 607263508Sdim SmallVectorImpl<char> &ResultPath); 608263508Sdim 609263508Sdimerror_code createUniqueDirectory(const Twine &Prefix, 610263508Sdim SmallVectorImpl<char> &ResultPath); 611263508Sdim 612263508Sdimenum OpenFlags { 613263508Sdim F_None = 0, 614263508Sdim 615263508Sdim /// F_Excl - When opening a file, this flag makes raw_fd_ostream 616263508Sdim /// report an error if the file already exists. 617263508Sdim F_Excl = 1, 618263508Sdim 619263508Sdim /// F_Append - When opening a file, if it already exists append to the 620263508Sdim /// existing file instead of returning an error. This may not be specified 621263508Sdim /// with F_Excl. 622263508Sdim F_Append = 2, 623263508Sdim 624263508Sdim /// F_Binary - The file should be opened in binary mode on platforms that 625263508Sdim /// make this distinction. 626263508Sdim F_Binary = 4 627263508Sdim}; 628263508Sdim 629263508Sdiminline OpenFlags operator|(OpenFlags A, OpenFlags B) { 630263508Sdim return OpenFlags(unsigned(A) | unsigned(B)); 631263508Sdim} 632263508Sdim 633263508Sdiminline OpenFlags &operator|=(OpenFlags &A, OpenFlags B) { 634263508Sdim A = A | B; 635263508Sdim return A; 636263508Sdim} 637263508Sdim 638263508Sdimerror_code openFileForWrite(const Twine &Name, int &ResultFD, OpenFlags Flags, 639263508Sdim unsigned Mode = 0666); 640263508Sdim 641263508Sdimerror_code openFileForRead(const Twine &Name, int &ResultFD); 642263508Sdim 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. 647243830Sdim/// @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. 658243830Sdim/// @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 664234353Sdim/// @brief Identify the type of a binary file based on how magical it is. 665234353Sdimfile_magic identify_magic(StringRef magic); 666234353Sdim 667218885Sdim/// @brief Get and identify \a path's type based on its content. 668218885Sdim/// 669218885Sdim/// @param path Input path. 670263508Sdim/// @param result Set to the type of file, or file_magic::unknown. 671243830Sdim/// @returns errc::success if result has been successfully set, otherwise a 672218885Sdim/// platform specific error_code. 673234353Sdimerror_code identify_magic(const Twine &path, file_magic &result); 674218885Sdim 675263508Sdimerror_code getUniqueID(const Twine Path, UniqueID &Result); 676218885Sdim 677239462Sdim/// This class represents a memory mapped file. It is based on 678239462Sdim/// boost::iostreams::mapped_file. 679239462Sdimclass mapped_file_region { 680239462Sdim mapped_file_region() LLVM_DELETED_FUNCTION; 681239462Sdim mapped_file_region(mapped_file_region&) LLVM_DELETED_FUNCTION; 682239462Sdim mapped_file_region &operator =(mapped_file_region&) LLVM_DELETED_FUNCTION; 683239462Sdim 684239462Sdimpublic: 685239462Sdim enum mapmode { 686243830Sdim readonly, ///< May only access map via const_data as read only. 687243830Sdim readwrite, ///< May access map via data and modify it. Written to path. 688243830Sdim priv ///< May modify via data, but changes are lost on destruction. 689239462Sdim }; 690239462Sdim 691239462Sdimprivate: 692239462Sdim /// Platform specific mapping state. 693239462Sdim mapmode Mode; 694239462Sdim uint64_t Size; 695239462Sdim void *Mapping; 696243830Sdim#ifdef LLVM_ON_WIN32 697239462Sdim int FileDescriptor; 698239462Sdim void *FileHandle; 699239462Sdim void *FileMappingHandle; 700239462Sdim#endif 701239462Sdim 702249423Sdim error_code init(int FD, bool CloseFD, uint64_t Offset); 703239462Sdim 704239462Sdimpublic: 705239462Sdim typedef char char_type; 706239462Sdim 707249423Sdim#if LLVM_HAS_RVALUE_REFERENCES 708239462Sdim mapped_file_region(mapped_file_region&&); 709239462Sdim mapped_file_region &operator =(mapped_file_region&&); 710239462Sdim#endif 711239462Sdim 712239462Sdim /// Construct a mapped_file_region at \a path starting at \a offset of length 713239462Sdim /// \a length and with access \a mode. 714239462Sdim /// 715239462Sdim /// \param path Path to the file to map. If it does not exist it will be 716239462Sdim /// created. 717239462Sdim /// \param mode How to map the memory. 718239462Sdim /// \param length Number of bytes to map in starting at \a offset. If the file 719239462Sdim /// is shorter than this, it will be extended. If \a length is 720239462Sdim /// 0, the entire file will be mapped. 721239462Sdim /// \param offset Byte offset from the beginning of the file where the map 722239462Sdim /// should begin. Must be a multiple of 723239462Sdim /// mapped_file_region::alignment(). 724239462Sdim /// \param ec This is set to errc::success if the map was constructed 725263508Sdim /// successfully. Otherwise it is set to a platform dependent error. 726239462Sdim mapped_file_region(const Twine &path, 727239462Sdim mapmode mode, 728239462Sdim uint64_t length, 729239462Sdim uint64_t offset, 730239462Sdim error_code &ec); 731239462Sdim 732239462Sdim /// \param fd An open file descriptor to map. mapped_file_region takes 733249423Sdim /// ownership if closefd is true. It must have been opended in the correct 734249423Sdim /// mode. 735239462Sdim mapped_file_region(int fd, 736249423Sdim bool closefd, 737239462Sdim mapmode mode, 738239462Sdim uint64_t length, 739239462Sdim uint64_t offset, 740239462Sdim error_code &ec); 741239462Sdim 742239462Sdim ~mapped_file_region(); 743239462Sdim 744239462Sdim mapmode flags() const; 745239462Sdim uint64_t size() const; 746239462Sdim char *data() const; 747239462Sdim 748239462Sdim /// Get a const view of the data. Modifying this memory has undefined 749263508Sdim /// behavior. 750239462Sdim const char *const_data() const; 751239462Sdim 752239462Sdim /// \returns The minimum alignment offset must be. 753239462Sdim static int alignment(); 754239462Sdim}; 755239462Sdim 756239462Sdim/// @brief Memory maps the contents of a file 757239462Sdim/// 758239462Sdim/// @param path Path to file to map. 759239462Sdim/// @param file_offset Byte offset in file where mapping should begin. 760243830Sdim/// @param size Byte length of range of the file to map. 761239462Sdim/// @param map_writable If true, the file will be mapped in r/w such 762239462Sdim/// that changes to the mapped buffer will be flushed back 763239462Sdim/// to the file. If false, the file will be mapped read-only 764239462Sdim/// and the buffer will be read-only. 765239462Sdim/// @param result Set to the start address of the mapped buffer. 766243830Sdim/// @returns errc::success if result has been successfully set, otherwise a 767239462Sdim/// platform specific error_code. 768239462Sdimerror_code map_file_pages(const Twine &path, off_t file_offset, size_t size, 769239462Sdim bool map_writable, void *&result); 770239462Sdim 771239462Sdim 772239462Sdim/// @brief Memory unmaps the contents of a file 773239462Sdim/// 774239462Sdim/// @param base Pointer to the start of the buffer. 775239462Sdim/// @param size Byte length of the range to unmmap. 776243830Sdim/// @returns errc::success if result has been successfully set, otherwise a 777239462Sdim/// platform specific error_code. 778239462Sdimerror_code unmap_file_pages(void *base, size_t size); 779239462Sdim 780263508Sdim/// Return the path to the main executable, given the value of argv[0] from 781263508Sdim/// program startup and the address of main itself. In extremis, this function 782263508Sdim/// may fail and return an empty path. 783263508Sdimstd::string getMainExecutable(const char *argv0, void *MainExecAddr); 784239462Sdim 785218885Sdim/// @} 786218885Sdim/// @name Iterators 787218885Sdim/// @{ 788218885Sdim 789218885Sdim/// directory_entry - A single entry in a directory. Caches the status either 790226633Sdim/// from the result of the iteration syscall, or the first time status is 791226633Sdim/// called. 792218885Sdimclass directory_entry { 793218885Sdim std::string Path; 794218885Sdim mutable file_status Status; 795218885Sdim 796218885Sdimpublic: 797226633Sdim explicit directory_entry(const Twine &path, file_status st = file_status()) 798218885Sdim : Path(path.str()) 799226633Sdim , Status(st) {} 800218885Sdim 801218885Sdim directory_entry() {} 802218885Sdim 803226633Sdim void assign(const Twine &path, file_status st = file_status()) { 804218885Sdim Path = path.str(); 805218885Sdim Status = st; 806218885Sdim } 807218885Sdim 808226633Sdim 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 821234353Sdimnamespace detail { 822234353Sdim struct DirIterState; 823234353Sdim 824234353Sdim error_code directory_iterator_construct(DirIterState&, StringRef); 825234353Sdim error_code directory_iterator_increment(DirIterState&); 826234353Sdim error_code directory_iterator_destruct(DirIterState&); 827234353Sdim 828234353Sdim /// DirIterState - Keeps state for the directory_iterator. It is reference 829234353Sdim /// counted in order to preserve InputIterator semantics on copy. 830234353Sdim struct DirIterState : public RefCountedBase<DirIterState> { 831234353Sdim DirIterState() 832234353Sdim : IterationHandle(0) {} 833234353Sdim 834234353Sdim ~DirIterState() { 835234353Sdim directory_iterator_destruct(*this); 836234353Sdim } 837234353Sdim 838234353Sdim intptr_t IterationHandle; 839234353Sdim directory_entry CurrentEntry; 840234353Sdim }; 841234353Sdim} 842234353Sdim 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 { 847234353Sdim IntrusiveRefCntPtr<detail::DirIterState> State; 848218885Sdim 849218885Sdimpublic: 850234353Sdim explicit directory_iterator(const Twine &path, error_code &ec) { 851234353Sdim State = new detail::DirIterState; 852218885Sdim SmallString<128> path_storage; 853234353Sdim ec = detail::directory_iterator_construct(*State, 854234353Sdim path.toStringRef(path_storage)); 855218885Sdim } 856218885Sdim 857234353Sdim explicit directory_iterator(const directory_entry &de, error_code &ec) { 858234353Sdim State = new detail::DirIterState; 859234353Sdim ec = detail::directory_iterator_construct(*State, de.path()); 860234353Sdim } 861234353Sdim 862218885Sdim /// Construct end iterator. 863263508Sdim directory_iterator() : State(0) {} 864218885Sdim 865218885Sdim // No operator++ because we need error_code. 866218885Sdim directory_iterator &increment(error_code &ec) { 867234353Sdim ec = directory_iterator_increment(*State); 868218885Sdim return *this; 869218885Sdim } 870218885Sdim 871234353Sdim const directory_entry &operator*() const { return State->CurrentEntry; } 872234353Sdim const directory_entry *operator->() const { return &State->CurrentEntry; } 873218885Sdim 874234353Sdim bool operator==(const directory_iterator &RHS) const { 875263508Sdim if (State == RHS.State) 876263508Sdim return true; 877263508Sdim if (RHS.State == 0) 878263508Sdim return State->CurrentEntry == directory_entry(); 879263508Sdim if (State == 0) 880263508Sdim return RHS.State->CurrentEntry == directory_entry(); 881234353Sdim return State->CurrentEntry == RHS.State->CurrentEntry; 882234353Sdim } 883234353Sdim 884218885Sdim bool operator!=(const directory_iterator &RHS) const { 885234353Sdim return !(*this == RHS); 886218885Sdim } 887218885Sdim // Other members as required by 888218885Sdim // C++ Std, 24.1.1 Input iterators [input.iterators] 889218885Sdim}; 890218885Sdim 891234353Sdimnamespace detail { 892234353Sdim /// RecDirIterState - Keeps state for the recursive_directory_iterator. It is 893234353Sdim /// reference counted in order to preserve InputIterator semantics on copy. 894234353Sdim struct RecDirIterState : public RefCountedBase<RecDirIterState> { 895234353Sdim RecDirIterState() 896234353Sdim : Level(0) 897234353Sdim , HasNoPushRequest(false) {} 898234353Sdim 899234353Sdim std::stack<directory_iterator, std::vector<directory_iterator> > Stack; 900234353Sdim uint16_t Level; 901234353Sdim bool HasNoPushRequest; 902234353Sdim }; 903234353Sdim} 904234353Sdim 905218885Sdim/// recursive_directory_iterator - Same as directory_iterator except for it 906218885Sdim/// recurses down into child directories. 907218885Sdimclass recursive_directory_iterator { 908234353Sdim IntrusiveRefCntPtr<detail::RecDirIterState> State; 909218885Sdim 910218885Sdimpublic: 911234353Sdim recursive_directory_iterator() {} 912234353Sdim explicit recursive_directory_iterator(const Twine &path, error_code &ec) 913234353Sdim : State(new detail::RecDirIterState) { 914234353Sdim State->Stack.push(directory_iterator(path, ec)); 915234353Sdim if (State->Stack.top() == directory_iterator()) 916234353Sdim State.reset(); 917234353Sdim } 918218885Sdim // No operator++ because we need error_code. 919234353Sdim recursive_directory_iterator &increment(error_code &ec) { 920263508Sdim const directory_iterator end_itr; 921218885Sdim 922234353Sdim if (State->HasNoPushRequest) 923234353Sdim State->HasNoPushRequest = false; 924234353Sdim else { 925234353Sdim file_status st; 926234353Sdim if ((ec = State->Stack.top()->status(st))) return *this; 927234353Sdim if (is_directory(st)) { 928234353Sdim State->Stack.push(directory_iterator(*State->Stack.top(), ec)); 929234353Sdim if (ec) return *this; 930234353Sdim if (State->Stack.top() != end_itr) { 931234353Sdim ++State->Level; 932234353Sdim return *this; 933234353Sdim } 934234353Sdim State->Stack.pop(); 935234353Sdim } 936234353Sdim } 937218885Sdim 938234353Sdim while (!State->Stack.empty() 939234353Sdim && State->Stack.top().increment(ec) == end_itr) { 940234353Sdim State->Stack.pop(); 941234353Sdim --State->Level; 942234353Sdim } 943234353Sdim 944234353Sdim // Check if we are done. If so, create an end iterator. 945234353Sdim if (State->Stack.empty()) 946234353Sdim State.reset(); 947234353Sdim 948234353Sdim return *this; 949234353Sdim } 950234353Sdim 951234353Sdim const directory_entry &operator*() const { return *State->Stack.top(); } 952234353Sdim const directory_entry *operator->() const { return &*State->Stack.top(); } 953234353Sdim 954218885Sdim // observers 955234353Sdim /// Gets the current level. Starting path is at level 0. 956234353Sdim int level() const { return State->Level; } 957234353Sdim 958218885Sdim /// Returns true if no_push has been called for this directory_entry. 959234353Sdim bool no_push_request() const { return State->HasNoPushRequest; } 960218885Sdim 961218885Sdim // modifiers 962218885Sdim /// Goes up one level if Level > 0. 963234353Sdim void pop() { 964263508Sdim assert(State && "Cannot pop an end iterator!"); 965234353Sdim assert(State->Level > 0 && "Cannot pop an iterator with level < 1"); 966234353Sdim 967263508Sdim const directory_iterator end_itr; 968234353Sdim error_code ec; 969234353Sdim do { 970234353Sdim if (ec) 971234353Sdim report_fatal_error("Error incrementing directory iterator."); 972234353Sdim State->Stack.pop(); 973234353Sdim --State->Level; 974234353Sdim } while (!State->Stack.empty() 975234353Sdim && State->Stack.top().increment(ec) == end_itr); 976234353Sdim 977234353Sdim // Check if we are done. If so, create an end iterator. 978234353Sdim if (State->Stack.empty()) 979234353Sdim State.reset(); 980234353Sdim } 981234353Sdim 982218885Sdim /// Does not go down into the current directory_entry. 983234353Sdim void no_push() { State->HasNoPushRequest = true; } 984218885Sdim 985234353Sdim bool operator==(const recursive_directory_iterator &RHS) const { 986234353Sdim return State == RHS.State; 987234353Sdim } 988234353Sdim 989234353Sdim bool operator!=(const recursive_directory_iterator &RHS) const { 990234353Sdim return !(*this == RHS); 991234353Sdim } 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