Home | History | Annotate | Download | only in Support
      1 //===-- Path.cpp - Implement OS Path Concept --------------------*- 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 header file implements the operating system Path concept.
     11 //
     12 //===----------------------------------------------------------------------===//
     13 
     14 #include "llvm/Support/Path.h"
     15 #include "llvm/Support/FileSystem.h"
     16 #include "llvm/Config/config.h"
     17 #include "llvm/Support/FileSystem.h"
     18 #include "llvm/Support/Endian.h"
     19 #include <cassert>
     20 #include <cstring>
     21 #include <ostream>
     22 using namespace llvm;
     23 using namespace sys;
     24 namespace {
     25 using support::ulittle32_t;
     26 }
     27 
     28 //===----------------------------------------------------------------------===//
     29 //=== WARNING: Implementation here must contain only TRULY operating system
     30 //===          independent code.
     31 //===----------------------------------------------------------------------===//
     32 
     33 bool Path::operator==(const Path &that) const {
     34   return path == that.path;
     35 }
     36 
     37 bool Path::operator<(const Path& that) const {
     38   return path < that.path;
     39 }
     40 
     41 Path
     42 Path::GetLLVMConfigDir() {
     43   Path result;
     44 #ifdef LLVM_ETCDIR
     45   if (result.set(LLVM_ETCDIR))
     46     return result;
     47 #endif
     48   return GetLLVMDefaultConfigDir();
     49 }
     50 
     51 LLVMFileType
     52 sys::IdentifyFileType(const char *magic, unsigned length) {
     53   assert(magic && "Invalid magic number string");
     54   assert(length >=4 && "Invalid magic number length");
     55   switch ((unsigned char)magic[0]) {
     56     case 0xDE:  // 0x0B17C0DE = BC wraper
     57       if (magic[1] == (char)0xC0 && magic[2] == (char)0x17 &&
     58           magic[3] == (char)0x0B)
     59         return Bitcode_FileType;
     60       break;
     61     case 'B':
     62       if (magic[1] == 'C' && magic[2] == (char)0xC0 && magic[3] == (char)0xDE)
     63         return Bitcode_FileType;
     64       break;
     65     case '!':
     66       if (length >= 8)
     67         if (memcmp(magic,"!<arch>\n",8) == 0)
     68           return Archive_FileType;
     69       break;
     70 
     71     case '\177':
     72       if (magic[1] == 'E' && magic[2] == 'L' && magic[3] == 'F') {
     73         if (length >= 18 && magic[17] == 0)
     74           switch (magic[16]) {
     75             default: break;
     76             case 1: return ELF_Relocatable_FileType;
     77             case 2: return ELF_Executable_FileType;
     78             case 3: return ELF_SharedObject_FileType;
     79             case 4: return ELF_Core_FileType;
     80           }
     81       }
     82       break;
     83 
     84     case 0xCA:
     85       if (magic[1] == char(0xFE) && magic[2] == char(0xBA) &&
     86           magic[3] == char(0xBE)) {
     87         // This is complicated by an overlap with Java class files.
     88         // See the Mach-O section in /usr/share/file/magic for details.
     89         if (length >= 8 && magic[7] < 43)
     90           // FIXME: Universal Binary of any type.
     91           return Mach_O_DynamicallyLinkedSharedLib_FileType;
     92       }
     93       break;
     94 
     95       // The two magic numbers for mach-o are:
     96       // 0xfeedface - 32-bit mach-o
     97       // 0xfeedfacf - 64-bit mach-o
     98     case 0xFE:
     99     case 0xCE:
    100     case 0xCF: {
    101       uint16_t type = 0;
    102       if (magic[0] == char(0xFE) && magic[1] == char(0xED) &&
    103           magic[2] == char(0xFA) &&
    104           (magic[3] == char(0xCE) || magic[3] == char(0xCF))) {
    105         /* Native endian */
    106         if (length >= 16) type = magic[14] << 8 | magic[15];
    107       } else if ((magic[0] == char(0xCE) || magic[0] == char(0xCF)) &&
    108                  magic[1] == char(0xFA) && magic[2] == char(0xED) &&
    109                  magic[3] == char(0xFE)) {
    110         /* Reverse endian */
    111         if (length >= 14) type = magic[13] << 8 | magic[12];
    112       }
    113       switch (type) {
    114         default: break;
    115         case 1: return Mach_O_Object_FileType;
    116         case 2: return Mach_O_Executable_FileType;
    117         case 3: return Mach_O_FixedVirtualMemorySharedLib_FileType;
    118         case 4: return Mach_O_Core_FileType;
    119         case 5: return Mach_O_PreloadExecutable_FileType;
    120         case 6: return Mach_O_DynamicallyLinkedSharedLib_FileType;
    121         case 7: return Mach_O_DynamicLinker_FileType;
    122         case 8: return Mach_O_Bundle_FileType;
    123         case 9: return Mach_O_DynamicallyLinkedSharedLibStub_FileType;
    124         case 10: return Mach_O_DSYMCompanion_FileType;
    125       }
    126       break;
    127     }
    128     case 0xF0: // PowerPC Windows
    129     case 0x83: // Alpha 32-bit
    130     case 0x84: // Alpha 64-bit
    131     case 0x66: // MPS R4000 Windows
    132     case 0x50: // mc68K
    133     case 0x4c: // 80386 Windows
    134       if (magic[1] == 0x01)
    135         return COFF_FileType;
    136 
    137     case 0x90: // PA-RISC Windows
    138     case 0x68: // mc68K Windows
    139       if (magic[1] == 0x02)
    140         return COFF_FileType;
    141       break;
    142 
    143     case 0x4d: // Possible MS-DOS stub on Windows PE file
    144       if (magic[1] == 0x5a) {
    145         uint32_t off = *reinterpret_cast<const ulittle32_t *>(magic + 0x3c);
    146         // PE/COFF file, either EXE or DLL.
    147         if (off < length && memcmp(magic + off, "PE\0\0",4) == 0)
    148           return COFF_FileType;
    149       }
    150       break;
    151 
    152     case 0x64: // x86-64 Windows.
    153       if (magic[1] == char(0x86))
    154         return COFF_FileType;
    155       break;
    156 
    157     default:
    158       break;
    159   }
    160   return Unknown_FileType;
    161 }
    162 
    163 bool
    164 Path::isArchive() const {
    165   LLVMFileType type;
    166   if (fs::identify_magic(str(), type))
    167     return false;
    168   return type == Archive_FileType;
    169 }
    170 
    171 bool
    172 Path::isDynamicLibrary() const {
    173   LLVMFileType type;
    174   if (fs::identify_magic(str(), type))
    175     return false;
    176   switch (type) {
    177     default: return false;
    178     case Mach_O_FixedVirtualMemorySharedLib_FileType:
    179     case Mach_O_DynamicallyLinkedSharedLib_FileType:
    180     case Mach_O_DynamicallyLinkedSharedLibStub_FileType:
    181     case ELF_SharedObject_FileType:
    182     case COFF_FileType:  return true;
    183   }
    184 }
    185 
    186 bool
    187 Path::isObjectFile() const {
    188   LLVMFileType type;
    189   if (fs::identify_magic(str(), type) || type == Unknown_FileType)
    190     return false;
    191   return true;
    192 }
    193 
    194 Path
    195 Path::FindLibrary(std::string& name) {
    196   std::vector<sys::Path> LibPaths;
    197   GetSystemLibraryPaths(LibPaths);
    198   for (unsigned i = 0; i < LibPaths.size(); ++i) {
    199     sys::Path FullPath(LibPaths[i]);
    200     FullPath.appendComponent("lib" + name + LTDL_SHLIB_EXT);
    201     if (FullPath.isDynamicLibrary())
    202       return FullPath;
    203     FullPath.eraseSuffix();
    204     FullPath.appendSuffix("a");
    205     if (FullPath.isArchive())
    206       return FullPath;
    207   }
    208   return sys::Path();
    209 }
    210 
    211 StringRef Path::GetDLLSuffix() {
    212   return &(LTDL_SHLIB_EXT[1]);
    213 }
    214 
    215 void
    216 Path::appendSuffix(StringRef suffix) {
    217   if (!suffix.empty()) {
    218     path.append(".");
    219     path.append(suffix);
    220   }
    221 }
    222 
    223 bool
    224 Path::isBitcodeFile() const {
    225   LLVMFileType type;
    226   if (fs::identify_magic(str(), type))
    227     return false;
    228   return type == Bitcode_FileType;
    229 }
    230 
    231 bool Path::hasMagicNumber(StringRef Magic) const {
    232   std::string actualMagic;
    233   if (getMagicNumber(actualMagic, static_cast<unsigned>(Magic.size())))
    234     return Magic == actualMagic;
    235   return false;
    236 }
    237 
    238 static void getPathList(const char*path, std::vector<Path>& Paths) {
    239   const char* at = path;
    240   const char* delim = strchr(at, PathSeparator);
    241   Path tmpPath;
    242   while (delim != 0) {
    243     std::string tmp(at, size_t(delim-at));
    244     if (tmpPath.set(tmp))
    245       if (tmpPath.canRead())
    246         Paths.push_back(tmpPath);
    247     at = delim + 1;
    248     delim = strchr(at, PathSeparator);
    249   }
    250 
    251   if (*at != 0)
    252     if (tmpPath.set(std::string(at)))
    253       if (tmpPath.canRead())
    254         Paths.push_back(tmpPath);
    255 }
    256 
    257 static StringRef getDirnameCharSep(StringRef path, const char *Sep) {
    258   assert(Sep[0] != '\0' && Sep[1] == '\0' &&
    259          "Sep must be a 1-character string literal.");
    260   if (path.empty())
    261     return ".";
    262 
    263   // If the path is all slashes, return a single slash.
    264   // Otherwise, remove all trailing slashes.
    265 
    266   signed pos = static_cast<signed>(path.size()) - 1;
    267 
    268   while (pos >= 0 && path[pos] == Sep[0])
    269     --pos;
    270 
    271   if (pos < 0)
    272     return path[0] == Sep[0] ? Sep : ".";
    273 
    274   // Any slashes left?
    275   signed i = 0;
    276 
    277   while (i < pos && path[i] != Sep[0])
    278     ++i;
    279 
    280   if (i == pos) // No slashes?  Return "."
    281     return ".";
    282 
    283   // There is at least one slash left.  Remove all trailing non-slashes.
    284   while (pos >= 0 && path[pos] != Sep[0])
    285     --pos;
    286 
    287   // Remove any trailing slashes.
    288   while (pos >= 0 && path[pos] == Sep[0])
    289     --pos;
    290 
    291   if (pos < 0)
    292     return path[0] == Sep[0] ? Sep : ".";
    293 
    294   return path.substr(0, pos+1);
    295 }
    296 
    297 // Include the truly platform-specific parts of this class.
    298 #if defined(LLVM_ON_UNIX)
    299 #include "Unix/Path.inc"
    300 #endif
    301 #if defined(LLVM_ON_WIN32)
    302 #include "Windows/Path.inc"
    303 #endif
    304