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