XRootD
XrdXrootdXeqFAttr.cc
Go to the documentation of this file.
1 /******************************************************************************/
2 /* */
3 /* X r d X r o o t d X e q F A t t r . c c */
4 /* */
5 /* (c) 2018 by the Board of Trustees of the Leland Stanford, Jr., University */
6 /* Produced by Andrew Hanushevsky for Stanford University under contract */
7 /* DE-AC02-76-SFO0515 with the Department of Energy */
8 /* */
9 /* This file is part of the XRootD software suite. */
10 /* */
11 /* XRootD is free software: you can redistribute it and/or modify it under */
12 /* the terms of the GNU Lesser General Public License as published by the */
13 /* Free Software Foundation, either version 3 of the License, or (at your */
14 /* option) any later version. */
15 /* */
16 /* XRootD is distributed in the hope that it will be useful, but WITHOUT */
17 /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
18 /* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
19 /* License for more details. */
20 /* */
21 /* You should have received a copy of the GNU Lesser General Public License */
22 /* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
23 /* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */
24 /* */
25 /* The copyright holder's institutional names and contributor's names may not */
26 /* be used to endorse or promote products derived from this software without */
27 /* specific prior written permission of the institution or contributor. */
28 /******************************************************************************/
29 
30 #include <cstdio>
31 #include <cstring>
32 #include <arpa/inet.h>
33 #include <sys/uio.h>
34 #include <unistd.h>
35 
36 #include "XProtocol/XProtocol.hh"
37 #include "Xrd/XrdBuffer.hh"
38 #include "Xrd/XrdLink.hh"
39 #include "XrdOuc/XrdOucErrInfo.hh"
40 #include "XrdSfs/XrdSfsFAttr.hh"
48 
49 /******************************************************************************/
50 /* L o c a l S t r u c t u r e s */
51 /******************************************************************************/
52 
53 namespace
54 {
55 struct faCTL
56 {
57 XrdSfsFAInfo *info; // Pointer to attribute information
58 char *buff; // Buffer to be decoded
59 char *bend; // Pointer to last byte of buffer + 1
60 int vnsz; // Size of variable name segment
61 short iNum; // Number of info entries
62 short iEnd; // Index number of last entry processed
63 bool verr; // True if a value is in error, otherwise it's the name
64 
65  faCTL(char *bp, char *bz, int anum)
66  : info(new XrdSfsFAInfo[anum]), buff(bp), bend(bz),
67  vnsz(0), iNum(anum), iEnd(0), verr(false) {}
68  ~faCTL() {if (info) delete [] info;}
69 };
70 }
71 
72 #define CRED (const XrdSecEntity *)Client
73 
74 #define FATTR_NAMESPACE 'U'
75 
76 /******************************************************************************/
77 /* D e c o d e */
78 /******************************************************************************/
79 
80 namespace
81 {
82 XErrorCode Decode(faCTL &ctl, int MaxNsz, int MaxVsz)
83 {
84  char *bP = ctl.buff, *bend = ctl.bend;
85  int n, vsize;
86 
87 // Decode variable names as kXR_unt16 0 || kXR_char var[n] || kXR_char 0
88 //
89  ctl.verr = false;
90 
91  for (int i = 0; i < ctl.iNum; i++)
92  {ctl.iEnd = i;
93  if (bP+sizeof(kXR_unt16) >= bend) return kXR_ArgMissing;
94 
95  // Validate name prefix and force variable into the user namespace
96  //
97  if (*bP || *(bP+1)) return kXR_ArgInvalid;
98  ctl.info[i].Name = bP;
99  *bP++ = FATTR_NAMESPACE;
100  *bP++ = '.';
101 
102  // Process the name (null terminated string)
103  //
104  n = strlen(bP);
105  if (!n || n > MaxNsz)
106  return (n ? kXR_ArgTooLong : kXR_ArgMissing);
107  ctl.info[i].NLen = n;
108  bP += n+1;
109  }
110 
111 // If there are no values, then we are done
112 //
113  ctl.vnsz = bP - ctl.buff;
114  if (!MaxVsz) return (bP != bend ? kXR_BadPayload : (XErrorCode)0);
115  ctl.verr = true;
116 
117 // Decode variable values as kXR_int32 n || kXR_char val[n]
118 //
119  for (int i = 0; i < ctl.iNum; i++)
120  {ctl.iEnd = i;
121 
122  // Get the length
123  //
124  if (bP+sizeof(kXR_int32) > bend) return kXR_ArgInvalid;
125  memcpy(&vsize, bP, sizeof(kXR_int32));
126  vsize = ntohl(vsize);
127  if (vsize < 0 || vsize > MaxVsz) return kXR_ArgTooLong;
128  bP += sizeof(kXR_int32);
129 
130  // Get the value
131  //
132  ctl.info[i].Value = bP;
133  ctl.info[i].VLen = vsize;
134  bP += vsize;
135  if (bP > bend) return kXR_ArgInvalid;
136  }
137 
138 // Make sure nothing remains in the buffer
139 //
140  if (bP != bend) return kXR_BadPayload;
141  return (XErrorCode)0;
142 }
143 }
144 
145 /******************************************************************************/
146 /* F i l l R C */
147 /******************************************************************************/
148 
149 namespace
150 {
151 void FillRC(kXR_char *faRC, XrdSfsFAInfo *info, int inum)
152 {
153  kXR_unt16 rc;
154  int nerrs = 0;
155 
156 // Set status code for each element
157 //
158  for (int i = 0; i < inum; i++)
159  {if (info[i].faRC == 0) info[i].Name[0] = info[i].Name[1] = '\0';
160  else {nerrs++;
161  rc = htons(XProtocol::mapError(info[i].faRC));
162  memcpy(info[i].Name, &rc, sizeof(rc));
163  }
164  }
165 
166 // Complete vector and return length
167 //
168  faRC[0] = nerrs;
169  faRC[1] = inum;
170 }
171 }
172 
173 /******************************************************************************/
174 /* I O V e c */
175 /******************************************************************************/
176 
177 namespace
178 {
179 class IOVec
180 {
181 public:
182 struct iovec *Alloc(int &num)
183  {static int iovmax = -1;
184  if (iovmax == -1) {
185 #ifdef _SC_IOV_MAX
186  iovmax = sysconf(_SC_IOV_MAX);
187  if (iovmax == -1)
188 #endif
189 #ifdef IOV_MAX
190  iovmax = IOV_MAX;
191 #else
192  iovmax = 1024;
193 #endif
194  }
195  if (num > iovmax) num = iovmax;
196  theIOV = new struct iovec[num];
197  return theIOV;
198  }
199 
200  IOVec() : theIOV(0) {}
201  ~IOVec() {if (theIOV) delete [] theIOV;}
202 
203 private:
204 struct iovec *theIOV;
205 };
206 }
207 
208 /******************************************************************************/
209 /* S e n d E r r */
210 /******************************************************************************/
211 
212 namespace
213 {
214 int SendErr(XrdXrootdResponse &Resp, faCTL &ctl, XErrorCode eCode)
215 {
216  char eBuff[1024];
217 
218  snprintf(eBuff, sizeof(eBuff), "%s processing fattr %s argument #%d",
219  XProtocol::errName(eCode), (ctl.verr ? "data" : "name"), ctl.iNum);
220 
221  return Resp.Send(eCode, eBuff);
222 }
223 
224 
225 /* For future use
226 int SendErr(XrdXrootdResponse &Resp, const char *what, const char *path, int rc)
227 {
228  int eCode = XProtocol::mapError(rc);
229  char eBuff[2048];
230 
231  snprintf(eBuff, sizeof(eBuff), "%s processing fattr %s %s",
232  XProtocol::errName(eCode), what, path);
233 
234  return Resp.Send((XErrorCode)eCode, eBuff);
235 }
236 */
237 }
238 
239 /******************************************************************************/
240 /* d o _ F A t t r */
241 /******************************************************************************/
242 
243 int XrdXrootdProtocol::do_FAttr()
244 {
245  const char *eTxt;
246  char *fn, *fnCgi;
247  int faCode = static_cast<int>(Request.fattr.subcode); // Is unsigned
248  int popt, ropt, n, dlen = Request.header.dlen;
249  bool isRO;
250 
251 // Make sure we are configured for extended attributes
252 //
253  if (!usxMaxNsz)
254  return Response.Send(kXR_Unsupported, "fattr request is not supported");
255 
256 // Prevalidate the subcode (it is unsigned)
257 //
258  if (faCode > kXR_fatrrMaxSC)
259  return Response.Send( kXR_ArgInvalid, "fattr subcode is invalid");
260 
261 // Determine whether we will be reading or writing attributes
262 //
263  if (faCode == kXR_fattrGet || faCode == kXR_fattrList)
264  {isRO = true;
265  eTxt = "Inspecting file attributes";
266  } else {
267  isRO = false;
268  eTxt = "Modifying file attributes";
269  }
270 
271 // Make sure we have the right number of arguments
272 //
273  if (faCode != kXR_fattrList && !dlen)
275  "Required arguments for fattr request not present");
276 
277 // This operation may refer to an open file. Make sure it exists and is
278 // opened in a compatible mode. Otherwise, verify that the target file
279 // can be properly accessed by the client. If so, process the request.
280 //
281  if (!dlen || argp->buff[0] == 0)
282  {XrdXrootdFile *fp;
284  char *theArg = argp->buff;
285 
286  if (!FTab || !(fp = FTab->Get(fh.handle)))
287  return Response.Send(kXR_FileNotOpen,
288  "fattr does not refer to an open file");
289  if (!isRO && fp->FileMode != 'w')
291  "fattr request modifies a file open for reading");
292  if (dlen) {dlen--; theArg++;}
293 
294  return ProcFAttr(fp->FileKey, 0, theArg, dlen, faCode, false);
295  }
296 
297 // The operation is being targetted to a file path. First, get path length.
298 //
299  fn = argp->buff;
300  n = strlen(argp->buff); // Always ends with a null byte!
301 
302 // Prescreen the path and handle any redirects
303 //
304  if (rpCheck(fn, &fnCgi)) return rpEmsg(eTxt, fn);
305  if (!(popt = Squash(fn))) return vpEmsg(eTxt, fn);
306  if (Route[RD_open1].Host[rdType] && (ropt = RPList.Validate(fn)))
307  return Response.Send(kXR_redirect, Route[ropt].Port[rdType],
308  Route[ropt].Host[rdType]);
309 
310 // Hand this off to the attribute processor
311 //
312  return ProcFAttr(fn, fnCgi, argp->buff+n+1, dlen-n-1, faCode, true);
313 }
314 
315 /******************************************************************************/
316 /* P r o c F A t t r */
317 /******************************************************************************/
318 
319 int XrdXrootdProtocol::ProcFAttr(char *faPath, char *faCgi, char *faArgs,
320  int faALen, int faCode, bool doAChk)
321 {
322  int fNumAttr = static_cast<int>(Request.fattr.numattr);
323 
324 // Prevalidate the number of attributes (list must have zero)
325 //
326  if ((faCode == kXR_fattrList && fNumAttr != 0)
327  || (faCode != kXR_fattrList && (fNumAttr == 0 || fNumAttr > kXR_faMaxVars)))
328  return Response.Send( kXR_ArgInvalid, "fattr numattr is invalid");
329 
330 // Allocate an SFS control object now
331 //
332  XrdSfsFACtl sfsCtl(faPath, faCgi, fNumAttr);
333  sfsCtl.nPfx[0] = FATTR_NAMESPACE;
334  sfsCtl.nPfx[1] = '.';
335  if (doAChk) sfsCtl.opts = XrdSfsFACtl::accChk;
336 
337 // If this is merely a list then go do it as there is nothing to parse
338 //
339  if (faCode == kXR_fattrList) return XeqFALst(sfsCtl);
340 
341 // Parse the request buffer as needed
342 //
343  faCTL ctl(faArgs, faArgs+faALen, fNumAttr);
344  XErrorCode rc =
345  Decode(ctl, usxMaxNsz, (faCode == kXR_fattrSet ? usxMaxVsz : 0));
346  if (rc) return SendErr(Response, ctl, rc);
347 
348 // Transfer info ownership
349 //
350  sfsCtl.info = ctl.info;
351  ctl.info = 0;
352 
353 // Perform the requested action
354 //
355  if (faCode == kXR_fattrDel) return XeqFADel(sfsCtl, faArgs, ctl.vnsz);
356  if (faCode == kXR_fattrGet) return XeqFAGet(sfsCtl, faArgs, ctl.vnsz);
357  if (faCode == kXR_fattrSet) return XeqFASet(sfsCtl, faArgs, ctl.vnsz);
358 
359  return Response.Send(kXR_Unsupported, "fattr request is not supported");
360 }
361 
362 /******************************************************************************/
363 /* X e q F A D e l */
364 /******************************************************************************/
365 
366 int XrdXrootdProtocol::XeqFADel(XrdSfsFACtl &ctl, char *faVars, int faVLen)
367 {
369  struct iovec iov[3];
370  kXR_char faRC[2];
371  int rc;
372 
373 // Set correct subcode
374 //
375  ctl.rqst = XrdSfsFACtl::faDel;
376 
377 // Execute the action
378 //
379  if ((rc = osFS->FAttr(&ctl, eInfo, CRED)))
380  return fsError(rc, XROOTD_MON_OPENW, eInfo, ctl.path, (char *)ctl.pcgi);
381 
382 // Format the response
383 //
384  FillRC(faRC, ctl.info, ctl.iNum);
385 
386 // Send off the response
387 //
388  iov[1].iov_base = faRC;
389  iov[1].iov_len = sizeof(faRC);
390  iov[2].iov_base = faVars;
391  iov[2].iov_len = faVLen;
392  return Response.Send(iov, 3, sizeof(faRC) + faVLen);
393 }
394 
395 /******************************************************************************/
396 /* X e q F A G e t */
397 /******************************************************************************/
398 
399 int XrdXrootdProtocol::XeqFAGet(XrdSfsFACtl &ctl, char *faVars, int faVLen)
400 {
402  IOVec iovHelper;
403  struct iovec *iov;
404  kXR_char faRC[2];
405  XResponseType rcode;
406  int k, rc, dlen, vLen;
407 
408 // Set correct subcode
409 //
410  ctl.rqst = XrdSfsFACtl::faGet;
411 
412 // Execute the action
413 //
414  if ((rc = osFS->FAttr(&ctl, eInfo, CRED)))
415  return fsError(rc, XROOTD_MON_OPENR, eInfo, ctl.path, (char *)ctl.pcgi);
416 
417 // Format the common response
418 //
419  FillRC(faRC, ctl.info, ctl.iNum);
420 
421 // Allocate an iovec. We need two elements for each info entry.
422 //
423  int iovNum = ctl.iNum*2+3;
424  iov = iovHelper.Alloc(iovNum);
425 
426 // Prefill the io vector (number of errors, vars, followed the rc-names
427 //
428  iov[1].iov_base = faRC;
429  iov[1].iov_len = sizeof(faRC);
430  iov[2].iov_base = faVars;
431  iov[2].iov_len = faVLen;
432  dlen = sizeof(faRC) + faVLen;
433  k = 3;
434 
435 // Return the value for for each variable, segment the response, if need be
436 //
437  for (int i = 0; i < ctl.iNum; i++)
438  {iov[k ].iov_base = &ctl.info[i].VLen;
439  iov[k++].iov_len = sizeof(ctl.info[i].VLen);
440  dlen += sizeof(ctl.info[i].VLen);
441  if (ctl.info[i].faRC || ctl.info[i].VLen == 0) ctl.info[i].VLen = 0;
442  else {vLen = ctl.info[i].VLen;
443  ctl.info[i].VLen = htonl(ctl.info[i].VLen);
444  iov[k ].iov_base = (void *)ctl.info[i].Value;
445  iov[k++].iov_len = vLen;
446  dlen += vLen;
447  }
448  if (k+1 >= iovNum)
449  {rcode = (i+1 == ctl.iNum ? kXR_ok : kXR_oksofar);
450  if ((rc = Response.Send(rcode, iov, k, dlen))) return rc;
451  k = 1; dlen = 0;
452  }
453  }
454 
455 // Check if we need to send out the last amount of data
456 //
457  return (dlen ? Response.Send(iov, k, dlen) : 0);
458 }
459 
460 /******************************************************************************/
461 /* X e q F A L s d */
462 /******************************************************************************/
463 
464 int XrdXrootdProtocol::XeqFALsd(XrdSfsFACtl &ctl)
465 {
466  IOVec iovHelper;
467  struct iovec *iov;
468  XResponseType rcode;
469  int k = 1, rc = 0, dlen = 0, vLen;
470  bool xresp = false;
471 
472 // Make sure we have something to send
473 //
474  if (!ctl.iNum) return Response.Send();
475 
476 // Allocate an iovec. We need three elements for each info entry.
477 //
478  int iovNum = ctl.iNum*3+1;
479  iov = iovHelper.Alloc(iovNum);
480 
481 // Return the value for for each variable, segment the response, if need be
482 //
483  for (int i = 0; i < ctl.iNum; i++)
484  {if (ctl.info[i].faRC) continue;
485  iov[k ].iov_base = ctl.info[i].Name;
486  iov[k++].iov_len = ctl.info[i].NLen+1;
487  dlen += ctl.info[i].NLen+1;
488 
489  vLen = ctl.info[i].VLen;
490  ctl.info[i].VLen = htonl(vLen);
491  iov[k ].iov_base = &ctl.info[i].VLen;
492  iov[k++].iov_len = sizeof(ctl.info[i].VLen);
493  dlen += sizeof(ctl.info[i].VLen);
494 
495  iov[k ].iov_base = (void *)ctl.info[i].Value;
496  iov[k++].iov_len = vLen;
497  dlen += vLen;
498 
499  if (k+2 >= iovNum)
500  {rcode = (i+1 == ctl.iNum ? kXR_ok : kXR_oksofar);
501  if ((rc = Response.Send(rcode, iov, k, dlen))) return rc;
502  k = 1; dlen = 0; xresp = true;
503  }
504  }
505 
506 // Check if we need to send out the last amount of data
507 //
508  return (dlen ? Response.Send(iov, k, dlen) : 0);
509 
510 // Check if anything was sent at all
511 //
512  return (xresp ? 0 : Response.Send());
513 }
514 
515 /******************************************************************************/
516 /* X e q F A L s t */
517 /******************************************************************************/
518 
519 int XrdXrootdProtocol::XeqFALst(XrdSfsFACtl &ctl)
520 {
521  struct iovec iov[16];
523  int rc;
524 
525 // Set correct subcode
526 //
527  ctl.rqst = XrdSfsFACtl::faLst;
528 
529 // Set correct options
530 //
532  ctl.opts |= XrdSfsFACtl::retval;
533 
534 // Execute the action
535 //
536  if ((rc = osFS->FAttr(&ctl, eInfo, CRED)))
537  return fsError(rc, XROOTD_MON_OPENR, eInfo, ctl.path, (char *)ctl.pcgi);
538 
539 // Check for more complicated return
540 //
541  if (ctl.opts & XrdSfsFACtl::retval) return XeqFALsd(ctl);
542 
543 // If there is only a single buffer, hen we can do a simple response
544 //
545  if (!ctl.fabP) return Response.Send();
546  if (ctl.fabP->next == 0)
547  return Response.Send(ctl.fabP->data, ctl.fabP->dlen);
548 
549 // Send of the response in as many segments as we need
550 //
551  int dlen = 0, i = 1;
552  XrdSfsFABuff *dP = ctl.fabP;
553 
554  while(dP)
555  {iov[i].iov_base = dP->data;
556  iov[i].iov_len = dP->dlen;
557  dlen += dP->dlen;
558  dP = dP->next;
559  i++;
560  if (i == (int)sizeof(iov))
561  {rc = Response.Send((dP ? kXR_oksofar : kXR_ok), iov, i, dlen);
562  if (rc || dP == 0) return rc;
563  dlen = 0;
564  i = 1;
565  }
566  }
567 
568 // Check if we need to send out the last amount of data
569 //
570  return (dlen ? Response.Send(iov, i, dlen) : 0);
571 }
572 
573 /******************************************************************************/
574 /* d o _ F A S e t */
575 /******************************************************************************/
576 
577 int XrdXrootdProtocol::XeqFASet(XrdSfsFACtl &ctl, char *faVars, int faVLen)
578 {
580  struct iovec iov[3];
581  kXR_char faRC[2];
582  int rc;
583 
584 // Set correct subcode and options
585 //
586  ctl.rqst = XrdSfsFACtl::faSet;
588  ctl.opts |= XrdSfsFACtl::newAtr;
589 
590 // Execute the action
591 //
592  if ((rc = osFS->FAttr(&ctl, eInfo, CRED)))
593  return fsError(rc, XROOTD_MON_OPENW, eInfo, ctl.path, (char *)ctl.pcgi);
594 
595 // Format the response
596 //
597  FillRC(faRC, ctl.info, ctl.iNum);
598 
599 // Send off the response
600 //
601  iov[1].iov_base = faRC;
602  iov[1].iov_len = sizeof(faRC);
603  iov[2].iov_base = faVars;
604  iov[2].iov_len = faVLen;
605  return Response.Send(iov, 3, sizeof(faRC) + faVLen);
606 }
XErrorCode
Definition: XProtocol.hh:987
@ kXR_ArgInvalid
Definition: XProtocol.hh:988
@ kXR_InvalidRequest
Definition: XProtocol.hh:994
@ kXR_ArgMissing
Definition: XProtocol.hh:989
@ kXR_BadPayload
Definition: XProtocol.hh:1014
@ kXR_FileNotOpen
Definition: XProtocol.hh:992
@ kXR_Unsupported
Definition: XProtocol.hh:1001
@ kXR_ArgTooLong
Definition: XProtocol.hh:990
@ kXR_fattrDel
Definition: XProtocol.hh:270
@ kXR_fattrSet
Definition: XProtocol.hh:273
@ kXR_fattrList
Definition: XProtocol.hh:272
@ kXR_fattrGet
Definition: XProtocol.hh:271
@ kXR_fatrrMaxSC
Definition: XProtocol.hh:274
struct ClientFattrRequest fattr
Definition: XProtocol.hh:852
XResponseType
Definition: XProtocol.hh:896
@ kXR_redirect
Definition: XProtocol.hh:902
@ kXR_oksofar
Definition: XProtocol.hh:898
@ kXR_ok
Definition: XProtocol.hh:897
struct ClientRequestHdr header
Definition: XProtocol.hh:844
@ kXR_faMaxVars
Definition: XProtocol.hh:280
kXR_int32 dlen
Definition: XProtocol.hh:159
int kXR_int32
Definition: XPtypes.hh:89
unsigned short kXR_unt16
Definition: XPtypes.hh:67
unsigned char kXR_char
Definition: XPtypes.hh:65
char data[4]
Start of data.
Definition: XrdSfsFAttr.hh:63
int dlen
Data Length in subsequent buffer.
Definition: XrdSfsFAttr.hh:62
XrdSfsFABuff * next
Definition: XrdSfsFAttr.hh:61
if(Avsz)
const kXR_char XROOTD_MON_OPENW
const kXR_char XROOTD_MON_OPENR
#define FATTR_NAMESPACE
#define CRED
static const char * errName(kXR_int32 errCode)
Definition: XProtocol.cc:130
static int mapError(int rc)
Definition: XProtocol.hh:1358
char * buff
Definition: XrdBuffer.hh:45
virtual int FAttr(XrdSfsFACtl *faReq, XrdOucErrInfo &eInfo, const XrdSecEntity *client=0)
XrdXrootdFile * Get(int fnum)
static XrdXrootdXPath RPList
XrdXrootdFileTable * FTab
XrdXrootdMonitor::User Monitor
XrdXrootdResponse Response
static struct XrdXrootdProtocol::RD_Table Route[RD_Num]
static XrdSfsFileSystem * osFS
int Validate(const char *pd, const int pl=0)
static const int aData
Definition: XProtocol.hh:298
static const int isNew
Definition: XProtocol.hh:297
kXR_char fhandle[4]
Definition: XProtocol.hh:288
XrdSfsFABuff * fabP
-> Additional memory that was allocated
Definition: XrdSfsFAttr.hh:79
static const int retval
Above plus return actual attr value.
Definition: XrdSfsFAttr.hh:91
const char * path
The file path to act on (logical)
Definition: XrdSfsFAttr.hh:74
unsigned char rqst
Type of file attribute request (see below)
Definition: XrdSfsFAttr.hh:82
const char * pcgi
Opaque information (null if none)
Definition: XrdSfsFAttr.hh:75
static const int accChk
Perform access check.
Definition: XrdSfsFAttr.hh:87
static const int newAtr
For set the attribute must not exist.
Definition: XrdSfsFAttr.hh:88
XrdSfsFAInfo * info
Pointer to attribute information.
Definition: XrdSfsFAttr.hh:77
unsigned char opts
Request options (see below)
Definition: XrdSfsFAttr.hh:83
unsigned short iNum
Number of info entries.
Definition: XrdSfsFAttr.hh:81
char * Name
Variable name.
Definition: XrdSfsFAttr.hh:45
int VLen
Variable value length (aligned)
Definition: XrdSfsFAttr.hh:47
char * Value
Variable value.
Definition: XrdSfsFAttr.hh:46
short NLen
Length of name not including null byte.
Definition: XrdSfsFAttr.hh:48
int faRC
Action return code for this element.
Definition: XrdSfsFAttr.hh:49