XRootD
XrdOfsFAttr.cc
Go to the documentation of this file.
1 /******************************************************************************/
2 /* */
3 /* X r d O f s 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 Deprtment 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 "XrdOfs/XrdOfs.hh"
31 #include "XrdOfs/XrdOfsTrace.hh"
32 #include "XrdOfs/XrdOfsSecurity.hh"
33 
34 #include "XrdOss/XrdOss.hh"
35 
36 #include "XrdOuc/XrdOucEnv.hh"
37 #include "XrdOuc/XrdOucExport.hh"
38 
39 #include "XrdSec/XrdSecEntity.hh"
40 
41 #include "XrdSfs/XrdSfsFAttr.hh"
42 #include "XrdSfs/XrdSfsFlags.hh"
44 
45 #include "XrdSys/XrdSysFAttr.hh"
46 
47 /******************************************************************************/
48 /* E r r o r R o u t i n g O b j e c t */
49 /******************************************************************************/
50 
51 extern XrdSysTrace OfsTrace;
52 
53 /******************************************************************************/
54 /* F i l e S y s t e m O b j e c t */
55 /******************************************************************************/
56 
57 extern XrdOfs* XrdOfsFS;
58 
59 /******************************************************************************/
60 /* S t o r a g e S y s t e m O b j e c t */
61 /******************************************************************************/
62 
63 extern XrdOss *XrdOfsOss;
64 
65 /******************************************************************************/
66 /* L o c a l F u n c t i o n s a n d O b j e c t s */
67 /******************************************************************************/
68 
69 namespace
70 {
71 XrdSysMutex faMutex;
72 
73 static const int faSize = 8192-sizeof(XrdSfsFABuff);
74 }
75 
76 /******************************************************************************/
77 /* G e t F A B u f f */
78 /******************************************************************************/
79 
80 namespace
81 {
82 bool GetFABuff(XrdSfsFACtl &faCtl, int sz=0)
83 {
84  XrdSfsFABuff *fabP = (XrdSfsFABuff *)malloc(sz + sizeof(XrdSfsFABuff));
85 
86 // Check if we allocate a buffer
87 //
88  if (!fabP) return false;
89 
90 // Setup the buffer
91 //
92  fabP->next = faCtl.fabP;
93  faCtl.fabP = fabP;
94  fabP->dlen = sz;
95  return true;
96 }
97 }
98 
99 /******************************************************************************/
100 /* G e t F A V a l */
101 /******************************************************************************/
102 
103 namespace
104 {
105 bool GetFAVal(XrdSfsFACtl &faCtl, char *&bP, int &bL, unsigned int k)
106 {
107  int rc;
108 
109 // Get the attribute value
110 //
111  rc = XrdSysFAttr::Xat->Get(faCtl.info[k].Name, bP, bL, faCtl.pfnP);
112 
113 // If all went well, record the value and update incoming information
114 //
115  if (rc >= 0)
116  {faCtl.info[k].faRC = 0;
117  faCtl.info[k].Value = bP;
118  faCtl.info[k].VLen = rc;
119  bP += rc; bL -= rc;
120  return true;
121  }
122 
123 // Check for any error other than buffer too small
124 //
125  if (rc != -ERANGE)
126  {faCtl.info[k].faRC = -rc;
127  return true;
128  }
129 
130 // Buffer is too small, tell the caller to recover
131 //
132  return false;
133 }
134 }
135 
136 /******************************************************************************/
137 /* G u l p F A V a l */
138 /******************************************************************************/
139 
140 namespace
141 {
142 bool GulpFAVal(XrdSfsFACtl &faCtl, char *&bP, int &bL, unsigned int k)
143 {
144  XrdSysMutexHelper mHelper(faMutex);
145  char *bzP = 0;
146  int n = 0;
147 
148 // Get the size of the attribute value
149 //
150  if (!GetFAVal(faCtl, bzP, n, k))
151  {faCtl.info[k].faRC = ERANGE;
152  faCtl.info[k].VLen = 0;
153  return true;
154  }
155 
156 // Allocate a new buffer to hold this and possible some more values
157 //
158  n = faCtl.info[k].VLen;
159  faCtl.info[k].VLen = 0;
160  if (n < faSize/2) n = faSize;
161  if (!GetFABuff(faCtl, n)) return false;
162 
163 // Now fetch the variable in a right sized buffer
164 //
165  bP = faCtl.fabP->data;
166  bL = faCtl.fabP->dlen;
167  if (!GetFAVal(faCtl, bP, bL, k)) faCtl.info[k].faRC = ERANGE;
168  else {bP += faCtl.info[k].VLen;
169  bL -= faCtl.info[k].VLen;
170  }
171  return true;
172 }
173 }
174 
175 /******************************************************************************/
176 /* S e t N o M e m */
177 /******************************************************************************/
178 
179 namespace
180 {
181 int SetNoMem(XrdSfsFACtl &faCtl, unsigned int iX)
182 {
183 
184 // Set no memory error for remaining attributes
185 //
186  for (unsigned int i = iX; i < faCtl.iNum; i++) faCtl.info[i].faRC = ENOMEM;
187  return SFS_OK;
188 }
189 }
190 
191 /******************************************************************************/
192 /* F A t t r */
193 /******************************************************************************/
194 
196  XrdOucErrInfo &einfo,
197  const XrdSecEntity *client)
198 {
199  EPNAME("FAttr");
200  const char *tident = einfo.getErrUser();
201  char pfnbuff[MAXPATHLEN+8];
202  const char *accType;
203  long long xOpts;
204 
205  struct faArgs {const char *name; int fArg; Access_Operation aop;};
206 
207  static faArgs faTab[] = {{ "del fattr", SFS_O_RDWR, AOP_Update}, // del
208  { "get fattr", 0, AOP_Read}, // get
209  {"list fattr", 0, AOP_Read}, // list
210  { "set fattr", SFS_O_RDWR, AOP_Update} // set
211  };
212  static const int faNum = sizeof(faTab)/sizeof(struct faArgs);
213 
214  int rc;
215 
216 // Check if we need only return support information
217 //
218  if (!faReq)
219  {XrdOucEnv *envP = einfo.getEnv();
220  ZTRACE(fsctl, "FAttr req=info");
221  if (!envP || !usxMaxNsz)
222  {einfo.setErrInfo(ENOTSUP, "Not supported.");
223  return SFS_ERROR;
224  }
225  envP->PutInt("usxMaxNsz", usxMaxNsz);
226  envP->PutInt("usxMaxVsz", usxMaxVsz);
227  return SFS_OK;
228  }
229 
230 // Setup for to perform attribute functions
231 //
232  XrdSfsFACtl &faCtl = *faReq;
233  XrdOucEnv FAttr_Env(faCtl.pcgi,0,client);
234 
235 // Make sure request code is valid (we also set some options)
236 //
237  if (faCtl.rqst > faNum)
238  return Emsg(epname, einfo, EINVAL, "process fattrs", faCtl.path);
239  accType = faTab[faCtl.rqst].name;
240 
241 // Trace this call
242 //
243  ZTRACE(fsctl, "FAttr " <<accType <<' ' <<faCtl.path);
244 
245 // Extract the export options if we can
246 //
247  xOpts = (ossRPList ? ossRPList->Find(faCtl.path) : 0);
248 
249 // Perform authrorization and redirection if required
250 //
251  if (faCtl.opts & XrdSfsFACtl::accChk)
252  {int luFlag = faTab[faCtl.rqst].fArg;
253  Access_Operation aOP = faTab[faCtl.rqst].aop;
254 
255  AUTHORIZE(client, 0, aOP, accType ,faCtl.path, einfo);
256 
257  if (Finder && Finder->isRemote()
258  && (rc = Finder->Locate(einfo, faCtl.path, luFlag, &FAttr_Env)))
259  return fsError(einfo, rc);
260 
261  if (aOP == AOP_Update && xOpts & XRDEXP_NOTRW)
262  return Emsg(epname, einfo, EROFS, accType, faCtl.path);
263  }
264 
265 // If this is a proxy server then hand this request to the storage system
266 // as it will need to be executed elsewhere.
267 //
268  if (OssIsProxy)
269  {faCtl.envP = &FAttr_Env;
270  rc = XrdOfsOss->FSctl(XRDOSS_FSCTLFA, 0, (const char *)&faCtl);
271  if (rc) return XrdOfsFS->Emsg(epname, einfo, rc, accType, faCtl.path);
272  return SFS_OK;
273  }
274 
275 // Make sure we can use xattrs on the path
276 //
277  if (xOpts & XRDEXP_NOXATTR)
278  return XrdOfsFS->Emsg(epname, einfo, EPERM, accType, faCtl.path);
279 
280 // Convert the lfn to a pfn for actual calls to the attribute processor
281 //
282  faCtl.pfnP = XrdOfsOss->Lfn2Pfn(faCtl.path, pfnbuff, sizeof(pfnbuff), rc);
283  if (!faCtl.pfnP) return XrdOfsFS->Emsg(epname,einfo,rc,accType,faCtl.path);
284 
285 // Fan out for processing this on the local file system
286 //
287  switch(faCtl.rqst)
288  {case XrdSfsFACtl::faDel:
289  return ctlFADel(faCtl, FAttr_Env, einfo);
290  break;
291  case XrdSfsFACtl::faGet:
292  return ctlFAGet(faCtl, FAttr_Env, einfo);
293  break;
294  case XrdSfsFACtl::faLst:
295  return ctlFALst(faCtl, FAttr_Env, einfo);
296  break;
297  case XrdSfsFACtl::faSet:
298  return ctlFASet(faCtl, FAttr_Env, einfo);
299  break;
300  default: break;
301  }
302 
303 // The request code is not one we understand
304 //
305  return XrdOfsFS->Emsg(epname, einfo, EINVAL, "process fattrs", faCtl.path);
306 }
307 
308 /******************************************************************************/
309 /* c t l F A D e l */
310 /******************************************************************************/
311 
312 int XrdOfs::ctlFADel(XrdSfsFACtl &faCtl, XrdOucEnv &faEnv, XrdOucErrInfo &einfo)
313 {
314 
315 // Delete each variable
316 //
317  for (unsigned int i = 0; i < faCtl.iNum; i++)
318  faCtl.info[i].faRC = XrdSysFAttr::Xat->Del(faCtl.info[i].Name,faCtl.pfnP);
319 
320 // All done
321 //
322  return SFS_OK;
323 }
324 
325 /******************************************************************************/
326 /* c t l F A L s t */
327 /******************************************************************************/
328 
329 int XrdOfs::ctlFALst(XrdSfsFACtl &faCtl, XrdOucEnv &faEnv, XrdOucErrInfo &einfo)
330 {
331  EPNAME("ctlFALst");
332  XrdSysXAttr::AList *alP, *aEnt;
333  char *nP, *bP;
334  int bL, rc, pfLen, iX = 0, faSize = 0, fvSize = 0;
335  bool getMsz = (faCtl.opts & XrdSfsFACtl::retvsz) == XrdSfsFACtl::retvsz;
336  bool getVal = (faCtl.opts & XrdSfsFACtl::retval) == XrdSfsFACtl::retval;
337  bool xPlode = (faCtl.opts & XrdSfsFACtl::xplode) != 0;
338 
339 // Get all of the attribute names
340 //
341  rc = XrdSysFAttr::Xat->List(&alP, faCtl.pfnP, -1, getMsz);
342  if (rc < 0) return Emsg(epname, einfo, -rc, "list fattrs", faCtl.path);
343 
344 // Count up attributes
345 //
346  faCtl.info = 0;
347  faCtl.iNum = 0;
348  pfLen = (*faCtl.nPfx ? sizeof(faCtl.nPfx) : 0);
349  aEnt = alP;
350  while(aEnt)
351  {if (aEnt->Nlen)
352  {if (!pfLen || !strncmp(faCtl.nPfx, aEnt->Name, pfLen))
353  {faCtl.iNum++;
354  faSize += aEnt->Nlen - pfLen + 1;
355  } else aEnt->Nlen = 0;
356  }
357  aEnt = aEnt->Next;
358  }
359 
360 // If there are no attributes of interest, we are done.
361 //
362  if (!faCtl.iNum) return SFS_OK;
363 
364 // Allocate sufficient memory to hold the complete list
365 //
366  if (!GetFABuff(faCtl, faSize))
367  {XrdSysFAttr::Xat->Free(alP);
368  return Emsg(epname, einfo, ENOMEM, "list fattrs", faCtl.path);
369  }
370 
371 // Allocate an info vector if caller wants this exploded
372 //
373  if (xPlode) faCtl.info = new XrdSfsFAInfo[faCtl.iNum];
374  else faCtl.info = 0;
375 
376 // Copy over the names
377 //
378  nP = faCtl.fabP->data;
379  aEnt = alP;
380  while(aEnt)
381  {if (aEnt->Nlen)
382  {strcpy(nP, aEnt->Name+pfLen);
383  if (xPlode)
384  {faCtl.info[iX].Name = nP;
385  faCtl.info[iX].NLen = aEnt->Nlen - pfLen;
386  faCtl.info[iX].VLen = aEnt->Vlen;
387  if (getVal && aEnt->Vlen) faCtl.info[iX].Value = aEnt->Name;
388  fvSize += aEnt->Vlen;
389  iX++;
390  }
391  nP += aEnt->Nlen-pfLen+1;
392  }
393  aEnt = aEnt->Next;
394  }
395 
396 // If we don't need to return values, we are done
397 //
398  if (!getVal)
399  {XrdSysFAttr::Xat->Free(alP);
400  return SFS_OK;
401  }
402 
403 // Allocate a buffer to hold all of the values
404 //
405  if (!GetFABuff(faCtl, fvSize))
406  {XrdSysFAttr::Xat->Free(alP);
407  return SetNoMem(faCtl, 0);
408  }
409 
410 // Setup to retrieve attributes
411 //
412  bP = faCtl.fabP->data;
413  bL = faCtl.fabP->dlen;
414 
415 // Retrieve the attribute values
416 //
417  for (unsigned int i = 0; i < faCtl.iNum; i++)
418  {if (faCtl.info[i].VLen)
419  {nP = faCtl.info[i].Name;
420  faCtl.info[i].Name = faCtl.info[i].Value;
421  faCtl.info[i].Value = 0;
422  if (!GetFAVal(faCtl, bP, bL, i) && !GulpFAVal(faCtl, bP, bL, i))
423  {XrdSysFAttr::Xat->Free(alP);
424  return SetNoMem(faCtl, i);
425  }
426  faCtl.info[i].Name = nP;
427  }
428  }
429 
430 // Free up the buffer list and return success
431 //
432  XrdSysFAttr::Xat->Free(alP);
433  return SFS_OK;
434 }
435 
436 /******************************************************************************/
437 /* c t l F A G e t */
438 /******************************************************************************/
439 
440 int XrdOfs::ctlFAGet(XrdSfsFACtl &faCtl, XrdOucEnv &faEnv, XrdOucErrInfo &einfo)
441 {
442  char *bP;
443  int bL;
444 
445 // Allocate the initial buffer. We make it big enough to, hopefully get all
446 // of the attributes, though we may have to reallocate.
447 //
448  if (!GetFABuff(faCtl, faSize)) return SetNoMem(faCtl, 0);
449 
450 // Setup to retrieve attributes
451 //
452  bP = faCtl.fabP->data;
453  bL = faCtl.fabP->dlen;
454 
455 // Get each variable. Unfortunately, we need to allocate a buffer for each
456 // one as we don't know the size.
457 //
458  for (unsigned int i = 0; i < faCtl.iNum; i++)
459  {if (bL < 8)
460  {if (!GetFABuff(faCtl, faSize)) return SetNoMem(faCtl, i);
461  bP = faCtl.fabP->data;
462  bL = faCtl.fabP->dlen;
463  }
464 
465  if (!GetFAVal(faCtl, bP, bL, i) && !GulpFAVal(faCtl, bP, bL, i))
466  return SetNoMem(faCtl, i);
467  }
468 
469  return SFS_OK;
470 }
471 
472 /******************************************************************************/
473 /* c t l F A S e t */
474 /******************************************************************************/
475 
476 int XrdOfs::ctlFASet(XrdSfsFACtl &faCtl, XrdOucEnv &faEnv, XrdOucErrInfo &einfo)
477 {
478  int isNew = (faCtl.opts & XrdSfsFACtl::newAtr) != 0;
479 
480 // Lock this code if we are replacing variables
481 //
482  if (!isNew) faMutex.Lock();
483 
484 // Set each variable
485 //
486  for (unsigned int i = 0; i < faCtl.iNum; i++)
487  faCtl.info[i].faRC = XrdSysFAttr::Xat->Set(faCtl.info[i].Name,
488  faCtl.info[i].Value,
489  faCtl.info[i].VLen,
490  faCtl.pfnP, -1, isNew);
491 
492 // Unlock the mutex if we locked it
493 //
494  if (!isNew) faMutex.UnLock();
495 
496 // All done
497  return SFS_OK;
498 }
Access_Operation
The following are supported operations.
@ AOP_Update
open() r/w or append
@ AOP_Read
open() r/o, prepare()
#define tident
#define EPNAME(x)
Definition: XrdBwmTrace.hh:56
#define ZTRACE(act, x)
Definition: XrdBwmTrace.hh:52
XrdOss * XrdOfsOss
Definition: XrdOfs.cc:163
XrdSysTrace OfsTrace
XrdOfs * XrdOfsFS
Definition: XrdOfsFS.cc:47
#define AUTHORIZE(usr, env, optype, action, pathp, edata)
#define XRDOSS_FSCTLFA
Definition: XrdOss.hh:492
#define XRDEXP_NOTRW
Definition: XrdOucExport.hh:45
#define XRDEXP_NOXATTR
Definition: XrdOucExport.hh:64
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
#define SFS_ERROR
#define SFS_O_RDWR
#define SFS_OK
virtual int isRemote()
virtual int Locate(XrdOucErrInfo &Resp, const char *path, int flags, XrdOucEnv *Info=0)=0
XrdCmsClient * Finder
Definition: XrdOfs.hh:429
int FAttr(XrdSfsFACtl *faReq, XrdOucErrInfo &eInfo, const XrdSecEntity *client=0)
Definition: XrdOfsFAttr.cc:195
int fsctl(const int cmd, const char *args, XrdOucErrInfo &out_error, const XrdSecEntity *client=0)
Definition: XrdOfsFSctl.cc:93
static int Emsg(const char *, XrdOucErrInfo &, int, const char *x, XrdOfsHandle *hP)
Definition: XrdOfs.cc:2513
static int fsError(XrdOucErrInfo &myError, int rc)
Definition: XrdOfs.cc:2628
virtual int FSctl(int cmd, int alen, const char *args, char **resp=0)
Definition: XrdOss.cc:66
virtual int Lfn2Pfn(const char *Path, char *buff, int blen)
Definition: XrdOss.hh:873
void PutInt(const char *varname, long value)
Definition: XrdOucEnv.cc:268
int setErrInfo(int code, const char *emsg)
XrdOucEnv * getEnv()
const char * getErrUser()
unsigned long long Find(const char *pathname)
Definition: XrdOucPList.hh:112
static XrdSysXAttr * Xat
Definition: XrdSysFAttr.hh:51
char Name[1]
Start of the name (size of struct is dynamic)
Definition: XrdSysXAttr.hh:56
int Vlen
The length of the attribute value;.
Definition: XrdSysXAttr.hh:54
virtual int List(AList **aPL, const char *Path, int fd=-1, int getSz=0)=0
virtual int Get(const char *Aname, void *Aval, int Avsz, const char *Path, int fd=-1)=0
virtual int Set(const char *Aname, const void *Aval, int Avsz, const char *Path, int fd=-1, int isNew=0)=0
int Nlen
The length of the attribute name that follows.
Definition: XrdSysXAttr.hh:55
virtual void Free(AList *aPL)=0
virtual int Del(const char *Aname, const char *Path, int fd=-1)=0
AList * Next
-> next element.
Definition: XrdSysXAttr.hh:53
XrdOucEnv * envP
Definition: XrdPss.cc:109
char nPfx[2]
The namespace being used.
Definition: XrdSfsFAttr.hh:80
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 * pfnP
The file path to act on (physical)
Definition: XrdSfsFAttr.hh:76
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 retvsz
Above plus return size of attr value.
Definition: XrdSfsFAttr.hh:90
static const int xplode
Construct an info vec from faList.
Definition: XrdSfsFAttr.hh:89
static const int newAtr
For set the attribute must not exist.
Definition: XrdSfsFAttr.hh:88
XrdOucEnv * envP
Optional environmental information.
Definition: XrdSfsFAttr.hh:78
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