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 using namespace edm::storage;
18 
19 DavixFile::DavixFile(void) {}
20 
21 DavixFile::DavixFile(const char *name, int flags /* = IOFlags::OpenRead */, int perms /* = 066 */) {
22  open(name, flags, perms);
23 }
24 
25 DavixFile::DavixFile(const std::string &name, int flags /* = IOFlags::OpenRead */, int perms /* = 066 */) {
26  open(name.c_str(), flags, perms);
27 }
28 
29 DavixFile::~DavixFile(void) {
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 " << err->getErrMsg().c_str() << " and error code "
44  << 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 " << err->getErrMsg().c_str() << " and error code "
60  << err->getStatus();
61  ex.addContext("Calling DavixFile::abort()");
62  throw ex;
63  }
64  }
65  return;
66 }
67 
68 void DavixFile::configureDavixLogLevel() {
69  long logLevel = 0;
70  char *logptr = nullptr;
71  char const *const davixDebug = std::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, DavixError **davixErr) {
110  std::string ucert, ukey;
111  char default_proxy[64];
112  snprintf(default_proxy, sizeof(default_proxy), "/tmp/x509up_u%d", geteuid());
113  // X509_USER_PROXY
114  if (std::getenv("X509_USER_PROXY")) {
115  edm::LogInfo("DavixFile") << "X509_USER_PROXY found in environment."
116  << " Will use it for authentication";
117  ucert = ukey = std::getenv("X509_USER_PROXY");
118  }
119  // Default proxy location
120  else if (access(default_proxy, R_OK) == 0) {
121  edm::LogInfo("DavixFile") << "Found proxy in default location " << default_proxy
122  << " Will use it for authentication";
123  ucert = ukey = default_proxy;
124  }
125  // X509_USER_CERT
126  else if (std::getenv("X509_USER_CERT")) {
127  ucert = std::getenv("X509_USER_CERT");
128  }
129  // X509_USER_KEY only if X509_USER_CERT was found
130  if (!ucert.empty() && std::getenv("X509_USER_KEY")) {
131  edm::LogInfo("DavixFile") << "X509_USER_{CERT|KEY} found in environment"
132  << " Will use it for authentication";
133  ukey = std::getenv("X509_USER_KEY");
134  }
135  // Check if vars are set...
136  if (ucert.empty() || ukey.empty()) {
137  edm::LogWarning("DavixFile") << "Was not able to find proxy in $X509_USER_PROXY, "
138  << "X509_USER_{CERT|KEY} or default proxy creation location. "
139  << "Will try without authentication";
140  return -1;
141  }
142  return cert->loadFromFilePEM(ukey, ucert, "", davixErr);
143 }
144 
145 void DavixFile::create(const char *name, bool exclusive /* = false */, int perms /* = 066 */) {
146  open(name,
148  perms);
149 }
150 
151 void DavixFile::create(const std::string &name, bool exclusive /* = false */, int perms /* = 066 */) {
152  open(name.c_str(),
154  perms);
155 }
156 
157 void DavixFile::open(const std::string &name, int flags /* = IOFlags::OpenRead */, int perms /* = 066 */) {
158  open(name.c_str(), flags, perms);
159 }
160 
161 void DavixFile::open(const char *name, int flags /* = IOFlags::OpenRead */, int perms /* = 066 */) {
162  // Actual open
163  if ((name == nullptr) || (*name == 0)) {
165  ex << "Cannot open a file without name";
166  ex.addContext("Calling DavixFile::open()");
167  throw ex;
168  }
169  m_name = name;
170 
171  if ((flags & IOFlags::OpenRead) == 0) {
173  ex << "Must open file '" << name << "' at least for read";
174  ex.addContext("Calling DavixFile::open()");
175  throw ex;
176  }
177 
178  if (m_davixPosix && m_fd) {
180  ex << "Davix::open(name='" << m_name << "') failed on already open file";
181  ex.addContext("Calling DavixFile::open()");
182  throw ex;
183  }
184  configureDavixLogLevel();
185  // Translate our flags to system flags
186  int openflags = 0;
187 
188  if (flags & IOFlags::OpenRead)
189  openflags |= O_RDONLY;
190 
191  DavixError *davixErr = nullptr;
192  RequestParams davixReqParams;
193  // Set up X509 authentication
194  davixReqParams.setClientCertCallbackX509(&X509Authentication, nullptr);
195  // Set also CERT_DIR if it is set in envinroment, otherwise use default
196  const char *cert_dir = nullptr;
197  if ((cert_dir = std::getenv("X509_CERT_DIR")) == nullptr)
198  cert_dir = "/etc/grid-security/certificates";
199  davixReqParams.addCertificateAuthorityPath(cert_dir);
200 
201  m_davixPosix = std::make_unique<DavPosix>(new Context());
202  m_fd = m_davixPosix->open(&davixReqParams, name, openflags, &davixErr);
203 
204  // Check Davix Error
205  if (davixErr) {
206  std::unique_ptr<DavixError> davixErrManaged(davixErr);
208  ex << "Davix::open(name='" << m_name << "') failed with "
209  << "error '" << davixErr->getErrMsg().c_str() << " and error code " << davixErr->getStatus();
210  ex.addContext("Calling DavixFile::open()");
211  throw ex;
212  }
213  if (!m_fd) {
215  ex << "Davix::open(name='" << m_name << "') failed as fd is NULL";
216  ex.addContext("Calling DavixFile::open()");
217  throw ex;
218  }
219 }
220 
221 IOSize DavixFile::readv(IOBuffer *into, IOSize buffers) {
222  assert(!buffers || into);
223 
224  // Davix does not support 0 buffers;
225  if (buffers == 0)
226  return 0;
227 
228  DavixError *davixErr = nullptr;
229 
230  std::vector<DavIOVecInput> input_vector(buffers);
231  std::vector<DavIOVecOuput> output_vector(buffers);
232  IOSize total = 0; // Total requested bytes
233  for (IOSize i = 0; i < buffers; ++i) {
234  input_vector[i].diov_size = into[i].size();
235  input_vector[i].diov_buffer = static_cast<char *>(into[i].data());
236  total += into[i].size();
237  }
238 
239  ssize_t s = m_davixPosix->preadVec(m_fd, input_vector.data(), output_vector.data(), buffers, &davixErr);
240  if (davixErr) {
241  std::unique_ptr<DavixError> davixErrManaged(davixErr);
243  ex << "Davix::readv(name='" << m_name << "', buffers=" << (buffers) << ") failed with error "
244  << davixErr->getErrMsg().c_str() << " and error code " << davixErr->getStatus() << " and call returned " << s
245  << " bytes";
246  ex.addContext("Calling DavixFile::readv()");
247  throw ex;
248  }
249  // Davix limits number of requests sent to the server
250  // to improve performance and it does range coalescing.
251  // So we can`t check what preadVec returns with what was requested.
252  // Example: If two ranges are overlapping, [10, 20] and [20, 30] which is
253  // coalesced into [10, 30] and it will contain one less byte than was requested.
254  // Only check if returned val <= 0 and make proper actions.
255  if (s < 0) {
257  ex << "Davix::readv(name='" << m_name << "') failed and call returned " << s;
258  ex.addContext("Calling DavixFile::readv()");
259  throw ex;
260  } else if (s == 0) {
261  // end of file
262  return 0;
263  }
264  return total;
265 }
266 
267 IOSize DavixFile::readv(IOPosBuffer *into, IOSize buffers) {
268  assert(!buffers || into);
269 
270  // Davix does not support 0 buffers;
271  if (buffers == 0)
272  return 0;
273 
274  DavixError *davixErr = nullptr;
275 
276  std::vector<DavIOVecInput> input_vector(buffers);
277  std::vector<DavIOVecOuput> output_vector(buffers);
278  IOSize total = 0;
279  for (IOSize i = 0; i < buffers; ++i) {
280  input_vector[i].diov_offset = into[i].offset();
281  input_vector[i].diov_size = into[i].size();
282  input_vector[i].diov_buffer = static_cast<char *>(into[i].data());
283  total += into[i].size();
284  }
285  ssize_t s = m_davixPosix->preadVec(m_fd, input_vector.data(), output_vector.data(), buffers, &davixErr);
286  if (davixErr) {
287  std::unique_ptr<DavixError> davixErrManaged(davixErr);
289  ex << "Davix::readv(name='" << m_name << "', n=" << buffers << ") failed with error "
290  << davixErr->getErrMsg().c_str() << " and error code " << davixErr->getStatus() << " and call returned " << s
291  << " bytes";
292  ex.addContext("Calling DavixFile::readv()");
293  throw ex;
294  }
295  // Davix limits number of requests sent to the server
296  // to improve performance and it does range coalescing.
297  // So we can`t check what preadVec returns with what was requested.
298  // Example: If two ranges are overlapping, [10, 20] and [20, 30] which is
299  // coalesced into [10, 30] and it will contain one less byte than was requested.
300  // Only check if returned val <= 0 and make proper actions.
301  if (s < 0) {
303  ex << "Davix::readv(name='" << m_name << "', n=" << buffers << ") failed and call returned " << s;
304  ex.addContext("Calling DavixFile::readv()");
305  throw ex;
306  } else if (s == 0) {
307  // end of file
308  return 0;
309  }
310  return total;
311 }
312 
314  DavixError *davixErr = nullptr;
315  m_davixPosix->fadvise(m_fd, 0, n, AdviseRandom);
316  IOSize done = 0;
317  while (done < n) {
318  ssize_t s = m_davixPosix->read(m_fd, (char *)into + done, n - done, &davixErr);
319  if (davixErr) {
320  std::unique_ptr<DavixError> davixErrManaged(davixErr);
322  ex << "Davix::read(name='" << m_name << "', n=" << (n - done) << ") failed with error "
323  << davixErr->getErrMsg().c_str() << " and error code " << davixErr->getStatus() << " and call returned " << s
324  << " bytes";
325  ex.addContext("Calling DavixFile::read()");
326  throw ex;
327  }
328  if (s < 0) {
330  ex << "Davix::read(name='" << m_name << "', n=" << (n - done) << ") failed and call returned " << s;
331  ex.addContext("Calling DavixFile::read()");
332  throw ex;
333  } else if (s == 0) {
334  // end of file
335  break;
336  }
337  done += s;
338  }
339  return done;
340 }
341 
342 IOSize DavixFile::write(const void *from, IOSize n) {
344  ex << "DavixFile::write(name='" << m_name << "') not implemented";
345  ex.addContext("Calling DavixFile::write()");
346  throw ex;
347 }
348 
350  DavixError *davixErr = nullptr;
351  if (whence != CURRENT && whence != SET && whence != END) {
352  cms::Exception ex("FilePositionError");
353  ex << "DavixFile::position() called with incorrect 'whence' parameter";
354  ex.addContext("Calling DavixFile::position()");
355  throw ex;
356  }
358  size_t mywhence = (whence == SET ? SEEK_SET : whence == CURRENT ? SEEK_CUR : SEEK_END);
359 
360  if ((result = m_davixPosix->lseek(m_fd, offset, mywhence, &davixErr)) == -1) {
361  cms::Exception ex("FilePositionError");
362  ex << "Davix::lseek(name='" << m_name << "', offset=" << offset << ", whence=" << mywhence << ") failed with error "
363  << davixErr->getErrMsg().c_str() << " and error code " << davixErr->getStatus() << " and "
364  << "call returned " << result;
365  ex.addContext("Calling DavixFile::position()");
366  throw ex;
367  }
368 
369  return result;
370 }
371 
372 void DavixFile::resize(IOOffset /* size */) {
373  cms::Exception ex("FileResizeError");
374  ex << "DavixFile::resize(name='" << m_name << "') not implemented";
375  ex.addContext("Calling DavixFile::resize()");
376  throw ex;
377 }
int64_t IOOffset
Definition: IOTypes.h:20
static const TGPicture * info(bool iBackgroundIsBlack)
def create(alignables, pedeDump, additionalData, outputFile, config)
assert(be >=bs)
IOOffset offset() const
Definition: IOPosBuffer.h:41
static int X509Authentication(void *userdata, const SessionInfo &info, X509Credential *cert, DavixError **davixErr)
Definition: DavixFile.cc:109
void * data() const
Definition: IOBuffer.h:33
IOSize size() const
Definition: IOBuffer.h:36
Log< level::Info, false > LogInfo
size_t IOSize
Definition: IOTypes.h:15
void addContext(std::string const &context)
Definition: Exception.cc:169
static int position[264][3]
Definition: ReadPGInfo.cc:289
Log< level::Warning, false > LogWarning
def move(src, dest)
Definition: eostools.py:511
static std::once_flag davixDebugInit
Definition: DavixFile.cc:14