1//===- llvm/Support/Unix/Path.inc - Unix Path Implementation ----*- C++ -*-===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This file implements the Unix specific implementation of the Path API. 11// 12//===----------------------------------------------------------------------===// 13 14//===----------------------------------------------------------------------===// 15//=== WARNING: Implementation here must contain only generic UNIX code that 16//=== is guaranteed to work on *all* UNIX variants. 17//===----------------------------------------------------------------------===// 18 19#include "Unix.h" 20#include "llvm/Support/Process.h" 21#include <limits.h> 22#include <stdio.h> 23#if HAVE_SYS_STAT_H 24#include <sys/stat.h> 25#endif 26#if HAVE_FCNTL_H 27#include <fcntl.h> 28#endif 29#ifdef HAVE_SYS_MMAN_H 30#include <sys/mman.h> 31#endif 32#if HAVE_DIRENT_H 33# include <dirent.h> 34# define NAMLEN(dirent) strlen((dirent)->d_name) 35#else 36# define dirent direct 37# define NAMLEN(dirent) (dirent)->d_namlen 38# if HAVE_SYS_NDIR_H 39# include <sys/ndir.h> 40# endif 41# if HAVE_SYS_DIR_H 42# include <sys/dir.h> 43# endif 44# if HAVE_NDIR_H 45# include <ndir.h> 46# endif 47#endif 48 49#ifdef __APPLE__ 50#include <mach-o/dyld.h> 51#endif 52 53// Both stdio.h and cstdio are included via different pathes and 54// stdcxx's cstdio doesn't include stdio.h, so it doesn't #undef the macros 55// either. 56#undef ferror 57#undef feof 58 59// For GNU Hurd 60#if defined(__GNU__) && !defined(PATH_MAX) 61# define PATH_MAX 4096 62#endif 63 64using namespace llvm; 65 66namespace { 67 /// This class automatically closes the given file descriptor when it goes out 68 /// of scope. You can take back explicit ownership of the file descriptor by 69 /// calling take(). The destructor does not verify that close was successful. 70 /// Therefore, never allow this class to call close on a file descriptor that 71 /// has been read from or written to. 72 struct AutoFD { 73 int FileDescriptor; 74 75 AutoFD(int fd) : FileDescriptor(fd) {} 76 ~AutoFD() { 77 if (FileDescriptor >= 0) 78 ::close(FileDescriptor); 79 } 80 81 int take() { 82 int ret = FileDescriptor; 83 FileDescriptor = -1; 84 return ret; 85 } 86 87 operator int() const {return FileDescriptor;} 88 }; 89 90 error_code TempDir(SmallVectorImpl<char> &result) { 91 // FIXME: Don't use TMPDIR if program is SUID or SGID enabled. 92 const char *dir = 0; 93 (dir = std::getenv("TMPDIR" )) || 94 (dir = std::getenv("TMP" )) || 95 (dir = std::getenv("TEMP" )) || 96 (dir = std::getenv("TEMPDIR")) || 97#ifdef P_tmpdir 98 (dir = P_tmpdir) || 99#endif 100 (dir = "/tmp"); 101 102 result.clear(); 103 StringRef d(dir); 104 result.append(d.begin(), d.end()); 105 return error_code::success(); 106 } 107} 108 109static error_code createUniqueEntity(const Twine &Model, int &ResultFD, 110 SmallVectorImpl<char> &ResultPath, 111 bool MakeAbsolute, unsigned Mode, 112 FSEntity Type) { 113 SmallString<128> ModelStorage; 114 Model.toVector(ModelStorage); 115 116 if (MakeAbsolute) { 117 // Make model absolute by prepending a temp directory if it's not already. 118 bool absolute = sys::path::is_absolute(Twine(ModelStorage)); 119 if (!absolute) { 120 SmallString<128> TDir; 121 if (error_code ec = TempDir(TDir)) return ec; 122 sys::path::append(TDir, Twine(ModelStorage)); 123 ModelStorage.swap(TDir); 124 } 125 } 126 127 // From here on, DO NOT modify model. It may be needed if the randomly chosen 128 // path already exists. 129 ResultPath = ModelStorage; 130 // Null terminate. 131 ResultPath.push_back(0); 132 ResultPath.pop_back(); 133 134retry_random_path: 135 // Replace '%' with random chars. 136 for (unsigned i = 0, e = ModelStorage.size(); i != e; ++i) { 137 if (ModelStorage[i] == '%') 138 ResultPath[i] = "0123456789abcdef"[sys::Process::GetRandomNumber() & 15]; 139 } 140 141 // Try to open + create the file. 142 switch (Type) { 143 case FS_File: { 144 int RandomFD = ::open(ResultPath.begin(), O_RDWR | O_CREAT | O_EXCL, Mode); 145 if (RandomFD == -1) { 146 int SavedErrno = errno; 147 // If the file existed, try again, otherwise, error. 148 if (SavedErrno == errc::file_exists) 149 goto retry_random_path; 150 return error_code(SavedErrno, system_category()); 151 } 152 153 ResultFD = RandomFD; 154 return error_code::success(); 155 } 156 157 case FS_Name: { 158 bool Exists; 159 error_code EC = sys::fs::exists(ResultPath.begin(), Exists); 160 if (EC) 161 return EC; 162 if (Exists) 163 goto retry_random_path; 164 return error_code::success(); 165 } 166 167 case FS_Dir: { 168 bool Existed; 169 error_code EC = sys::fs::create_directory(ResultPath.begin(), Existed); 170 if (EC) 171 return EC; 172 if (Existed) 173 goto retry_random_path; 174 return error_code::success(); 175 } 176 } 177 llvm_unreachable("Invalid Type"); 178} 179 180namespace llvm { 181namespace sys { 182namespace fs { 183#if defined(__FreeBSD__) || defined (__NetBSD__) || defined(__Bitrig__) || \ 184 defined(__OpenBSD__) || defined(__minix) || defined(__FreeBSD_kernel__) || \ 185 defined(__linux__) || defined(__CYGWIN__) 186static int 187test_dir(char buf[PATH_MAX], char ret[PATH_MAX], 188 const char *dir, const char *bin) 189{ 190 struct stat sb; 191 192 snprintf(buf, PATH_MAX, "%s/%s", dir, bin); 193 if (realpath(buf, ret) == NULL) 194 return (1); 195 if (stat(buf, &sb) != 0) 196 return (1); 197 198 return (0); 199} 200 201static char * 202getprogpath(char ret[PATH_MAX], const char *bin) 203{ 204 char *pv, *s, *t, buf[PATH_MAX]; 205 206 /* First approach: absolute path. */ 207 if (bin[0] == '/') { 208 if (test_dir(buf, ret, "/", bin) == 0) 209 return (ret); 210 return (NULL); 211 } 212 213 /* Second approach: relative path. */ 214 if (strchr(bin, '/') != NULL) { 215 if (getcwd(buf, PATH_MAX) == NULL) 216 return (NULL); 217 if (test_dir(buf, ret, buf, bin) == 0) 218 return (ret); 219 return (NULL); 220 } 221 222 /* Third approach: $PATH */ 223 if ((pv = getenv("PATH")) == NULL) 224 return (NULL); 225 s = pv = strdup(pv); 226 if (pv == NULL) 227 return (NULL); 228 while ((t = strsep(&s, ":")) != NULL) { 229 if (test_dir(buf, ret, t, bin) == 0) { 230 free(pv); 231 return (ret); 232 } 233 } 234 free(pv); 235 return (NULL); 236} 237#endif // __FreeBSD__ || __NetBSD__ || __FreeBSD_kernel__ 238 239/// GetMainExecutable - Return the path to the main executable, given the 240/// value of argv[0] from program startup. 241std::string getMainExecutable(const char *argv0, void *MainAddr) { 242#if defined(__APPLE__) 243 // On OS X the executable path is saved to the stack by dyld. Reading it 244 // from there is much faster than calling dladdr, especially for large 245 // binaries with symbols. 246 char exe_path[MAXPATHLEN]; 247 uint32_t size = sizeof(exe_path); 248 if (_NSGetExecutablePath(exe_path, &size) == 0) { 249 char link_path[MAXPATHLEN]; 250 if (realpath(exe_path, link_path)) 251 return link_path; 252 } 253#elif defined(__FreeBSD__) || defined (__NetBSD__) || defined(__Bitrig__) || \ 254 defined(__OpenBSD__) || defined(__minix) || defined(__FreeBSD_kernel__) 255 char exe_path[PATH_MAX]; 256 257 if (getprogpath(exe_path, argv0) != NULL) 258 return exe_path; 259#elif defined(__linux__) || defined(__CYGWIN__) 260 char exe_path[MAXPATHLEN]; 261 StringRef aPath("/proc/self/exe"); 262 if (sys::fs::exists(aPath)) { 263 // /proc is not always mounted under Linux (chroot for example). 264 ssize_t len = readlink(aPath.str().c_str(), exe_path, sizeof(exe_path)); 265 if (len >= 0) 266 return StringRef(exe_path, len); 267 } else { 268 // Fall back to the classical detection. 269 if (getprogpath(exe_path, argv0) != NULL) 270 return exe_path; 271 } 272#elif defined(HAVE_DLFCN_H) 273 // Use dladdr to get executable path if available. 274 Dl_info DLInfo; 275 int err = dladdr(MainAddr, &DLInfo); 276 if (err == 0) 277 return ""; 278 279 // If the filename is a symlink, we need to resolve and return the location of 280 // the actual executable. 281 char link_path[MAXPATHLEN]; 282 if (realpath(DLInfo.dli_fname, link_path)) 283 return link_path; 284#else 285#error GetMainExecutable is not implemented on this host yet. 286#endif 287 return ""; 288} 289 290TimeValue file_status::getLastModificationTime() const { 291 TimeValue Ret; 292 Ret.fromEpochTime(fs_st_mtime); 293 return Ret; 294} 295 296UniqueID file_status::getUniqueID() const { 297 return UniqueID(fs_st_dev, fs_st_ino); 298} 299 300error_code current_path(SmallVectorImpl<char> &result) { 301 result.clear(); 302 303 const char *pwd = ::getenv("PWD"); 304 llvm::sys::fs::file_status PWDStatus, DotStatus; 305 if (pwd && llvm::sys::path::is_absolute(pwd) && 306 !llvm::sys::fs::status(pwd, PWDStatus) && 307 !llvm::sys::fs::status(".", DotStatus) && 308 PWDStatus.getUniqueID() == DotStatus.getUniqueID()) { 309 result.append(pwd, pwd + strlen(pwd)); 310 return error_code::success(); 311 } 312 313#ifdef MAXPATHLEN 314 result.reserve(MAXPATHLEN); 315#else 316// For GNU Hurd 317 result.reserve(1024); 318#endif 319 320 while (true) { 321 if (::getcwd(result.data(), result.capacity()) == 0) { 322 // See if there was a real error. 323 if (errno != errc::not_enough_memory) 324 return error_code(errno, system_category()); 325 // Otherwise there just wasn't enough space. 326 result.reserve(result.capacity() * 2); 327 } else 328 break; 329 } 330 331 result.set_size(strlen(result.data())); 332 return error_code::success(); 333} 334 335error_code create_directory(const Twine &path, bool &existed) { 336 SmallString<128> path_storage; 337 StringRef p = path.toNullTerminatedStringRef(path_storage); 338 339 if (::mkdir(p.begin(), S_IRWXU | S_IRWXG) == -1) { 340 if (errno != errc::file_exists) 341 return error_code(errno, system_category()); 342 existed = true; 343 } else 344 existed = false; 345 346 return error_code::success(); 347} 348 349error_code create_hard_link(const Twine &to, const Twine &from) { 350 // Get arguments. 351 SmallString<128> from_storage; 352 SmallString<128> to_storage; 353 StringRef f = from.toNullTerminatedStringRef(from_storage); 354 StringRef t = to.toNullTerminatedStringRef(to_storage); 355 356 if (::link(t.begin(), f.begin()) == -1) 357 return error_code(errno, system_category()); 358 359 return error_code::success(); 360} 361 362error_code create_symlink(const Twine &to, const Twine &from) { 363 // Get arguments. 364 SmallString<128> from_storage; 365 SmallString<128> to_storage; 366 StringRef f = from.toNullTerminatedStringRef(from_storage); 367 StringRef t = to.toNullTerminatedStringRef(to_storage); 368 369 if (::symlink(t.begin(), f.begin()) == -1) 370 return error_code(errno, system_category()); 371 372 return error_code::success(); 373} 374 375error_code remove(const Twine &path, bool &existed) { 376 SmallString<128> path_storage; 377 StringRef p = path.toNullTerminatedStringRef(path_storage); 378 379 struct stat buf; 380 if (stat(p.begin(), &buf) != 0) { 381 if (errno != errc::no_such_file_or_directory) 382 return error_code(errno, system_category()); 383 existed = false; 384 return error_code::success(); 385 } 386 387 // Note: this check catches strange situations. In all cases, LLVM should 388 // only be involved in the creation and deletion of regular files. This 389 // check ensures that what we're trying to erase is a regular file. It 390 // effectively prevents LLVM from erasing things like /dev/null, any block 391 // special file, or other things that aren't "regular" files. 392 if (!S_ISREG(buf.st_mode) && !S_ISDIR(buf.st_mode)) 393 return make_error_code(errc::operation_not_permitted); 394 395 if (::remove(p.begin()) == -1) { 396 if (errno != errc::no_such_file_or_directory) 397 return error_code(errno, system_category()); 398 existed = false; 399 } else 400 existed = true; 401 402 return error_code::success(); 403} 404 405error_code rename(const Twine &from, const Twine &to) { 406 // Get arguments. 407 SmallString<128> from_storage; 408 SmallString<128> to_storage; 409 StringRef f = from.toNullTerminatedStringRef(from_storage); 410 StringRef t = to.toNullTerminatedStringRef(to_storage); 411 412 if (::rename(f.begin(), t.begin()) == -1) 413 return error_code(errno, system_category()); 414 415 return error_code::success(); 416} 417 418error_code resize_file(const Twine &path, uint64_t size) { 419 SmallString<128> path_storage; 420 StringRef p = path.toNullTerminatedStringRef(path_storage); 421 422 if (::truncate(p.begin(), size) == -1) 423 return error_code(errno, system_category()); 424 425 return error_code::success(); 426} 427 428error_code exists(const Twine &path, bool &result) { 429 SmallString<128> path_storage; 430 StringRef p = path.toNullTerminatedStringRef(path_storage); 431 432 if (::access(p.begin(), F_OK) == -1) { 433 if (errno != errc::no_such_file_or_directory) 434 return error_code(errno, system_category()); 435 result = false; 436 } else 437 result = true; 438 439 return error_code::success(); 440} 441 442bool can_write(const Twine &Path) { 443 SmallString<128> PathStorage; 444 StringRef P = Path.toNullTerminatedStringRef(PathStorage); 445 return 0 == access(P.begin(), W_OK); 446} 447 448bool can_execute(const Twine &Path) { 449 SmallString<128> PathStorage; 450 StringRef P = Path.toNullTerminatedStringRef(PathStorage); 451 452 if (0 != access(P.begin(), R_OK | X_OK)) 453 return false; 454 struct stat buf; 455 if (0 != stat(P.begin(), &buf)) 456 return false; 457 if (!S_ISREG(buf.st_mode)) 458 return false; 459 return true; 460} 461 462bool equivalent(file_status A, file_status B) { 463 assert(status_known(A) && status_known(B)); 464 return A.fs_st_dev == B.fs_st_dev && 465 A.fs_st_ino == B.fs_st_ino; 466} 467 468error_code equivalent(const Twine &A, const Twine &B, bool &result) { 469 file_status fsA, fsB; 470 if (error_code ec = status(A, fsA)) return ec; 471 if (error_code ec = status(B, fsB)) return ec; 472 result = equivalent(fsA, fsB); 473 return error_code::success(); 474} 475 476static error_code fillStatus(int StatRet, const struct stat &Status, 477 file_status &Result) { 478 if (StatRet != 0) { 479 error_code ec(errno, system_category()); 480 if (ec == errc::no_such_file_or_directory) 481 Result = file_status(file_type::file_not_found); 482 else 483 Result = file_status(file_type::status_error); 484 return ec; 485 } 486 487 file_type Type = file_type::type_unknown; 488 489 if (S_ISDIR(Status.st_mode)) 490 Type = file_type::directory_file; 491 else if (S_ISREG(Status.st_mode)) 492 Type = file_type::regular_file; 493 else if (S_ISBLK(Status.st_mode)) 494 Type = file_type::block_file; 495 else if (S_ISCHR(Status.st_mode)) 496 Type = file_type::character_file; 497 else if (S_ISFIFO(Status.st_mode)) 498 Type = file_type::fifo_file; 499 else if (S_ISSOCK(Status.st_mode)) 500 Type = file_type::socket_file; 501 502 perms Perms = static_cast<perms>(Status.st_mode); 503 Result = 504 file_status(Type, Perms, Status.st_dev, Status.st_ino, Status.st_mtime, 505 Status.st_uid, Status.st_gid, Status.st_size); 506 507 return error_code::success(); 508} 509 510error_code status(const Twine &Path, file_status &Result) { 511 SmallString<128> PathStorage; 512 StringRef P = Path.toNullTerminatedStringRef(PathStorage); 513 514 struct stat Status; 515 int StatRet = ::stat(P.begin(), &Status); 516 return fillStatus(StatRet, Status, Result); 517} 518 519error_code status(int FD, file_status &Result) { 520 struct stat Status; 521 int StatRet = ::fstat(FD, &Status); 522 return fillStatus(StatRet, Status, Result); 523} 524 525error_code setLastModificationAndAccessTime(int FD, TimeValue Time) { 526#if defined(HAVE_FUTIMENS) 527 timespec Times[2]; 528 Times[0].tv_sec = Time.toPosixTime(); 529 Times[0].tv_nsec = 0; 530 Times[1] = Times[0]; 531 if (::futimens(FD, Times)) 532#elif defined(HAVE_FUTIMES) 533 timeval Times[2]; 534 Times[0].tv_sec = Time.toPosixTime(); 535 Times[0].tv_usec = 0; 536 Times[1] = Times[0]; 537 if (::futimes(FD, Times)) 538#else 539#error Missing futimes() and futimens() 540#endif 541 return error_code(errno, system_category()); 542 return error_code::success(); 543} 544 545error_code mapped_file_region::init(int FD, bool CloseFD, uint64_t Offset) { 546 AutoFD ScopedFD(FD); 547 if (!CloseFD) 548 ScopedFD.take(); 549 550 // Figure out how large the file is. 551 struct stat FileInfo; 552 if (fstat(FD, &FileInfo) == -1) 553 return error_code(errno, system_category()); 554 uint64_t FileSize = FileInfo.st_size; 555 556 if (Size == 0) 557 Size = FileSize; 558 else if (FileSize < Size) { 559 // We need to grow the file. 560 if (ftruncate(FD, Size) == -1) 561 return error_code(errno, system_category()); 562 } 563 564 int flags = (Mode == readwrite) ? MAP_SHARED : MAP_PRIVATE; 565 int prot = (Mode == readonly) ? PROT_READ : (PROT_READ | PROT_WRITE); 566#ifdef MAP_FILE 567 flags |= MAP_FILE; 568#endif 569 Mapping = ::mmap(0, Size, prot, flags, FD, Offset); 570 if (Mapping == MAP_FAILED) 571 return error_code(errno, system_category()); 572 return error_code::success(); 573} 574 575mapped_file_region::mapped_file_region(const Twine &path, 576 mapmode mode, 577 uint64_t length, 578 uint64_t offset, 579 error_code &ec) 580 : Mode(mode) 581 , Size(length) 582 , Mapping() { 583 // Make sure that the requested size fits within SIZE_T. 584 if (length > std::numeric_limits<size_t>::max()) { 585 ec = make_error_code(errc::invalid_argument); 586 return; 587 } 588 589 SmallString<128> path_storage; 590 StringRef name = path.toNullTerminatedStringRef(path_storage); 591 int oflags = (mode == readonly) ? O_RDONLY : O_RDWR; 592 int ofd = ::open(name.begin(), oflags); 593 if (ofd == -1) { 594 ec = error_code(errno, system_category()); 595 return; 596 } 597 598 ec = init(ofd, true, offset); 599 if (ec) 600 Mapping = 0; 601} 602 603mapped_file_region::mapped_file_region(int fd, 604 bool closefd, 605 mapmode mode, 606 uint64_t length, 607 uint64_t offset, 608 error_code &ec) 609 : Mode(mode) 610 , Size(length) 611 , Mapping() { 612 // Make sure that the requested size fits within SIZE_T. 613 if (length > std::numeric_limits<size_t>::max()) { 614 ec = make_error_code(errc::invalid_argument); 615 return; 616 } 617 618 ec = init(fd, closefd, offset); 619 if (ec) 620 Mapping = 0; 621} 622 623mapped_file_region::~mapped_file_region() { 624 if (Mapping) 625 ::munmap(Mapping, Size); 626} 627 628#if LLVM_HAS_RVALUE_REFERENCES 629mapped_file_region::mapped_file_region(mapped_file_region &&other) 630 : Mode(other.Mode), Size(other.Size), Mapping(other.Mapping) { 631 other.Mapping = 0; 632} 633#endif 634 635mapped_file_region::mapmode mapped_file_region::flags() const { 636 assert(Mapping && "Mapping failed but used anyway!"); 637 return Mode; 638} 639 640uint64_t mapped_file_region::size() const { 641 assert(Mapping && "Mapping failed but used anyway!"); 642 return Size; 643} 644 645char *mapped_file_region::data() const { 646 assert(Mapping && "Mapping failed but used anyway!"); 647 assert(Mode != readonly && "Cannot get non const data for readonly mapping!"); 648 return reinterpret_cast<char*>(Mapping); 649} 650 651const char *mapped_file_region::const_data() const { 652 assert(Mapping && "Mapping failed but used anyway!"); 653 return reinterpret_cast<const char*>(Mapping); 654} 655 656int mapped_file_region::alignment() { 657 return process::get_self()->page_size(); 658} 659 660error_code detail::directory_iterator_construct(detail::DirIterState &it, 661 StringRef path){ 662 SmallString<128> path_null(path); 663 DIR *directory = ::opendir(path_null.c_str()); 664 if (directory == 0) 665 return error_code(errno, system_category()); 666 667 it.IterationHandle = reinterpret_cast<intptr_t>(directory); 668 // Add something for replace_filename to replace. 669 path::append(path_null, "."); 670 it.CurrentEntry = directory_entry(path_null.str()); 671 return directory_iterator_increment(it); 672} 673 674error_code detail::directory_iterator_destruct(detail::DirIterState &it) { 675 if (it.IterationHandle) 676 ::closedir(reinterpret_cast<DIR *>(it.IterationHandle)); 677 it.IterationHandle = 0; 678 it.CurrentEntry = directory_entry(); 679 return error_code::success(); 680} 681 682error_code detail::directory_iterator_increment(detail::DirIterState &it) { 683 errno = 0; 684 dirent *cur_dir = ::readdir(reinterpret_cast<DIR *>(it.IterationHandle)); 685 if (cur_dir == 0 && errno != 0) { 686 return error_code(errno, system_category()); 687 } else if (cur_dir != 0) { 688 StringRef name(cur_dir->d_name, NAMLEN(cur_dir)); 689 if ((name.size() == 1 && name[0] == '.') || 690 (name.size() == 2 && name[0] == '.' && name[1] == '.')) 691 return directory_iterator_increment(it); 692 it.CurrentEntry.replace_filename(name); 693 } else 694 return directory_iterator_destruct(it); 695 696 return error_code::success(); 697} 698 699error_code get_magic(const Twine &path, uint32_t len, 700 SmallVectorImpl<char> &result) { 701 SmallString<128> PathStorage; 702 StringRef Path = path.toNullTerminatedStringRef(PathStorage); 703 result.set_size(0); 704 705 // Open path. 706 std::FILE *file = std::fopen(Path.data(), "rb"); 707 if (file == 0) 708 return error_code(errno, system_category()); 709 710 // Reserve storage. 711 result.reserve(len); 712 713 // Read magic! 714 size_t size = std::fread(result.data(), 1, len, file); 715 if (std::ferror(file) != 0) { 716 std::fclose(file); 717 return error_code(errno, system_category()); 718 } else if (size != len) { 719 if (std::feof(file) != 0) { 720 std::fclose(file); 721 result.set_size(size); 722 return make_error_code(errc::value_too_large); 723 } 724 } 725 std::fclose(file); 726 result.set_size(size); 727 return error_code::success(); 728} 729 730error_code map_file_pages(const Twine &path, off_t file_offset, size_t size, 731 bool map_writable, void *&result) { 732 SmallString<128> path_storage; 733 StringRef name = path.toNullTerminatedStringRef(path_storage); 734 int oflags = map_writable ? O_RDWR : O_RDONLY; 735 int ofd = ::open(name.begin(), oflags); 736 if ( ofd == -1 ) 737 return error_code(errno, system_category()); 738 AutoFD fd(ofd); 739 int flags = map_writable ? MAP_SHARED : MAP_PRIVATE; 740 int prot = map_writable ? (PROT_READ|PROT_WRITE) : PROT_READ; 741#ifdef MAP_FILE 742 flags |= MAP_FILE; 743#endif 744 result = ::mmap(0, size, prot, flags, fd, file_offset); 745 if (result == MAP_FAILED) { 746 return error_code(errno, system_category()); 747 } 748 749 return error_code::success(); 750} 751 752error_code unmap_file_pages(void *base, size_t size) { 753 if ( ::munmap(base, size) == -1 ) 754 return error_code(errno, system_category()); 755 756 return error_code::success(); 757} 758 759error_code openFileForRead(const Twine &Name, int &ResultFD) { 760 SmallString<128> Storage; 761 StringRef P = Name.toNullTerminatedStringRef(Storage); 762 while ((ResultFD = open(P.begin(), O_RDONLY)) < 0) { 763 if (errno != EINTR) 764 return error_code(errno, system_category()); 765 } 766 return error_code::success(); 767} 768 769error_code openFileForWrite(const Twine &Name, int &ResultFD, 770 sys::fs::OpenFlags Flags, unsigned Mode) { 771 // Verify that we don't have both "append" and "excl". 772 assert((!(Flags & sys::fs::F_Excl) || !(Flags & sys::fs::F_Append)) && 773 "Cannot specify both 'excl' and 'append' file creation flags!"); 774 775 int OpenFlags = O_WRONLY | O_CREAT; 776 777 if (Flags & F_Append) 778 OpenFlags |= O_APPEND; 779 else 780 OpenFlags |= O_TRUNC; 781 782 if (Flags & F_Excl) 783 OpenFlags |= O_EXCL; 784 785 SmallString<128> Storage; 786 StringRef P = Name.toNullTerminatedStringRef(Storage); 787 while ((ResultFD = open(P.begin(), OpenFlags, Mode)) < 0) { 788 if (errno != EINTR) 789 return error_code(errno, system_category()); 790 } 791 return error_code::success(); 792} 793 794} // end namespace fs 795} // end namespace sys 796} // end namespace llvm 797