56 static const std::string VERSION =
"0.2.0";
58 static const std::string gUserAgent =
"ROOT/" + std::string(gROOT->GetVersion()) +
59 " TDavixFile/" + VERSION +
" davix/" + Davix::version();
62 #define ENVPFX "Davix."
66 using namespace Davix;
68 const char* grid_mode_opt =
"grid_mode=yes";
69 const char* ca_check_opt =
"ca_check=no";
70 const char* s3_seckey_opt =
"s3seckey=";
71 const char* s3_acckey_opt =
"s3acckey=";
72 const char* s3_region_opt =
"s3region=";
73 const char* s3_token_opt =
"s3token=";
74 const char* s3_alternate_opt =
"s3alternate=";
75 const char* open_mode_read =
"READ";
76 const char* open_mode_create =
"CREATE";
77 const char* open_mode_new =
"NEW";
78 const char* open_mode_update =
"UPDATE";
80 static TMutex createLock;
81 static Context* davix_context_s = NULL;
86 bool isno(
const char *str)
88 if (!str)
return false;
90 if (!strcmp(str,
"n") || !strcmp(str,
"no") || !strcmp(str,
"0") || !strcmp(str,
"false"))
return true;
96 bool strToBool(
const char *str,
bool defvalue) {
97 if(!str)
return defvalue;
99 if(strcmp(str,
"n") == 0 || strcmp(str,
"no") == 0 || strcmp(str,
"0") == 0 || strcmp(str,
"false") == 0)
return false;
100 if(strcmp(str,
"y") == 0 || strcmp(str,
"yes") == 0 || strcmp(str,
"1") == 0 || strcmp(str,
"true") == 0)
return true;
107 int configure_open_flag(
const std::string &str,
int old_flag)
109 if (strcasecmp(str.c_str(), open_mode_read) == 0)
110 old_flag |= O_RDONLY;
111 if ((strcasecmp(str.c_str(), open_mode_create) == 0)
112 || (strcasecmp(str.c_str(), open_mode_new) == 0)) {
113 old_flag |= (O_CREAT | O_WRONLY | O_TRUNC);
115 if ((strcasecmp(str.c_str(), open_mode_update) == 0)) {
116 old_flag |= (O_RDWR);
123 static void ConfigureDavixLogLevel()
125 Int_t log_level = (gEnv) ? gEnv->GetValue(
"Davix.Debug", 0) : 0;
129 davix_set_log_level(0);
132 davix_set_log_level(DAVIX_LOG_WARNING);
135 davix_set_log_level(DAVIX_LOG_VERBOSE);
138 davix_set_log_level(DAVIX_LOG_DEBUG);
141 davix_set_log_level(DAVIX_LOG_ALL);
151 static void TDavixFile_http_get_ucert(std::string &ucert, std::string &ukey)
153 char default_proxy[64];
154 const char *genvvar = 0, *genvvar1 = 0;
156 genvvar = gEnv->GetValue(
"Davix.GSI.UserProxy", (
const char *) NULL);
158 ucert = ukey = genvvar;
160 Info(
"TDavixFile_http_get_ucert",
"Found proxy in gEnv");
165 if (getenv(
"X509_USER_PROXY")) {
167 Info(
"TDavixFile_http_get_ucert",
"Found proxy in X509_USER_PROXY");
168 ucert = ukey = getenv(
"X509_USER_PROXY");
173 snprintf(default_proxy,
sizeof(default_proxy),
"/tmp/x509up_u%d",
176 if (access(default_proxy, R_OK) == 0) {
178 Info(
"TDavixFile_http_get_ucert",
"Found proxy in /tmp");
179 ucert = ukey = default_proxy;
184 genvvar = gEnv->GetValue(
"Davix.GSI.UserCert", (
const char *) NULL);
185 genvvar1 = gEnv->GetValue(
"Davix.GSI.UserKey", (
const char *) NULL);
186 if (genvvar || genvvar1) {
188 Info(
"TDavixFile_http_get_ucert",
"Found cert and key in gEnv");
196 if (getenv(
"X509_USER_CERT"))
197 ucert = getenv(
"X509_USER_CERT");
198 if (getenv(
"X509_USER_KEY"))
199 ukey = getenv(
"X509_USER_KEY");
201 if ((ucert.size() > 0) || (ukey.size() > 0)) {
203 Info(
"TDavixFile_http_get_ucert",
"Found cert and key in gEnv");
211 static int TDavixFile_http_authn_cert_X509(
void *userdata,
const Davix::SessionInfo &info,
212 Davix::X509Credential *cert, Davix::DavixError **err)
216 std::string ucert, ukey;
217 TDavixFile_http_get_ucert(ucert, ukey);
219 if (ucert.empty() || ukey.empty()) {
220 Davix::DavixError::setupError(err,
"TDavixFile",
221 Davix::StatusCode::AuthentificationError,
222 "Could not set the user's proxy or certificate");
225 return cert->loadFromFilePEM(ukey, ucert,
"", err);
231 TDavixFileInternal::~TDavixFileInternal()
239 Context *TDavixFileInternal::getDavixInstance()
241 if (davix_context_s == NULL) {
242 TLockGuard guard(&createLock);
243 if (davix_context_s == NULL) {
244 davix_context_s =
new Context();
247 return davix_context_s;
252 Davix_fd *TDavixFileInternal::Open()
254 DavixError *davixErr = NULL;
255 Davix_fd *fd = davixPosix->open(davixParam, fUrl.GetUrl(), oflags, &davixErr);
262 DavixError *davixErr2 = NULL;
264 DavFile file(*davixContext, Davix::Uri(fUrl.GetUrl()));
265 std::vector<DavFile> replicasLocal = file.getReplicas(NULL, &davixErr2);
266 for(
size_t i = 0; i < replicasLocal.size(); i++) {
267 replicas.push_back(replicasLocal[i].getUri().getString());
271 DavixError::clearError(&davixErr2);
273 if(replicas.empty()) {
276 Error(
"DavixOpen",
"can not open file \"%s\" with davix: %s (%d)",
278 davixErr->getErrMsg().c_str(), davixErr->getStatus());
280 DavixError::clearError(&davixErr);
283 davixPosix->fadvise(fd, 0, 300, Davix::AdviseRandom);
291 void TDavixFileInternal::Close()
293 DavixError *davixErr = NULL;
294 if (davixFd != NULL && davixPosix->close(davixFd, &davixErr)) {
295 Error(
"DavixClose",
"can not to close file with davix: %s (%d)",
296 davixErr->getErrMsg().c_str(), davixErr->getStatus());
297 DavixError::clearError(&davixErr);
303 void TDavixFileInternal::enableGridMode()
305 const char *env_var = NULL;
308 Info(
"enableGridMode",
" grid mode enabled !");
310 if( ( env_var = getenv(
"X509_CERT_DIR")) == NULL){
311 env_var=
"/etc/grid-security/certificates/";
313 davixParam->addCertificateAuthorityPath(env_var);
315 Info(
"enableGridMode",
"Adding CAdir %s", env_var);
328 template<
typename TRequestParams = Davix::RequestParams>
329 static auto awsRegion(TRequestParams *parameters,
const char *region)
330 -> decltype(parameters->setAwsRegion(region), void())
332 if (gDebug > 1) Info(
"awsRegion",
"Setting S3 Region to '%s' - v4 signature will be used", region);
333 parameters->setAwsRegion(region);
336 template<
typename TRequestParams = Davix::RequestParams>
337 static void awsRegion(...) {
338 Warning(
"setAwsRegion",
"Unable to set AWS region, not supported by this version of davix");
342 template<
typename TRequestParams = Davix::RequestParams>
343 static auto awsToken(TRequestParams *parameters,
const char *token)
344 -> decltype(parameters->setAwsToken(token), void())
346 if (gDebug > 1) Info(
"awsToken",
"Setting S3 STS temporary credentials");
347 parameters->setAwsToken(token);
350 template<
typename TRequestParams = Davix::RequestParams>
351 static void awsToken(...) {
352 Warning(
"awsToken",
"Unable to set AWS token, not supported by this version of davix");
356 template<
typename TRequestParams = Davix::RequestParams>
357 static auto awsAlternate(TRequestParams *parameters,
bool option)
358 -> decltype(parameters->setAwsAlternate(option), void())
360 if (gDebug > 1) Info(
"awsAlternate",
"Setting S3 path-based bucket option (s3alternate)");
361 parameters->setAwsAlternate(option);
364 template<
typename TRequestParams = Davix::RequestParams>
365 static void awsAlternate(...) {
366 Warning(
"awsAlternate",
"Unable to set AWS path-based bucket option (s3alternate), not supported by this version of davix");
369 void TDavixFileInternal::setAwsRegion(
const std::string & region) {
370 if(!region.empty()) {
371 awsRegion(davixParam, region.c_str());
375 void TDavixFileInternal::setAwsToken(
const std::string & token) {
377 awsToken(davixParam, token.c_str());
381 void TDavixFileInternal::setAwsAlternate(
const bool & option) {
382 awsAlternate(davixParam, option);
386 void TDavixFileInternal::setS3Auth(
const std::string &secret,
const std::string &access,
387 const std::string ®ion,
const std::string &token)
390 Info(
"setS3Auth",
" Aws S3 tokens configured");
392 davixParam->setAwsAuthorizationKeys(secret, access);
393 davixParam->setProtocol(RequestProtocol::AwsS3);
395 setAwsRegion(region);
401 void TDavixFileInternal::parseConfig()
403 const char *env_var = NULL, *env_var2 = NULL;
405 davixParam->setTransparentRedirectionSupport(
true);
406 davixParam->setClientCertCallbackX509(&TDavixFile_http_authn_cert_X509, NULL);
409 env_var = gEnv->GetValue(
"Davix.GSI.CAdir", (
const char *) NULL);
411 davixParam->addCertificateAuthorityPath(env_var);
413 Info(
"parseConfig",
"Add CAdir: %s", env_var);
416 bool ca_check_local = !isno(gEnv->GetValue(
"Davix.GSI.CACheck", (
const char *)
"y"));
417 davixParam->setSSLCAcheck(ca_check_local);
419 Info(
"parseConfig",
"Setting CAcheck to %s", ((ca_check_local) ? (
"true") : (
"false")));
422 if (((env_var = gEnv->GetValue(
"Davix.S3.SecretKey", getenv(
"S3_SECRET_KEY"))) != NULL)
423 && ((env_var2 = gEnv->GetValue(
"Davix.S3.AccessKey", getenv(
"S3_ACCESS_KEY"))) != NULL)) {
424 Info(
"parseConfig",
"Setting S3 SecretKey and AccessKey. Access Key : %s ", env_var2);
425 davixParam->setAwsAuthorizationKeys(env_var, env_var2);
428 if ( (env_var = gEnv->GetValue(
"Davix.S3.Region", getenv(
"S3_REGION"))) != NULL) {
429 setAwsRegion(env_var);
432 if( (env_var = gEnv->GetValue(
"Davix.S3.Token", getenv(
"S3_TOKEN"))) != NULL) {
433 setAwsToken(env_var);
436 if( (env_var = gEnv->GetValue(
"Davix.S3.Alternate", getenv(
"S3_ALTERNATE"))) != NULL) {
437 setAwsAlternate(strToBool(env_var,
false));
441 env_var = gEnv->GetValue(
"Davix.GSI.GridMode", (
const char *)
"y");
449 void TDavixFileInternal::parseParams(Option_t *option)
451 std::stringstream ss(option);
453 std::vector<std::string> parsed_options;
455 std::string s3seckey, s3acckey, s3region, s3token;
457 while (std::getline(ss, item,
' ')) {
458 parsed_options.push_back(item);
461 for (std::vector<std::string>::iterator it = parsed_options.begin(); it < parsed_options.end(); ++it) {
463 if ((strcasecmp(it->c_str(), grid_mode_opt)) == 0) {
467 if ((strcasecmp(it->c_str(), ca_check_opt)) == 0) {
468 davixParam->setSSLCAcheck(
false);
471 if (strncasecmp(it->c_str(), s3_seckey_opt, strlen(s3_seckey_opt)) == 0) {
472 s3seckey = std::string(it->c_str() + strlen(s3_seckey_opt));
475 if (strncasecmp(it->c_str(), s3_acckey_opt, strlen(s3_acckey_opt)) == 0) {
476 s3acckey = std::string(it->c_str() + strlen(s3_acckey_opt));
479 if (strncasecmp(it->c_str(), s3_region_opt, strlen(s3_region_opt)) == 0) {
480 s3region = std::string(it->c_str() + strlen(s3_region_opt));
483 if (strncasecmp(it->c_str(), s3_token_opt, strlen(s3_token_opt)) == 0) {
484 s3token = std::string(it->c_str() + strlen(s3_token_opt));
487 if (strncasecmp(it->c_str(), s3_alternate_opt, strlen(s3_alternate_opt)) == 0) {
488 setAwsAlternate(strToBool(it->c_str() + strlen(s3_alternate_opt),
false));
491 oflags = configure_open_flag(*it, oflags);
494 if (s3seckey.size() > 0) {
495 setS3Auth(s3seckey, s3acckey, s3region, s3token);
504 void TDavixFileInternal::init()
506 davixPosix =
new DavPosix(davixContext);
507 davixParam =
new RequestParams();
508 davixParam->setUserAgent(gUserAgent);
509 davixParam->setMetalinkMode(Davix::MetalinkMode::Disable);
510 ConfigureDavixLogLevel();
517 Int_t TDavixFileInternal::DavixStat(
const char *url,
struct stat *st)
519 DavixError *davixErr = NULL;
521 if (davixPosix->stat(davixParam, url, st, &davixErr) < 0) {
523 Error(
"DavixStat",
"can not stat the file with davix: %s (%d)",
524 davixErr->getErrMsg().c_str(), davixErr->getStatus());
525 DavixError::clearError(&davixErr);
535 TDavixFile::TDavixFile(
const char *url, Option_t *opt,
const char *ftitle, Int_t compress) : TFile(url,
"WEB"),
536 d_ptr(new TDavixFileInternal(fUrl, opt))
545 TDavixFile::~TDavixFile()
553 void TDavixFile::Init(Bool_t init)
559 if ((d_ptr->getDavixFileInstance()) == NULL){
569 TString TDavixFile::GetNewUrl() {
570 std::vector<std::string> replicas = d_ptr->getReplicas();
572 if(!replicas.empty()) {
573 std::stringstream ss;
574 for(
size_t i = 0; i < replicas.size(); i++) {
576 if(i != replicas.size()-1) ss <<
"|";
586 void TDavixFile::Seek(Long64_t offset, ERelativeTo pos)
588 TLockGuard guard(&(d_ptr->positionLock));
591 fOffset = offset + fArchiveOffset;
599 Error(
"Seek",
"seeking from end in archive is not (yet) supported");
600 fOffset = fEND - offset;
605 Info(
"Seek",
" move cursor to %lld"
613 Bool_t TDavixFile::ReadBuffer(
char *buf, Int_t len)
615 TLockGuard guard(&(d_ptr->positionLock));
617 if ((fd = d_ptr->getDavixFileInstance()) == NULL)
619 Long64_t ret = DavixReadBuffer(fd, buf, len);
624 Info(
"ReadBuffer",
"%lld bytes of data read sequentially"
625 " (%d requested)", ret, len);
632 Bool_t TDavixFile::ReadBuffer(
char *buf, Long64_t pos, Int_t len)
635 if ((fd = d_ptr->getDavixFileInstance()) == NULL)
638 Long64_t ret = DavixPReadBuffer(fd, buf, pos, len);
643 Info(
"ReadBuffer",
"%lld bytes of data read from offset"
644 " %lld (%d requested)", ret, pos, len);
650 Bool_t TDavixFile::ReadBufferAsync(Long64_t offs, Int_t len)
653 if ((fd = d_ptr->getDavixFileInstance()) == NULL)
656 d_ptr->davixPosix->fadvise(fd, static_cast<dav_off_t>(offs), static_cast<dav_size_t>(len), Davix::AdviseRandom);
659 Info(
"ReadBufferAsync",
"%d bytes of data prefected from offset"
660 " %lld ", len, offs);
666 Bool_t TDavixFile::ReadBuffers(
char *buf, Long64_t *pos, Int_t *len, Int_t nbuf)
669 if ((fd = d_ptr->getDavixFileInstance()) == NULL)
672 Long64_t ret = DavixReadBuffers(fd, buf, pos, len, nbuf);
677 Info(
"ReadBuffers",
"%lld bytes of data read from a list of %d buffers",
685 Bool_t TDavixFile::WriteBuffer(
const char *buf, Int_t len)
688 if ((fd = d_ptr->getDavixFileInstance()) == NULL)
691 Long64_t ret = DavixWriteBuffer(fd, buf, len);
696 Info(
"WriteBuffer",
"%lld bytes of data write"
697 " %d requested", ret, len);
703 void TDavixFile::setCACheck(Bool_t check)
705 d_ptr->davixParam->setSSLCAcheck((
bool)check);
710 void TDavixFile::enableGridMode()
712 d_ptr->enableGridMode();
717 bool TDavixFileInternal::isMyDird(
void *fd)
719 TLockGuard l(&(openLock));
720 std::vector<void *>::iterator f = std::find(dirdVec.begin(), dirdVec.end(), fd);
721 return (f != dirdVec.end());
726 void TDavixFileInternal::addDird(
void *fd)
728 TLockGuard l(&(openLock));
729 dirdVec.push_back(fd);
734 void TDavixFileInternal::removeDird(
void *fd)
736 TLockGuard l(&(openLock));
737 std::vector<void *>::iterator f = std::find(dirdVec.begin(), dirdVec.end(), fd);
738 if (f != dirdVec.end())
744 Long64_t TDavixFile::GetSize()
const
747 Int_t ret = d_ptr->DavixStat(fUrl.GetUrl(), &st);
750 Info(
"GetSize",
"file size requested: %lld", (Long64_t)st.st_size);
758 Double_t TDavixFile::eventStart()
768 void TDavixFile::eventStop(Double_t t_start, Long64_t len,
bool read)
774 SetFileBytesRead(GetFileBytesRead() + len);
775 SetFileReadCalls(GetFileReadCalls() + 1);
778 gPerfStats->FileReadEvent(
this, (Int_t) len, t_start);
781 SetFileBytesWritten(GetFileBytesWritten() + len);
787 Long64_t TDavixFile::DavixReadBuffer(Davix_fd *fd,
char *buf, Int_t len)
789 DavixError *davixErr = NULL;
790 Double_t start_time = eventStart();
792 Long64_t ret = d_ptr->davixPosix->pread(fd, buf, len, fOffset, &davixErr);
794 Error(
"DavixReadBuffer",
"can not read data with davix: %s (%d)",
795 davixErr->getErrMsg().c_str(), davixErr->getStatus());
796 DavixError::clearError(&davixErr);
799 eventStop(start_time, ret);
807 Long64_t TDavixFile::DavixWriteBuffer(Davix_fd *fd,
const char *buf, Int_t len)
809 DavixError *davixErr = NULL;
810 Double_t start_time = eventStart();
812 Long64_t ret = d_ptr->davixPosix->pwrite(fd, buf, len, fOffset, &davixErr);
814 Error(
"DavixWriteBuffer",
"can not write data with davix: %s (%d)",
815 davixErr->getErrMsg().c_str(), davixErr->getStatus());
816 DavixError::clearError(&davixErr);
819 eventStop(start_time, ret,
false);
827 Long64_t TDavixFile::DavixPReadBuffer(Davix_fd *fd,
char *buf, Long64_t pos, Int_t len)
829 DavixError *davixErr = NULL;
830 Double_t start_time = eventStart();
832 Long64_t ret = d_ptr->davixPosix->pread(fd, buf, len, pos, &davixErr);
834 Error(
"DavixPReadBuffer",
"can not read data with davix: %s (%d)",
835 davixErr->getErrMsg().c_str(), davixErr->getStatus());
836 DavixError::clearError(&davixErr);
838 eventStop(start_time, ret);
847 Long64_t TDavixFile::DavixReadBuffers(Davix_fd *fd,
char *buf, Long64_t *pos, Int_t *len, Int_t nbuf)
849 DavixError *davixErr = NULL;
850 Double_t start_time = eventStart();
851 DavIOVecInput in[nbuf];
852 DavIOVecOuput out[nbuf];
855 for (Int_t i = 0; i < nbuf; ++i) {
856 in[i].diov_buffer = &buf[lastPos];
857 in[i].diov_offset = pos[i];
858 in[i].diov_size = len[i];
862 Long64_t ret = d_ptr->davixPosix->preadVec(fd, in, out, nbuf, &davixErr);
864 Error(
"DavixReadBuffers",
"can not read data with davix: %s (%d)",
865 davixErr->getErrMsg().c_str(), davixErr->getStatus());
866 DavixError::clearError(&davixErr);
868 eventStop(start_time, ret);