XRootD
XrdClHttpFilesystem.cc
Go to the documentation of this file.
1 /******************************************************************************/
2 /* Copyright (C) 2025, Pelican Project, Morgridge Institute for Research */
3 /* */
4 /* This file is part of the XrdClHttp client plugin for XRootD. */
5 /* */
6 /* XRootD is free software: you can redistribute it and/or modify it under */
7 /* the terms of the GNU Lesser General Public License as published by the */
8 /* Free Software Foundation, either version 3 of the License, or (at your */
9 /* option) any later version. */
10 /* */
11 /* XRootD is distributed in the hope that it will be useful, but WITHOUT */
12 /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
13 /* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
14 /* License for more details. */
15 /* */
16 /* The copyright holder's institutional names and contributor's names may not */
17 /* be used to endorse or promote products derived from this software without */
18 /* specific prior written permission of the institution or contributor. */
19 /******************************************************************************/
20 
21 #include "XrdClHttpFactory.hh"
22 #include "XrdClHttpFilesystem.hh"
23 #include "XrdClHttpOps.hh"
24 #include "XrdClHttpResponses.hh"
26 
27 #include "XrdCl/XrdClAnyObject.hh"
28 #include "XrdCl/XrdClDefaultEnv.hh"
30 #include "XProtocol/XProtocol.hh"
31 
32 #include <algorithm>
33 #include <cerrno>
34 #include <condition_variable>
35 #include <chrono>
36 #include <exception>
37 #include <memory>
38 #include <mutex>
39 #include <optional>
40 #include <string>
41 
42 using namespace XrdClHttp;
43 using namespace std::string_literals;
44 
45 namespace
46 {
47 
48 // Blocks the calling thread until the operation it is given to completes.
49 class SyncResponseHandler final : public XrdCl::ResponseHandler
50 {
51 public:
52  // The operation gives the ownership of both objects to this handler. The
53  // result of the operation comes from the operation itself, thus this
54  // handler reads neither of them and releases them immediately.
55  void HandleResponse(XrdCl::XRootDStatus *status,
56  XrdCl::AnyObject *response) override
57  {
58  if (status != nullptr)
59  {
60  const std::unique_ptr<XrdCl::XRootDStatus> owned_status{status};
61  }
62 
63  if (response != nullptr)
64  {
65  const std::unique_ptr<XrdCl::AnyObject> owned_response{response};
66  }
67 
68  {
69  const std::lock_guard<std::mutex> lock{mutex};
70  is_ready = true;
71  }
72 
73  is_ready_changed.notify_all();
74  }
75 
76  // Return false when the wait takes more than the timeout.
77  bool wait(std::chrono::seconds timeout = std::chrono::seconds(0))
78  {
79  std::unique_lock<std::mutex> lock{mutex};
80 
81  bool ready = true;
82 
83  if (timeout.count() > 0)
84  ready = is_ready_changed.wait_for(lock, timeout, [this]{ return is_ready; });
85  else
86  is_ready_changed.wait(lock, [this]{ return is_ready; });
87 
88  is_ready = false;
89 
90  return ready;
91  }
92 
93 private:
94  std::mutex mutex{};
95  std::condition_variable is_ready_changed{};
96  bool is_ready{false};
97 };
98 
99 // Adds fixed headers, such as the Authorization header of one endpoint, to
100 // the headers of a request.
101 class ExtraHeaderCallout final : public XrdClHttp::HeaderCallout
102 {
103 public:
104  explicit ExtraHeaderCallout(HeaderList extra) : extra(std::move(extra)) {}
105 
106  std::shared_ptr<HeaderList> GetHeaders(const std::string &,
107  const std::string &,
108  const HeaderList &headers) override
109  {
110  auto result = std::make_shared<HeaderList>(headers);
111  result->insert(result->end(), extra.begin(), extra.end());
112  return result;
113  }
114 
115 private:
116  const HeaderList extra;
117 };
118 
119 }
120 
121 Filesystem::Filesystem(const std::string &url, std::shared_ptr<HandlerQueue> queue, XrdCl::Log *log)
122  : m_queue(queue),
123  m_logger(log),
124  m_url(url)
125 {
126  m_logger->Debug(kLogXrdClHttp, "Constructing filesystem object with base URL %s", url.c_str());
127  // When constructed from the root protocol handler, we've observed it include the
128  // path here (the code paths appear to be slightly different from http://). Strip
129  // it out so it's not included twice later.
130  m_url.SetPath("/");
132  m_url.SetParams(map);
133 }
134 
135 Filesystem::~Filesystem() noexcept {}
136 
138 Filesystem::QueueOperation(std::unique_ptr<CurlOperation> operation,
139  const char *description)
140 {
141  try
142  {
143  m_queue->Produce(std::move(operation));
144  }
145  catch(const std::exception &ex)
146  {
147  m_logger->Warning(kLogXrdClHttp,
148  "Failed to add %s to queue: %s", description, ex.what());
150  EIO, ex.what());
151  }
152  return XrdCl::XRootDStatus();
153 }
154 
156 Filesystem::DirList(const std::string &path,
158  XrdCl::ResponseHandler *handler,
159  time_t timeout )
160 {
162 
163  auto full_url = GetCurrentURL(path);
164 
165  m_logger->Debug(kLogXrdClHttp, "Filesystem::DirList path %s", path.c_str());
166  auto listdirOp = std::make_unique<XrdClHttp::CurlListdirOp>(
167  handler, full_url,
168  m_url.GetHostName() + ":" + std::to_string(m_url.GetPort()),
169  SendResponseInfo(), ts, m_logger,
170  GetConnCallout(), m_header_callout.load(std::memory_order_acquire));
171  return QueueOperation(std::move(listdirOp), "directory list operation");
172 }
173 
174 CreateConnCalloutType
175 Filesystem::GetConnCallout() const {
176  std::string pointer_str;
177  if (!GetProperty("XrdClConnectionCallout", pointer_str) && pointer_str.empty()) {
178  return nullptr;
179  }
180  long long pointer;
181  try {
182  pointer = std::stoll(pointer_str, nullptr, 16);
183  } catch (...) {
184  return nullptr;
185  }
186  if (!pointer) {
187  return nullptr;
188  }
189  return reinterpret_cast<CreateConnCalloutType>(pointer);
190 }
191 
192 bool
193 Filesystem::GetProperty(const std::string &name,
194  std::string &value) const
195 {
196  std::shared_lock lock(m_properties_mutex);
197 
198  const auto p = m_properties.find(name);
199  if (p == std::end(m_properties)) {
200  return false;
201  }
202 
203  value = p->second;
204  return true;
205 }
206 
207 // Trivial implementation of the "locate" call
208 //
209 // On Linux, this is invoked by the XrdCl client prior to directory listings.
210 // Given there's no concept of multiple locations currently, we just return
211 // the original host and port as the available "location".
213 Filesystem::Locate( const std::string &path,
215  XrdCl::ResponseHandler *handler,
216  time_t timeout )
217 {
218  if (!handler) return XrdCl::XRootDStatus();
219 
220  auto locateInfo = std::make_unique<XrdCl::LocationInfo>();
221  locateInfo->Add(XrdCl::LocationInfo::Location(m_url.GetHostName() + ":" + std::to_string(m_url.GetPort()), XrdCl::LocationInfo::ServerOnline, XrdCl::LocationInfo::Read));
222 
223  auto obj = std::make_unique<XrdCl::AnyObject>();
224  obj->Set(locateInfo.release());
225  handler->HandleResponse(new XrdCl::XRootDStatus(), obj.release());
226 
227  return XrdCl::XRootDStatus();
228 }
229 
230 XrdCl::XRootDStatus Filesystem::MkDir(const std::string &path,
232  XrdCl::Access::Mode mode,
233  XrdCl::ResponseHandler *handler,
234  time_t timeout)
235 {
237 
238  auto full_url = GetCurrentURL(path);
239  m_logger->Debug(kLogXrdClHttp, "Filesystem::MkDir path %s", full_url.c_str());
240 
241  auto mkdirOp = std::make_unique<CurlMkcolOp>(
242  handler, full_url, ts, m_logger, SendResponseInfo(), GetConnCallout(),
243  m_header_callout.load(std::memory_order_acquire));
244  return QueueOperation(std::move(mkdirOp), "filesystem mkdir operation");
245 }
246 
248  const std::vector<std::string> &fileList,
250  uint8_t priority,
251  XrdCl::ResponseHandler *handler,
252  time_t timeout)
253 {
254  (void)priority;
255 
256  if(fileList.empty())
257  {
259  EINVAL, "missing prepare file list");
260  }
261 
263  auto tapeOp = std::make_unique<CurlTapePrepareOp>(
264  handler, m_url.GetURL(), fileList, flags, ts, m_logger,
265  GetConnCallout(),
266  m_header_callout.load(std::memory_order_acquire));
267  return QueueOperation(std::move(tapeOp), "Tape prepare operation");
268 }
269 
271  const XrdCl::Buffer &arg,
272  XrdCl::ResponseHandler *handler,
273  time_t timeout)
274 {
276  std::unique_ptr<CurlOperation> operation;
277  const char *description = nullptr;
278 
279  switch(queryCode)
280  {
283  operation = std::make_unique<CurlTapeQueryOp>(
284  handler, m_url.GetURL(), queryCode, arg, ts, m_logger,
285  GetConnCallout(),
286  m_header_callout.load(std::memory_order_acquire));
287  description = "Tape query operation";
288  break;
290  {
291  const auto url = GetCurrentURL(arg.ToString());
292  m_logger->Debug(kLogXrdClHttp,
293  "XrdClHttp::Filesystem::Query checksum path %s", url.c_str());
294 
295  XrdClHttp::ChecksumType preferred =
296  XrdClHttp::ChecksumType::kAll;
297  XrdCl::URL urlObj;
298  urlObj.FromString(url);
299  const auto iter = urlObj.GetParams().find("cks.type");
300  if(iter != urlObj.GetParams().end())
301  {
302  preferred = XrdClHttp::GetTypeFromString(iter->second);
303  if(preferred == XrdClHttp::ChecksumType::kUnknown)
304  {
305  m_logger->Error(kLogXrdClHttp,
306  "Unknown checksum type %s", iter->second.c_str());
308  XrdCl::errInvalidArgs, EINVAL,
309  "unknown checksum type '" + iter->second + "'");
310  }
311  }
312  operation = std::make_unique<CurlChecksumOp>(
313  handler, url, preferred, ts, m_logger, SendResponseInfo(),
314  GetConnCallout(),
315  m_header_callout.load(std::memory_order_acquire));
316  description = "checksum operation";
317  break;
318  }
320  {
321  const std::string path = arg.ToString();
322  m_logger->Debug(kLogXrdClHttp,
323  "XrdClHttp::Filesystem::Query xattr full_url %s, path %s",
324  m_url.GetURL().c_str(), path.c_str());
325  operation = std::make_unique<CurlQueryOp>(
326  handler, path, ts, m_logger, SendResponseInfo(),
327  GetConnCallout(), queryCode,
328  m_header_callout.load(std::memory_order_acquire));
329  description = "xattr query operation";
330  break;
331  }
332  default:
333  return XrdCl::XRootDStatus(
335  }
336 
337  return QueueOperation(std::move(operation), description);
338 }
339 
341 Filesystem::Rm(const std::string &path,
342  XrdCl::ResponseHandler *handler,
343  time_t timeout)
344 {
346 
347  auto full_url = GetCurrentURL(path);
348  m_logger->Debug(kLogXrdClHttp, "Filesystem::Rm path %s", full_url.c_str());
349 
350  auto deleteOp = std::make_unique<CurlDeleteOp>(
351  handler, full_url, ts, m_logger, SendResponseInfo(),
352  GetConnCallout(), m_header_callout.load(std::memory_order_acquire));
353  return QueueOperation(std::move(deleteOp), "filesystem delete operation");
354 }
355 
357 Filesystem::RmDir(const std::string &path,
358  XrdCl::ResponseHandler *handler,
359  time_t timeout)
360 {
361  return Rm(path, handler, timeout);
362 }
363 
364 bool
365 Filesystem::SetProperty(const std::string &name,
366  const std::string &value)
367 {
368  if (name == "XrdClHttpHeaderCallout") {
369  long long pointer;
370  try {
371  pointer = std::stoll(value, nullptr, 16);
372  } catch (...) {
373  pointer = 0;
374  }
375  if (!pointer) {
376  pointer = 0;
377  }
378  m_header_callout.store(reinterpret_cast<XrdClHttp::HeaderCallout*>(pointer), std::memory_order_release);
379  }
380 
381  std::unique_lock lock(m_properties_mutex);
382  m_properties[name] = value;
383  return true;
384 }
385 
387 Filesystem::Stat(const std::string &path,
388  XrdCl::ResponseHandler *handler,
389  time_t timeout)
390 {
392 
393  auto full_url = GetCurrentURL(path);
394  m_logger->Debug(kLogXrdClHttp, "Filesystem::Stat path %s", full_url.c_str());
395 
396  auto statOp = std::make_unique<CurlStatOp>(
397  handler, full_url, ts, m_logger, SendResponseInfo(),
398  GetConnCallout(), m_header_callout.load(std::memory_order_acquire));
399  return QueueOperation(std::move(statOp), "filesystem stat operation");
400 }
401 
402 // Returns true if the URL uses the http or the https protocol. A third party
403 // copy is possible only between these two protocols.
404 static bool is_http_url( const std::string &url )
405 {
406  const std::string protocol = XrdCl::URL(url).GetProtocol();
407  return protocol == "http" || protocol == "https" || protocol == "dav" || protocol == "davs";
408 }
409 
410 // The operations a third party copy runs. The unit tests replace them by
411 // declaring XrdClHttp::StatOp and XrdClHttp::CopyOp before they include this
412 // file, because the lookup of the unqualified name stops at namespace
413 // XrdClHttp.
414 namespace XrdClHttp
415 {
416  namespace ThirdPartyCopyOpTypes
417  {
418  using StatOp = CurlStatOp;
419  using CopyOp = CurlCopyOp;
420  }
421 }
422 
423 using namespace XrdClHttp::ThirdPartyCopyOpTypes;
424 
425 // Inside namespace XrdClHttp for the same name lookup of StatOp as above.
426 namespace XrdClHttp
427 {
428 // Stat the URL with the given extra headers. Returns the size, or nothing when
429 // the stat fails, does not finish in time, or cannot be queued.
430 static std::optional<std::size_t> stat_size(HandlerQueue &queue,
431  const std::string &url,
432  const CurlCopyOp::Headers &hdrs,
433  time_t timeout,
434  XrdCl::Log *log,
435  const char *what)
436 {
437  try
438  {
439  const auto callout = std::make_shared<ExtraHeaderCallout>(hdrs);
440  const auto rh = std::make_shared<SyncResponseHandler>();
441  const auto op = std::make_shared<StatOp>(rh.get(), url, timespec{timeout, 0}, log, true, nullptr, callout.get());
442 
443  // The queue may run the operation after this function returns, thus
444  // the operation keeps its handler and header callout alive.
445  queue.Produce(std::shared_ptr<StatOp>(op.get(), [callout, rh, op](auto){}));
446 
447  if (!rh->wait(std::chrono::seconds(timeout)))
448  log->Warning(kLogXrdClHttp, "Failed to stat the %s: Operation timed out", what);
449  else if (!op->IsDone() || op->HasFailed())
450  log->Debug(kLogXrdClHttp, "Failed to stat the %s", what);
451  else
452  return static_cast<std::size_t>(op->GetStatInfo().first);
453  }
454  catch (const std::exception &e) {
455  log->Warning(kLogXrdClHttp, "Failed to stat the %s - %s", what, e.what());
456  }
457 
458  return std::nullopt;
459 }
460 }
461 
463  const std::string &dest,
464  const XrdCl::PropertyList *properties,
465  XrdCl::ProgressHandler *progress_handler,
466  time_t timeout )
467 {
468  XrdCl::Log *const log = XrdCl::DefaultEnv::GetLog();
469  log->Debug(kLogXrdClHttp, "XrdClHttp::ThirdPartyCopy src %s dst %s", source.c_str(), dest.c_str());
470 
471  if (!is_http_url(source) || !is_http_url(dest))
472  {
473  log->Error(kLogXrdClHttp, "Third party copy can only be done between http(s) protocols");
475  "Third party copy can only be done between http(s) protocols");
476  }
477 
478  TpcMode mode = TpcMode::Pull;
479  int number_of_streams = 1;
480  time_t init_timeout = 0;
481  time_t tpc_timeout = 0;
482  std::string token_file;
483  bool force_overwrite = false;
484 
485  if (properties)
486  {
487  mode = properties->Get<std::string>("thirdPartyMode") != "push" ? TpcMode::Pull : TpcMode::Push;
488  properties->Get("initTimeout", init_timeout);
489  properties->Get("tpcTimeout", tpc_timeout);
490  token_file = properties->Get<std::string>("thirdPartyTokenFile");
491  properties->Get("force", force_overwrite);
492  }
493 
494  // The tpcTimeout property takes precedence over the timeout argument.
495  if (tpc_timeout == 0)
496  tpc_timeout = timeout;
497 
498  if (auto env = XrdCl::DefaultEnv::GetEnv(); env)
499  env->GetInt("SubStreamsPerChannel", number_of_streams);
500 
501  CurlCopyOp::Headers headers;
502  CurlCopyOp::Headers src_hdrs;
503  CurlCopyOp::Headers dst_hdrs;
504 
505  if (!token_file.empty() && !ParseTokenFile(token_file, src_hdrs, dst_hdrs))
507  "Failed to parse the token file '" + token_file + "'");
508 
509  const auto is_unsecure = [] (const CurlCopyOp::Headers &hdrs, const std::string &url)
510  {
511  return XrdCl::URL(url).GetProtocol() != "https"s &&
512  std::any_of(hdrs.begin(), hdrs.end(),
513  [] (const auto &header) { return header.first == "Authorization"s; });
514  };
515 
516  if (is_unsecure(src_hdrs, source) || is_unsecure(dst_hdrs, dest))
517  {
518  log->Error(kLogXrdClHttp, "Refusing to send an Authorization header over an unencrypted http URL");
520  "Refusing to send an Authorization header over an unencrypted http URL");
521  }
522 
523  // In push mode the source writes the destination with a PUT, which may
524  // replace an existing file whatever the Overwrite header says. Thus check
525  // the destination first, as the destination server may not honor it.
526  if (mode == TpcMode::Push && !force_overwrite &&
527  stat_size(*m_queue, dest, dst_hdrs, init_timeout, log, "destination"))
528  {
529  log->Error(kLogXrdClHttp, "The destination %s exists", dest.c_str());
531  "The destination exists; use --force to replace it");
532  }
533 
534  headers.emplace_back("X-Number-Of-Streams"s, std::to_string(number_of_streams));
535 
536  // The destination headers reach the destination in both modes: directly
537  // in pull mode, with the TransferHeader prefix in push mode.
538  dst_hdrs.emplace_back("Overwrite"s, force_overwrite ? "T"s : "F"s);
539 
540  std::size_t size = 0;
541 
542  if (progress_handler)
543  {
544  size = stat_size(*m_queue, source, src_hdrs, init_timeout, log, "source").value_or(0);
545  progress_handler->HandleProgress(0, size);
546  }
547 
548  const auto rh = std::make_shared<SyncResponseHandler>();
549  const auto op = std::make_shared<CopyOp>(rh.get(), source, src_hdrs, dest, dst_hdrs, headers,
550  mode, timespec{tpc_timeout, 0}, log, nullptr);
551  op->SetProgressHandler(progress_handler);
552 
553  try
554  {
555  m_queue->Produce(std::shared_ptr<CopyOp>(op.get(), [rh, op](auto){}));
556  }
557  catch (const std::exception &e) {
558  log->Warning(kLogXrdClHttp, "Failed to add copy op to queue - %s", e.what());
560  }
561 
562  if (!rh->wait(std::chrono::seconds(tpc_timeout)))
563  return XrdCl::XRootDStatus(XrdCl::stError, XrdCl::errOperationExpired, 0, "Operation expired: Operation timed out"s);
564 
565  if (op->IsDone() && !op->IsSentSuccessfully())
566  return XrdCl::XRootDStatus(XrdCl::stError, XrdCl::errPipelineFailed, 0, op->GetSendingFailureMessage());
567 
568  if (progress_handler && size > 0)
569  progress_handler->HandleProgress(size, size);
570 
571  return XrdCl::XRootDStatus();
572 }
573 
574 bool Filesystem::SendResponseInfo() const {
575  std::string val;
576  return GetProperty(ResponseInfoProperty, val) && val == "true";
577 }
578 
579 std::string Filesystem::GetCurrentURL(const std::string &path) const {
580 
581  // Compute the URL without trailing slash.
582  auto prefix = m_url.GetURL();
583  std::string_view prefix_view = prefix;
584  while (!prefix_view.empty() && prefix_view[prefix_view.size() - 1] == '/')
585  prefix_view = prefix_view.substr(0, prefix_view.size() - 1);
586 
587  // Compute the target path without the '/' prefix
588  std::string_view path_view = path;
589  while (!path_view.empty() && path_view[0] == '/')
590  path_view = path_view.substr(1);
591  auto retval = std::string(prefix_view) + "/" + std::string(path_view);
592 
593  // Add in the query parameters, if relevant.
594  {
595  std::shared_lock lock(m_properties_mutex);
596  auto iter = m_properties.find("XrdClHttpQueryParam");
597  if (iter != m_properties.end() && !iter->second.empty()) {
598  retval += ((retval.find('?') == std::string::npos) ? '?' : ':') + iter->second;
599  }
600  }
601  return retval;
602 }
@ kXR_ItExists
Definition: XProtocol.hh:1050
int extra
Definition: XrdAccTest.cc:63
static std::string ts()
timestamp output for logging messages
Definition: XrdCephOss.cc:53
struct stat Stat
Definition: XrdCks.cc:49
static bool is_http_url(const std::string &url)
#define ResponseInfoProperty
std::vector< std::pair< std::string, std::string > > Headers
static struct timespec GetHeaderTimeoutWithDefault(time_t oper_timeout)
virtual XrdCl::XRootDStatus ThirdPartyCopy(const std::string &source, const std::string &dest, const XrdCl::PropertyList *properties, XrdCl::ProgressHandler *progress_handler, time_t timeout=0) override
Filesystem(const std::string &, std::shared_ptr< HandlerQueue > queue, XrdCl::Log *log)
Binary blob representation.
Definition: XrdClBuffer.hh:34
std::string ToString() const
Convert the buffer to a string.
Definition: XrdClBuffer.hh:215
static Log * GetLog()
Get default log.
static Env * GetEnv()
Get default client environment.
@ Read
read access is allowed
@ ServerOnline
server node where the file is online
Handle diagnostics.
Definition: XrdClLog.hh:101
void Error(uint64_t topic, const char *format,...)
Report an error.
Definition: XrdClLog.cc:231
void Warning(uint64_t topic, const char *format,...)
Report a warning.
Definition: XrdClLog.cc:248
void Debug(uint64_t topic, const char *format,...)
Print a debug message.
Definition: XrdClLog.cc:282
Handle the progress of an asynchronous operation.
virtual void HandleProgress(std::size_t processed, std::size_t total=0)=0
A key-value pair map storing both keys and values as strings.
bool Get(const std::string &name, Item &item) const
Handle an async response.
virtual void HandleResponse(XRootDStatus *status, AnyObject *response)
URL representation.
Definition: XrdClURL.hh:31
std::map< std::string, std::string > ParamsMap
Definition: XrdClURL.hh:33
bool FromString(const std::string &url)
Parse a string and fill the URL fields.
Definition: XrdClURL.cc:59
const std::string & GetProtocol() const
Get the protocol.
Definition: XrdClURL.hh:118
const ParamsMap & GetParams() const
Get the URL params.
Definition: XrdClURL.hh:244
std::vector< std::pair< std::string, std::string > > HeaderList
static std::optional< std::size_t > stat_size(HandlerQueue &queue, const std::string &url, const CurlCopyOp::Headers &hdrs, time_t timeout, XrdCl::Log *log, const char *what)
ChecksumType GetTypeFromString(const std::string &str)
bool ParseTokenFile(const std::string &token_file, CurlCopyOp::Headers &src_hdrs, CurlCopyOp::Headers &dst_hdrs)
const uint16_t errErrorResponse
Definition: XrdClStatus.hh:105
MkDirImpl< false > MkDir
const uint16_t errOperationExpired
Definition: XrdClStatus.hh:90
const uint16_t errNotImplemented
Operation is not implemented.
Definition: XrdClStatus.hh:64
RmImpl< false > Rm
const uint16_t stError
An error occurred that could potentially be retried.
Definition: XrdClStatus.hh:32
LocateImpl< false > Locate
const uint16_t errInternal
Internal error.
Definition: XrdClStatus.hh:56
const uint16_t errOSError
Definition: XrdClStatus.hh:61
const uint16_t errPipelineFailed
Pipeline failed and operation couldn't be executed.
Definition: XrdClStatus.hh:66
const uint16_t errInvalidArgs
Definition: XrdClStatus.hh:58
RmDirImpl< false > RmDir
PrepareImpl< false > Prepare
DirListImpl< false > DirList
QueryImpl< false > Query
const uint16_t errAuthFailed
Definition: XrdClStatus.hh:88
const uint64_t kLogXrdClHttp
Mode
Access mode.
Flags
Open flags, may be or'd when appropriate.
Code
XRootD query request codes.
@ XAttr
Query file extended attributes.
@ Opaque
Implementation dependent.
@ Checksum
Query file checksum.
@ Prepare
Query prepare status.