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 const int iovmax = XrdSys::getIovMax();
184  if (num > iovmax) num = iovmax;
185  theIOV = new struct iovec[num];
186  return theIOV;
187  }
188 
189  IOVec() : theIOV(0) {}
190  ~IOVec() {if (theIOV) delete [] theIOV;}
191 
192 private:
193 struct iovec *theIOV;
194 };
195 }
196 
197 /******************************************************************************/
198 /* S e n d E r r */
199 /******************************************************************************/
200 
201 namespace
202 {
203 int SendErr(XrdXrootdResponse &Resp, faCTL &ctl, XErrorCode eCode)
204 {
205  char eBuff[1024];
206 
207  snprintf(eBuff, sizeof(eBuff), "%s processing fattr %s argument #%d",
208  XProtocol::errName(eCode), (ctl.verr ? "data" : "name"), ctl.iNum);
209 
210  return Resp.Send(eCode, eBuff);
211 }
212 
213 
214 /* For future use
215 int SendErr(XrdXrootdResponse &Resp, const char *what, const char *path, int rc)
216 {
217  int eCode = XProtocol::mapError(rc);
218  char eBuff[2048];
219 
220  snprintf(eBuff, sizeof(eBuff), "%s processing fattr %s %s",
221  XProtocol::errName(eCode), what, path);
222 
223  return Resp.Send((XErrorCode)eCode, eBuff);
224 }
225 */
226 }
227 
228 /******************************************************************************/
229 /* d o _ F A t t r */
230 /******************************************************************************/
231 
232 int XrdXrootdProtocol::do_FAttr()
233 {
234  const char *eTxt;
235  char *fn, *fnCgi;
236  int faCode = static_cast<int>(Request.fattr.subcode); // Is unsigned
237  int popt, ropt, n, dlen = Request.header.dlen;
238  bool isRO;
239 
240 // Make sure we are configured for extended attributes
241 //
242  if (!usxMaxNsz)
243  return Response.Send(kXR_Unsupported, "fattr request is not supported");
244 
245 // Prevalidate the subcode (it is unsigned)
246 //
247  if (faCode > kXR_fatrrMaxSC)
248  return Response.Send( kXR_ArgInvalid, "fattr subcode is invalid");
249 
250 // Determine whether we will be reading or writing attributes
251 //
252  if (faCode == kXR_fattrGet || faCode == kXR_fattrList)
253  {isRO = true;
254  eTxt = "Inspecting file attributes";
255  } else {
256  isRO = false;
257  eTxt = "Modifying file attributes";
258  }
259 
260 // Make sure we have the right number of arguments
261 //
262  if (faCode != kXR_fattrList && !dlen)
264  "Required arguments for fattr request not present");
265 
266 // This operation may refer to an open file. Make sure it exists and is
267 // opened in a compatible mode. Otherwise, verify that the target file
268 // can be properly accessed by the client. If so, process the request.
269 //
270  if (!dlen || argp->buff[0] == 0)
271  {XrdXrootdFile *fp;
273  char *theArg = argp->buff;
274 
275  if (!FTab || !(fp = FTab->Get(fh.handle)))
276  return Response.Send(kXR_FileNotOpen,
277  "fattr does not refer to an open file");
278  if (!isRO && fp->FileMode != 'w')
280  "fattr request modifies a file open for reading");
281  if (dlen) {dlen--; theArg++;}
282 
283  return ProcFAttr(fp->FileKey, 0, theArg, dlen, faCode, false);
284  }
285 
286 // The operation is being targetted to a file path. First, get path length.
287 //
288  fn = argp->buff;
289  n = strlen(argp->buff); // Always ends with a null byte!
290 
291 // Prescreen the path and handle any redirects
292 //
293  if (rpCheck(fn, &fnCgi)) return rpEmsg(eTxt, fn);
294  if (!(popt = Squash(fn))) return vpEmsg(eTxt, fn);
295  if (Route[RD_open1].Host[rdType] && (ropt = RPList.Validate(fn)))
296  return Response.Send(kXR_redirect, Route[ropt].Port[rdType],
297  Route[ropt].Host[rdType]);
298 
299 // Hand this off to the attribute processor
300 //
301  return ProcFAttr(fn, fnCgi, argp->buff+n+1, dlen-n-1, faCode, true);
302 }
303 
304 /******************************************************************************/
305 /* P r o c F A t t r */
306 /******************************************************************************/
307 
308 int XrdXrootdProtocol::ProcFAttr(char *faPath, char *faCgi, char *faArgs,
309  int faALen, int faCode, bool doAChk)
310 {
311  int fNumAttr = static_cast<int>(Request.fattr.numattr);
312 
313 // Prevalidate the number of attributes (list must have zero)
314 //
315  if ((faCode == kXR_fattrList && fNumAttr != 0)
316  || (faCode != kXR_fattrList && (fNumAttr == 0 || fNumAttr > kXR_faMaxVars)))
317  return Response.Send( kXR_ArgInvalid, "fattr numattr is invalid");
318 
319 // Allocate an SFS control object now
320 //
321  XrdSfsFACtl sfsCtl(faPath, faCgi, fNumAttr);
322  sfsCtl.nPfx[0] = FATTR_NAMESPACE;
323  sfsCtl.nPfx[1] = '.';
324  if (doAChk) sfsCtl.opts = XrdSfsFACtl::accChk;
325 
326 // If this is merely a list then go do it as there is nothing to parse
327 //
328  if (faCode == kXR_fattrList) return XeqFALst(sfsCtl);
329 
330 // Parse the request buffer as needed
331 //
332  faCTL ctl(faArgs, faArgs+faALen, fNumAttr);
333  XErrorCode rc =
334  Decode(ctl, usxMaxNsz, (faCode == kXR_fattrSet ? usxMaxVsz : 0));
335  if (rc) return SendErr(Response, ctl, rc);
336 
337 // Transfer info ownership
338 //
339  sfsCtl.info = ctl.info;
340  ctl.info = 0;
341 
342 // Perform the requested action
343 //
344  if (faCode == kXR_fattrDel) return XeqFADel(sfsCtl, faArgs, ctl.vnsz);
345  if (faCode == kXR_fattrGet) return XeqFAGet(sfsCtl, faArgs, ctl.vnsz);
346  if (faCode == kXR_fattrSet) return XeqFASet(sfsCtl, faArgs, ctl.vnsz);
347 
348  return Response.Send(kXR_Unsupported, "fattr request is not supported");
349 }
350 
351 /******************************************************************************/
352 /* X e q F A D e l */
353 /******************************************************************************/
354 
355 int XrdXrootdProtocol::XeqFADel(XrdSfsFACtl &ctl, char *faVars, int faVLen)
356 {
358  struct iovec iov[3];
359  kXR_char faRC[2];
360  int rc;
361 
362 // Set correct subcode
363 //
364  ctl.rqst = XrdSfsFACtl::faDel;
365 
366 // Execute the action
367 //
368  if ((rc = osFS->FAttr(&ctl, eInfo, CRED)))
369  return fsError(rc, XROOTD_MON_OPENW, eInfo, ctl.path, (char *)ctl.pcgi);
370 
371 // Format the response
372 //
373  FillRC(faRC, ctl.info, ctl.iNum);
374 
375 // Send off the response
376 //
377  iov[1].iov_base = faRC;
378  iov[1].iov_len = sizeof(faRC);
379  iov[2].iov_base = faVars;
380  iov[2].iov_len = faVLen;
381  return Response.Send(iov, 3, sizeof(faRC) + faVLen);
382 }
383 
384 /******************************************************************************/
385 /* X e q F A G e t */
386 /******************************************************************************/
387 
388 int XrdXrootdProtocol::XeqFAGet(XrdSfsFACtl &ctl, char *faVars, int faVLen)
389 {
391  IOVec iovHelper;
392  struct iovec *iov;
393  kXR_char faRC[2];
394  XResponseType rcode;
395  int k, rc, dlen, vLen;
396 
397 // Set correct subcode
398 //
399  ctl.rqst = XrdSfsFACtl::faGet;
400 
401 // Execute the action
402 //
403  if ((rc = osFS->FAttr(&ctl, eInfo, CRED)))
404  return fsError(rc, XROOTD_MON_OPENR, eInfo, ctl.path, (char *)ctl.pcgi);
405 
406 // Format the common response
407 //
408  FillRC(faRC, ctl.info, ctl.iNum);
409 
410 // Allocate an iovec. We need two elements for each info entry.
411 //
412  int iovNum = ctl.iNum*2+3;
413  iov = iovHelper.Alloc(iovNum);
414 
415 // Prefill the io vector (number of errors, vars, followed the rc-names
416 //
417  iov[1].iov_base = faRC;
418  iov[1].iov_len = sizeof(faRC);
419  iov[2].iov_base = faVars;
420  iov[2].iov_len = faVLen;
421  dlen = sizeof(faRC) + faVLen;
422  k = 3;
423 
424 // Return the value for for each variable, segment the response, if need be
425 //
426  for (int i = 0; i < ctl.iNum; i++)
427  {iov[k ].iov_base = &ctl.info[i].VLen;
428  iov[k++].iov_len = sizeof(ctl.info[i].VLen);
429  dlen += sizeof(ctl.info[i].VLen);
430  if (ctl.info[i].faRC || ctl.info[i].VLen == 0) ctl.info[i].VLen = 0;
431  else {vLen = ctl.info[i].VLen;
432  ctl.info[i].VLen = htonl(ctl.info[i].VLen);
433  iov[k ].iov_base = (void *)ctl.info[i].Value;
434  iov[k++].iov_len = vLen;
435  dlen += vLen;
436  }
437  if (k+1 >= iovNum)
438  {rcode = (i+1 == ctl.iNum ? kXR_ok : kXR_oksofar);
439  if ((rc = Response.Send(rcode, iov, k, dlen))) return rc;
440  k = 1; dlen = 0;
441  }
442  }
443 
444 // Check if we need to send out the last amount of data
445 //
446  return (dlen ? Response.Send(iov, k, dlen) : 0);
447 }
448 
449 /******************************************************************************/
450 /* X e q F A L s d */
451 /******************************************************************************/
452 
453 int XrdXrootdProtocol::XeqFALsd(XrdSfsFACtl &ctl)
454 {
455  IOVec iovHelper;
456  struct iovec *iov;
457  XResponseType rcode;
458  int k = 1, rc = 0, dlen = 0, vLen;
459  bool xresp = false;
460 
461 // Make sure we have something to send
462 //
463  if (!ctl.iNum) return Response.Send();
464 
465 // Allocate an iovec. We need three elements for each info entry.
466 //
467  int iovNum = ctl.iNum*3+1;
468  iov = iovHelper.Alloc(iovNum);
469 
470 // Return the value for for each variable, segment the response, if need be
471 //
472  for (int i = 0; i < ctl.iNum; i++)
473  {if (ctl.info[i].faRC) continue;
474  iov[k ].iov_base = ctl.info[i].Name;
475  iov[k++].iov_len = ctl.info[i].NLen+1;
476  dlen += ctl.info[i].NLen+1;
477 
478  vLen = ctl.info[i].VLen;
479  ctl.info[i].VLen = htonl(vLen);
480  iov[k ].iov_base = &ctl.info[i].VLen;
481  iov[k++].iov_len = sizeof(ctl.info[i].VLen);
482  dlen += sizeof(ctl.info[i].VLen);
483 
484  iov[k ].iov_base = (void *)ctl.info[i].Value;
485  iov[k++].iov_len = vLen;
486  dlen += vLen;
487 
488  if (k+2 >= iovNum)
489  {rcode = (i+1 == ctl.iNum ? kXR_ok : kXR_oksofar);
490  if ((rc = Response.Send(rcode, iov, k, dlen))) return rc;
491  k = 1; dlen = 0; xresp = true;
492  }
493  }
494 
495 // Check if we need to send out the last amount of data
496 //
497  return (dlen ? Response.Send(iov, k, dlen) : 0);
498 
499 // Check if anything was sent at all
500 //
501  return (xresp ? 0 : Response.Send());
502 }
503 
504 /******************************************************************************/
505 /* X e q F A L s t */
506 /******************************************************************************/
507 
508 int XrdXrootdProtocol::XeqFALst(XrdSfsFACtl &ctl)
509 {
510  struct iovec iov[16];
512  int rc;
513 
514 // Set correct subcode
515 //
516  ctl.rqst = XrdSfsFACtl::faLst;
517 
518 // Set correct options
519 //
521  ctl.opts |= XrdSfsFACtl::retval;
522 
523 // Execute the action
524 //
525  if ((rc = osFS->FAttr(&ctl, eInfo, CRED)))
526  return fsError(rc, XROOTD_MON_OPENR, eInfo, ctl.path, (char *)ctl.pcgi);
527 
528 // Check for more complicated return
529 //
530  if (ctl.opts & XrdSfsFACtl::retval) return XeqFALsd(ctl);
531 
532 // If there is only a single buffer, hen we can do a simple response
533 //
534  if (!ctl.fabP) return Response.Send();
535  if (ctl.fabP->next == 0)
536  return Response.Send(ctl.fabP->data, ctl.fabP->dlen);
537 
538 // Send of the response in as many segments as we need
539 //
540  int dlen = 0, i = 1;
541  XrdSfsFABuff *dP = ctl.fabP;
542 
543  while(dP)
544  {iov[i].iov_base = dP->data;
545  iov[i].iov_len = dP->dlen;
546  dlen += dP->dlen;
547  dP = dP->next;
548  i++;
549  if (i == (int)sizeof(iov))
550  {rc = Response.Send((dP ? kXR_oksofar : kXR_ok), iov, i, dlen);
551  if (rc || dP == 0) return rc;
552  dlen = 0;
553  i = 1;
554  }
555  }
556 
557 // Check if we need to send out the last amount of data
558 //
559  return (dlen ? Response.Send(iov, i, dlen) : 0);
560 }
561 
562 /******************************************************************************/
563 /* d o _ F A S e t */
564 /******************************************************************************/
565 
566 int XrdXrootdProtocol::XeqFASet(XrdSfsFACtl &ctl, char *faVars, int faVLen)
567 {
569  struct iovec iov[3];
570  kXR_char faRC[2];
571  int rc;
572 
573 // Set correct subcode and options
574 //
575  ctl.rqst = XrdSfsFACtl::faSet;
577  ctl.opts |= XrdSfsFACtl::newAtr;
578 
579 // Execute the action
580 //
581  if ((rc = osFS->FAttr(&ctl, eInfo, CRED)))
582  return fsError(rc, XROOTD_MON_OPENW, eInfo, ctl.path, (char *)ctl.pcgi);
583 
584 // Format the response
585 //
586  FillRC(faRC, ctl.info, ctl.iNum);
587 
588 // Send off the response
589 //
590  iov[1].iov_base = faRC;
591  iov[1].iov_len = sizeof(faRC);
592  iov[2].iov_base = faVars;
593  iov[2].iov_len = faVLen;
594  return Response.Send(iov, 3, sizeof(faRC) + faVLen);
595 }
XErrorCode
Definition: XProtocol.hh:989
@ kXR_ArgInvalid
Definition: XProtocol.hh:990
@ kXR_InvalidRequest
Definition: XProtocol.hh:996
@ kXR_ArgMissing
Definition: XProtocol.hh:991
@ kXR_BadPayload
Definition: XProtocol.hh:1016
@ kXR_FileNotOpen
Definition: XProtocol.hh:994
@ kXR_Unsupported
Definition: XProtocol.hh:1003
@ kXR_ArgTooLong
Definition: XProtocol.hh:992
@ 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:854
XResponseType
Definition: XProtocol.hh:898
@ kXR_redirect
Definition: XProtocol.hh:904
@ kXR_oksofar
Definition: XProtocol.hh:900
@ kXR_ok
Definition: XProtocol.hh:899
struct ClientRequestHdr header
Definition: XProtocol.hh:846
@ 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:1361
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)
int getIovMax()
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