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 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
192private:
193struct iovec *theIOV;
194};
195}
196
197/******************************************************************************/
198/* S e n d E r r */
199/******************************************************************************/
200
201namespace
202{
203int 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
215int 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
232int 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)
263 return Response.Send(kXR_ArgMissing,
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;
272 XrdXrootdFHandle fh(Request.fattr.fhandle);
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')
279 return Response.Send(kXR_InvalidRequest,
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
308int 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
355int XrdXrootdProtocol::XeqFADel(XrdSfsFACtl &ctl, char *faVars, int faVLen)
356{
357 XrdOucErrInfo eInfo(Link->ID, Monitor.Did, clientPV);
358 struct iovec iov[3];
359 kXR_char faRC[2];
360 int rc;
361
362// Set correct subcode
363//
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
388int XrdXrootdProtocol::XeqFAGet(XrdSfsFACtl &ctl, char *faVars, int faVLen)
389{
390 XrdOucErrInfo eInfo(Link->ID, Monitor.Did, clientPV);
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//
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
453int 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
508int XrdXrootdProtocol::XeqFALst(XrdSfsFACtl &ctl)
509{
510 struct iovec iov[16];
511 XrdOucErrInfo eInfo(Link->ID, Monitor.Did, clientPV);
512 int rc;
513
514// Set correct subcode
515//
517
518// Set correct options
519//
520 if (Request.fattr.options & ClientFattrRequest::aData)
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
566int XrdXrootdProtocol::XeqFASet(XrdSfsFACtl &ctl, char *faVars, int faVLen)
567{
568 XrdOucErrInfo eInfo(Link->ID, Monitor.Did, clientPV);
569 struct iovec iov[3];
570 kXR_char faRC[2];
571 int rc;
572
573// Set correct subcode and options
574//
576 if (Request.fattr.options & ClientFattrRequest::isNew)
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
@ kXR_FileNotOpen
Definition XProtocol.hh:994
@ kXR_Unsupported
@ 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
XResponseType
Definition XProtocol.hh:898
@ kXR_redirect
Definition XProtocol.hh:904
@ kXR_oksofar
Definition XProtocol.hh:900
@ kXR_ok
Definition XProtocol.hh:899
@ 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)
static XrdXrootdXPath RPList
XrdXrootdFileTable * FTab
XrdXrootdMonitor::User Monitor
XrdXrootdResponse Response
static struct XrdXrootdProtocol::RD_Table Route[RD_Num]
static XrdSfsFileSystem * osFS
int getIovMax()
static const int aData
Definition XProtocol.hh:298
static const int isNew
Definition XProtocol.hh:297
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.