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