XRootD
Loading...
Searching...
No Matches
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
37#include "Xrd/XrdBuffer.hh"
38#include "Xrd/XrdLink.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
53namespace
54{
55struct faCTL
56{
57XrdSfsFAInfo *info; // Pointer to attribute information
58char *buff; // Buffer to be decoded
59char *bend; // Pointer to last byte of buffer + 1
60int vnsz; // Size of variable name segment
61short iNum; // Number of info entries
62short iEnd; // Index number of last entry processed
63bool 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
80namespace
81{
82XErrorCode 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
149namespace
150{
151void 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
177namespace
178{
179class IOVec
180{
181public:
182struct 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
203private:
204struct iovec *theIOV;
205};
206}
207
208/******************************************************************************/
209/* S e n d E r r */
210/******************************************************************************/
211
212namespace
213{
214int 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
226int 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
243int 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)))
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
319int 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
366int 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//
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
399int 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//
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
464int 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
519int XrdXrootdProtocol::XeqFALst(XrdSfsFACtl &ctl)
520{
521 struct iovec iov[16];
523 int rc;
524
525// Set correct subcode
526//
528
529// Set correct options
530//
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
577int 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//
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
@ kXR_FileNotOpen
Definition XProtocol.hh:992
@ kXR_Unsupported
@ 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
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.
int dlen
Data Length in subsequent buffer.
XrdSfsFABuff * next
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)
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)
ssize_t Send(int fd, KernelBuffer &buffer)
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
static const int retval
Above plus return actual attr value.
const char * path
The file path to act on (logical)
unsigned char rqst
Type of file attribute request (see below)
const char * pcgi
Opaque information (null if none)
static const int accChk
Perform access check.
static const int newAtr
For set the attribute must not exist.
XrdSfsFAInfo * info
Pointer to attribute information.
unsigned char opts
Request options (see below)
unsigned short iNum
Number of info entries.
char * Name
Variable name.
int VLen
Variable value length (aligned)
char * Value
Variable value.
short NLen
Length of name not including null byte.
int faRC
Action return code for this element.