File indexing completed on 2024-04-06 12:31:46
0001 #include "Utilities/DavixAdaptor/interface/DavixFile.h"
0002 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0003 #include "FWCore/Utilities/interface/EDMException.h"
0004 #include "FWCore/Utilities/interface/Exception.h"
0005 #include <cassert>
0006 #include <davix.hpp>
0007 #include <cerrno>
0008 #include <fcntl.h>
0009 #include <cstdlib>
0010 #include <unistd.h>
0011 #include <vector>
0012 #include <mutex>
0013
0014 static std::once_flag davixDebugInit;
0015
0016 using namespace Davix;
0017 using namespace edm::storage;
0018
0019 DavixFile::DavixFile(void) {}
0020
0021 DavixFile::DavixFile(const char *name, int flags , int perms ) {
0022 open(name, flags, perms);
0023 }
0024
0025 DavixFile::DavixFile(const std::string &name, int flags , int perms ) {
0026 open(name.c_str(), flags, perms);
0027 }
0028
0029 DavixFile::~DavixFile(void) {
0030 close();
0031 return;
0032 }
0033
0034 void DavixFile::close(void) {
0035 if (m_davixPosix && m_fd) {
0036 auto davixPosix = std::move(m_davixPosix);
0037 DavixError *err = nullptr;
0038 davixPosix->close(m_fd, &err);
0039 m_fd = nullptr;
0040 if (err) {
0041 std::unique_ptr<DavixError> davixErrManaged(err);
0042 cms::Exception ex("FileCloseError");
0043 ex << "Davix::close(name='" << m_name << ") failed with error " << err->getErrMsg().c_str() << " and error code "
0044 << err->getStatus();
0045 ex.addContext("Calling DavixFile::close()");
0046 throw ex;
0047 }
0048 }
0049 return;
0050 }
0051
0052 void DavixFile::abort(void) {
0053 if (m_davixPosix && m_fd) {
0054 DavixError *err = nullptr;
0055 m_davixPosix->close(m_fd, &err);
0056 if (err) {
0057 std::unique_ptr<DavixError> davixErrManaged(err);
0058 cms::Exception ex("FileAbortError");
0059 ex << "Davix::abort(name='" << m_name << ") failed with error " << err->getErrMsg().c_str() << " and error code "
0060 << err->getStatus();
0061 ex.addContext("Calling DavixFile::abort()");
0062 throw ex;
0063 }
0064 }
0065 return;
0066 }
0067
0068 void DavixFile::configureDavixLogLevel() {
0069 long logLevel = 0;
0070 char *logptr = nullptr;
0071 char const *const davixDebug = std::getenv("Davix_Debug");
0072 if (davixDebug != nullptr) {
0073 logLevel = strtol(davixDebug, &logptr, 0);
0074 if (errno) {
0075 edm::LogWarning("DavixFile") << "Got error while converting "
0076 << "Davix_Debug env variable to integer. "
0077 "Will use default log level 0";
0078 logLevel = 0;
0079 }
0080 if (logptr == davixDebug) {
0081 edm::LogWarning("DavixFile") << "Failed to convert to integer "
0082 << "Davix_Debug env variable; Will use default log level 0";
0083 logLevel = 0;
0084 } else if (*logptr != '\0') {
0085 edm::LogWarning("DavixFile") << "Failed to parse extra junk "
0086 << "from Davix_Debug env variable. Will use default log level 0";
0087 logLevel = 0;
0088 }
0089 }
0090 switch (logLevel) {
0091 case 0:
0092 std::call_once(davixDebugInit, davix_set_log_level, 0);
0093 break;
0094 case 1:
0095 std::call_once(davixDebugInit, davix_set_log_level, DAVIX_LOG_WARNING);
0096 break;
0097 case 2:
0098 std::call_once(davixDebugInit, davix_set_log_level, DAVIX_LOG_VERBOSE);
0099 break;
0100 case 3:
0101 std::call_once(davixDebugInit, davix_set_log_level, DAVIX_LOG_DEBUG);
0102 break;
0103 default:
0104 std::call_once(davixDebugInit, davix_set_log_level, DAVIX_LOG_ALL);
0105 break;
0106 }
0107 }
0108
0109 static int X509Authentication(void *userdata, const SessionInfo &info, X509Credential *cert, DavixError **davixErr) {
0110 std::string ucert, ukey;
0111 char default_proxy[64];
0112 snprintf(default_proxy, sizeof(default_proxy), "/tmp/x509up_u%d", geteuid());
0113
0114 if (std::getenv("X509_USER_PROXY")) {
0115 edm::LogInfo("DavixFile") << "X509_USER_PROXY found in environment."
0116 << " Will use it for authentication";
0117 ucert = ukey = std::getenv("X509_USER_PROXY");
0118 }
0119
0120 else if (access(default_proxy, R_OK) == 0) {
0121 edm::LogInfo("DavixFile") << "Found proxy in default location " << default_proxy
0122 << " Will use it for authentication";
0123 ucert = ukey = default_proxy;
0124 }
0125
0126 else if (std::getenv("X509_USER_CERT")) {
0127 ucert = std::getenv("X509_USER_CERT");
0128 }
0129
0130 if (!ucert.empty() && std::getenv("X509_USER_KEY")) {
0131 edm::LogInfo("DavixFile") << "X509_USER_{CERT|KEY} found in environment"
0132 << " Will use it for authentication";
0133 ukey = std::getenv("X509_USER_KEY");
0134 }
0135
0136 if (ucert.empty() || ukey.empty()) {
0137 edm::LogWarning("DavixFile") << "Was not able to find proxy in $X509_USER_PROXY, "
0138 << "X509_USER_{CERT|KEY} or default proxy creation location. "
0139 << "Will try without authentication";
0140 return -1;
0141 }
0142 return cert->loadFromFilePEM(ukey, ucert, "", davixErr);
0143 }
0144
0145 void DavixFile::create(const char *name, bool exclusive , int perms ) {
0146 open(name,
0147 (IOFlags::OpenCreate | IOFlags::OpenWrite | IOFlags::OpenTruncate | (exclusive ? IOFlags::OpenExclusive : 0)),
0148 perms);
0149 }
0150
0151 void DavixFile::create(const std::string &name, bool exclusive , int perms ) {
0152 open(name.c_str(),
0153 (IOFlags::OpenCreate | IOFlags::OpenWrite | IOFlags::OpenTruncate | (exclusive ? IOFlags::OpenExclusive : 0)),
0154 perms);
0155 }
0156
0157 void DavixFile::open(const std::string &name, int flags , int perms ) {
0158 open(name.c_str(), flags, perms);
0159 }
0160
0161 void DavixFile::open(const char *name, int flags , int perms ) {
0162
0163 if ((name == nullptr) || (*name == 0)) {
0164 edm::Exception ex(edm::errors::FileOpenError);
0165 ex << "Cannot open a file without name";
0166 ex.addContext("Calling DavixFile::open()");
0167 throw ex;
0168 }
0169 m_name = name;
0170
0171 if ((flags & IOFlags::OpenRead) == 0) {
0172 edm::Exception ex(edm::errors::FileOpenError);
0173 ex << "Must open file '" << name << "' at least for read";
0174 ex.addContext("Calling DavixFile::open()");
0175 throw ex;
0176 }
0177
0178 if (m_davixPosix && m_fd) {
0179 edm::Exception ex(edm::errors::FileOpenError);
0180 ex << "Davix::open(name='" << m_name << "') failed on already open file";
0181 ex.addContext("Calling DavixFile::open()");
0182 throw ex;
0183 }
0184 configureDavixLogLevel();
0185
0186 int openflags = 0;
0187
0188 if (flags & IOFlags::OpenRead)
0189 openflags |= O_RDONLY;
0190
0191 DavixError *davixErr = nullptr;
0192 RequestParams davixReqParams;
0193
0194 davixReqParams.setClientCertCallbackX509(&X509Authentication, nullptr);
0195
0196 const char *cert_dir = nullptr;
0197 if ((cert_dir = std::getenv("X509_CERT_DIR")) == nullptr)
0198 cert_dir = "/etc/grid-security/certificates";
0199 davixReqParams.addCertificateAuthorityPath(cert_dir);
0200
0201 m_davixPosix = std::make_unique<DavPosix>(new Context());
0202 m_fd = m_davixPosix->open(&davixReqParams, name, openflags, &davixErr);
0203
0204
0205 if (davixErr) {
0206 std::unique_ptr<DavixError> davixErrManaged(davixErr);
0207 edm::Exception ex(edm::errors::FileOpenError);
0208 ex << "Davix::open(name='" << m_name << "') failed with "
0209 << "error '" << davixErr->getErrMsg().c_str() << " and error code " << davixErr->getStatus();
0210 ex.addContext("Calling DavixFile::open()");
0211 throw ex;
0212 }
0213 if (!m_fd) {
0214 edm::Exception ex(edm::errors::FileOpenError);
0215 ex << "Davix::open(name='" << m_name << "') failed as fd is NULL";
0216 ex.addContext("Calling DavixFile::open()");
0217 throw ex;
0218 }
0219 }
0220
0221 IOSize DavixFile::readv(IOBuffer *into, IOSize buffers) {
0222 assert(!buffers || into);
0223
0224
0225 if (buffers == 0)
0226 return 0;
0227
0228 DavixError *davixErr = nullptr;
0229
0230 std::vector<DavIOVecInput> input_vector(buffers);
0231 std::vector<DavIOVecOuput> output_vector(buffers);
0232 IOSize total = 0;
0233 for (IOSize i = 0; i < buffers; ++i) {
0234 input_vector[i].diov_size = into[i].size();
0235 input_vector[i].diov_buffer = static_cast<char *>(into[i].data());
0236 total += into[i].size();
0237 }
0238
0239 ssize_t s = m_davixPosix->preadVec(m_fd, input_vector.data(), output_vector.data(), buffers, &davixErr);
0240 if (davixErr) {
0241 std::unique_ptr<DavixError> davixErrManaged(davixErr);
0242 edm::Exception ex(edm::errors::FileReadError);
0243 ex << "Davix::readv(name='" << m_name << "', buffers=" << (buffers) << ") failed with error "
0244 << davixErr->getErrMsg().c_str() << " and error code " << davixErr->getStatus() << " and call returned " << s
0245 << " bytes";
0246 ex.addContext("Calling DavixFile::readv()");
0247 throw ex;
0248 }
0249
0250
0251
0252
0253
0254
0255 if (s < 0) {
0256 edm::Exception ex(edm::errors::FileReadError);
0257 ex << "Davix::readv(name='" << m_name << "') failed and call returned " << s;
0258 ex.addContext("Calling DavixFile::readv()");
0259 throw ex;
0260 } else if (s == 0) {
0261
0262 return 0;
0263 }
0264 return total;
0265 }
0266
0267 IOSize DavixFile::readv(IOPosBuffer *into, IOSize buffers) {
0268 assert(!buffers || into);
0269
0270
0271 if (buffers == 0)
0272 return 0;
0273
0274 DavixError *davixErr = nullptr;
0275
0276 std::vector<DavIOVecInput> input_vector(buffers);
0277 std::vector<DavIOVecOuput> output_vector(buffers);
0278 IOSize total = 0;
0279 for (IOSize i = 0; i < buffers; ++i) {
0280 input_vector[i].diov_offset = into[i].offset();
0281 input_vector[i].diov_size = into[i].size();
0282 input_vector[i].diov_buffer = static_cast<char *>(into[i].data());
0283 total += into[i].size();
0284 }
0285 ssize_t s = m_davixPosix->preadVec(m_fd, input_vector.data(), output_vector.data(), buffers, &davixErr);
0286 if (davixErr) {
0287 std::unique_ptr<DavixError> davixErrManaged(davixErr);
0288 edm::Exception ex(edm::errors::FileReadError);
0289 ex << "Davix::readv(name='" << m_name << "', n=" << buffers << ") failed with error "
0290 << davixErr->getErrMsg().c_str() << " and error code " << davixErr->getStatus() << " and call returned " << s
0291 << " bytes";
0292 ex.addContext("Calling DavixFile::readv()");
0293 throw ex;
0294 }
0295
0296
0297
0298
0299
0300
0301 if (s < 0) {
0302 edm::Exception ex(edm::errors::FileReadError);
0303 ex << "Davix::readv(name='" << m_name << "', n=" << buffers << ") failed and call returned " << s;
0304 ex.addContext("Calling DavixFile::readv()");
0305 throw ex;
0306 } else if (s == 0) {
0307
0308 return 0;
0309 }
0310 return total;
0311 }
0312
0313 IOSize DavixFile::read(void *into, IOSize n) {
0314 DavixError *davixErr = nullptr;
0315 m_davixPosix->fadvise(m_fd, 0, n, AdviseRandom);
0316 IOSize done = 0;
0317 while (done < n) {
0318 ssize_t s = m_davixPosix->read(m_fd, (char *)into + done, n - done, &davixErr);
0319 if (davixErr) {
0320 std::unique_ptr<DavixError> davixErrManaged(davixErr);
0321 edm::Exception ex(edm::errors::FileReadError);
0322 ex << "Davix::read(name='" << m_name << "', n=" << (n - done) << ") failed with error "
0323 << davixErr->getErrMsg().c_str() << " and error code " << davixErr->getStatus() << " and call returned " << s
0324 << " bytes";
0325 ex.addContext("Calling DavixFile::read()");
0326 throw ex;
0327 }
0328 if (s < 0) {
0329 edm::Exception ex(edm::errors::FileReadError);
0330 ex << "Davix::read(name='" << m_name << "', n=" << (n - done) << ") failed and call returned " << s;
0331 ex.addContext("Calling DavixFile::read()");
0332 throw ex;
0333 } else if (s == 0) {
0334
0335 break;
0336 }
0337 done += s;
0338 }
0339 return done;
0340 }
0341
0342 IOSize DavixFile::write(const void *from, IOSize n) {
0343 edm::Exception ex(edm::errors::FileWriteError);
0344 ex << "DavixFile::write(name='" << m_name << "') not implemented";
0345 ex.addContext("Calling DavixFile::write()");
0346 throw ex;
0347 }
0348
0349 IOOffset DavixFile::position(IOOffset offset, Relative whence ) {
0350 DavixError *davixErr = nullptr;
0351 if (whence != CURRENT && whence != SET && whence != END) {
0352 cms::Exception ex("FilePositionError");
0353 ex << "DavixFile::position() called with incorrect 'whence' parameter";
0354 ex.addContext("Calling DavixFile::position()");
0355 throw ex;
0356 }
0357 IOOffset result;
0358 size_t mywhence = (whence == SET ? SEEK_SET : whence == CURRENT ? SEEK_CUR : SEEK_END);
0359
0360 if ((result = m_davixPosix->lseek(m_fd, offset, mywhence, &davixErr)) == -1) {
0361 cms::Exception ex("FilePositionError");
0362 ex << "Davix::lseek(name='" << m_name << "', offset=" << offset << ", whence=" << mywhence << ") failed with error "
0363 << davixErr->getErrMsg().c_str() << " and error code " << davixErr->getStatus() << " and "
0364 << "call returned " << result;
0365 ex.addContext("Calling DavixFile::position()");
0366 throw ex;
0367 }
0368
0369 return result;
0370 }
0371
0372 void DavixFile::resize(IOOffset ) {
0373 cms::Exception ex("FileResizeError");
0374 ex << "DavixFile::resize(name='" << m_name << "') not implemented";
0375 ex.addContext("Calling DavixFile::resize()");
0376 throw ex;
0377 }