1263509Sdim//===- llvm/Support/Unix/Path.inc - Unix Path Implementation ----*- 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// 10263509Sdim// This file implements the Unix specific implementation of the Path API. 11218885Sdim// 12218885Sdim//===----------------------------------------------------------------------===// 13218885Sdim 14218885Sdim//===----------------------------------------------------------------------===// 15218885Sdim//=== WARNING: Implementation here must contain only generic UNIX code that 16218885Sdim//=== is guaranteed to work on *all* UNIX variants. 17218885Sdim//===----------------------------------------------------------------------===// 18218885Sdim 19218885Sdim#include "Unix.h" 20263509Sdim#include "llvm/Support/Process.h" 21263509Sdim#include <limits.h> 22263509Sdim#include <stdio.h> 23218885Sdim#if HAVE_SYS_STAT_H 24218885Sdim#include <sys/stat.h> 25218885Sdim#endif 26218885Sdim#if HAVE_FCNTL_H 27218885Sdim#include <fcntl.h> 28218885Sdim#endif 29218885Sdim#ifdef HAVE_SYS_MMAN_H 30218885Sdim#include <sys/mman.h> 31218885Sdim#endif 32218885Sdim#if HAVE_DIRENT_H 33218885Sdim# include <dirent.h> 34218885Sdim# define NAMLEN(dirent) strlen((dirent)->d_name) 35218885Sdim#else 36218885Sdim# define dirent direct 37218885Sdim# define NAMLEN(dirent) (dirent)->d_namlen 38218885Sdim# if HAVE_SYS_NDIR_H 39218885Sdim# include <sys/ndir.h> 40218885Sdim# endif 41218885Sdim# if HAVE_SYS_DIR_H 42218885Sdim# include <sys/dir.h> 43218885Sdim# endif 44218885Sdim# if HAVE_NDIR_H 45218885Sdim# include <ndir.h> 46218885Sdim# endif 47218885Sdim#endif 48218885Sdim 49218885Sdim#ifdef __APPLE__ 50218885Sdim#include <mach-o/dyld.h> 51218885Sdim#endif 52218885Sdim 53263509Sdim// Both stdio.h and cstdio are included via different pathes and 54263509Sdim// stdcxx's cstdio doesn't include stdio.h, so it doesn't #undef the macros 55263509Sdim// either. 56263509Sdim#undef ferror 57263509Sdim#undef feof 58263509Sdim 59235633Sdim// For GNU Hurd 60263509Sdim#if defined(__GNU__) && !defined(PATH_MAX) 61263509Sdim# define PATH_MAX 4096 62235633Sdim#endif 63235633Sdim 64263509Sdimusing namespace llvm; 65218885Sdim 66218885Sdimnamespace { 67263509Sdim /// This class automatically closes the given file descriptor when it goes out 68263509Sdim /// of scope. You can take back explicit ownership of the file descriptor by 69263509Sdim /// calling take(). The destructor does not verify that close was successful. 70263509Sdim /// Therefore, never allow this class to call close on a file descriptor that 71263509Sdim /// has been read from or written to. 72263509Sdim struct AutoFD { 73263509Sdim int FileDescriptor; 74218885Sdim 75263509Sdim AutoFD(int fd) : FileDescriptor(fd) {} 76263509Sdim ~AutoFD() { 77263509Sdim if (FileDescriptor >= 0) 78263509Sdim ::close(FileDescriptor); 79263509Sdim } 80218885Sdim 81263509Sdim int take() { 82263509Sdim int ret = FileDescriptor; 83263509Sdim FileDescriptor = -1; 84263509Sdim return ret; 85263509Sdim } 86218885Sdim 87263509Sdim operator int() const {return FileDescriptor;} 88263509Sdim }; 89218885Sdim 90263509Sdim error_code TempDir(SmallVectorImpl<char> &result) { 91263509Sdim // FIXME: Don't use TMPDIR if program is SUID or SGID enabled. 92263509Sdim const char *dir = 0; 93263509Sdim (dir = std::getenv("TMPDIR" )) || 94263509Sdim (dir = std::getenv("TMP" )) || 95263509Sdim (dir = std::getenv("TEMP" )) || 96263509Sdim (dir = std::getenv("TEMPDIR")) || 97263509Sdim#ifdef P_tmpdir 98263509Sdim (dir = P_tmpdir) || 99263509Sdim#endif 100263509Sdim (dir = "/tmp"); 101263509Sdim 102263509Sdim result.clear(); 103263509Sdim StringRef d(dir); 104263509Sdim result.append(d.begin(), d.end()); 105263509Sdim return error_code::success(); 106263509Sdim } 107218885Sdim} 108218885Sdim 109263509Sdimstatic error_code createUniqueEntity(const Twine &Model, int &ResultFD, 110263509Sdim SmallVectorImpl<char> &ResultPath, 111263509Sdim bool MakeAbsolute, unsigned Mode, 112263509Sdim FSEntity Type) { 113263509Sdim SmallString<128> ModelStorage; 114263509Sdim Model.toVector(ModelStorage); 115218885Sdim 116263509Sdim if (MakeAbsolute) { 117263509Sdim // Make model absolute by prepending a temp directory if it's not already. 118263509Sdim bool absolute = sys::path::is_absolute(Twine(ModelStorage)); 119263509Sdim if (!absolute) { 120263509Sdim SmallString<128> TDir; 121263509Sdim if (error_code ec = TempDir(TDir)) return ec; 122263509Sdim sys::path::append(TDir, Twine(ModelStorage)); 123263509Sdim ModelStorage.swap(TDir); 124263509Sdim } 125263509Sdim } 126218885Sdim 127263509Sdim // From here on, DO NOT modify model. It may be needed if the randomly chosen 128263509Sdim // path already exists. 129263509Sdim ResultPath = ModelStorage; 130263509Sdim // Null terminate. 131263509Sdim ResultPath.push_back(0); 132263509Sdim ResultPath.pop_back(); 133218885Sdim 134263509Sdimretry_random_path: 135263509Sdim // Replace '%' with random chars. 136263509Sdim for (unsigned i = 0, e = ModelStorage.size(); i != e; ++i) { 137263509Sdim if (ModelStorage[i] == '%') 138263509Sdim ResultPath[i] = "0123456789abcdef"[sys::Process::GetRandomNumber() & 15]; 139263509Sdim } 140218885Sdim 141263509Sdim // Try to open + create the file. 142263509Sdim switch (Type) { 143263509Sdim case FS_File: { 144263509Sdim int RandomFD = ::open(ResultPath.begin(), O_RDWR | O_CREAT | O_EXCL, Mode); 145263509Sdim if (RandomFD == -1) { 146263509Sdim int SavedErrno = errno; 147263509Sdim // If the file existed, try again, otherwise, error. 148263509Sdim if (SavedErrno == errc::file_exists) 149263509Sdim goto retry_random_path; 150263509Sdim return error_code(SavedErrno, system_category()); 151263509Sdim } 152218885Sdim 153263509Sdim ResultFD = RandomFD; 154263509Sdim return error_code::success(); 155218885Sdim } 156218885Sdim 157263509Sdim case FS_Name: { 158263509Sdim bool Exists; 159263509Sdim error_code EC = sys::fs::exists(ResultPath.begin(), Exists); 160263509Sdim if (EC) 161263509Sdim return EC; 162263509Sdim if (Exists) 163263509Sdim goto retry_random_path; 164263509Sdim return error_code::success(); 165218885Sdim } 166218885Sdim 167263509Sdim case FS_Dir: { 168263509Sdim bool Existed; 169263509Sdim error_code EC = sys::fs::create_directory(ResultPath.begin(), Existed); 170263509Sdim if (EC) 171263509Sdim return EC; 172263509Sdim if (Existed) 173263509Sdim goto retry_random_path; 174263509Sdim return error_code::success(); 175218885Sdim } 176218885Sdim } 177263509Sdim llvm_unreachable("Invalid Type"); 178218885Sdim} 179218885Sdim 180263509Sdimnamespace llvm { 181263509Sdimnamespace sys { 182263509Sdimnamespace fs { 183245431Sdim#if defined(__FreeBSD__) || defined (__NetBSD__) || defined(__Bitrig__) || \ 184245431Sdim defined(__OpenBSD__) || defined(__minix) || defined(__FreeBSD_kernel__) || \ 185263509Sdim defined(__linux__) || defined(__CYGWIN__) || defined(__DragonFly__) 186218885Sdimstatic int 187218885Sdimtest_dir(char buf[PATH_MAX], char ret[PATH_MAX], 188218885Sdim const char *dir, const char *bin) 189218885Sdim{ 190218885Sdim struct stat sb; 191218885Sdim 192218885Sdim snprintf(buf, PATH_MAX, "%s/%s", dir, bin); 193218885Sdim if (realpath(buf, ret) == NULL) 194218885Sdim return (1); 195218885Sdim if (stat(buf, &sb) != 0) 196218885Sdim return (1); 197218885Sdim 198218885Sdim return (0); 199218885Sdim} 200218885Sdim 201218885Sdimstatic char * 202218885Sdimgetprogpath(char ret[PATH_MAX], const char *bin) 203218885Sdim{ 204218885Sdim char *pv, *s, *t, buf[PATH_MAX]; 205218885Sdim 206218885Sdim /* First approach: absolute path. */ 207218885Sdim if (bin[0] == '/') { 208218885Sdim if (test_dir(buf, ret, "/", bin) == 0) 209218885Sdim return (ret); 210218885Sdim return (NULL); 211218885Sdim } 212218885Sdim 213218885Sdim /* Second approach: relative path. */ 214218885Sdim if (strchr(bin, '/') != NULL) { 215218885Sdim if (getcwd(buf, PATH_MAX) == NULL) 216218885Sdim return (NULL); 217218885Sdim if (test_dir(buf, ret, buf, bin) == 0) 218218885Sdim return (ret); 219218885Sdim return (NULL); 220218885Sdim } 221218885Sdim 222218885Sdim /* Third approach: $PATH */ 223218885Sdim if ((pv = getenv("PATH")) == NULL) 224218885Sdim return (NULL); 225218885Sdim s = pv = strdup(pv); 226218885Sdim if (pv == NULL) 227218885Sdim return (NULL); 228218885Sdim while ((t = strsep(&s, ":")) != NULL) { 229218885Sdim if (test_dir(buf, ret, t, bin) == 0) { 230218885Sdim free(pv); 231218885Sdim return (ret); 232218885Sdim } 233218885Sdim } 234218885Sdim free(pv); 235218885Sdim return (NULL); 236218885Sdim} 237235633Sdim#endif // __FreeBSD__ || __NetBSD__ || __FreeBSD_kernel__ 238218885Sdim 239218885Sdim/// GetMainExecutable - Return the path to the main executable, given the 240218885Sdim/// value of argv[0] from program startup. 241263509Sdimstd::string getMainExecutable(const char *argv0, void *MainAddr) { 242218885Sdim#if defined(__APPLE__) 243218885Sdim // On OS X the executable path is saved to the stack by dyld. Reading it 244218885Sdim // from there is much faster than calling dladdr, especially for large 245218885Sdim // binaries with symbols. 246218885Sdim char exe_path[MAXPATHLEN]; 247218885Sdim uint32_t size = sizeof(exe_path); 248218885Sdim if (_NSGetExecutablePath(exe_path, &size) == 0) { 249218885Sdim char link_path[MAXPATHLEN]; 250218885Sdim if (realpath(exe_path, link_path)) 251263509Sdim return link_path; 252218885Sdim } 253245431Sdim#elif defined(__FreeBSD__) || defined (__NetBSD__) || defined(__Bitrig__) || \ 254263509Sdim defined(__OpenBSD__) || defined(__minix) || defined(__DragonFly__) || \ 255263509Sdim defined(__FreeBSD_kernel__) 256218885Sdim char exe_path[PATH_MAX]; 257218885Sdim 258218885Sdim if (getprogpath(exe_path, argv0) != NULL) 259263509Sdim return exe_path; 260218885Sdim#elif defined(__linux__) || defined(__CYGWIN__) 261218885Sdim char exe_path[MAXPATHLEN]; 262245431Sdim StringRef aPath("/proc/self/exe"); 263245431Sdim if (sys::fs::exists(aPath)) { 264245431Sdim // /proc is not always mounted under Linux (chroot for example). 265245431Sdim ssize_t len = readlink(aPath.str().c_str(), exe_path, sizeof(exe_path)); 266245431Sdim if (len >= 0) 267263509Sdim return StringRef(exe_path, len); 268245431Sdim } else { 269245431Sdim // Fall back to the classical detection. 270245431Sdim if (getprogpath(exe_path, argv0) != NULL) 271263509Sdim return exe_path; 272245431Sdim } 273218885Sdim#elif defined(HAVE_DLFCN_H) 274218885Sdim // Use dladdr to get executable path if available. 275218885Sdim Dl_info DLInfo; 276218885Sdim int err = dladdr(MainAddr, &DLInfo); 277218885Sdim if (err == 0) 278263509Sdim return ""; 279218885Sdim 280218885Sdim // If the filename is a symlink, we need to resolve and return the location of 281218885Sdim // the actual executable. 282218885Sdim char link_path[MAXPATHLEN]; 283218885Sdim if (realpath(DLInfo.dli_fname, link_path)) 284263509Sdim return link_path; 285218885Sdim#else 286218885Sdim#error GetMainExecutable is not implemented on this host yet. 287218885Sdim#endif 288263509Sdim return ""; 289218885Sdim} 290218885Sdim 291263509SdimTimeValue file_status::getLastModificationTime() const { 292263509Sdim TimeValue Ret; 293263509Sdim Ret.fromEpochTime(fs_st_mtime); 294263509Sdim return Ret; 295263509Sdim} 296218885Sdim 297263509SdimUniqueID file_status::getUniqueID() const { 298263509Sdim return UniqueID(fs_st_dev, fs_st_ino); 299218885Sdim} 300218885Sdim 301263509Sdimerror_code current_path(SmallVectorImpl<char> &result) { 302263509Sdim result.clear(); 303218885Sdim 304263509Sdim const char *pwd = ::getenv("PWD"); 305263509Sdim llvm::sys::fs::file_status PWDStatus, DotStatus; 306263509Sdim if (pwd && llvm::sys::path::is_absolute(pwd) && 307263509Sdim !llvm::sys::fs::status(pwd, PWDStatus) && 308263509Sdim !llvm::sys::fs::status(".", DotStatus) && 309263509Sdim PWDStatus.getUniqueID() == DotStatus.getUniqueID()) { 310263509Sdim result.append(pwd, pwd + strlen(pwd)); 311263509Sdim return error_code::success(); 312263509Sdim } 313263509Sdim 314263509Sdim#ifdef MAXPATHLEN 315263509Sdim result.reserve(MAXPATHLEN); 316263509Sdim#else 317263509Sdim// For GNU Hurd 318263509Sdim result.reserve(1024); 319263509Sdim#endif 320263509Sdim 321263509Sdim while (true) { 322263509Sdim if (::getcwd(result.data(), result.capacity()) == 0) { 323263509Sdim // See if there was a real error. 324263509Sdim if (errno != errc::not_enough_memory) 325263509Sdim return error_code(errno, system_category()); 326263509Sdim // Otherwise there just wasn't enough space. 327263509Sdim result.reserve(result.capacity() * 2); 328263509Sdim } else 329263509Sdim break; 330263509Sdim } 331263509Sdim 332263509Sdim result.set_size(strlen(result.data())); 333263509Sdim return error_code::success(); 334218885Sdim} 335218885Sdim 336263509Sdimerror_code create_directory(const Twine &path, bool &existed) { 337263509Sdim SmallString<128> path_storage; 338263509Sdim StringRef p = path.toNullTerminatedStringRef(path_storage); 339218885Sdim 340263509Sdim if (::mkdir(p.begin(), S_IRWXU | S_IRWXG) == -1) { 341263509Sdim if (errno != errc::file_exists) 342263509Sdim return error_code(errno, system_category()); 343263509Sdim existed = true; 344263509Sdim } else 345263509Sdim existed = false; 346263509Sdim 347263509Sdim return error_code::success(); 348218885Sdim} 349218885Sdim 350263509Sdimerror_code create_hard_link(const Twine &to, const Twine &from) { 351263509Sdim // Get arguments. 352263509Sdim SmallString<128> from_storage; 353263509Sdim SmallString<128> to_storage; 354263509Sdim StringRef f = from.toNullTerminatedStringRef(from_storage); 355263509Sdim StringRef t = to.toNullTerminatedStringRef(to_storage); 356263509Sdim 357263509Sdim if (::link(t.begin(), f.begin()) == -1) 358263509Sdim return error_code(errno, system_category()); 359263509Sdim 360263509Sdim return error_code::success(); 361218885Sdim} 362218885Sdim 363263509Sdimerror_code create_symlink(const Twine &to, const Twine &from) { 364263509Sdim // Get arguments. 365263509Sdim SmallString<128> from_storage; 366263509Sdim SmallString<128> to_storage; 367263509Sdim StringRef f = from.toNullTerminatedStringRef(from_storage); 368263509Sdim StringRef t = to.toNullTerminatedStringRef(to_storage); 369263509Sdim 370263509Sdim if (::symlink(t.begin(), f.begin()) == -1) 371263509Sdim return error_code(errno, system_category()); 372263509Sdim 373263509Sdim return error_code::success(); 374218885Sdim} 375218885Sdim 376263509Sdimerror_code remove(const Twine &path, bool &existed) { 377263509Sdim SmallString<128> path_storage; 378263509Sdim StringRef p = path.toNullTerminatedStringRef(path_storage); 379263509Sdim 380218885Sdim struct stat buf; 381263509Sdim if (stat(p.begin(), &buf) != 0) { 382263509Sdim if (errno != errc::no_such_file_or_directory) 383263509Sdim return error_code(errno, system_category()); 384263509Sdim existed = false; 385263509Sdim return error_code::success(); 386263509Sdim } 387218885Sdim 388263509Sdim // Note: this check catches strange situations. In all cases, LLVM should 389263509Sdim // only be involved in the creation and deletion of regular files. This 390263509Sdim // check ensures that what we're trying to erase is a regular file. It 391263509Sdim // effectively prevents LLVM from erasing things like /dev/null, any block 392263509Sdim // special file, or other things that aren't "regular" files. 393263509Sdim if (!S_ISREG(buf.st_mode) && !S_ISDIR(buf.st_mode)) 394263509Sdim return make_error_code(errc::operation_not_permitted); 395263509Sdim 396263509Sdim if (::remove(p.begin()) == -1) { 397263509Sdim if (errno != errc::no_such_file_or_directory) 398263509Sdim return error_code(errno, system_category()); 399263509Sdim existed = false; 400263509Sdim } else 401263509Sdim existed = true; 402263509Sdim 403263509Sdim return error_code::success(); 404218885Sdim} 405218885Sdim 406263509Sdimerror_code rename(const Twine &from, const Twine &to) { 407263509Sdim // Get arguments. 408263509Sdim SmallString<128> from_storage; 409263509Sdim SmallString<128> to_storage; 410263509Sdim StringRef f = from.toNullTerminatedStringRef(from_storage); 411263509Sdim StringRef t = to.toNullTerminatedStringRef(to_storage); 412218885Sdim 413263509Sdim if (::rename(f.begin(), t.begin()) == -1) 414263509Sdim return error_code(errno, system_category()); 415263509Sdim 416263509Sdim return error_code::success(); 417218885Sdim} 418218885Sdim 419263509Sdimerror_code resize_file(const Twine &path, uint64_t size) { 420263509Sdim SmallString<128> path_storage; 421263509Sdim StringRef p = path.toNullTerminatedStringRef(path_storage); 422263509Sdim 423263509Sdim if (::truncate(p.begin(), size) == -1) 424263509Sdim return error_code(errno, system_category()); 425263509Sdim 426263509Sdim return error_code::success(); 427218885Sdim} 428218885Sdim 429263509Sdimerror_code exists(const Twine &path, bool &result) { 430263509Sdim SmallString<128> path_storage; 431263509Sdim StringRef p = path.toNullTerminatedStringRef(path_storage); 432218885Sdim 433263509Sdim if (::access(p.begin(), F_OK) == -1) { 434263509Sdim if (errno != errc::no_such_file_or_directory) 435263509Sdim return error_code(errno, system_category()); 436263509Sdim result = false; 437263509Sdim } else 438263509Sdim result = true; 439218885Sdim 440263509Sdim return error_code::success(); 441263509Sdim} 442218885Sdim 443263509Sdimbool can_write(const Twine &Path) { 444263509Sdim SmallString<128> PathStorage; 445263509Sdim StringRef P = Path.toNullTerminatedStringRef(PathStorage); 446263509Sdim return 0 == access(P.begin(), W_OK); 447218885Sdim} 448218885Sdim 449263509Sdimbool can_execute(const Twine &Path) { 450263509Sdim SmallString<128> PathStorage; 451263509Sdim StringRef P = Path.toNullTerminatedStringRef(PathStorage); 452263509Sdim 453263509Sdim if (0 != access(P.begin(), R_OK | X_OK)) 454218885Sdim return false; 455218885Sdim struct stat buf; 456263509Sdim if (0 != stat(P.begin(), &buf)) 457218885Sdim return false; 458218885Sdim if (!S_ISREG(buf.st_mode)) 459218885Sdim return false; 460218885Sdim return true; 461218885Sdim} 462218885Sdim 463263509Sdimbool equivalent(file_status A, file_status B) { 464263509Sdim assert(status_known(A) && status_known(B)); 465263509Sdim return A.fs_st_dev == B.fs_st_dev && 466263509Sdim A.fs_st_ino == B.fs_st_ino; 467263509Sdim} 468218885Sdim 469263509Sdimerror_code equivalent(const Twine &A, const Twine &B, bool &result) { 470263509Sdim file_status fsA, fsB; 471263509Sdim if (error_code ec = status(A, fsA)) return ec; 472263509Sdim if (error_code ec = status(B, fsB)) return ec; 473263509Sdim result = equivalent(fsA, fsB); 474263509Sdim return error_code::success(); 475263509Sdim} 476218885Sdim 477263509Sdimstatic error_code fillStatus(int StatRet, const struct stat &Status, 478263509Sdim file_status &Result) { 479263509Sdim if (StatRet != 0) { 480263509Sdim error_code ec(errno, system_category()); 481263509Sdim if (ec == errc::no_such_file_or_directory) 482263509Sdim Result = file_status(file_type::file_not_found); 483218885Sdim else 484263509Sdim Result = file_status(file_type::status_error); 485263509Sdim return ec; 486218885Sdim } 487218885Sdim 488263509Sdim file_type Type = file_type::type_unknown; 489218885Sdim 490263509Sdim if (S_ISDIR(Status.st_mode)) 491263509Sdim Type = file_type::directory_file; 492263509Sdim else if (S_ISREG(Status.st_mode)) 493263509Sdim Type = file_type::regular_file; 494263509Sdim else if (S_ISBLK(Status.st_mode)) 495263509Sdim Type = file_type::block_file; 496263509Sdim else if (S_ISCHR(Status.st_mode)) 497263509Sdim Type = file_type::character_file; 498263509Sdim else if (S_ISFIFO(Status.st_mode)) 499263509Sdim Type = file_type::fifo_file; 500263509Sdim else if (S_ISSOCK(Status.st_mode)) 501263509Sdim Type = file_type::socket_file; 502218885Sdim 503263509Sdim perms Perms = static_cast<perms>(Status.st_mode); 504263509Sdim Result = 505263509Sdim file_status(Type, Perms, Status.st_dev, Status.st_ino, Status.st_mtime, 506263509Sdim Status.st_uid, Status.st_gid, Status.st_size); 507263509Sdim 508263509Sdim return error_code::success(); 509218885Sdim} 510218885Sdim 511263509Sdimerror_code status(const Twine &Path, file_status &Result) { 512263509Sdim SmallString<128> PathStorage; 513263509Sdim StringRef P = Path.toNullTerminatedStringRef(PathStorage); 514263509Sdim 515263509Sdim struct stat Status; 516263509Sdim int StatRet = ::stat(P.begin(), &Status); 517263509Sdim return fillStatus(StatRet, Status, Result); 518218885Sdim} 519218885Sdim 520263509Sdimerror_code status(int FD, file_status &Result) { 521263509Sdim struct stat Status; 522263509Sdim int StatRet = ::fstat(FD, &Status); 523263509Sdim return fillStatus(StatRet, Status, Result); 524218885Sdim} 525218885Sdim 526263509Sdimerror_code setLastModificationAndAccessTime(int FD, TimeValue Time) { 527263509Sdim#if defined(HAVE_FUTIMENS) 528263509Sdim timespec Times[2]; 529263509Sdim Times[0].tv_sec = Time.toPosixTime(); 530263509Sdim Times[0].tv_nsec = 0; 531263509Sdim Times[1] = Times[0]; 532263509Sdim if (::futimens(FD, Times)) 533263509Sdim#elif defined(HAVE_FUTIMES) 534263509Sdim timeval Times[2]; 535263509Sdim Times[0].tv_sec = Time.toPosixTime(); 536263509Sdim Times[0].tv_usec = 0; 537263509Sdim Times[1] = Times[0]; 538263509Sdim if (::futimes(FD, Times)) 539263509Sdim#else 540263509Sdim#error Missing futimes() and futimens() 541263509Sdim#endif 542263509Sdim return error_code(errno, system_category()); 543263509Sdim return error_code::success(); 544218885Sdim} 545218885Sdim 546263509Sdimerror_code mapped_file_region::init(int FD, bool CloseFD, uint64_t Offset) { 547263509Sdim AutoFD ScopedFD(FD); 548263509Sdim if (!CloseFD) 549263509Sdim ScopedFD.take(); 550218885Sdim 551263509Sdim // Figure out how large the file is. 552263509Sdim struct stat FileInfo; 553263509Sdim if (fstat(FD, &FileInfo) == -1) 554263509Sdim return error_code(errno, system_category()); 555263509Sdim uint64_t FileSize = FileInfo.st_size; 556218885Sdim 557263509Sdim if (Size == 0) 558263509Sdim Size = FileSize; 559263509Sdim else if (FileSize < Size) { 560263509Sdim // We need to grow the file. 561263509Sdim if (ftruncate(FD, Size) == -1) 562263509Sdim return error_code(errno, system_category()); 563218885Sdim } 564218885Sdim 565263509Sdim int flags = (Mode == readwrite) ? MAP_SHARED : MAP_PRIVATE; 566263509Sdim int prot = (Mode == readonly) ? PROT_READ : (PROT_READ | PROT_WRITE); 567263509Sdim#ifdef MAP_FILE 568263509Sdim flags |= MAP_FILE; 569263509Sdim#endif 570263509Sdim Mapping = ::mmap(0, Size, prot, flags, FD, Offset); 571263509Sdim if (Mapping == MAP_FAILED) 572263509Sdim return error_code(errno, system_category()); 573263509Sdim return error_code::success(); 574218885Sdim} 575218885Sdim 576263509Sdimmapped_file_region::mapped_file_region(const Twine &path, 577263509Sdim mapmode mode, 578263509Sdim uint64_t length, 579263509Sdim uint64_t offset, 580263509Sdim error_code &ec) 581263509Sdim : Mode(mode) 582263509Sdim , Size(length) 583263509Sdim , Mapping() { 584263509Sdim // Make sure that the requested size fits within SIZE_T. 585263509Sdim if (length > std::numeric_limits<size_t>::max()) { 586263509Sdim ec = make_error_code(errc::invalid_argument); 587263509Sdim return; 588263509Sdim } 589218885Sdim 590263509Sdim SmallString<128> path_storage; 591263509Sdim StringRef name = path.toNullTerminatedStringRef(path_storage); 592263509Sdim int oflags = (mode == readonly) ? O_RDONLY : O_RDWR; 593263509Sdim int ofd = ::open(name.begin(), oflags); 594263509Sdim if (ofd == -1) { 595263509Sdim ec = error_code(errno, system_category()); 596263509Sdim return; 597263509Sdim } 598263509Sdim 599263509Sdim ec = init(ofd, true, offset); 600263509Sdim if (ec) 601263509Sdim Mapping = 0; 602218885Sdim} 603218885Sdim 604263509Sdimmapped_file_region::mapped_file_region(int fd, 605263509Sdim bool closefd, 606263509Sdim mapmode mode, 607263509Sdim uint64_t length, 608263509Sdim uint64_t offset, 609263509Sdim error_code &ec) 610263509Sdim : Mode(mode) 611263509Sdim , Size(length) 612263509Sdim , Mapping() { 613263509Sdim // Make sure that the requested size fits within SIZE_T. 614263509Sdim if (length > std::numeric_limits<size_t>::max()) { 615263509Sdim ec = make_error_code(errc::invalid_argument); 616263509Sdim return; 617218885Sdim } 618263509Sdim 619263509Sdim ec = init(fd, closefd, offset); 620263509Sdim if (ec) 621263509Sdim Mapping = 0; 622218885Sdim} 623218885Sdim 624263509Sdimmapped_file_region::~mapped_file_region() { 625263509Sdim if (Mapping) 626263509Sdim ::munmap(Mapping, Size); 627218885Sdim} 628218885Sdim 629263509Sdim#if LLVM_HAS_RVALUE_REFERENCES 630263509Sdimmapped_file_region::mapped_file_region(mapped_file_region &&other) 631263509Sdim : Mode(other.Mode), Size(other.Size), Mapping(other.Mapping) { 632263509Sdim other.Mapping = 0; 633263509Sdim} 634263509Sdim#endif 635218885Sdim 636263509Sdimmapped_file_region::mapmode mapped_file_region::flags() const { 637263509Sdim assert(Mapping && "Mapping failed but used anyway!"); 638263509Sdim return Mode; 639263509Sdim} 640218885Sdim 641263509Sdimuint64_t mapped_file_region::size() const { 642263509Sdim assert(Mapping && "Mapping failed but used anyway!"); 643263509Sdim return Size; 644263509Sdim} 645218885Sdim 646263509Sdimchar *mapped_file_region::data() const { 647263509Sdim assert(Mapping && "Mapping failed but used anyway!"); 648263509Sdim assert(Mode != readonly && "Cannot get non const data for readonly mapping!"); 649263509Sdim return reinterpret_cast<char*>(Mapping); 650263509Sdim} 651218885Sdim 652263509Sdimconst char *mapped_file_region::const_data() const { 653263509Sdim assert(Mapping && "Mapping failed but used anyway!"); 654263509Sdim return reinterpret_cast<const char*>(Mapping); 655263509Sdim} 656218885Sdim 657263509Sdimint mapped_file_region::alignment() { 658263509Sdim return process::get_self()->page_size(); 659218885Sdim} 660218885Sdim 661263509Sdimerror_code detail::directory_iterator_construct(detail::DirIterState &it, 662263509Sdim StringRef path){ 663263509Sdim SmallString<128> path_null(path); 664263509Sdim DIR *directory = ::opendir(path_null.c_str()); 665263509Sdim if (directory == 0) 666263509Sdim return error_code(errno, system_category()); 667218885Sdim 668263509Sdim it.IterationHandle = reinterpret_cast<intptr_t>(directory); 669263509Sdim // Add something for replace_filename to replace. 670263509Sdim path::append(path_null, "."); 671263509Sdim it.CurrentEntry = directory_entry(path_null.str()); 672263509Sdim return directory_iterator_increment(it); 673218885Sdim} 674218885Sdim 675263509Sdimerror_code detail::directory_iterator_destruct(detail::DirIterState &it) { 676263509Sdim if (it.IterationHandle) 677263509Sdim ::closedir(reinterpret_cast<DIR *>(it.IterationHandle)); 678263509Sdim it.IterationHandle = 0; 679263509Sdim it.CurrentEntry = directory_entry(); 680263509Sdim return error_code::success(); 681218885Sdim} 682218885Sdim 683263509Sdimerror_code detail::directory_iterator_increment(detail::DirIterState &it) { 684263509Sdim errno = 0; 685263509Sdim dirent *cur_dir = ::readdir(reinterpret_cast<DIR *>(it.IterationHandle)); 686263509Sdim if (cur_dir == 0 && errno != 0) { 687263509Sdim return error_code(errno, system_category()); 688263509Sdim } else if (cur_dir != 0) { 689263509Sdim StringRef name(cur_dir->d_name, NAMLEN(cur_dir)); 690263509Sdim if ((name.size() == 1 && name[0] == '.') || 691263509Sdim (name.size() == 2 && name[0] == '.' && name[1] == '.')) 692263509Sdim return directory_iterator_increment(it); 693263509Sdim it.CurrentEntry.replace_filename(name); 694263509Sdim } else 695263509Sdim return directory_iterator_destruct(it); 696218885Sdim 697263509Sdim return error_code::success(); 698218885Sdim} 699218885Sdim 700263509Sdimerror_code get_magic(const Twine &path, uint32_t len, 701263509Sdim SmallVectorImpl<char> &result) { 702263509Sdim SmallString<128> PathStorage; 703263509Sdim StringRef Path = path.toNullTerminatedStringRef(PathStorage); 704263509Sdim result.set_size(0); 705218885Sdim 706263509Sdim // Open path. 707263509Sdim std::FILE *file = std::fopen(Path.data(), "rb"); 708263509Sdim if (file == 0) 709263509Sdim return error_code(errno, system_category()); 710218885Sdim 711263509Sdim // Reserve storage. 712263509Sdim result.reserve(len); 713218885Sdim 714263509Sdim // Read magic! 715263509Sdim size_t size = std::fread(result.data(), 1, len, file); 716263509Sdim if (std::ferror(file) != 0) { 717263509Sdim std::fclose(file); 718263509Sdim return error_code(errno, system_category()); 719263509Sdim } else if (size != len) { 720263509Sdim if (std::feof(file) != 0) { 721263509Sdim std::fclose(file); 722263509Sdim result.set_size(size); 723263509Sdim return make_error_code(errc::value_too_large); 724218885Sdim } 725218885Sdim } 726263509Sdim std::fclose(file); 727263509Sdim result.set_size(size); 728263509Sdim return error_code::success(); 729218885Sdim} 730218885Sdim 731263509Sdimerror_code map_file_pages(const Twine &path, off_t file_offset, size_t size, 732263509Sdim bool map_writable, void *&result) { 733263509Sdim SmallString<128> path_storage; 734263509Sdim StringRef name = path.toNullTerminatedStringRef(path_storage); 735263509Sdim int oflags = map_writable ? O_RDWR : O_RDONLY; 736263509Sdim int ofd = ::open(name.begin(), oflags); 737263509Sdim if ( ofd == -1 ) 738263509Sdim return error_code(errno, system_category()); 739263509Sdim AutoFD fd(ofd); 740263509Sdim int flags = map_writable ? MAP_SHARED : MAP_PRIVATE; 741263509Sdim int prot = map_writable ? (PROT_READ|PROT_WRITE) : PROT_READ; 742263509Sdim#ifdef MAP_FILE 743263509Sdim flags |= MAP_FILE; 744263509Sdim#endif 745263509Sdim result = ::mmap(0, size, prot, flags, fd, file_offset); 746263509Sdim if (result == MAP_FAILED) { 747263509Sdim return error_code(errno, system_category()); 748263509Sdim } 749263509Sdim 750263509Sdim return error_code::success(); 751218885Sdim} 752218885Sdim 753263509Sdimerror_code unmap_file_pages(void *base, size_t size) { 754263509Sdim if ( ::munmap(base, size) == -1 ) 755263509Sdim return error_code(errno, system_category()); 756263509Sdim 757263509Sdim return error_code::success(); 758218885Sdim} 759218885Sdim 760263509Sdimerror_code openFileForRead(const Twine &Name, int &ResultFD) { 761263509Sdim SmallString<128> Storage; 762263509Sdim StringRef P = Name.toNullTerminatedStringRef(Storage); 763263509Sdim while ((ResultFD = open(P.begin(), O_RDONLY)) < 0) { 764263509Sdim if (errno != EINTR) 765263509Sdim return error_code(errno, system_category()); 766218885Sdim } 767263509Sdim return error_code::success(); 768218885Sdim} 769218885Sdim 770263509Sdimerror_code openFileForWrite(const Twine &Name, int &ResultFD, 771263509Sdim sys::fs::OpenFlags Flags, unsigned Mode) { 772263509Sdim // Verify that we don't have both "append" and "excl". 773263509Sdim assert((!(Flags & sys::fs::F_Excl) || !(Flags & sys::fs::F_Append)) && 774263509Sdim "Cannot specify both 'excl' and 'append' file creation flags!"); 775218885Sdim 776263509Sdim int OpenFlags = O_WRONLY | O_CREAT; 777263509Sdim 778263509Sdim if (Flags & F_Append) 779263509Sdim OpenFlags |= O_APPEND; 780218885Sdim else 781263509Sdim OpenFlags |= O_TRUNC; 782218885Sdim 783263509Sdim if (Flags & F_Excl) 784263509Sdim OpenFlags |= O_EXCL; 785218885Sdim 786263509Sdim SmallString<128> Storage; 787263509Sdim StringRef P = Name.toNullTerminatedStringRef(Storage); 788263509Sdim while ((ResultFD = open(P.begin(), OpenFlags, Mode)) < 0) { 789263509Sdim if (errno != EINTR) 790263509Sdim return error_code(errno, system_category()); 791263509Sdim } 792263509Sdim return error_code::success(); 793218885Sdim} 794218885Sdim 795263509Sdim} // end namespace fs 796263509Sdim} // end namespace sys 797263509Sdim} // end namespace llvm 798