File indexing completed on 2024-10-12 04:20:44
0001
0002
0003
0004 #include <atomic>
0005 #include <cstdlib>
0006 #include <vector>
0007 #include <cassert>
0008 #include <filesystem>
0009
0010 #include "FWCore/Utilities/interface/FileInPath.h"
0011 #include "FWCore/Utilities/interface/EDMException.h"
0012 #include "FWCore/Utilities/interface/Parse.h"
0013 #include "FWCore/Utilities/interface/resolveSymbolicLinks.h"
0014
0015 namespace {
0016
0017 std::atomic<bool> s_fileLookupDisabled{false};
0018
0019
0020
0021
0022
0023 const std::string PathVariableName("CMSSW_SEARCH_PATH");
0024
0025 const std::string LOCALTOP("CMSSW_BASE");
0026 const std::string RELEASETOP("CMSSW_RELEASE_BASE");
0027 const std::string DATATOP("CMSSW_DATA_PATH");
0028
0029 #if 1
0030
0031
0032
0033 const std::string BASE("BASE");
0034 #endif
0035 const std::string version("V001");
0036
0037
0038 std::string removeSymLinks(std::string const& envName) {
0039 char const* const var = std::getenv(envName.c_str());
0040 if (var == nullptr) {
0041 return std::string();
0042 }
0043 std::string path = var;
0044 edm::resolveSymbolicLinks(path);
0045 return path;
0046 }
0047
0048 std::string removeSymLinksSrc(std::string const& envName) {
0049 char const* const var = std::getenv(envName.c_str());
0050 if (var == nullptr) {
0051 return std::string();
0052 }
0053 std::string const src = "/src";
0054 std::string path = var + src;
0055 edm::resolveSymbolicLinks(path);
0056 size_t actualSize = path.size() - src.size();
0057 assert(path.substr(actualSize, src.size()) == src);
0058 return path.substr(0, actualSize);
0059 }
0060
0061 std::string removeSymLinksTokens(std::string const& envName) {
0062 char const* const var = std::getenv(envName.c_str());
0063 if (var == nullptr) {
0064 return std::string();
0065 }
0066 std::string theSearchPath;
0067 typedef std::vector<std::string> stringvec_t;
0068 stringvec_t pathElements = edm::tokenize(std::string(var), ":");
0069 for (auto& element : pathElements) {
0070 edm::resolveSymbolicLinks(element);
0071 if (!theSearchPath.empty())
0072 theSearchPath += ":";
0073 theSearchPath += element;
0074 }
0075 return theSearchPath;
0076 }
0077
0078
0079
0080
0081
0082
0083
0084 bool locateFile(std::filesystem::path p, std::string const& relative) {
0085 p /= relative;
0086
0087 if (!std::filesystem::exists(p))
0088 return false;
0089
0090 if (std::filesystem::is_directory(p)) {
0091 throw edm::Exception(edm::errors::FileInPathError) << "Path " << p.string() << " is a directory, not a file\n";
0092 }
0093
0094 if (std::filesystem::is_symlink(std::filesystem::symlink_status(p))) {
0095 throw edm::Exception(edm::errors::FileInPathError)
0096 << "Path " << p.string() << " is a symbolic link, not a file\n";
0097 }
0098 return true;
0099 }
0100 }
0101
0102 namespace edm {
0103
0104 FileInPath::FileInPath() : relativePath_(), canonicalFilename_(), location_(Unknown) {
0105 if (s_fileLookupDisabled) {
0106 return;
0107 }
0108 getEnvironment();
0109 }
0110
0111 FileInPath::FileInPath(const std::string& r) : relativePath_(r), canonicalFilename_(), location_(Unknown) {
0112 if (s_fileLookupDisabled) {
0113 return;
0114 }
0115 getEnvironment();
0116 initialize_();
0117 }
0118
0119 FileInPath::FileInPath(char const* r) : relativePath_(r ? r : ""), canonicalFilename_(), location_(Unknown) {
0120 if (s_fileLookupDisabled) {
0121 return;
0122 }
0123 if (r == nullptr) {
0124 throw edm::Exception(edm::errors::FileInPathError) << "Relative path must not be null\n";
0125 }
0126 getEnvironment();
0127 initialize_();
0128 }
0129
0130 void FileInPath::swap(FileInPath& other) {
0131 relativePath_.swap(other.relativePath_);
0132 canonicalFilename_.swap(other.canonicalFilename_);
0133 std::swap(location_, other.location_);
0134 localTop_.swap(other.localTop_);
0135 releaseTop_.swap(other.releaseTop_);
0136 dataTop_.swap(other.dataTop_);
0137 searchPath_.swap(other.searchPath_);
0138 }
0139
0140 const std::string& FileInPath::relativePath() const { return relativePath_; }
0141
0142 FileInPath::LocationCode FileInPath::location() const { return location_; }
0143
0144 const std::string& FileInPath::fullPath() const { return canonicalFilename_; }
0145
0146 void FileInPath::write(std::ostream& os) const {
0147 if (location_ == Unknown) {
0148 if (relativePath_.empty()) {
0149 os << version << " @ " << location_;
0150 } else {
0151 os << version << ' ' << relativePath_ << ' ' << location_;
0152 }
0153 } else if (location_ == Local) {
0154
0155 if (localTop_.empty()) {
0156 throw edm::Exception(edm::errors::FileInPathError) << "Environment Variable " << LOCALTOP << " is not set.\n";
0157 }
0158 std::string::size_type pos = canonicalFilename_.find(localTop_);
0159 if (pos != 0) {
0160 throw edm::Exception(edm::errors::FileInPathError)
0161 << "Path " << canonicalFilename_ << " is not in the local release area " << localTop_ << "\n";
0162 }
0163 os << version << ' ' << relativePath_ << ' ' << location_ << ' ' << canonicalFilename_.substr(localTop_.size());
0164 } else if (location_ == Release) {
0165
0166 if (releaseTop_.empty()) {
0167 throw edm::Exception(edm::errors::FileInPathError) << "Environment Variable " << RELEASETOP << " is not set.\n";
0168 }
0169 std::string::size_type pos = canonicalFilename_.find(releaseTop_);
0170 if (pos != 0) {
0171 throw edm::Exception(edm::errors::FileInPathError)
0172 << "Path " << canonicalFilename_ << " is not in the base release area " << releaseTop_ << "\n";
0173 }
0174 os << version << ' ' << relativePath_ << ' ' << location_ << ' ' << canonicalFilename_.substr(releaseTop_.size());
0175 } else if (location_ == Data) {
0176
0177 if (dataTop_.empty()) {
0178 throw edm::Exception(edm::errors::FileInPathError) << "Environment Variable " << DATATOP << " is not set.\n";
0179 }
0180 std::string::size_type pos = canonicalFilename_.find(dataTop_);
0181 if (pos != 0) {
0182 throw edm::Exception(edm::errors::FileInPathError)
0183 << "Path " << canonicalFilename_ << " is not in the data area " << dataTop_ << "\n";
0184 }
0185 os << version << ' ' << relativePath_ << ' ' << location_ << ' ' << canonicalFilename_.substr(dataTop_.size());
0186 }
0187 }
0188
0189 void FileInPath::read(std::istream& is) {
0190 std::string vsn;
0191 std::string relname;
0192 std::string canFilename;
0193 #if 1
0194
0195
0196 is >> vsn;
0197 if (!is)
0198 return;
0199 bool oldFormat = (version != vsn);
0200 if (oldFormat) {
0201 relname = vsn;
0202 bool local;
0203 is >> local;
0204 location_ = (local ? Local : Release);
0205 is >> canFilename;
0206 } else {
0207
0208 int loc;
0209 is >> relname >> loc;
0210 location_ = static_cast<FileInPath::LocationCode>(loc);
0211 if (location_ != Unknown) {
0212 is >> canFilename;
0213 } else if (relname == "@") {
0214 relname = "";
0215 }
0216 }
0217 #else
0218 is >> vsn >> relname >> loc >> canFilename;
0219 #endif
0220 if (!is)
0221 return;
0222 relativePath_ = relname;
0223 if (location_ == Local) {
0224 if (localTop_.empty()) {
0225 throw edm::Exception(edm::errors::FileInPathError) << "Environment Variable " << LOCALTOP << " is not set.\n"
0226 << "Trying to read Local file: " << canFilename << ".\n";
0227 }
0228 #if 1
0229
0230
0231 if (oldFormat) {
0232 canonicalFilename_ = canFilename;
0233 } else
0234 #endif
0235 canonicalFilename_ = localTop_ + canFilename;
0236 } else if (location_ == Release) {
0237 if (releaseTop_.empty()) {
0238 throw edm::Exception(edm::errors::FileInPathError) << "Environment Variable " << RELEASETOP << " is not set.\n";
0239 }
0240 #if 1
0241
0242
0243 if (oldFormat) {
0244 std::string::size_type pos = canFilename.find(BASE);
0245 if (pos == 0) {
0246
0247 canonicalFilename_ = releaseTop_ + canFilename.substr(BASE.size());
0248 } else {
0249
0250 canonicalFilename_ = canFilename;
0251 }
0252 } else
0253 #endif
0254 canonicalFilename_ = releaseTop_ + canFilename;
0255 } else if (location_ == Data) {
0256 if (dataTop_.empty()) {
0257 throw edm::Exception(edm::errors::FileInPathError) << "Environment Variable " << DATATOP << " is not set.\n";
0258 }
0259 canonicalFilename_ = dataTop_ + canFilename;
0260 }
0261 }
0262
0263 void FileInPath::readFromParameterSetBlob(std::istream& is) {
0264 std::string vsn;
0265 std::string relname;
0266 std::string canFilename;
0267 is >> vsn;
0268 if (!is)
0269 return;
0270 bool oldFormat = (version != vsn);
0271 if (oldFormat) {
0272 relname = vsn;
0273 bool local;
0274 is >> local;
0275 location_ = (local ? Local : Release);
0276 is >> canFilename;
0277 } else {
0278
0279 int loc;
0280 is >> relname >> loc;
0281 location_ = static_cast<FileInPath::LocationCode>(loc);
0282 if (location_ != Unknown) {
0283 is >> canFilename;
0284 } else if (relname == "@") {
0285 relname = "";
0286 }
0287 }
0288 if (!is)
0289 return;
0290 relativePath_ = relname;
0291 if (location_ == Local) {
0292 if (localTop_.empty()) {
0293 localTop_ = "@LOCAL";
0294 }
0295 if (oldFormat) {
0296 canonicalFilename_ = canFilename;
0297 } else
0298 canonicalFilename_ = localTop_ + canFilename;
0299 } else if (location_ == Release) {
0300 if (releaseTop_.empty()) {
0301 releaseTop_ = "@RELEASE";
0302 }
0303 if (oldFormat) {
0304 std::string::size_type pos = canFilename.find(BASE);
0305 if (pos == 0) {
0306
0307 canonicalFilename_ = releaseTop_ + canFilename.substr(BASE.size());
0308 } else {
0309
0310 canonicalFilename_ = canFilename;
0311 }
0312 } else
0313 canonicalFilename_ = releaseTop_ + canFilename;
0314 } else if (location_ == Data) {
0315 if (dataTop_.empty()) {
0316 throw edm::Exception(edm::errors::FileInPathError) << "Environment Variable " << DATATOP << " is not set.\n";
0317 }
0318 canonicalFilename_ = dataTop_ + canFilename;
0319 }
0320 }
0321
0322
0323 std::string const& FileInPath::searchPath() {
0324 static std::string const s_searchPath = removeSymLinksTokens(PathVariableName);
0325 return s_searchPath;
0326 }
0327
0328
0329 void FileInPath::getEnvironment() {
0330 searchPath_ = searchPath();
0331 if (searchPath_.empty()) {
0332 throw edm::Exception(edm::errors::FileInPathError) << PathVariableName << " must be defined\n";
0333 }
0334
0335 static std::string const releaseTop = removeSymLinksSrc(RELEASETOP);
0336 releaseTop_ = releaseTop;
0337
0338 static std::string const localTop = removeSymLinksSrc(LOCALTOP);
0339 localTop_ = localTop;
0340
0341 static std::string const dataTop = removeSymLinks(DATATOP);
0342 dataTop_ = dataTop;
0343
0344 if (releaseTop_.empty()) {
0345
0346
0347
0348 releaseTop_ = localTop_;
0349 localTop_.clear();
0350 }
0351 if (releaseTop_ == localTop_) {
0352
0353
0354
0355 localTop_.clear();
0356 }
0357 }
0358
0359 void FileInPath::initialize_() {
0360 if (relativePath_.empty()) {
0361 throw edm::Exception(edm::errors::FileInPathError) << "Relative path must not be empty\n";
0362 }
0363
0364
0365 typedef std::vector<std::string> stringvec_t;
0366 stringvec_t pathElements = tokenize(searchPath_, ":");
0367 for (auto const& element : pathElements) {
0368
0369 std::filesystem::path pathPrefix(element);
0370
0371
0372
0373 if (locateFile(pathPrefix, relativePath_)) {
0374
0375 relativePath_ = std::filesystem::path(relativePath_).lexically_normal().string();
0376
0377
0378
0379 canonicalFilename_ = std::filesystem::absolute(pathPrefix / relativePath_).string();
0380 if (canonicalFilename_.empty()) {
0381 throw edm::Exception(edm::errors::FileInPathError)
0382 << "fullPath is empty"
0383 << "\nrelativePath() is: " << relativePath_ << "\npath prefix is: " << pathPrefix.string() << '\n';
0384 }
0385
0386
0387
0388 for (std::filesystem::path br = pathPrefix.parent_path();
0389 !std::filesystem::weakly_canonical(br).string().empty();
0390 br = br.parent_path()) {
0391 if (!localTop_.empty()) {
0392
0393 std::filesystem::path local_(localTop_);
0394
0395 if (br == local_) {
0396 location_ = Local;
0397 return;
0398 }
0399 }
0400
0401 if (!releaseTop_.empty()) {
0402
0403 std::filesystem::path release_(releaseTop_);
0404
0405 if (br == release_) {
0406 location_ = Release;
0407 return;
0408 }
0409 }
0410
0411 if (!dataTop_.empty()) {
0412
0413 std::filesystem::path data_(dataTop_);
0414
0415 if (br == data_) {
0416 location_ = Data;
0417 return;
0418 }
0419 }
0420 }
0421 }
0422 }
0423
0424
0425
0426 throw edm::Exception(edm::errors::FileInPathError)
0427 << "edm::FileInPath unable to find file " << relativePath_ << " anywhere in the search path."
0428 << "\nThe search path is defined by: " << PathVariableName << "\n${" << PathVariableName
0429 << "} is: " << std::getenv(PathVariableName.c_str())
0430 << "\nCurrent directory is: " << std::filesystem::current_path().string() << "\n";
0431 }
0432
0433 void FileInPath::disableFileLookup() { s_fileLookupDisabled = true; }
0434
0435 std::string FileInPath::findFile(const std::string& iFileName) {
0436
0437 auto pathElements = tokenize(searchPath(), ":");
0438 for (auto const& element : pathElements) {
0439
0440
0441 std::filesystem::path pathPrefix(element);
0442
0443
0444
0445 if (locateFile(pathPrefix, iFileName)) {
0446
0447 return std::filesystem::absolute(pathPrefix / iFileName).string();
0448 }
0449 }
0450 return {};
0451 }
0452
0453 }