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