1//===- llvm/Support/Unix/PathV2.cpp - 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 PathV2 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#if HAVE_SYS_STAT_H 22#include <sys/stat.h> 23#endif 24#if HAVE_FCNTL_H 25#include <fcntl.h> 26#endif 27#ifdef HAVE_SYS_MMAN_H 28#include <sys/mman.h> 29#endif 30#if HAVE_DIRENT_H 31# include <dirent.h> 32# define NAMLEN(dirent) strlen((dirent)->d_name) 33#else 34# define dirent direct 35# define NAMLEN(dirent) (dirent)->d_namlen 36# if HAVE_SYS_NDIR_H 37# include <sys/ndir.h> 38# endif 39# if HAVE_SYS_DIR_H 40# include <sys/dir.h> 41# endif 42# if HAVE_NDIR_H 43# include <ndir.h> 44# endif 45#endif 46#if HAVE_STDIO_H 47#include <stdio.h> 48#endif 49#if HAVE_LIMITS_H 50#include <limits.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 109namespace llvm { 110namespace sys { 111namespace fs { 112 113error_code current_path(SmallVectorImpl<char> &result) { 114#ifdef MAXPATHLEN 115 result.reserve(MAXPATHLEN); 116#else 117// For GNU Hurd 118 result.reserve(1024); 119#endif 120 121 while (true) { 122 if (::getcwd(result.data(), result.capacity()) == 0) { 123 // See if there was a real error. 124 if (errno != errc::not_enough_memory) 125 return error_code(errno, system_category()); 126 // Otherwise there just wasn't enough space. 127 result.reserve(result.capacity() * 2); 128 } else 129 break; 130 } 131 132 result.set_size(strlen(result.data())); 133 return error_code::success(); 134} 135 136error_code copy_file(const Twine &from, const Twine &to, copy_option copt) { 137 // Get arguments. 138 SmallString<128> from_storage; 139 SmallString<128> to_storage; 140 StringRef f = from.toNullTerminatedStringRef(from_storage); 141 StringRef t = to.toNullTerminatedStringRef(to_storage); 142 143 const size_t buf_sz = 32768; 144 char buffer[buf_sz]; 145 int from_file = -1, to_file = -1; 146 147 // Open from. 148 if ((from_file = ::open(f.begin(), O_RDONLY)) < 0) 149 return error_code(errno, system_category()); 150 AutoFD from_fd(from_file); 151 152 // Stat from. 153 struct stat from_stat; 154 if (::stat(f.begin(), &from_stat) != 0) 155 return error_code(errno, system_category()); 156 157 // Setup to flags. 158 int to_flags = O_CREAT | O_WRONLY; 159 if (copt == copy_option::fail_if_exists) 160 to_flags |= O_EXCL; 161 162 // Open to. 163 if ((to_file = ::open(t.begin(), to_flags, from_stat.st_mode)) < 0) 164 return error_code(errno, system_category()); 165 AutoFD to_fd(to_file); 166 167 // Copy! 168 ssize_t sz, sz_read = 1, sz_write; 169 while (sz_read > 0 && 170 (sz_read = ::read(from_fd, buffer, buf_sz)) > 0) { 171 // Allow for partial writes - see Advanced Unix Programming (2nd Ed.), 172 // Marc Rochkind, Addison-Wesley, 2004, page 94 173 sz_write = 0; 174 do { 175 if ((sz = ::write(to_fd, buffer + sz_write, sz_read - sz_write)) < 0) { 176 sz_read = sz; // cause read loop termination. 177 break; // error. 178 } 179 sz_write += sz; 180 } while (sz_write < sz_read); 181 } 182 183 // After all the file operations above the return value of close actually 184 // matters. 185 if (::close(from_fd.take()) < 0) sz_read = -1; 186 if (::close(to_fd.take()) < 0) sz_read = -1; 187 188 // Check for errors. 189 if (sz_read < 0) 190 return error_code(errno, system_category()); 191 192 return error_code::success(); 193} 194 195error_code create_directory(const Twine &path, bool &existed) { 196 SmallString<128> path_storage; 197 StringRef p = path.toNullTerminatedStringRef(path_storage); 198 199 if (::mkdir(p.begin(), S_IRWXU | S_IRWXG) == -1) { 200 if (errno != errc::file_exists) 201 return error_code(errno, system_category()); 202 existed = true; 203 } else 204 existed = false; 205 206 return error_code::success(); 207} 208 209error_code create_hard_link(const Twine &to, const Twine &from) { 210 // Get arguments. 211 SmallString<128> from_storage; 212 SmallString<128> to_storage; 213 StringRef f = from.toNullTerminatedStringRef(from_storage); 214 StringRef t = to.toNullTerminatedStringRef(to_storage); 215 216 if (::link(t.begin(), f.begin()) == -1) 217 return error_code(errno, system_category()); 218 219 return error_code::success(); 220} 221 222error_code create_symlink(const Twine &to, const Twine &from) { 223 // Get arguments. 224 SmallString<128> from_storage; 225 SmallString<128> to_storage; 226 StringRef f = from.toNullTerminatedStringRef(from_storage); 227 StringRef t = to.toNullTerminatedStringRef(to_storage); 228 229 if (::symlink(t.begin(), f.begin()) == -1) 230 return error_code(errno, system_category()); 231 232 return error_code::success(); 233} 234 235error_code remove(const Twine &path, bool &existed) { 236 SmallString<128> path_storage; 237 StringRef p = path.toNullTerminatedStringRef(path_storage); 238 239 if (::remove(p.begin()) == -1) { 240 if (errno != errc::no_such_file_or_directory) 241 return error_code(errno, system_category()); 242 existed = false; 243 } else 244 existed = true; 245 246 return error_code::success(); 247} 248 249error_code rename(const Twine &from, const Twine &to) { 250 // Get arguments. 251 SmallString<128> from_storage; 252 SmallString<128> to_storage; 253 StringRef f = from.toNullTerminatedStringRef(from_storage); 254 StringRef t = to.toNullTerminatedStringRef(to_storage); 255 256 if (::rename(f.begin(), t.begin()) == -1) { 257 // If it's a cross device link, copy then delete, otherwise return the error 258 if (errno == EXDEV) { 259 if (error_code ec = copy_file(from, to, copy_option::overwrite_if_exists)) 260 return ec; 261 bool Existed; 262 if (error_code ec = remove(from, Existed)) 263 return ec; 264 } else 265 return error_code(errno, system_category()); 266 } 267 268 return error_code::success(); 269} 270 271error_code resize_file(const Twine &path, uint64_t size) { 272 SmallString<128> path_storage; 273 StringRef p = path.toNullTerminatedStringRef(path_storage); 274 275 if (::truncate(p.begin(), size) == -1) 276 return error_code(errno, system_category()); 277 278 return error_code::success(); 279} 280 281error_code exists(const Twine &path, bool &result) { 282 SmallString<128> path_storage; 283 StringRef p = path.toNullTerminatedStringRef(path_storage); 284 285 if (::access(p.begin(), F_OK) == -1) { 286 if (errno != errc::no_such_file_or_directory) 287 return error_code(errno, system_category()); 288 result = false; 289 } else 290 result = true; 291 292 return error_code::success(); 293} 294 295bool equivalent(file_status A, file_status B) { 296 assert(status_known(A) && status_known(B)); 297 return A.fs_st_dev == B.fs_st_dev && 298 A.fs_st_ino == B.fs_st_ino; 299} 300 301error_code equivalent(const Twine &A, const Twine &B, bool &result) { 302 file_status fsA, fsB; 303 if (error_code ec = status(A, fsA)) return ec; 304 if (error_code ec = status(B, fsB)) return ec; 305 result = equivalent(fsA, fsB); 306 return error_code::success(); 307} 308 309error_code file_size(const Twine &path, uint64_t &result) { 310 SmallString<128> path_storage; 311 StringRef p = path.toNullTerminatedStringRef(path_storage); 312 313 struct stat status; 314 if (::stat(p.begin(), &status) == -1) 315 return error_code(errno, system_category()); 316 if (!S_ISREG(status.st_mode)) 317 return make_error_code(errc::operation_not_permitted); 318 319 result = status.st_size; 320 return error_code::success(); 321} 322 323error_code status(const Twine &path, file_status &result) { 324 SmallString<128> path_storage; 325 StringRef p = path.toNullTerminatedStringRef(path_storage); 326 327 struct stat status; 328 if (::stat(p.begin(), &status) != 0) { 329 error_code ec(errno, system_category()); 330 if (ec == errc::no_such_file_or_directory) 331 result = file_status(file_type::file_not_found); 332 else 333 result = file_status(file_type::status_error); 334 return ec; 335 } 336 337 perms prms = static_cast<perms>(status.st_mode & perms_mask); 338 339 if (S_ISDIR(status.st_mode)) 340 result = file_status(file_type::directory_file, prms); 341 else if (S_ISREG(status.st_mode)) 342 result = file_status(file_type::regular_file, prms); 343 else if (S_ISBLK(status.st_mode)) 344 result = file_status(file_type::block_file, prms); 345 else if (S_ISCHR(status.st_mode)) 346 result = file_status(file_type::character_file, prms); 347 else if (S_ISFIFO(status.st_mode)) 348 result = file_status(file_type::fifo_file, prms); 349 else if (S_ISSOCK(status.st_mode)) 350 result = file_status(file_type::socket_file, prms); 351 else 352 result = file_status(file_type::type_unknown, prms); 353 354 result.fs_st_dev = status.st_dev; 355 result.fs_st_ino = status.st_ino; 356 357 return error_code::success(); 358} 359 360// Modifies permissions on a file. 361error_code permissions(const Twine &path, perms prms) { 362 if ((prms & add_perms) && (prms & remove_perms)) 363 llvm_unreachable("add_perms and remove_perms are mutually exclusive"); 364 365 // Get current permissions 366 file_status info; 367 if (error_code ec = status(path, info)) { 368 return ec; 369 } 370 371 // Set updated permissions. 372 SmallString<128> path_storage; 373 StringRef p = path.toNullTerminatedStringRef(path_storage); 374 perms permsToSet; 375 if (prms & add_perms) { 376 permsToSet = (info.permissions() | prms) & perms_mask; 377 } else if (prms & remove_perms) { 378 permsToSet = (info.permissions() & ~prms) & perms_mask; 379 } else { 380 permsToSet = prms & perms_mask; 381 } 382 if (::chmod(p.begin(), static_cast<mode_t>(permsToSet))) { 383 return error_code(errno, system_category()); 384 } 385 386 return error_code::success(); 387} 388 389// Since this is most often used for temporary files, mode defaults to 0600. 390error_code unique_file(const Twine &model, int &result_fd, 391 SmallVectorImpl<char> &result_path, 392 bool makeAbsolute, unsigned mode) { 393 SmallString<128> Model; 394 model.toVector(Model); 395 // Null terminate. 396 Model.c_str(); 397 398 if (makeAbsolute) { 399 // Make model absolute by prepending a temp directory if it's not already. 400 bool absolute = path::is_absolute(Twine(Model)); 401 if (!absolute) { 402 SmallString<128> TDir; 403 if (error_code ec = TempDir(TDir)) return ec; 404 path::append(TDir, Twine(Model)); 405 Model.swap(TDir); 406 } 407 } 408 409 // From here on, DO NOT modify model. It may be needed if the randomly chosen 410 // path already exists. 411 SmallString<128> RandomPath = Model; 412 413retry_random_path: 414 // Replace '%' with random chars. 415 for (unsigned i = 0, e = Model.size(); i != e; ++i) { 416 if (Model[i] == '%') 417 RandomPath[i] = "0123456789abcdef"[sys::Process::GetRandomNumber() & 15]; 418 } 419 420 // Try to open + create the file. 421rety_open_create: 422 int RandomFD = ::open(RandomPath.c_str(), O_RDWR | O_CREAT | O_EXCL, mode); 423 if (RandomFD == -1) { 424 // If the file existed, try again, otherwise, error. 425 if (errno == errc::file_exists) 426 goto retry_random_path; 427 // If path prefix doesn't exist, try to create it. 428 if (errno == errc::no_such_file_or_directory && 429 !exists(path::parent_path(RandomPath))) { 430 StringRef p(RandomPath); 431 SmallString<64> dir_to_create; 432 for (path::const_iterator i = path::begin(p), 433 e = --path::end(p); i != e; ++i) { 434 path::append(dir_to_create, *i); 435 bool Exists; 436 if (error_code ec = exists(Twine(dir_to_create), Exists)) return ec; 437 if (!Exists) { 438 // Don't try to create network paths. 439 if (i->size() > 2 && (*i)[0] == '/' && 440 (*i)[1] == '/' && 441 (*i)[2] != '/') 442 return make_error_code(errc::no_such_file_or_directory); 443 if (::mkdir(dir_to_create.c_str(), 0700) == -1) 444 return error_code(errno, system_category()); 445 } 446 } 447 goto rety_open_create; 448 } 449 return error_code(errno, system_category()); 450 } 451 452 // Make the path absolute. 453 char real_path_buff[PATH_MAX + 1]; 454 if (realpath(RandomPath.c_str(), real_path_buff) == NULL) { 455 int error = errno; 456 ::close(RandomFD); 457 ::unlink(RandomPath.c_str()); 458 return error_code(error, system_category()); 459 } 460 461 result_path.clear(); 462 StringRef d(real_path_buff); 463 result_path.append(d.begin(), d.end()); 464 465 result_fd = RandomFD; 466 return error_code::success(); 467} 468 469error_code mapped_file_region::init(int fd, uint64_t offset) { 470 AutoFD FD(fd); 471 472 // Figure out how large the file is. 473 struct stat FileInfo; 474 if (fstat(fd, &FileInfo) == -1) 475 return error_code(errno, system_category()); 476 uint64_t FileSize = FileInfo.st_size; 477 478 if (Size == 0) 479 Size = FileSize; 480 else if (FileSize < Size) { 481 // We need to grow the file. 482 if (ftruncate(fd, Size) == -1) 483 return error_code(errno, system_category()); 484 } 485 486 int flags = (Mode == readwrite) ? MAP_SHARED : MAP_PRIVATE; 487 int prot = (Mode == readonly) ? PROT_READ : (PROT_READ | PROT_WRITE); 488#ifdef MAP_FILE 489 flags |= MAP_FILE; 490#endif 491 Mapping = ::mmap(0, Size, prot, flags, fd, offset); 492 if (Mapping == MAP_FAILED) 493 return error_code(errno, system_category()); 494 return error_code::success(); 495} 496 497mapped_file_region::mapped_file_region(const Twine &path, 498 mapmode mode, 499 uint64_t length, 500 uint64_t offset, 501 error_code &ec) 502 : Mode(mode) 503 , Size(length) 504 , Mapping() { 505 // Make sure that the requested size fits within SIZE_T. 506 if (length > std::numeric_limits<size_t>::max()) { 507 ec = make_error_code(errc::invalid_argument); 508 return; 509 } 510 511 SmallString<128> path_storage; 512 StringRef name = path.toNullTerminatedStringRef(path_storage); 513 int oflags = (mode == readonly) ? O_RDONLY : O_RDWR; 514 int ofd = ::open(name.begin(), oflags); 515 if (ofd == -1) { 516 ec = error_code(errno, system_category()); 517 return; 518 } 519 520 ec = init(ofd, offset); 521 if (ec) 522 Mapping = 0; 523} 524 525mapped_file_region::mapped_file_region(int fd, 526 mapmode mode, 527 uint64_t length, 528 uint64_t offset, 529 error_code &ec) 530 : Mode(mode) 531 , Size(length) 532 , Mapping() { 533 // Make sure that the requested size fits within SIZE_T. 534 if (length > std::numeric_limits<size_t>::max()) { 535 ec = make_error_code(errc::invalid_argument); 536 return; 537 } 538 539 ec = init(fd, offset); 540 if (ec) 541 Mapping = 0; 542} 543 544mapped_file_region::~mapped_file_region() { 545 if (Mapping) 546 ::munmap(Mapping, Size); 547} 548 549#if LLVM_USE_RVALUE_REFERENCES 550mapped_file_region::mapped_file_region(mapped_file_region &&other) 551 : Mode(other.Mode), Size(other.Size), Mapping(other.Mapping) { 552 other.Mapping = 0; 553} 554#endif 555 556mapped_file_region::mapmode mapped_file_region::flags() const { 557 assert(Mapping && "Mapping failed but used anyway!"); 558 return Mode; 559} 560 561uint64_t mapped_file_region::size() const { 562 assert(Mapping && "Mapping failed but used anyway!"); 563 return Size; 564} 565 566char *mapped_file_region::data() const { 567 assert(Mapping && "Mapping failed but used anyway!"); 568 assert(Mode != readonly && "Cannot get non const data for readonly mapping!"); 569 return reinterpret_cast<char*>(Mapping); 570} 571 572const char *mapped_file_region::const_data() const { 573 assert(Mapping && "Mapping failed but used anyway!"); 574 return reinterpret_cast<const char*>(Mapping); 575} 576 577int mapped_file_region::alignment() { 578 return Process::GetPageSize(); 579} 580 581error_code detail::directory_iterator_construct(detail::DirIterState &it, 582 StringRef path){ 583 SmallString<128> path_null(path); 584 DIR *directory = ::opendir(path_null.c_str()); 585 if (directory == 0) 586 return error_code(errno, system_category()); 587 588 it.IterationHandle = reinterpret_cast<intptr_t>(directory); 589 // Add something for replace_filename to replace. 590 path::append(path_null, "."); 591 it.CurrentEntry = directory_entry(path_null.str()); 592 return directory_iterator_increment(it); 593} 594 595error_code detail::directory_iterator_destruct(detail::DirIterState &it) { 596 if (it.IterationHandle) 597 ::closedir(reinterpret_cast<DIR *>(it.IterationHandle)); 598 it.IterationHandle = 0; 599 it.CurrentEntry = directory_entry(); 600 return error_code::success(); 601} 602 603error_code detail::directory_iterator_increment(detail::DirIterState &it) { 604 errno = 0; 605 dirent *cur_dir = ::readdir(reinterpret_cast<DIR *>(it.IterationHandle)); 606 if (cur_dir == 0 && errno != 0) { 607 return error_code(errno, system_category()); 608 } else if (cur_dir != 0) { 609 StringRef name(cur_dir->d_name, NAMLEN(cur_dir)); 610 if ((name.size() == 1 && name[0] == '.') || 611 (name.size() == 2 && name[0] == '.' && name[1] == '.')) 612 return directory_iterator_increment(it); 613 it.CurrentEntry.replace_filename(name); 614 } else 615 return directory_iterator_destruct(it); 616 617 return error_code::success(); 618} 619 620error_code get_magic(const Twine &path, uint32_t len, 621 SmallVectorImpl<char> &result) { 622 SmallString<128> PathStorage; 623 StringRef Path = path.toNullTerminatedStringRef(PathStorage); 624 result.set_size(0); 625 626 // Open path. 627 std::FILE *file = std::fopen(Path.data(), "rb"); 628 if (file == 0) 629 return error_code(errno, system_category()); 630 631 // Reserve storage. 632 result.reserve(len); 633 634 // Read magic! 635 size_t size = std::fread(result.data(), 1, len, file); 636 if (std::ferror(file) != 0) { 637 std::fclose(file); 638 return error_code(errno, system_category()); 639 } else if (size != result.size()) { 640 if (std::feof(file) != 0) { 641 std::fclose(file); 642 result.set_size(size); 643 return make_error_code(errc::value_too_large); 644 } 645 } 646 std::fclose(file); 647 result.set_size(len); 648 return error_code::success(); 649} 650 651error_code map_file_pages(const Twine &path, off_t file_offset, size_t size, 652 bool map_writable, void *&result) { 653 SmallString<128> path_storage; 654 StringRef name = path.toNullTerminatedStringRef(path_storage); 655 int oflags = map_writable ? O_RDWR : O_RDONLY; 656 int ofd = ::open(name.begin(), oflags); 657 if ( ofd == -1 ) 658 return error_code(errno, system_category()); 659 AutoFD fd(ofd); 660 int flags = map_writable ? MAP_SHARED : MAP_PRIVATE; 661 int prot = map_writable ? (PROT_READ|PROT_WRITE) : PROT_READ; 662#ifdef MAP_FILE 663 flags |= MAP_FILE; 664#endif 665 result = ::mmap(0, size, prot, flags, fd, file_offset); 666 if (result == MAP_FAILED) { 667 return error_code(errno, system_category()); 668 } 669 670 return error_code::success(); 671} 672 673error_code unmap_file_pages(void *base, size_t size) { 674 if ( ::munmap(base, size) == -1 ) 675 return error_code(errno, system_category()); 676 677 return error_code::success(); 678} 679 680 681} // end namespace fs 682} // end namespace sys 683} // end namespace llvm 684