Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TDavixFile.cxx
Go to the documentation of this file.
1 // @(#)root/net:$Id$
2 // Author: Adrien Devresse and Tigran Mkrtchyan
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2013, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 //////////////////////////////////////////////////////////////////////////
13 // //
14 // TDavixFile //
15 // //
16 // A TDavixFile is like a normal TFile except that it uses //
17 // libdavix to read/write remote files. //
18 // It supports HTTP and HTTPS in a number of dialects and options //
19 // e.g. S3 is one of them //
20 // Other caracteristics come from the full support of Davix, //
21 // e.g. full redirection support in any circumstance //
22 // //
23 // Authors: Adrien Devresse (CERN IT/SDC) //
24 // Tigran Mkrtchyan (DESY) //
25 // //
26 // Checks and ROOT5 porting: //
27 // Fabrizio Furano (CERN IT/SDC) //
28 // //
29 // September 2013 //
30 // //
31 //////////////////////////////////////////////////////////////////////////
32 
33 
34 #include "TDavixFile.h"
35 #include "TROOT.h"
36 #include "TSocket.h"
37 #include "Bytes.h"
38 #include "TError.h"
39 #include "TSystem.h"
40 #include "TEnv.h"
41 #include "TBase64.h"
42 #include "TVirtualPerfStats.h"
43 #include "TDavixFileInternal.h"
44 #include "TSocket.h"
45 
46 #include <errno.h>
47 #include <stdlib.h>
48 #include <unistd.h>
49 #include <fcntl.h>
50 #include <davix.hpp>
51 #include <sstream>
52 #include <string>
53 #include <cstring>
54 
55 
56 static const std::string VERSION = "0.2.0";
57 
58 static const std::string gUserAgent = "ROOT/" + std::string(gROOT->GetVersion()) +
59 " TDavixFile/" + VERSION + " davix/" + Davix::version();
60 
61 // The prefix that is used to find the variables in the gEnv
62 #define ENVPFX "Davix."
63 
64 ClassImp(TDavixFile);
65 
66 using namespace Davix;
67 
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";
79 
80 static TMutex createLock;
81 static Context* davix_context_s = NULL;
82 
83 
84 ////////////////////////////////////////////////////////////////////////////////
85 
86 bool isno(const char *str)
87 {
88  if (!str) return false;
89 
90  if (!strcmp(str, "n") || !strcmp(str, "no") || !strcmp(str, "0") || !strcmp(str, "false")) return true;
91 
92  return false;
93 
94 }
95 
96 bool strToBool(const char *str, bool defvalue) {
97  if(!str) return defvalue;
98 
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;
101 
102  return defvalue;
103 }
104 
105 ////////////////////////////////////////////////////////////////////////////////
106 
107 int configure_open_flag(const std::string &str, int old_flag)
108 {
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);
114  }
115  if ((strcasecmp(str.c_str(), open_mode_update) == 0)) {
116  old_flag |= (O_RDWR);
117  }
118  return old_flag;
119 }
120 
121 ////////////////////////////////////////////////////////////////////////////////
122 
123 static void ConfigureDavixLogLevel()
124 {
125  Int_t log_level = (gEnv) ? gEnv->GetValue("Davix.Debug", 0) : 0;
126 
127  switch (log_level) {
128  case 0:
129  davix_set_log_level(0);
130  break;
131  case 1:
132  davix_set_log_level(DAVIX_LOG_WARNING);
133  break;
134  case 2:
135  davix_set_log_level(DAVIX_LOG_VERBOSE);
136  break;
137  case 3:
138  davix_set_log_level(DAVIX_LOG_DEBUG);
139  break;
140  default:
141  davix_set_log_level(DAVIX_LOG_ALL);
142  break;
143  }
144 }
145 
146 ///////////////////////////////////////////////////////////////////
147 // Authn implementation, Locate and get VOMS cred if exist
148 
149 ////////////////////////////////////////////////////////////////////////////////
150 
151 static void TDavixFile_http_get_ucert(std::string &ucert, std::string &ukey)
152 {
153  char default_proxy[64];
154  const char *genvvar = 0, *genvvar1 = 0;
155  // The gEnv has higher priority, let's look for a proxy cert
156  genvvar = gEnv->GetValue("Davix.GSI.UserProxy", (const char *) NULL);
157  if (genvvar) {
158  ucert = ukey = genvvar;
159  if (gDebug > 0)
160  Info("TDavixFile_http_get_ucert", "Found proxy in gEnv");
161  return;
162  }
163 
164  // Try explicit environment for proxy
165  if (getenv("X509_USER_PROXY")) {
166  if (gDebug > 0)
167  Info("TDavixFile_http_get_ucert", "Found proxy in X509_USER_PROXY");
168  ucert = ukey = getenv("X509_USER_PROXY");
169  return;
170  }
171 
172  // Try with default location
173  snprintf(default_proxy, sizeof(default_proxy), "/tmp/x509up_u%d",
174  geteuid());
175 
176  if (access(default_proxy, R_OK) == 0) {
177  if (gDebug > 0)
178  Info("TDavixFile_http_get_ucert", "Found proxy in /tmp");
179  ucert = ukey = default_proxy;
180  return;
181  }
182 
183  // It seems we got no proxy, let's try to gather the keys
184  genvvar = gEnv->GetValue("Davix.GSI.UserCert", (const char *) NULL);
185  genvvar1 = gEnv->GetValue("Davix.GSI.UserKey", (const char *) NULL);
186  if (genvvar || genvvar1) {
187  if (gDebug > 0)
188  Info("TDavixFile_http_get_ucert", "Found cert and key in gEnv");
189 
190  ucert = genvvar;
191  ukey = genvvar1;
192  return;
193  }
194 
195  // try with X509_* environment
196  if (getenv("X509_USER_CERT"))
197  ucert = getenv("X509_USER_CERT");
198  if (getenv("X509_USER_KEY"))
199  ukey = getenv("X509_USER_KEY");
200 
201  if ((ucert.size() > 0) || (ukey.size() > 0)) {
202  if (gDebug > 0)
203  Info("TDavixFile_http_get_ucert", "Found cert and key in gEnv");
204  }
205  return;
206 
207 }
208 
209 ////////////////////////////////////////////////////////////////////////////////
210 
211 static int TDavixFile_http_authn_cert_X509(void *userdata, const Davix::SessionInfo &info,
212  Davix::X509Credential *cert, Davix::DavixError **err)
213 {
214  (void) userdata; // keep quiete compilation warnings
215  (void) info;
216  std::string ucert, ukey;
217  TDavixFile_http_get_ucert(ucert, ukey);
218 
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");
223  return -1;
224  }
225  return cert->loadFromFilePEM(ukey, ucert, "", err);
226 }
227 /////////////////////////////////////////////////////////////////////////////////////////////
228 
229 ////////////////////////////////////////////////////////////////////////////////
230 
231 TDavixFileInternal::~TDavixFileInternal()
232 {
233  delete davixPosix;
234  delete davixParam;
235 }
236 
237 ////////////////////////////////////////////////////////////////////////////////
238 
239 Context *TDavixFileInternal::getDavixInstance()
240 {
241  if (davix_context_s == NULL) {
242  TLockGuard guard(&createLock);
243  if (davix_context_s == NULL) {
244  davix_context_s = new Context();
245  }
246  }
247  return davix_context_s;
248 }
249 
250 ////////////////////////////////////////////////////////////////////////////////
251 
252 Davix_fd *TDavixFileInternal::Open()
253 {
254  DavixError *davixErr = NULL;
255  Davix_fd *fd = davixPosix->open(davixParam, fUrl.GetUrl(), oflags, &davixErr);
256  if (fd == NULL) {
257  // An error has occurred.. We might be able to recover with metalinks.
258  // Try to populate the replicas vector. If successful, TFile will try
259  // the replicas one by one
260 
261  replicas.clear();
262  DavixError *davixErr2 = NULL;
263  try {
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());
268  }
269  }
270  catch(...) {}
271  DavixError::clearError(&davixErr2);
272 
273  if(replicas.empty()) {
274  // I was unable to retrieve a list of replicas: propagate the original
275  // error.
276  Error("DavixOpen", "can not open file \"%s\" with davix: %s (%d)",
277  fUrl.GetUrl(),
278  davixErr->getErrMsg().c_str(), davixErr->getStatus());
279  }
280  DavixError::clearError(&davixErr);
281  } else {
282  // setup ROOT style read
283  davixPosix->fadvise(fd, 0, 300, Davix::AdviseRandom);
284  }
285 
286  return fd;
287 }
288 
289 ////////////////////////////////////////////////////////////////////////////////
290 
291 void TDavixFileInternal::Close()
292 {
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);
298  }
299 }
300 
301 ////////////////////////////////////////////////////////////////////////////////
302 
303 void TDavixFileInternal::enableGridMode()
304 {
305  const char *env_var = NULL;
306 
307  if (gDebug > 1)
308  Info("enableGridMode", " grid mode enabled !");
309 
310  if( ( env_var = getenv("X509_CERT_DIR")) == NULL){
311  env_var= "/etc/grid-security/certificates/";
312  }
313  davixParam->addCertificateAuthorityPath(env_var);
314  if (gDebug > 0)
315  Info("enableGridMode", "Adding CAdir %s", env_var);
316 }
317 
318 ////////////////////////////////////////////////////////////////////////////////
319 
320 // Only newer versions of davix support setting the S3 region and STS tokens.
321 // But it's only possible to check the davix version through a #define starting from
322 // 0.6.4.
323 // I have no way to check if setAwsRegion is available, so let's use SFINAE. :-)
324 // The first overload will always take priority - if "substitution" fails, meaning
325 // setAwsRegion is not there, the compiler will pick the second overload with
326 // the ellipses. (...)
327 
328 template<typename TRequestParams = Davix::RequestParams>
329 static auto awsRegion(TRequestParams *parameters, const char *region)
330  -> decltype(parameters->setAwsRegion(region), void())
331 {
332  if (gDebug > 1) Info("awsRegion", "Setting S3 Region to '%s' - v4 signature will be used", region);
333  parameters->setAwsRegion(region);
334 }
335 
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");
339 }
340 
341 // Identical SFINAE trick as above for setAwsToken
342 template<typename TRequestParams = Davix::RequestParams>
343 static auto awsToken(TRequestParams *parameters, const char *token)
344  -> decltype(parameters->setAwsToken(token), void())
345 {
346  if (gDebug > 1) Info("awsToken", "Setting S3 STS temporary credentials");
347  parameters->setAwsToken(token);
348 }
349 
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");
353 }
354 
355 // Identical SFINAE trick as above for setAwsAlternate
356 template<typename TRequestParams = Davix::RequestParams>
357 static auto awsAlternate(TRequestParams *parameters, bool option)
358  -> decltype(parameters->setAwsAlternate(option), void())
359 {
360  if (gDebug > 1) Info("awsAlternate", "Setting S3 path-based bucket option (s3alternate)");
361  parameters->setAwsAlternate(option);
362 }
363 
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");
367 }
368 
369 void TDavixFileInternal::setAwsRegion(const std::string & region) {
370  if(!region.empty()) {
371  awsRegion(davixParam, region.c_str());
372  }
373 }
374 
375 void TDavixFileInternal::setAwsToken(const std::string & token) {
376  if(!token.empty()) {
377  awsToken(davixParam, token.c_str());
378  }
379 }
380 
381 void TDavixFileInternal::setAwsAlternate(const bool & option) {
382  awsAlternate(davixParam, option);
383 }
384 
385 
386 void TDavixFileInternal::setS3Auth(const std::string &secret, const std::string &access,
387  const std::string &region, const std::string &token)
388 {
389  if (gDebug > 1) {
390  Info("setS3Auth", " Aws S3 tokens configured");
391  }
392  davixParam->setAwsAuthorizationKeys(secret, access);
393  davixParam->setProtocol(RequestProtocol::AwsS3);
394 
395  setAwsRegion(region);
396  setAwsToken(token);
397 }
398 
399 ////////////////////////////////////////////////////////////////////////////////
400 
401 void TDavixFileInternal::parseConfig()
402 {
403  const char *env_var = NULL, *env_var2 = NULL;
404  // default opts
405  davixParam->setTransparentRedirectionSupport(true);
406  davixParam->setClientCertCallbackX509(&TDavixFile_http_authn_cert_X509, NULL);
407 
408  // setup CADIR
409  env_var = gEnv->GetValue("Davix.GSI.CAdir", (const char *) NULL);
410  if (env_var) {
411  davixParam->addCertificateAuthorityPath(env_var);
412  if (gDebug > 0)
413  Info("parseConfig", "Add CAdir: %s", env_var);
414  }
415  // CA Check
416  bool ca_check_local = !isno(gEnv->GetValue("Davix.GSI.CACheck", (const char *)"y"));
417  davixParam->setSSLCAcheck(ca_check_local);
418  if (gDebug > 0)
419  Info("parseConfig", "Setting CAcheck to %s", ((ca_check_local) ? ("true") : ("false")));
420 
421  // S3 Auth
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);
426 
427  // need to set region?
428  if ( (env_var = gEnv->GetValue("Davix.S3.Region", getenv("S3_REGION"))) != NULL) {
429  setAwsRegion(env_var);
430  }
431  // need to set STS token?
432  if( (env_var = gEnv->GetValue("Davix.S3.Token", getenv("S3_TOKEN"))) != NULL) {
433  setAwsToken(env_var);
434  }
435  // need to set aws alternate?
436  if( (env_var = gEnv->GetValue("Davix.S3.Alternate", getenv("S3_ALTERNATE"))) != NULL) {
437  setAwsAlternate(strToBool(env_var, false));
438  }
439  }
440 
441  env_var = gEnv->GetValue("Davix.GSI.GridMode", (const char *)"y");
442  if (!isno(env_var))
443  enableGridMode();
444 }
445 
446 ////////////////////////////////////////////////////////////////////////////////
447 /// intput params
448 
449 void TDavixFileInternal::parseParams(Option_t *option)
450 {
451  std::stringstream ss(option);
452  std::string item;
453  std::vector<std::string> parsed_options;
454  // parameters
455  std::string s3seckey, s3acckey, s3region, s3token;
456 
457  while (std::getline(ss, item, ' ')) {
458  parsed_options.push_back(item);
459  }
460 
461  for (std::vector<std::string>::iterator it = parsed_options.begin(); it < parsed_options.end(); ++it) {
462  // grid mode option
463  if ((strcasecmp(it->c_str(), grid_mode_opt)) == 0) {
464  enableGridMode();
465  }
466  // ca check option
467  if ((strcasecmp(it->c_str(), ca_check_opt)) == 0) {
468  davixParam->setSSLCAcheck(false);
469  }
470  // s3 sec key
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));
473  }
474  // s3 access key
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));
477  }
478  // s3 region
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));
481  }
482  // s3 sts token
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));
485  }
486  // s3 alternate option
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));
489  }
490  // open mods
491  oflags = configure_open_flag(*it, oflags);
492  }
493 
494  if (s3seckey.size() > 0) {
495  setS3Auth(s3seckey, s3acckey, s3region, s3token);
496  }
497 
498  if (oflags == 0) // default open mode
499  oflags = O_RDONLY;
500 }
501 
502 ////////////////////////////////////////////////////////////////////////////////
503 
504 void TDavixFileInternal::init()
505 {
506  davixPosix = new DavPosix(davixContext);
507  davixParam = new RequestParams();
508  davixParam->setUserAgent(gUserAgent);
509  davixParam->setMetalinkMode(Davix::MetalinkMode::Disable);
510  ConfigureDavixLogLevel();
511  parseConfig();
512  parseParams(opt);
513 }
514 
515 ////////////////////////////////////////////////////////////////////////////////
516 
517 Int_t TDavixFileInternal::DavixStat(const char *url, struct stat *st)
518 {
519  DavixError *davixErr = NULL;
520 
521  if (davixPosix->stat(davixParam, url, st, &davixErr) < 0) {
522 
523  Error("DavixStat", "can not stat the file with davix: %s (%d)",
524  davixErr->getErrMsg().c_str(), davixErr->getStatus());
525  DavixError::clearError(&davixErr);
526  return 0;
527  }
528  return 1;
529 }
530 
531 /////////////////////////////////////////////////////////////////////////////////////////////
532 
533 ////////////////////////////////////////////////////////////////////////////////
534 
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))
537 {
538  (void) ftitle;
539  (void) compress;
540  Init(kFALSE);
541 }
542 
543 ////////////////////////////////////////////////////////////////////////////////
544 
545 TDavixFile::~TDavixFile()
546 {
547  d_ptr->Close();
548  delete d_ptr;
549 }
550 
551 ////////////////////////////////////////////////////////////////////////////////
552 
553 void TDavixFile::Init(Bool_t init)
554 {
555  (void) init;
556  //initialize davix
557  d_ptr->init();
558  // pre-open file
559  if ((d_ptr->getDavixFileInstance()) == NULL){
560  MakeZombie();
561  gDirectory = gROOT;
562  return;
563  }
564  TFile::Init(kFALSE);
565  fOffset = 0;
566  fD = -2; // so TFile::IsOpen() will return true when in TFile::~TFi */
567 }
568 
569 TString TDavixFile::GetNewUrl() {
570  std::vector<std::string> replicas = d_ptr->getReplicas();
571  TString newUrl;
572  if(!replicas.empty()) {
573  std::stringstream ss;
574  for(size_t i = 0; i < replicas.size(); i++) {
575  ss << replicas[i];
576  if(i != replicas.size()-1) ss << "|";
577  }
578  newUrl = ss.str();
579  }
580  return newUrl;
581 }
582 
583 ////////////////////////////////////////////////////////////////////////////////
584 /// Set position from where to start reading.
585 
586 void TDavixFile::Seek(Long64_t offset, ERelativeTo pos)
587 {
588  TLockGuard guard(&(d_ptr->positionLock));
589  switch (pos) {
590  case kBeg:
591  fOffset = offset + fArchiveOffset;
592  break;
593  case kCur:
594  fOffset += offset;
595  break;
596  case kEnd:
597  // this option is not used currently in the ROOT code
598  if (fArchiveOffset)
599  Error("Seek", "seeking from end in archive is not (yet) supported");
600  fOffset = fEND - offset; // is fEND really EOF or logical EOF?
601  break;
602  }
603 
604  if (gDebug > 1)
605  Info("Seek", " move cursor to %lld"
606  , fOffset);
607 }
608 
609 ////////////////////////////////////////////////////////////////////////////////
610 /// Read specified byte range from remote file via HTTP.
611 /// Returns kTRUE in case of error.
612 
613 Bool_t TDavixFile::ReadBuffer(char *buf, Int_t len)
614 {
615  TLockGuard guard(&(d_ptr->positionLock));
616  Davix_fd *fd;
617  if ((fd = d_ptr->getDavixFileInstance()) == NULL)
618  return kTRUE;
619  Long64_t ret = DavixReadBuffer(fd, buf, len);
620  if (ret < 0)
621  return kTRUE;
622 
623  if (gDebug > 1)
624  Info("ReadBuffer", "%lld bytes of data read sequentially"
625  " (%d requested)", ret, len);
626 
627  return kFALSE;
628 }
629 
630 ////////////////////////////////////////////////////////////////////////////////
631 
632 Bool_t TDavixFile::ReadBuffer(char *buf, Long64_t pos, Int_t len)
633 {
634  Davix_fd *fd;
635  if ((fd = d_ptr->getDavixFileInstance()) == NULL)
636  return kTRUE;
637 
638  Long64_t ret = DavixPReadBuffer(fd, buf, pos, len);
639  if (ret < 0)
640  return kTRUE;
641 
642  if (gDebug > 1)
643  Info("ReadBuffer", "%lld bytes of data read from offset"
644  " %lld (%d requested)", ret, pos, len);
645  return kFALSE;
646 }
647 
648 ////////////////////////////////////////////////////////////////////////////////
649 
650 Bool_t TDavixFile::ReadBufferAsync(Long64_t offs, Int_t len)
651 {
652  Davix_fd *fd;
653  if ((fd = d_ptr->getDavixFileInstance()) == NULL)
654  return kFALSE;
655 
656  d_ptr->davixPosix->fadvise(fd, static_cast<dav_off_t>(offs), static_cast<dav_size_t>(len), Davix::AdviseRandom);
657 
658  if (gDebug > 1)
659  Info("ReadBufferAsync", "%d bytes of data prefected from offset"
660  " %lld ", len, offs);
661  return kFALSE;
662 }
663 
664 ////////////////////////////////////////////////////////////////////////////////
665 
666 Bool_t TDavixFile::ReadBuffers(char *buf, Long64_t *pos, Int_t *len, Int_t nbuf)
667 {
668  Davix_fd *fd;
669  if ((fd = d_ptr->getDavixFileInstance()) == NULL)
670  return kTRUE;
671 
672  Long64_t ret = DavixReadBuffers(fd, buf, pos, len, nbuf);
673  if (ret < 0)
674  return kTRUE;
675 
676  if (gDebug > 1)
677  Info("ReadBuffers", "%lld bytes of data read from a list of %d buffers",
678  ret, nbuf);
679 
680  return kFALSE;
681 }
682 
683 ////////////////////////////////////////////////////////////////////////////////
684 
685 Bool_t TDavixFile::WriteBuffer(const char *buf, Int_t len)
686 {
687  Davix_fd *fd;
688  if ((fd = d_ptr->getDavixFileInstance()) == NULL)
689  return kTRUE;
690 
691  Long64_t ret = DavixWriteBuffer(fd, buf, len);
692  if (ret < 0)
693  return kTRUE;
694 
695  if (gDebug > 1)
696  Info("WriteBuffer", "%lld bytes of data write"
697  " %d requested", ret, len);
698  return kFALSE;
699 }
700 
701 ////////////////////////////////////////////////////////////////////////////////
702 
703 void TDavixFile::setCACheck(Bool_t check)
704 {
705  d_ptr->davixParam->setSSLCAcheck((bool)check);
706 }
707 
708 ////////////////////////////////////////////////////////////////////////////////
709 
710 void TDavixFile::enableGridMode()
711 {
712  d_ptr->enableGridMode();
713 }
714 
715 ////////////////////////////////////////////////////////////////////////////////
716 
717 bool TDavixFileInternal::isMyDird(void *fd)
718 {
719  TLockGuard l(&(openLock));
720  std::vector<void *>::iterator f = std::find(dirdVec.begin(), dirdVec.end(), fd);
721  return (f != dirdVec.end());
722 }
723 
724 ////////////////////////////////////////////////////////////////////////////////
725 
726 void TDavixFileInternal::addDird(void *fd)
727 {
728  TLockGuard l(&(openLock));
729  dirdVec.push_back(fd);
730 }
731 
732 ////////////////////////////////////////////////////////////////////////////////
733 
734 void TDavixFileInternal::removeDird(void *fd)
735 {
736  TLockGuard l(&(openLock));
737  std::vector<void *>::iterator f = std::find(dirdVec.begin(), dirdVec.end(), fd);
738  if (f != dirdVec.end())
739  dirdVec.erase(f);
740 }
741 
742 ////////////////////////////////////////////////////////////////////////////////
743 
744 Long64_t TDavixFile::GetSize() const
745 {
746  struct stat st;
747  Int_t ret = d_ptr->DavixStat(fUrl.GetUrl(), &st);
748  if (ret) {
749  if (gDebug > 1)
750  Info("GetSize", "file size requested: %lld", (Long64_t)st.st_size);
751  return st.st_size;
752  }
753  return -1;
754 }
755 
756 ////////////////////////////////////////////////////////////////////////////////
757 
758 Double_t TDavixFile::eventStart()
759 {
760  if (gPerfStats)
761  return TTimeStamp();
762  return 0;
763 }
764 
765 ////////////////////////////////////////////////////////////////////////////////
766 /// set TFile state info
767 
768 void TDavixFile::eventStop(Double_t t_start, Long64_t len, bool read)
769 {
770  if(read) {
771  fBytesRead += len;
772  fReadCalls += 1;
773 
774  SetFileBytesRead(GetFileBytesRead() + len);
775  SetFileReadCalls(GetFileReadCalls() + 1);
776 
777  if (gPerfStats)
778  gPerfStats->FileReadEvent(this, (Int_t) len, t_start);
779  } else {
780  fBytesWrite += len;
781  SetFileBytesWritten(GetFileBytesWritten() + len);
782  }
783 }
784 
785 ////////////////////////////////////////////////////////////////////////////////
786 
787 Long64_t TDavixFile::DavixReadBuffer(Davix_fd *fd, char *buf, Int_t len)
788 {
789  DavixError *davixErr = NULL;
790  Double_t start_time = eventStart();
791 
792  Long64_t ret = d_ptr->davixPosix->pread(fd, buf, len, fOffset, &davixErr);
793  if (ret < 0) {
794  Error("DavixReadBuffer", "can not read data with davix: %s (%d)",
795  davixErr->getErrMsg().c_str(), davixErr->getStatus());
796  DavixError::clearError(&davixErr);
797  } else {
798  fOffset += ret;
799  eventStop(start_time, ret);
800  }
801 
802  return ret;
803 }
804 
805 ////////////////////////////////////////////////////////////////////////////////
806 
807 Long64_t TDavixFile::DavixWriteBuffer(Davix_fd *fd, const char *buf, Int_t len)
808 {
809  DavixError *davixErr = NULL;
810  Double_t start_time = eventStart();
811 
812  Long64_t ret = d_ptr->davixPosix->pwrite(fd, buf, len, fOffset, &davixErr);
813  if (ret < 0) {
814  Error("DavixWriteBuffer", "can not write data with davix: %s (%d)",
815  davixErr->getErrMsg().c_str(), davixErr->getStatus());
816  DavixError::clearError(&davixErr);
817  } else {
818  fOffset += ret;
819  eventStop(start_time, ret, false);
820  }
821 
822  return ret;
823 }
824 
825 ////////////////////////////////////////////////////////////////////////////////
826 
827 Long64_t TDavixFile::DavixPReadBuffer(Davix_fd *fd, char *buf, Long64_t pos, Int_t len)
828 {
829  DavixError *davixErr = NULL;
830  Double_t start_time = eventStart();
831 
832  Long64_t ret = d_ptr->davixPosix->pread(fd, buf, len, pos, &davixErr);
833  if (ret < 0) {
834  Error("DavixPReadBuffer", "can not read data with davix: %s (%d)",
835  davixErr->getErrMsg().c_str(), davixErr->getStatus());
836  DavixError::clearError(&davixErr);
837  } else {
838  eventStop(start_time, ret);
839  }
840 
841 
842  return ret;
843 }
844 
845 ////////////////////////////////////////////////////////////////////////////////
846 
847 Long64_t TDavixFile::DavixReadBuffers(Davix_fd *fd, char *buf, Long64_t *pos, Int_t *len, Int_t nbuf)
848 {
849  DavixError *davixErr = NULL;
850  Double_t start_time = eventStart();
851  DavIOVecInput in[nbuf];
852  DavIOVecOuput out[nbuf];
853 
854  int lastPos = 0;
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];
859  lastPos += len[i];
860  }
861 
862  Long64_t ret = d_ptr->davixPosix->preadVec(fd, in, out, nbuf, &davixErr);
863  if (ret < 0) {
864  Error("DavixReadBuffers", "can not read data with davix: %s (%d)",
865  davixErr->getErrMsg().c_str(), davixErr->getStatus());
866  DavixError::clearError(&davixErr);
867  } else {
868  eventStop(start_time, ret);
869  }
870 
871  return ret;
872 }