1218885Sdim//===-- Path.cpp - Implement OS Path Concept --------------------*- 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// 10218885Sdim// This header file implements the operating system Path concept. 11218885Sdim// 12218885Sdim//===----------------------------------------------------------------------===// 13218885Sdim 14218885Sdim#include "llvm/Support/Path.h" 15218885Sdim#include "llvm/Config/config.h" 16249423Sdim#include "llvm/Support/Endian.h" 17218885Sdim#include "llvm/Support/FileSystem.h" 18218885Sdim#include <cassert> 19218885Sdim#include <cstring> 20218885Sdim#include <ostream> 21218885Sdimusing namespace llvm; 22218885Sdimusing namespace sys; 23221345Sdimnamespace { 24221345Sdimusing support::ulittle32_t; 25221345Sdim} 26218885Sdim 27218885Sdim//===----------------------------------------------------------------------===// 28218885Sdim//=== WARNING: Implementation here must contain only TRULY operating system 29218885Sdim//=== independent code. 30218885Sdim//===----------------------------------------------------------------------===// 31218885Sdim 32218885Sdimbool Path::operator==(const Path &that) const { 33218885Sdim return path == that.path; 34218885Sdim} 35218885Sdim 36218885Sdimbool Path::operator<(const Path& that) const { 37218885Sdim return path < that.path; 38218885Sdim} 39218885Sdim 40218885SdimLLVMFileType 41218885Sdimsys::IdentifyFileType(const char *magic, unsigned length) { 42218885Sdim assert(magic && "Invalid magic number string"); 43218885Sdim assert(length >=4 && "Invalid magic number length"); 44218885Sdim switch ((unsigned char)magic[0]) { 45218885Sdim case 0xDE: // 0x0B17C0DE = BC wraper 46218885Sdim if (magic[1] == (char)0xC0 && magic[2] == (char)0x17 && 47218885Sdim magic[3] == (char)0x0B) 48218885Sdim return Bitcode_FileType; 49218885Sdim break; 50218885Sdim case 'B': 51218885Sdim if (magic[1] == 'C' && magic[2] == (char)0xC0 && magic[3] == (char)0xDE) 52218885Sdim return Bitcode_FileType; 53218885Sdim break; 54218885Sdim case '!': 55218885Sdim if (length >= 8) 56218885Sdim if (memcmp(magic,"!<arch>\n",8) == 0) 57218885Sdim return Archive_FileType; 58218885Sdim break; 59218885Sdim 60218885Sdim case '\177': 61218885Sdim if (magic[1] == 'E' && magic[2] == 'L' && magic[3] == 'F') { 62239462Sdim bool Data2MSB = magic[5] == 2; 63239462Sdim unsigned high = Data2MSB ? 16 : 17; 64239462Sdim unsigned low = Data2MSB ? 17 : 16; 65239462Sdim if (length >= 18 && magic[high] == 0) 66239462Sdim switch (magic[low]) { 67218885Sdim default: break; 68218885Sdim case 1: return ELF_Relocatable_FileType; 69218885Sdim case 2: return ELF_Executable_FileType; 70218885Sdim case 3: return ELF_SharedObject_FileType; 71218885Sdim case 4: return ELF_Core_FileType; 72218885Sdim } 73218885Sdim } 74218885Sdim break; 75218885Sdim 76218885Sdim case 0xCA: 77218885Sdim if (magic[1] == char(0xFE) && magic[2] == char(0xBA) && 78218885Sdim magic[3] == char(0xBE)) { 79218885Sdim // This is complicated by an overlap with Java class files. 80218885Sdim // See the Mach-O section in /usr/share/file/magic for details. 81218885Sdim if (length >= 8 && magic[7] < 43) 82218885Sdim // FIXME: Universal Binary of any type. 83218885Sdim return Mach_O_DynamicallyLinkedSharedLib_FileType; 84218885Sdim } 85218885Sdim break; 86218885Sdim 87221345Sdim // The two magic numbers for mach-o are: 88221345Sdim // 0xfeedface - 32-bit mach-o 89221345Sdim // 0xfeedfacf - 64-bit mach-o 90218885Sdim case 0xFE: 91221345Sdim case 0xCE: 92221345Sdim case 0xCF: { 93218885Sdim uint16_t type = 0; 94218885Sdim if (magic[0] == char(0xFE) && magic[1] == char(0xED) && 95234353Sdim magic[2] == char(0xFA) && 96221345Sdim (magic[3] == char(0xCE) || magic[3] == char(0xCF))) { 97218885Sdim /* Native endian */ 98218885Sdim if (length >= 16) type = magic[14] << 8 | magic[15]; 99221345Sdim } else if ((magic[0] == char(0xCE) || magic[0] == char(0xCF)) && 100221345Sdim magic[1] == char(0xFA) && magic[2] == char(0xED) && 101221345Sdim magic[3] == char(0xFE)) { 102218885Sdim /* Reverse endian */ 103218885Sdim if (length >= 14) type = magic[13] << 8 | magic[12]; 104218885Sdim } 105218885Sdim switch (type) { 106218885Sdim default: break; 107218885Sdim case 1: return Mach_O_Object_FileType; 108218885Sdim case 2: return Mach_O_Executable_FileType; 109218885Sdim case 3: return Mach_O_FixedVirtualMemorySharedLib_FileType; 110218885Sdim case 4: return Mach_O_Core_FileType; 111218885Sdim case 5: return Mach_O_PreloadExecutable_FileType; 112218885Sdim case 6: return Mach_O_DynamicallyLinkedSharedLib_FileType; 113218885Sdim case 7: return Mach_O_DynamicLinker_FileType; 114218885Sdim case 8: return Mach_O_Bundle_FileType; 115218885Sdim case 9: return Mach_O_DynamicallyLinkedSharedLibStub_FileType; 116226633Sdim case 10: return Mach_O_DSYMCompanion_FileType; 117218885Sdim } 118218885Sdim break; 119218885Sdim } 120218885Sdim case 0xF0: // PowerPC Windows 121218885Sdim case 0x83: // Alpha 32-bit 122218885Sdim case 0x84: // Alpha 64-bit 123218885Sdim case 0x66: // MPS R4000 Windows 124218885Sdim case 0x50: // mc68K 125218885Sdim case 0x4c: // 80386 Windows 126218885Sdim if (magic[1] == 0x01) 127218885Sdim return COFF_FileType; 128218885Sdim 129218885Sdim case 0x90: // PA-RISC Windows 130218885Sdim case 0x68: // mc68K Windows 131218885Sdim if (magic[1] == 0x02) 132218885Sdim return COFF_FileType; 133218885Sdim break; 134221345Sdim 135221345Sdim case 0x4d: // Possible MS-DOS stub on Windows PE file 136221345Sdim if (magic[1] == 0x5a) { 137221345Sdim uint32_t off = *reinterpret_cast<const ulittle32_t *>(magic + 0x3c); 138221345Sdim // PE/COFF file, either EXE or DLL. 139221345Sdim if (off < length && memcmp(magic + off, "PE\0\0",4) == 0) 140221345Sdim return COFF_FileType; 141221345Sdim } 142221345Sdim break; 143221345Sdim 144218885Sdim case 0x64: // x86-64 Windows. 145218885Sdim if (magic[1] == char(0x86)) 146218885Sdim return COFF_FileType; 147218885Sdim break; 148218885Sdim 149218885Sdim default: 150218885Sdim break; 151218885Sdim } 152218885Sdim return Unknown_FileType; 153218885Sdim} 154218885Sdim 155218885Sdimbool 156218885SdimPath::isArchive() const { 157234353Sdim fs::file_magic type; 158218885Sdim if (fs::identify_magic(str(), type)) 159218885Sdim return false; 160234353Sdim return type == fs::file_magic::archive; 161218885Sdim} 162218885Sdim 163218885Sdimbool 164218885SdimPath::isDynamicLibrary() const { 165234353Sdim fs::file_magic type; 166218885Sdim if (fs::identify_magic(str(), type)) 167218885Sdim return false; 168218885Sdim switch (type) { 169218885Sdim default: return false; 170234353Sdim case fs::file_magic::macho_fixed_virtual_memory_shared_lib: 171234353Sdim case fs::file_magic::macho_dynamically_linked_shared_lib: 172234353Sdim case fs::file_magic::macho_dynamically_linked_shared_lib_stub: 173234353Sdim case fs::file_magic::elf_shared_object: 174234353Sdim case fs::file_magic::pecoff_executable: return true; 175218885Sdim } 176218885Sdim} 177218885Sdim 178218885Sdimbool 179218885SdimPath::isObjectFile() const { 180234353Sdim fs::file_magic type; 181234353Sdim if (fs::identify_magic(str(), type) || type == fs::file_magic::unknown) 182218885Sdim return false; 183218885Sdim return true; 184218885Sdim} 185218885Sdim 186218885SdimPath 187218885SdimPath::FindLibrary(std::string& name) { 188218885Sdim std::vector<sys::Path> LibPaths; 189218885Sdim GetSystemLibraryPaths(LibPaths); 190218885Sdim for (unsigned i = 0; i < LibPaths.size(); ++i) { 191218885Sdim sys::Path FullPath(LibPaths[i]); 192218885Sdim FullPath.appendComponent("lib" + name + LTDL_SHLIB_EXT); 193218885Sdim if (FullPath.isDynamicLibrary()) 194218885Sdim return FullPath; 195218885Sdim FullPath.eraseSuffix(); 196218885Sdim FullPath.appendSuffix("a"); 197218885Sdim if (FullPath.isArchive()) 198218885Sdim return FullPath; 199218885Sdim } 200218885Sdim return sys::Path(); 201218885Sdim} 202218885Sdim 203218885SdimStringRef Path::GetDLLSuffix() { 204218885Sdim return &(LTDL_SHLIB_EXT[1]); 205218885Sdim} 206218885Sdim 207218885Sdimvoid 208218885SdimPath::appendSuffix(StringRef suffix) { 209218885Sdim if (!suffix.empty()) { 210218885Sdim path.append("."); 211218885Sdim path.append(suffix); 212218885Sdim } 213218885Sdim} 214218885Sdim 215218885Sdimbool 216218885SdimPath::isBitcodeFile() const { 217234353Sdim fs::file_magic type; 218218885Sdim if (fs::identify_magic(str(), type)) 219218885Sdim return false; 220234353Sdim return type == fs::file_magic::bitcode; 221218885Sdim} 222218885Sdim 223218885Sdimbool Path::hasMagicNumber(StringRef Magic) const { 224218885Sdim std::string actualMagic; 225218885Sdim if (getMagicNumber(actualMagic, static_cast<unsigned>(Magic.size()))) 226218885Sdim return Magic == actualMagic; 227218885Sdim return false; 228218885Sdim} 229218885Sdim 230218885Sdimstatic void getPathList(const char*path, std::vector<Path>& Paths) { 231218885Sdim const char* at = path; 232218885Sdim const char* delim = strchr(at, PathSeparator); 233218885Sdim Path tmpPath; 234218885Sdim while (delim != 0) { 235218885Sdim std::string tmp(at, size_t(delim-at)); 236218885Sdim if (tmpPath.set(tmp)) 237218885Sdim if (tmpPath.canRead()) 238218885Sdim Paths.push_back(tmpPath); 239218885Sdim at = delim + 1; 240218885Sdim delim = strchr(at, PathSeparator); 241218885Sdim } 242218885Sdim 243218885Sdim if (*at != 0) 244218885Sdim if (tmpPath.set(std::string(at))) 245218885Sdim if (tmpPath.canRead()) 246218885Sdim Paths.push_back(tmpPath); 247218885Sdim} 248218885Sdim 249218885Sdimstatic StringRef getDirnameCharSep(StringRef path, const char *Sep) { 250218885Sdim assert(Sep[0] != '\0' && Sep[1] == '\0' && 251218885Sdim "Sep must be a 1-character string literal."); 252218885Sdim if (path.empty()) 253218885Sdim return "."; 254218885Sdim 255218885Sdim // If the path is all slashes, return a single slash. 256218885Sdim // Otherwise, remove all trailing slashes. 257218885Sdim 258218885Sdim signed pos = static_cast<signed>(path.size()) - 1; 259218885Sdim 260218885Sdim while (pos >= 0 && path[pos] == Sep[0]) 261218885Sdim --pos; 262218885Sdim 263218885Sdim if (pos < 0) 264218885Sdim return path[0] == Sep[0] ? Sep : "."; 265218885Sdim 266218885Sdim // Any slashes left? 267218885Sdim signed i = 0; 268218885Sdim 269218885Sdim while (i < pos && path[i] != Sep[0]) 270218885Sdim ++i; 271218885Sdim 272218885Sdim if (i == pos) // No slashes? Return "." 273218885Sdim return "."; 274218885Sdim 275218885Sdim // There is at least one slash left. Remove all trailing non-slashes. 276218885Sdim while (pos >= 0 && path[pos] != Sep[0]) 277218885Sdim --pos; 278218885Sdim 279218885Sdim // Remove any trailing slashes. 280218885Sdim while (pos >= 0 && path[pos] == Sep[0]) 281218885Sdim --pos; 282218885Sdim 283218885Sdim if (pos < 0) 284218885Sdim return path[0] == Sep[0] ? Sep : "."; 285218885Sdim 286218885Sdim return path.substr(0, pos+1); 287218885Sdim} 288218885Sdim 289218885Sdim// Include the truly platform-specific parts of this class. 290218885Sdim#if defined(LLVM_ON_UNIX) 291218885Sdim#include "Unix/Path.inc" 292218885Sdim#endif 293218885Sdim#if defined(LLVM_ON_WIN32) 294218885Sdim#include "Windows/Path.inc" 295218885Sdim#endif 296