File indexing completed on 2024-04-06 12:13:13
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 FileInPath::FileInPath(FileInPath const& other)
0131 : relativePath_(other.relativePath_),
0132 canonicalFilename_(other.canonicalFilename_),
0133 location_(other.location_),
0134 localTop_(other.localTop_),
0135 releaseTop_(other.releaseTop_),
0136 dataTop_(other.dataTop_),
0137 searchPath_(other.searchPath_) {}
0138
0139 FileInPath::~FileInPath() {}
0140
0141 FileInPath& FileInPath::operator=(FileInPath const& other) {
0142 FileInPath temp(other);
0143 this->swap(temp);
0144 return *this;
0145 }
0146
0147 void FileInPath::swap(FileInPath& other) {
0148 relativePath_.swap(other.relativePath_);
0149 canonicalFilename_.swap(other.canonicalFilename_);
0150 std::swap(location_, other.location_);
0151 localTop_.swap(other.localTop_);
0152 releaseTop_.swap(other.releaseTop_);
0153 dataTop_.swap(other.dataTop_);
0154 searchPath_.swap(other.searchPath_);
0155 }
0156
0157 std::string FileInPath::relativePath() const { return relativePath_; }
0158
0159 FileInPath::LocationCode FileInPath::location() const { return location_; }
0160
0161 std::string FileInPath::fullPath() const { return canonicalFilename_; }
0162
0163 void FileInPath::write(std::ostream& os) const {
0164 if (location_ == Unknown) {
0165 if (relativePath_.empty()) {
0166 os << version << " @ " << location_;
0167 } else {
0168 os << version << ' ' << relativePath_ << ' ' << location_;
0169 }
0170 } else if (location_ == Local) {
0171
0172 if (localTop_.empty()) {
0173 throw edm::Exception(edm::errors::FileInPathError) << "Environment Variable " << LOCALTOP << " is not set.\n";
0174 }
0175 std::string::size_type pos = canonicalFilename_.find(localTop_);
0176 if (pos != 0) {
0177 throw edm::Exception(edm::errors::FileInPathError)
0178 << "Path " << canonicalFilename_ << " is not in the local release area " << localTop_ << "\n";
0179 }
0180 os << version << ' ' << relativePath_ << ' ' << location_ << ' ' << canonicalFilename_.substr(localTop_.size());
0181 } else if (location_ == Release) {
0182
0183 if (releaseTop_.empty()) {
0184 throw edm::Exception(edm::errors::FileInPathError) << "Environment Variable " << RELEASETOP << " is not set.\n";
0185 }
0186 std::string::size_type pos = canonicalFilename_.find(releaseTop_);
0187 if (pos != 0) {
0188 throw edm::Exception(edm::errors::FileInPathError)
0189 << "Path " << canonicalFilename_ << " is not in the base release area " << releaseTop_ << "\n";
0190 }
0191 os << version << ' ' << relativePath_ << ' ' << location_ << ' ' << canonicalFilename_.substr(releaseTop_.size());
0192 } else if (location_ == Data) {
0193
0194 if (dataTop_.empty()) {
0195 throw edm::Exception(edm::errors::FileInPathError) << "Environment Variable " << DATATOP << " is not set.\n";
0196 }
0197 std::string::size_type pos = canonicalFilename_.find(dataTop_);
0198 if (pos != 0) {
0199 throw edm::Exception(edm::errors::FileInPathError)
0200 << "Path " << canonicalFilename_ << " is not in the data area " << dataTop_ << "\n";
0201 }
0202 os << version << ' ' << relativePath_ << ' ' << location_ << ' ' << canonicalFilename_.substr(dataTop_.size());
0203 }
0204 }
0205
0206 void FileInPath::read(std::istream& is) {
0207 std::string vsn;
0208 std::string relname;
0209 std::string canFilename;
0210 #if 1
0211
0212
0213 is >> vsn;
0214 if (!is)
0215 return;
0216 bool oldFormat = (version != vsn);
0217 if (oldFormat) {
0218 relname = vsn;
0219 bool local;
0220 is >> local;
0221 location_ = (local ? Local : Release);
0222 is >> canFilename;
0223 } else {
0224
0225 int loc;
0226 is >> relname >> loc;
0227 location_ = static_cast<FileInPath::LocationCode>(loc);
0228 if (location_ != Unknown) {
0229 is >> canFilename;
0230 } else if (relname == "@") {
0231 relname = "";
0232 }
0233 }
0234 #else
0235 is >> vsn >> relname >> loc >> canFilename;
0236 #endif
0237 if (!is)
0238 return;
0239 relativePath_ = relname;
0240 if (location_ == Local) {
0241 if (localTop_.empty()) {
0242 throw edm::Exception(edm::errors::FileInPathError) << "Environment Variable " << LOCALTOP << " is not set.\n"
0243 << "Trying to read Local file: " << canFilename << ".\n";
0244 }
0245 #if 1
0246
0247
0248 if (oldFormat) {
0249 canonicalFilename_ = canFilename;
0250 } else
0251 #endif
0252 canonicalFilename_ = localTop_ + canFilename;
0253 } else if (location_ == Release) {
0254 if (releaseTop_.empty()) {
0255 throw edm::Exception(edm::errors::FileInPathError) << "Environment Variable " << RELEASETOP << " is not set.\n";
0256 }
0257 #if 1
0258
0259
0260 if (oldFormat) {
0261 std::string::size_type pos = canFilename.find(BASE);
0262 if (pos == 0) {
0263
0264 canonicalFilename_ = releaseTop_ + canFilename.substr(BASE.size());
0265 } else {
0266
0267 canonicalFilename_ = canFilename;
0268 }
0269 } else
0270 #endif
0271 canonicalFilename_ = releaseTop_ + canFilename;
0272 } else if (location_ == Data) {
0273 if (dataTop_.empty()) {
0274 throw edm::Exception(edm::errors::FileInPathError) << "Environment Variable " << DATATOP << " is not set.\n";
0275 }
0276 canonicalFilename_ = dataTop_ + canFilename;
0277 }
0278 }
0279
0280 void FileInPath::readFromParameterSetBlob(std::istream& is) {
0281 std::string vsn;
0282 std::string relname;
0283 std::string canFilename;
0284 is >> vsn;
0285 if (!is)
0286 return;
0287 bool oldFormat = (version != vsn);
0288 if (oldFormat) {
0289 relname = vsn;
0290 bool local;
0291 is >> local;
0292 location_ = (local ? Local : Release);
0293 is >> canFilename;
0294 } else {
0295
0296 int loc;
0297 is >> relname >> loc;
0298 location_ = static_cast<FileInPath::LocationCode>(loc);
0299 if (location_ != Unknown) {
0300 is >> canFilename;
0301 } else if (relname == "@") {
0302 relname = "";
0303 }
0304 }
0305 if (!is)
0306 return;
0307 relativePath_ = relname;
0308 if (location_ == Local) {
0309 if (localTop_.empty()) {
0310 localTop_ = "@LOCAL";
0311 }
0312 if (oldFormat) {
0313 canonicalFilename_ = canFilename;
0314 } else
0315 canonicalFilename_ = localTop_ + canFilename;
0316 } else if (location_ == Release) {
0317 if (releaseTop_.empty()) {
0318 releaseTop_ = "@RELEASE";
0319 }
0320 if (oldFormat) {
0321 std::string::size_type pos = canFilename.find(BASE);
0322 if (pos == 0) {
0323
0324 canonicalFilename_ = releaseTop_ + canFilename.substr(BASE.size());
0325 } else {
0326
0327 canonicalFilename_ = canFilename;
0328 }
0329 } else
0330 canonicalFilename_ = releaseTop_ + canFilename;
0331 } else if (location_ == Data) {
0332 if (dataTop_.empty()) {
0333 throw edm::Exception(edm::errors::FileInPathError) << "Environment Variable " << DATATOP << " is not set.\n";
0334 }
0335 canonicalFilename_ = dataTop_ + canFilename;
0336 }
0337 }
0338
0339
0340 std::string const& FileInPath::searchPath() {
0341 static std::string const s_searchPath = removeSymLinksTokens(PathVariableName);
0342 return s_searchPath;
0343 }
0344
0345
0346 void FileInPath::getEnvironment() {
0347 searchPath_ = searchPath();
0348 if (searchPath_.empty()) {
0349 throw edm::Exception(edm::errors::FileInPathError) << PathVariableName << " must be defined\n";
0350 }
0351
0352 static std::string const releaseTop = removeSymLinksSrc(RELEASETOP);
0353 releaseTop_ = releaseTop;
0354
0355 static std::string const localTop = removeSymLinksSrc(LOCALTOP);
0356 localTop_ = localTop;
0357
0358 static std::string const dataTop = removeSymLinks(DATATOP);
0359 dataTop_ = dataTop;
0360
0361 if (releaseTop_.empty()) {
0362
0363
0364
0365 releaseTop_ = localTop_;
0366 localTop_.clear();
0367 }
0368 if (releaseTop_ == localTop_) {
0369
0370
0371
0372 localTop_.clear();
0373 }
0374 }
0375
0376 void FileInPath::initialize_() {
0377 if (relativePath_.empty()) {
0378 throw edm::Exception(edm::errors::FileInPathError) << "Relative path must not be empty\n";
0379 }
0380
0381
0382 typedef std::vector<std::string> stringvec_t;
0383 stringvec_t pathElements = tokenize(searchPath_, ":");
0384 for (auto const& element : pathElements) {
0385
0386 std::filesystem::path pathPrefix(element);
0387
0388
0389
0390 if (locateFile(pathPrefix, relativePath_)) {
0391
0392 relativePath_ = std::filesystem::path(relativePath_).lexically_normal().string();
0393
0394
0395
0396 canonicalFilename_ = std::filesystem::absolute(pathPrefix / relativePath_).string();
0397 if (canonicalFilename_.empty()) {
0398 throw edm::Exception(edm::errors::FileInPathError)
0399 << "fullPath is empty"
0400 << "\nrelativePath() is: " << relativePath_ << "\npath prefix is: " << pathPrefix.string() << '\n';
0401 }
0402
0403
0404
0405 for (std::filesystem::path br = pathPrefix.parent_path();
0406 !std::filesystem::weakly_canonical(br).string().empty();
0407 br = br.parent_path()) {
0408 if (!localTop_.empty()) {
0409
0410 std::filesystem::path local_(localTop_);
0411
0412 if (br == local_) {
0413 location_ = Local;
0414 return;
0415 }
0416 }
0417
0418 if (!releaseTop_.empty()) {
0419
0420 std::filesystem::path release_(releaseTop_);
0421
0422 if (br == release_) {
0423 location_ = Release;
0424 return;
0425 }
0426 }
0427
0428 if (!dataTop_.empty()) {
0429
0430 std::filesystem::path data_(dataTop_);
0431
0432 if (br == data_) {
0433 location_ = Data;
0434 return;
0435 }
0436 }
0437 }
0438 }
0439 }
0440
0441
0442
0443 throw edm::Exception(edm::errors::FileInPathError)
0444 << "edm::FileInPath unable to find file " << relativePath_ << " anywhere in the search path."
0445 << "\nThe search path is defined by: " << PathVariableName << "\n${" << PathVariableName
0446 << "} is: " << std::getenv(PathVariableName.c_str())
0447 << "\nCurrent directory is: " << std::filesystem::current_path().string() << "\n";
0448 }
0449
0450 void FileInPath::disableFileLookup() { s_fileLookupDisabled = true; }
0451
0452 std::string FileInPath::findFile(const std::string& iFileName) {
0453
0454 auto pathElements = tokenize(searchPath(), ":");
0455 for (auto const& element : pathElements) {
0456
0457
0458 std::filesystem::path pathPrefix(element);
0459
0460
0461
0462 if (locateFile(pathPrefix, iFileName)) {
0463
0464 return std::filesystem::absolute(pathPrefix / iFileName).string();
0465 }
0466 }
0467 return {};
0468 }
0469
0470 }