1139823Simp// CODYlib -*- mode:c++ -*- 21541Srgrimes// Copyright (C) 2020 Nathan Sidwell, nathan@acm.org 31541Srgrimes// License: Apache v2.0 41541Srgrimes 51541Srgrimes// Cody 61541Srgrimes#include "internal.hh" 71541Srgrimes// OS 81541Srgrimes#include <fcntl.h> 91541Srgrimes#include <unistd.h> 101541Srgrimes#include <sys/stat.h> 111541Srgrimes#include <sys/types.h> 121541Srgrimes 131541Srgrimes#if ((defined (__unix__) \ 141541Srgrimes && defined _POSIX_C_SOURCE \ 151541Srgrimes && (_POSIX_C_SOURCE - 0) >= 200809L) \ 161541Srgrimes || (defined (__Apple__) \ 171541Srgrimes && defined (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) \ 181541Srgrimes && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 101000)) 191541Srgrimes// Autoconf test? 201541Srgrimes#define HAVE_FSTATAT 1 211541Srgrimes#else 221541Srgrimes#define HAVE_FSTATAT 0 231541Srgrimes#endif 241541Srgrimes 251541Srgrimes// Resolver code 261541Srgrimes 271541Srgrimes#if __windows__ 281541Srgrimesinline bool IsDirSep (char c) 291541Srgrimes{ 301541Srgrimes return c == '/' || c == '\\'; 311541Srgrimes} 3222521Sdysoninline bool IsAbsPath (char const *str) 331541Srgrimes{ 341541Srgrimes // IIRC windows has the concept of per-drive current directories, 3583651Speter // which make drive-using paths confusing. Let's not get into that. 3683651Speter return IsDirSep (str) 3783651Speter || (((str[0] >= 'A' && str[0] <= 'Z') 381541Srgrimes || (str[0] >= 'a' && str[0] <= 'z'))&& str[1] == ':'); 391541Srgrimes} 4012274Sbde#else 411541Srgrimesinline bool IsDirSep (char c) 4219449Sdfr{ 431541Srgrimes return c == '/'; 4415480Sbde} 451541Srgrimesinline bool IsAbsPath (char const *str) 4630354Sphk{ 471541Srgrimes return IsDirSep (str[0]); 481541Srgrimes} 4960041Sphk#endif 501541Srgrimes 511541Srgrimesconstexpr char DIR_SEPARATOR = '/'; 521541Srgrimes 531541Srgrimesconstexpr char DOT_REPLACE = ','; // Replace . directories 541541Srgrimesconstexpr char COLON_REPLACE = '-'; // Replace : (partition char) 551541Srgrimesconstexpr char const REPO_DIR[] = "cmi.cache"; 561541Srgrimes 5783651Speternamespace Cody { 5883651Speter 5975631SalfredResolver::~Resolver () 6075631Salfred{ 6183651Speter} 621541Srgrimes 631541Srgrimeschar const *Resolver::GetCMISuffix () 641541Srgrimes{ 65122698Salfred return "cmi"; 66122698Salfred} 67122698Salfred 689336Sdfrstd::string Resolver::GetCMIName (std::string const &module) 691541Srgrimes{ 709336Sdfr std::string result; 7183651Speter 7283651Speter result.reserve (module.size () + 8); 7383651Speter bool is_header = false; 7483651Speter bool is_abs = false; 7583651Speter 761541Srgrimes if (IsAbsPath (module.c_str ())) 77151897Srwatson is_header = is_abs = true; 7830309Sphk else if (module.front () == '.' && IsDirSep (module.c_str ()[1])) 7983651Speter is_header = true; 801541Srgrimes 811541Srgrimes if (is_abs) 8212457Sbde { 8344112Sdfr result.push_back ('.'); 8444112Sdfr result.append (module); 8589407Speter } 8689407Speter else 8789407Speter result = std::move (module); 8889407Speter 8989407Speter if (is_header) 90128111Speadar { 9189407Speter if (!is_abs) 9289324Speter result[0] = DOT_REPLACE; 9389324Speter 9489324Speter /* Map .. to DOT_REPLACE, DOT_REPLACE. */ 9589407Speter for (size_t ix = 1; ; ix++) 9689407Speter { 9789407Speter ix = result.find ('.', ix); 9889407Speter if (ix == result.npos) 9989407Speter break; 10089324Speter if (ix + 2 > result.size ()) 10189407Speter break; 10289407Speter if (result[ix + 1] != '.') 10389407Speter continue; 10489407Speter if (!IsDirSep (result[ix - 1])) 10589407Speter continue; 10689407Speter if (!IsDirSep (result[ix + 2])) 10789407Speter continue; 10889407Speter result[ix] = DOT_REPLACE; 10989407Speter result[ix + 1] = DOT_REPLACE; 11089407Speter } 11189407Speter } 11289407Speter else if (COLON_REPLACE != ':') 11389407Speter { 11489407Speter // There can only be one colon in a module name 11589407Speter auto colon = result.find (':'); 11689407Speter if (colon != result.npos) 11789407Speter result[colon] = COLON_REPLACE; 11889407Speter } 11989407Speter 12089407Speter if (char const *suffix = GetCMISuffix ()) 12189407Speter { 12289407Speter result.push_back ('.'); 12389407Speter result.append (suffix); 12489407Speter } 12589407Speter 12689407Speter return result; 12789407Speter} 12889407Speter 12989407Spetervoid Resolver::WaitUntilReady (Server *) 13089407Speter{ 13189407Speter} 13289407Speter 13389407SpeterResolver *Resolver::ConnectRequest (Server *s, unsigned version, 13489407Speter std::string &, std::string &) 13589407Speter{ 13689407Speter if (version > Version) 13789407Speter s->ErrorResponse ("version mismatch"); 13889407Speter else 13989407Speter s->ConnectResponse ("default"); 14089407Speter 14189407Speter return this; 14289407Speter} 14389407Speter 14489407Speterint Resolver::ModuleRepoRequest (Server *s) 14589407Speter{ 146111748Sdes s->PathnameResponse (REPO_DIR); 14789407Speter return 0; 14889407Speter} 14989407Speter 15089407Speter// Deprecated resolver functions 15189407Speterint Resolver::ModuleExportRequest (Server *s, Flags, std::string &module) 15289407Speter{ 15389407Speter auto cmi = GetCMIName (module); 15489324Speter s->PathnameResponse (cmi); 15589324Speter return 0; 15689324Speter} 15789324Speter 15889324Speterint Resolver::ModuleImportRequest (Server *s, Flags, std::string &module) 15989324Speter{ 16089407Speter auto cmi = GetCMIName (module); 16189407Speter s->PathnameResponse (cmi); 16289324Speter return 0; 16389407Speter} 16489324Speter 16589324Speterint Resolver::ModuleCompiledRequest (Server *s, Flags, std::string &) 16689324Speter{ 16789324Speter s->OKResponse (); 16889324Speter return 0; 16989324Speter} 17089324Speter 17189324Speterint Resolver::IncludeTranslateRequest (Server *s, Flags, std::string &include) 172104354Sscottl{ 17389324Speter bool xlate = false; 17489324Speter 17589324Speter // This is not the most efficient 17689324Speter auto cmi = GetCMIName (include); 17789324Speter struct stat statbuf; 17889324Speter 17983651Speter#if HAVE_FSTATAT 18083651Speter int fd_dir = open (REPO_DIR, O_RDONLY | O_CLOEXEC | O_DIRECTORY); 1811541Srgrimes if (fd_dir >= 0 18283651Speter && fstatat (fd_dir, cmi.c_str (), &statbuf, 0) == 0 1831541Srgrimes && S_ISREG (statbuf.st_mode)) 1841541Srgrimes // Sadly can't easily check if this process has read access, 18589324Speter // except by trying to open it. 18689324Speter xlate = true; 18789324Speter if (fd_dir >= 0) 18889324Speter close (fd_dir); 18989324Speter#else 19089324Speter std::string append = REPO_DIR; 19189324Speter append.push_back (DIR_SEPARATOR); 19289324Speter append.append (cmi); 19389324Speter if (stat (append.c_str (), &statbuf) == 0 1941541Srgrimes || S_ISREG (statbuf.st_mode)) 1951541Srgrimes xlate = true; 19683651Speter#endif 1971541Srgrimes 19883651Speter if (xlate) 19983651Speter s->PathnameResponse (cmi); 2001541Srgrimes else 20144246Speter s->BoolResponse (false); 2021541Srgrimes 2031541Srgrimes return 0; 20489324Speter} 2051541Srgrimes 20683651Spetervoid Resolver::ErrorResponse (Server *server, std::string &&msg) 20789324Speter{ 2081541Srgrimes server->ErrorResponse (msg); 20983651Speter} 21019449Sdfr 21189324Speter} 21231016Sphk