CMS 3D CMS Logo

DavixFile.cc
Go to the documentation of this file.
5 #include <cassert>
6 #include <davix.hpp>
7 #include <cerrno>
8 #include <fcntl.h>
9 #include <cstdlib>
10 #include <unistd.h>
11 #include <vector>
12 #include <mutex>
13 
14 static std::once_flag davixDebugInit;
15 
16 using namespace Davix;
17 
19 
20 DavixFile::DavixFile(const char *name, int flags /* = IOFlags::OpenRead */, int perms /* = 066 */) {
21  open(name, flags, perms);
22 }
23 
24 DavixFile::DavixFile(const std::string &name, int flags /* = IOFlags::OpenRead */,
25  int perms /* = 066 */) {
26  open(name.c_str(), flags, perms);
27 }
28 
30  close();
31  return;
32 }
33 
34 void DavixFile::close(void) {
35  if (m_davixPosix && m_fd) {
36  auto davixPosix = std::move(m_davixPosix);
37  DavixError *err = nullptr;
38  davixPosix->close(m_fd, &err);
39  m_fd = nullptr;
40  if (err) {
41  std::unique_ptr<DavixError> davixErrManaged(err);
42  cms::Exception ex("FileCloseError");
43  ex << "Davix::close(name='" << m_name << ") failed with error "
44  << err->getErrMsg().c_str() << " and error code " << err->getStatus();
45  ex.addContext("Calling DavixFile::close()");
46  throw ex;
47  }
48  }
49  return;
50 }
51 
52 void DavixFile::abort(void) {
53  if (m_davixPosix && m_fd) {
54  DavixError *err = nullptr;
55  m_davixPosix->close(m_fd, &err);
56  if (err) {
57  std::unique_ptr<DavixError> davixErrManaged(err);
58  cms::Exception ex("FileAbortError");
59  ex << "Davix::abort(name='" << m_name << ") failed with error "
60  << err->getErrMsg().c_str() << " and error code " << err->getStatus();
61  ex.addContext("Calling DavixFile::abort()");
62  throw ex;
63  }
64  }
65  return;
66 }
67 
69  long logLevel = 0;
70  char *logptr = nullptr;
71  char const * const davixDebug = getenv("Davix_Debug");
72  if (davixDebug != nullptr) {
73  logLevel = strtol(davixDebug, &logptr, 0);
74  if (errno) {
75  edm::LogWarning("DavixFile") << "Got error while converting "
76  << "Davix_Debug env variable to integer. "
77  "Will use default log level 0";
78  logLevel = 0;
79  }
80  if (logptr == davixDebug) {
81  edm::LogWarning("DavixFile") << "Failed to convert to integer "
82  << "Davix_Debug env variable; Will use default log level 0";
83  logLevel = 0;
84  } else if (*logptr != '\0') {
85  edm::LogWarning("DavixFile") << "Failed to parse extra junk "
86  << "from Davix_Debug env variable. Will use default log level 0";
87  logLevel = 0;
88  }
89  }
90  switch (logLevel) {
91  case 0:
92  std::call_once(davixDebugInit, davix_set_log_level, 0);
93  break;
94  case 1:
95  std::call_once(davixDebugInit, davix_set_log_level, DAVIX_LOG_WARNING);
96  break;
97  case 2:
98  std::call_once(davixDebugInit, davix_set_log_level, DAVIX_LOG_VERBOSE);
99  break;
100  case 3:
101  std::call_once(davixDebugInit, davix_set_log_level, DAVIX_LOG_DEBUG);
102  break;
103  default:
104  std::call_once(davixDebugInit, davix_set_log_level, DAVIX_LOG_ALL);
105  break;
106  }
107 }
108 
109 static int X509Authentication(void *userdata, const SessionInfo &info, X509Credential *cert,
110  DavixError **davixErr) {
111  std::string ucert, ukey;
112  char default_proxy[64];
113  snprintf(default_proxy, sizeof(default_proxy), "/tmp/x509up_u%d", geteuid());
114  // X509_USER_PROXY
115  if (getenv("X509_USER_PROXY")) {
116  edm::LogInfo("DavixFile") << "X509_USER_PROXY found in environment."
117  << " Will use it for authentication";
118  ucert = ukey = getenv("X509_USER_PROXY");
119  }
120  // Default proxy location
121  else if (access(default_proxy, R_OK) == 0) {
122  edm::LogInfo("DavixFile") << "Found proxy in default location " << default_proxy
123  << " Will use it for authentication";
124  ucert = ukey = default_proxy;
125  }
126  // X509_USER_CERT
127  else if (getenv("X509_USER_CERT")) {
128  ucert = getenv("X509_USER_CERT");
129  }
130  // X509_USER_KEY only if X509_USER_CERT was found
131  if (!ucert.empty() && getenv("X509_USER_KEY")) {
132  edm::LogInfo("DavixFile") << "X509_USER_{CERT|KEY} found in environment"
133  << " Will use it for authentication";
134  ukey = getenv("X509_USER_KEY");
135  }
136  // Check if vars are set...
137  if (ucert.empty() || ukey.empty()) {
138  edm::LogWarning("DavixFile") << "Was not able to find proxy in $X509_USER_PROXY, "
139  << "X509_USER_{CERT|KEY} or default proxy creation location. "
140  << "Will try without authentication";
141  return -1;
142  }
143  return cert->loadFromFilePEM(ukey, ucert, "", davixErr);
144 }
145 
146 void DavixFile::create(const char *name, bool exclusive /* = false */, int perms /* = 066 */) {
148  (exclusive ? IOFlags::OpenExclusive : 0)),
149  perms);
150 }
151 
152 void DavixFile::create(const std::string &name, bool exclusive /* = false */,
153  int perms /* = 066 */) {
155  (exclusive ? IOFlags::OpenExclusive : 0)),
156  perms);
157 }
158 
159 void DavixFile::open(const std::string &name, int flags /* = IOFlags::OpenRead */,
160  int perms /* = 066 */) {
161  open(name.c_str(), flags, perms);
162 }
163 
164 void DavixFile::open(const char *name, int flags /* = IOFlags::OpenRead */, int perms /* = 066 */) {
165  // Actual open
166  if ((name == nullptr) || (*name == 0)) {
168  ex << "Cannot open a file without name";
169  ex.addContext("Calling DavixFile::open()");
170  throw ex;
171  }
172  m_name = name;
173 
174  if ((flags & IOFlags::OpenRead) == 0) {
176  ex << "Must open file '" << name << "' at least for read";
177  ex.addContext("Calling DavixFile::open()");
178  throw ex;
179  }
180 
181  if (m_davixPosix && m_fd) {
183  ex << "Davix::open(name='" << m_name << "') failed on already open file";
184  ex.addContext("Calling DavixFile::open()");
185  throw ex;
186  }
187  configureDavixLogLevel();
188  // Translate our flags to system flags
189  int openflags = 0;
190 
191  if (flags & IOFlags::OpenRead)
192  openflags |= O_RDONLY;
193 
194  DavixError *davixErr = nullptr;
195  RequestParams davixReqParams;
196  // Set up X509 authentication
197  davixReqParams.setClientCertCallbackX509(&X509Authentication, nullptr);
198  // Set also CERT_DIR if it is set in envinroment, otherwise use default
199  const char *cert_dir = nullptr;
200  if ((cert_dir = getenv("X509_CERT_DIR")) == nullptr)
201  cert_dir = "/etc/grid-security/certificates";
202  davixReqParams.addCertificateAuthorityPath(cert_dir);
203 
204  m_davixPosix = std::make_unique<DavPosix>(new Context());
205  m_fd = m_davixPosix->open(&davixReqParams, name, openflags, &davixErr);
206 
207  // Check Davix Error
208  if (davixErr) {
209  std::unique_ptr<DavixError> davixErrManaged(davixErr);
211  ex << "Davix::open(name='" << m_name << "') failed with "
212  << "error '" << davixErr->getErrMsg().c_str() << " and error code " << davixErr->getStatus();
213  ex.addContext("Calling DavixFile::open()");
214  throw ex;
215  }
216  if (!m_fd) {
218  ex << "Davix::open(name='" << m_name << "') failed as fd is NULL";
219  ex.addContext("Calling DavixFile::open()");
220  throw ex;
221  }
222 }
223 
225  assert(!buffers || into);
226 
227  // Davix does not support 0 buffers;
228  if (buffers == 0)
229  return 0;
230 
231  DavixError *davixErr = nullptr;
232 
233  std::vector<DavIOVecInput> input_vector(buffers);
234  std::vector<DavIOVecOuput> output_vector(buffers);
235  IOSize total = 0; // Total requested bytes
236  for (IOSize i = 0; i < buffers; ++i) {
237  input_vector[i].diov_size = into[i].size();
238  input_vector[i].diov_buffer = static_cast<char *>(into[i].data());
239  total += into[i].size();
240  }
241 
242  ssize_t s = m_davixPosix->preadVec(m_fd, input_vector.data(), output_vector.data(), buffers, &davixErr);
243  if (davixErr) {
244  std::unique_ptr<DavixError> davixErrManaged(davixErr);
246  ex << "Davix::readv(name='" << m_name << "', buffers=" << (buffers)
247  << ") failed with error " << davixErr->getErrMsg().c_str() << " and error code "
248  << davixErr->getStatus() << " and call returned " << s << " bytes";
249  ex.addContext("Calling DavixFile::readv()");
250  throw ex;
251  }
252  // Davix limits number of requests sent to the server
253  // to improve performance and it does range coalescing.
254  // So we can`t check what preadVec returns with what was requested.
255  // Example: If two ranges are overlapping, [10, 20] and [20, 30] which is
256  // coalesced into [10, 30] and it will contain one less byte than was requested.
257  // Only check if returned val <= 0 and make proper actions.
258  if (s < 0) {
260  ex << "Davix::readv(name='" << m_name << "') failed and call returned " << s;
261  ex.addContext("Calling DavixFile::readv()");
262  throw ex;
263  } else if (s == 0) {
264  // end of file
265  return 0;
266  }
267  return total;
268 }
269 
271  assert(!buffers || into);
272 
273  // Davix does not support 0 buffers;
274  if (buffers == 0)
275  return 0;
276 
277  DavixError *davixErr = nullptr;
278 
279  std::vector<DavIOVecInput> input_vector(buffers);
280  std::vector<DavIOVecOuput> output_vector(buffers);
281  IOSize total = 0;
282  for (IOSize i = 0; i < buffers; ++i) {
283  input_vector[i].diov_offset = into[i].offset();
284  input_vector[i].diov_size = into[i].size();
285  input_vector[i].diov_buffer = static_cast<char *>(into[i].data());
286  total += into[i].size();
287  }
288  ssize_t s = m_davixPosix->preadVec(m_fd, input_vector.data(), output_vector.data(), buffers, &davixErr);
289  if (davixErr) {
290  std::unique_ptr<DavixError> davixErrManaged(davixErr);
292  ex << "Davix::readv(name='" << m_name << "', n=" << buffers << ") failed with error "
293  << davixErr->getErrMsg().c_str() << " and error code " << davixErr->getStatus()
294  << " and call returned " << s << " bytes";
295  ex.addContext("Calling DavixFile::readv()");
296  throw ex;
297  }
298  // Davix limits number of requests sent to the server
299  // to improve performance and it does range coalescing.
300  // So we can`t check what preadVec returns with what was requested.
301  // Example: If two ranges are overlapping, [10, 20] and [20, 30] which is
302  // coalesced into [10, 30] and it will contain one less byte than was requested.
303  // Only check if returned val <= 0 and make proper actions.
304  if (s < 0) {
306  ex << "Davix::readv(name='" << m_name << "', n=" << buffers
307  << ") failed and call returned " << s;
308  ex.addContext("Calling DavixFile::readv()");
309  throw ex;
310  } else if (s == 0) {
311  // end of file
312  return 0;
313  }
314  return total;
315 }
316 
318  DavixError *davixErr = nullptr;
319  m_davixPosix->fadvise(m_fd, 0, n, AdviseRandom);
320  IOSize done = 0;
321  while (done < n) {
322  ssize_t s = m_davixPosix->read(m_fd, (char *)into + done, n - done, &davixErr);
323  if (davixErr) {
324  std::unique_ptr<DavixError> davixErrManaged(davixErr);
326  ex << "Davix::read(name='" << m_name << "', n=" << (n - done)
327  << ") failed with error " << davixErr->getErrMsg().c_str() << " and error code "
328  << davixErr->getStatus() << " and call returned " << s << " bytes";
329  ex.addContext("Calling DavixFile::read()");
330  throw ex;
331  }
332  if (s < 0) {
334  ex << "Davix::read(name='" << m_name << "', n=" << (n - done)
335  << ") failed and call returned " << s;
336  ex.addContext("Calling DavixFile::read()");
337  throw ex;
338  } else if (s == 0) {
339  // end of file
340  break;
341  }
342  done += s;
343  }
344  return done;
345 }
346 
347 IOSize DavixFile::write(const void *from, IOSize n) {
349  ex << "DavixFile::write(name='" << m_name << "') not implemented";
350  ex.addContext("Calling DavixFile::write()");
351  throw ex;
352 }
353 
355  DavixError *davixErr = nullptr;
356  if (whence != CURRENT && whence != SET && whence != END) {
357  cms::Exception ex("FilePositionError");
358  ex << "DavixFile::position() called with incorrect 'whence' parameter";
359  ex.addContext("Calling DavixFile::position()");
360  throw ex;
361  }
363  size_t mywhence = (whence == SET ? SEEK_SET : whence == CURRENT ? SEEK_CUR : SEEK_END);
364 
365  if ((result = m_davixPosix->lseek(m_fd, offset, mywhence, &davixErr)) == -1) {
366  cms::Exception ex("FilePositionError");
367  ex << "Davix::lseek(name='" << m_name << "', offset=" << offset
368  << ", whence=" << mywhence << ") failed with error " << davixErr->getErrMsg().c_str()
369  << " and error code " << davixErr->getStatus() << " and "
370  << "call returned " << result;
371  ex.addContext("Calling DavixFile::position()");
372  throw ex;
373  }
374 
375  return result;
376 }
377 
378 void DavixFile::resize(IOOffset /* size */) {
379  cms::Exception ex("FileResizeError");
380  ex << "DavixFile::resize(name='" << m_name << "') not implemented";
381  ex.addContext("Calling DavixFile::resize()");
382  throw ex;
383 }
static void configureDavixLogLevel()
Definition: DavixFile.cc:68
static const TGPicture * info(bool iBackgroundIsBlack)
IOSize write(const void *from, IOSize n) override
Definition: DavixFile.cc:347
void * data(void) const
Definition: IOBuffer.h:45
IOSize readv(IOBuffer *into, IOSize buffers) override
Definition: DavixFile.cc:224
std::vector< Variable::Flags > flags
Definition: MVATrainer.cc:135
virtual void abort(void)
Definition: DavixFile.cc:52
virtual void create(const char *name, bool exclusive=false, int perms=0666)
Definition: DavixFile.cc:146
DavixFile(void)
Definition: DavixFile.cc:18
Relative
Definition: Storage.h:23
static int X509Authentication(void *userdata, const SessionInfo &info, X509Credential *cert, DavixError **davixErr)
Definition: DavixFile.cc:109
virtual IOOffset position(void) const
Definition: Storage.cc:95
void close(void) override
Definition: DavixFile.cc:34
int read(void)
Definition: IOInput.cc:54
IOOffset offset(void) const
Definition: IOPosBuffer.h:54
void * data(void) const
Definition: IOPosBuffer.h:59
IOSize size(void) const
Definition: IOBuffer.h:50
IOSize size(void) const
Definition: IOPosBuffer.h:64
void addContext(std::string const &context)
Definition: Exception.cc:165
virtual void open(const char *name, int flags=IOFlags::OpenRead, int perms=0666)
Definition: DavixFile.cc:164
int64_t IOOffset
Definition: IOTypes.h:19
void resize(IOOffset size) override
Definition: DavixFile.cc:378
size_t IOSize
Definition: IOTypes.h:14
~DavixFile(void) override
Definition: DavixFile.cc:29
def move(src, dest)
Definition: eostools.py:511
static std::once_flag davixDebugInit
Definition: DavixFile.cc:14