XRootD
XrdXrootdXeq.cc
Go to the documentation of this file.
1 /******************************************************************************/
2 /* */
3 /* X r d X r o o t d X e q . c c */
4 /* */
5 /* (c) 2004 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 <cctype>
31 #include <cstdio>
32 #include <map>
33 #include <memory>
34 #include <mutex>
35 #include <string>
36 #include <sys/time.h>
37 #include <vector>
38 
40 #include "XrdSfs/XrdSfsFlags.hh"
41 #include "XrdSys/XrdSysError.hh"
42 #include "XrdSys/XrdSysPlatform.hh"
43 #include "XrdSys/XrdSysTimer.hh"
44 #include "XrdCks/XrdCksData.hh"
45 #include "XrdOuc/XrdOucCloneSeg.hh"
46 #include "XrdOuc/XrdOucEnv.hh"
47 #include "XrdOuc/XrdOucReqID.hh"
48 #include "XrdOuc/XrdOucTList.hh"
49 #include "XrdOuc/XrdOucStream.hh"
50 #include "XrdOuc/XrdOucString.hh"
52 #include "XrdOuc/XrdOucUtils.hh"
56 #include "XrdSys/XrdSysE2T.hh"
57 #include "Xrd/XrdBuffer.hh"
58 #include "Xrd/XrdInet.hh"
59 #include "Xrd/XrdLinkCtl.hh"
78 
80 
81 #include "XrdVersion.hh"
82 
83 #ifndef ENODATA
84 #define ENODATA ENOATTR
85 #endif
86 
87 #ifndef ETIME
88 #define ETIME ETIMEDOUT
89 #endif
90 
91 /******************************************************************************/
92 /* G l o b a l s */
93 /******************************************************************************/
94 
96 
97 /******************************************************************************/
98 /* L o c a l S t r u c t u r e s */
99 /******************************************************************************/
100 
102  {unsigned int Sid;
103  int Pid;
104  int FD;
105  unsigned int Inst;
106 
107  void Mask() {if (bfEcb1 && bfEcb2)
108  {unsigned char buff[sizeof(int)*4];
109  bfEcb1->Encrypt((unsigned char*)&Sid, buff);
110  bfEcb2->Encrypt((unsigned char*)&FD, buff+8);
111  memcpy((void*)&Sid, (const void*)buff, sizeof(int)*4);
112  }
113  }
114 
115  void UnMask() {if (bfEcb1 && bfEcb2)
116  {unsigned char buff[sizeof(int)*4];
117  bfEcb1->Decrypt((unsigned char*)&Sid, buff);
118  bfEcb2->Decrypt((unsigned char*)&FD, buff+8);
119  memcpy((void*)&Sid, (const void*)buff, sizeof(int)*4);
120  }
121  }
122 
125 
126  private:
127  inline static
129  inline static
131  };
132 
133 /******************************************************************************/
134 /* L o c a l D e f i n e s */
135 /******************************************************************************/
136 
137 namespace
138 {
139 
140 const char *getTime()
141 {
142 static char buff[16];
143 char tuff[8];
144 struct timeval tv;
145 struct tm *tmp;
146 
147  if (gettimeofday(&tv, 0))
148  {perror("gettimeofday");
149  exit(255);
150  }
151  tmp = localtime(&tv.tv_sec);
152  if (!tmp)
153  {perror("localtime");
154  exit(255);
155  }
156  //012345678901234
157  if (strftime(buff, sizeof(buff), "%y%m%d:%H%M%S. ", tmp) <= 0)
158  {errno = EINVAL;
159  perror("strftime");
160  exit(255);
161  }
162 
163  snprintf(tuff, sizeof(tuff), "%d", static_cast<int>(tv.tv_usec/100000));
164  buff[14] = tuff[0];
165  return buff;
166 }
167 
168 // comment out genUEID as it is not used
169 //
170 
171 //int genUEID()
172 //{
173 // static XrdSysMutex ueidMutex;
174 // static int ueidVal = 1;
175 // AtomicBeg(ueidMutex);
176 // int n = AtomicInc(ueidVal);
177 // AtomicEnd(ueidMutex);
178 // return n;
179 //}
180 
181 // Startup time
182 // 012345670123456
183 // yymmdd:hhmmss.t
184 static const char *startUP = getTime();
185 }
186 
187 /******************************************************************************/
188 /* d o _ A u t h */
189 /******************************************************************************/
190 
191 int XrdXrootdProtocol::do_Auth()
192 {
193  XrdSecCredentials cred;
194  XrdSecParameters *parm = 0;
196  const char *eText;
197  int rc, n;
198 
199 // Ignore authenticate requests if security turned off
200 //
201  if (!CIA) return Response.Send();
202  cred.size = Request.header.dlen;
203  cred.buffer = argp->buff;
204 
205 // If we have no auth protocol or the current protocol is being changed by the
206 // client (the client can do so at any time), try to get it. Track number of
207 // times we got a protocol object as the read count (we will zero it out later).
208 // The credtype change check is always done. While the credtype is consistent,
209 // not all protocols provided this information in the past. So, old clients will
210 // not necessarily be able to switch protocols mid-stream.
211 //
212  if (!AuthProt
213  || strncmp(Entity.prot, (const char *)Request.auth.credtype,
214  sizeof(Request.auth.credtype)))
215  {if (AuthProt) AuthProt->Delete();
216  size_t size = sizeof(Request.auth.credtype);
217  strncpy(Entity.prot, (const char *)Request.auth.credtype, size);
218  if (!(AuthProt = CIA->getProtocol(Link->Host(), *(Link->AddrInfo()),
219  &cred, eMsg)))
220  {eText = eMsg.getErrText(rc);
221  eDest.Emsg("Xeq", "User authentication failed;", eText);
222  return Response.Send(kXR_AuthFailed, eText);
223  }
225  numReads++;
226  }
227 
228 // Now try to authenticate the client using the current protocol
229 //
230  if (!(rc = AuthProt->Authenticate(&cred, &parm, &eMsg))
232  {rc = Response.Send(); Status &= ~XRD_NEED_AUTH; SI->Bump(SI->LoginAU);
234  Client = &AuthProt->Entity; numReads = 0; strcpy(Entity.prot, "host");
237  if (Monitor.Logins() && Monitor.Auths()) MonAuth();
238  if (!logLogin(true)) return -1;
239  return rc;
240  }
241 
242 // If we need to continue authentication, tell the client as much
243 //
244  if (rc > 0)
245  {TRACEP(LOGIN, "more auth requested; sz=" <<(parm ? parm->size : 0));
246  if (parm) {rc = Response.Send(kXR_authmore, parm->buffer, parm->size);
247  delete parm;
248  return rc;
249  }
250  eDest.Emsg("Xeq", "Security requested additional auth w/o parms!");
251  return Response.Send(kXR_ServerError,"invalid authentication exchange");
252  }
253 
254 // Authentication failed. We will delete the authentication object and zero
255 // out the pointer. We can do this without any locks because this section is
256 // single threaded relative to a connection. To prevent guessing attacks, we
257 // wait a variable amount of time if there have been 3 or more tries.
258 //
259  if (AuthProt) {AuthProt->Delete(); AuthProt = 0;}
260  if ((n = numReads - 2) > 0) XrdSysTimer::Snooze(n > 5 ? 5 : n);
261 
262 // We got an error, bail out.
263 //
264  SI->Bump(SI->AuthBad);
265  eText = eMsg.getErrText(rc);
266  eDest.Emsg("Xeq", "User authentication failed;", eText);
267  return Response.Send(kXR_AuthFailed, eText);
268 }
269 
270 /******************************************************************************/
271 /* d o _ B i n d */
272 /******************************************************************************/
273 
274 int XrdXrootdProtocol::do_Bind()
275 {
277  XrdXrootdProtocol *pp;
278  XrdLink *lp;
279  int i, pPid, rc;
280  char buff[64], *cp, *dp;
281 
282 // Update misc stats count
283 //
284  SI->Bump(SI->miscCnt);
285 
286 // Check if binds need to occur on a TLS connection.
287 //
288  if ((doTLS & Req_TLSData) && !isTLS && !Link->hasBridge())
289  return Response.Send(kXR_TLSRequired, "bind requires TLS");
290 
291 // Find the link we are to bind to
292 //
293  sp->UnMask();
294  if (sp->FD <= 0 || !(lp = XrdLinkCtl::fd2link(sp->FD, sp->Inst)))
295  return Response.Send(kXR_NotFound, "session not found");
296 
297 // The link may have escaped so we need to hold this link and try again
298 //
299  lp->Hold(1);
300  if (lp != XrdLinkCtl::fd2link(sp->FD, sp->Inst))
301  {lp->Hold(0);
302  return Response.Send(kXR_NotFound, "session just closed");
303  }
304 
305 // Get the protocol associated with the link
306 //
307  if (!(pp=dynamic_cast<XrdXrootdProtocol *>(lp->getProtocol()))||lp != pp->Link)
308  {lp->Hold(0);
309  return Response.Send(kXR_ArgInvalid, "session protocol not xroot");
310  }
311 
312 // Verify that the parent protocol is fully logged in
313 //
314  if (!(pp->Status & XRD_LOGGEDIN) || (pp->Status & XRD_NEED_AUTH))
315  {lp->Hold(0);
316  return Response.Send(kXR_ArgInvalid, "session not logged in");
317  }
318 
319 // Verify that the bind is valid for the requestor
320 //
321  if (sp->Pid != myPID || sp->Sid != pp->mySID)
322  {lp->Hold(0);
323  return Response.Send(kXR_ArgInvalid, "invalid session ID");
324  }
325 
326 // For now, verify that the request is comming from the same host
327 //
328  if (strcmp(Link->Host(), lp->Host()))
329  {lp->Hold(0);
330  return Response.Send(kXR_NotAuthorized, "cross-host bind not allowed");
331  }
332 
333 // We need to hold the parent's stream mutex to prevent inspection or
334 // modification of other parallel binds that may occur
335 //
336  XrdSysMutexHelper smHelper(pp->streamMutex);
337 
338 // Find a slot for this path in parent protocol
339 //
340  for (i = 1; i < maxStreams && pp->Stream[i]; i++) {}
341  if (i >= maxStreams)
342  {lp->Hold(0);
343  return Response.Send(kXR_NoMemory, "bind limit exceeded");
344  }
345 
346 // Link this protocol to the parent
347 //
348  pp->Stream[i] = this;
349  Stream[0] = pp;
350  PathID = i;
351 
352 // Construct a login name for this bind session
353 //
354  cp = strdup(lp->ID);
355  if ( (dp = rindex(cp, '@'))) *dp = '\0';
356  if (!(dp = rindex(cp, '.'))) pPid = 0;
357  else {*dp++ = '\0'; pPid = strtol(dp, (char **)NULL, 10);}
358  Link->setID(cp, pPid);
359  free(cp);
360  CapVer = pp->CapVer;
362  boundRecycle = new XrdSysSemaphore(0);
363  clientPV = pp->clientPV;
365 
366 // Check if we need to enable packet marking for this stream
367 //
368  if (pp->pmDone)
369  {pmDone = true;
370  if (pp->pmHandle) pmHandle = PMark->Begin(*(Link->AddrInfo()),
371  *(pp->pmHandle), Link->ID);
372  }
373 
374 // Document the bind
375 //
376  smHelper.UnLock();
377  sprintf(buff, "FD %d#%d bound", Link->FDnum(), i);
378  eDest.Log(SYS_LOG_01, "Xeq", buff, lp->ID);
379 
380 // Get the required number of parallel I/O objects
381 //
383 
384 // There are no errors possible at this point unless the response fails
385 //
386  buff[0] = static_cast<char>(i);
387  if (!(rc = Response.Send(kXR_ok, buff, 1))) rc = -EINPROGRESS;
388 
389 // Return but keep the link disabled
390 //
391  lp->Hold(0);
392  return rc;
393 }
394 
395 /******************************************************************************/
396 /* d o _ C h k P n t */
397 /* */
398 /* Resides in XrdXrootdXeqChkPnt.cc */
399 /******************************************************************************/
400 
401 /******************************************************************************/
402 /* d o _ c h m o d */
403 /******************************************************************************/
404 
405 int XrdXrootdProtocol::do_Chmod()
406 {
407  int mode, rc;
408  char *opaque;
409  XrdOucErrInfo myError(Link->ID, Monitor.Did, clientPV);
410 
411 // Check for static routing
412 //
413  STATIC_REDIRECT(RD_chmod);
414 
415 // Unmarshall the data
416 //
417  mode = mapMode((int)ntohs(Request.chmod.mode));
418  if (rpCheck(argp->buff, &opaque)) return rpEmsg("Modifying", argp->buff);
419  if (!Squash(argp->buff)) return vpEmsg("Modifying", argp->buff);
420 
421 // Preform the actual function
422 //
423  rc = osFS->chmod(argp->buff, (XrdSfsMode)mode, myError, CRED, opaque);
424  TRACEP(FS, "chmod rc=" <<rc <<" mode=" <<Xrd::oct1 <<mode <<' ' <<argp->buff);
425  if (SFS_OK == rc) return Response.Send();
426 
427 // An error occurred
428 //
429  return fsError(rc, XROOTD_MON_CHMOD, myError, argp->buff, opaque);
430 }
431 
432 /******************************************************************************/
433 /* d o _ C K s u m */
434 /******************************************************************************/
435 
436 int XrdXrootdProtocol::do_CKsum(int canit)
437 {
438  char *opaque;
439  char *algT = JobCKT, *args[6];
440  int rc;
441 
442 // Check for static routing
443 //
444  STATIC_REDIRECT(RD_chksum);
445 
446 // Check if we support this operation
447 //
448  if (!JobCKT || (!JobLCL && !JobCKS))
449  return Response.Send(kXR_Unsupported, "query chksum is not supported");
450 
451 // Prescreen the path
452 //
453  if (rpCheck(argp->buff, &opaque)) return rpEmsg("Check summing", argp->buff);
454  if (!Squash(argp->buff)) return vpEmsg("Check summing", argp->buff);
455 
456 // If this is a cancel request, do it now
457 //
458  if (canit)
459  {if (JobCKS) JobCKS->Cancel(argp->buff, &Response);
460  return Response.Send();
461  }
462 
463 // Check if multiple checksums are supported and if so, pre-process
464 //
465  if (JobCKCGI && opaque && *opaque)
466  {char cksT[64];
467  algT = getCksType(opaque, cksT, sizeof(cksT));
468  if (!algT)
469  {char ebuf[1024];
470  snprintf(ebuf, sizeof(ebuf), "%s checksum not supported.", cksT);
471  return Response.Send(kXR_ServerError, ebuf);
472  }
473  }
474 
475 // If we are allowed to locally query the checksum to avoid computation, do it
476 //
477  if (JobLCL && (rc = do_CKsum(algT, argp->buff, opaque)) <= 0) return rc;
478 
479 // Just make absolutely sure we can continue with a calculation
480 //
481  if (!JobCKS)
482  return Response.Send(kXR_ServerError, "Logic error computing checksum.");
483 
484 // Check if multiple checksums are supported and construct right argument list
485 // We make a concession to a wrongly placed setfsuid/gid plugin. Fortunately,
486 // it only needs to know user's name but that can come from another plugin.
487 //
488  std::string keyval; // Contents will be copied prior to return!
489  if (JobCKCGI > 1 || JobLCL)
490  {args[0] = algT;
491  args[1] = algT;
492  args[2] = argp->buff;
493  args[3] = const_cast<char *>(Client->tident);
494  if (Client->eaAPI->Get(std::string("request.name"), keyval) && !keyval.empty())
495  args[4] = const_cast<char *>(keyval.c_str());
496  else if (Client->name) args[4] = Client->name;
497  else args[4] = 0;
498  args[5] = 0;
499  } else {
500  args[0] = algT;
501  args[1] = argp->buff;
502  args[2] = 0;
503  }
504 
505 // Preform the actual function
506 //
507  return JobCKS->Schedule(argp->buff, (const char **)args, &Response,
508  ((CapVer & kXR_vermask) >= kXR_ver002 ? 0 : JOB_Sync));
509 }
510 
511 /******************************************************************************/
512 
513 int XrdXrootdProtocol::do_CKsum(char *algT, const char *Path, char *Opaque)
514 {
515  static char Space = ' ';
516  XrdOucErrInfo myError(Link->ID, Monitor.Did, clientPV);
517  int CKTLen = strlen(algT);
518  int ec, rc = osFS->chksum(XrdSfsFileSystem::csGet, algT, Path,
519  myError, CRED, Opaque);
520  const char *csData = myError.getErrText(ec);
521 
522 // Diagnose any hard errors
523 //
524  if (rc) return fsError(rc, 0, myError, Path, Opaque);
525 
526 // Return result if it is actually available
527 //
528  if (*csData)
529  {if (*csData == '!') return Response.Send(csData+1);
530  struct iovec iov[4] = {{0,0}, {algT, (size_t)CKTLen}, {&Space, 1},
531  {(char *)csData, strlen(csData)+1}};
532  return Response.Send(iov, 4);
533  }
534 
535 // Diagnose soft errors
536 //
537  if (!JobCKS)
538  {const char *eTxt[2] = {JobCKT, " checksum not available."};
539  myError.setErrInfo(0, eTxt, 2);
540  return Response.Send(kXR_ChkSumErr, myError.getErrText());
541  }
542 
543 // Return indicating that we should try calculating the checksum
544 //
545  return 1;
546 }
547 
548 /******************************************************************************/
549 /* d o _ C l o n e */
550 /******************************************************************************/
551 
552 int XrdXrootdProtocol::do_Clone()
553 {
555  XrdXrootdFile* fP;
556  XrdSfsFile *dstFile, *srcFile = 0;
557  XrdOucErrInfo myError(Link->ID, Monitor.Did, clientPV);
558  int clVecNum, clVecLen = Request.header.dlen;
559  int currFH =- -1;
560 
561 // Make sure we can do this operation
562 //
563  if (!(fsFeatures & XrdSfs::hasFICL))
564  return Response.Send(kXR_Unsupported, "file cloning is not supported");
565 
566 // Make sure target file is actually open
567 //
568  if (!FTab || !(fP = FTab->Get(fh.handle)))
570  "clone does not refer to an open dest file");
571  dstFile = fP->XrdSfsp;
572 
573 // Compute number of elements in the clone vector and make sure we have no
574 // partial elements.
575 //
576  clVecNum = clVecLen / sizeof(XrdProto::clone_list);
577  if ( (clVecNum <= 0) ||
578  (clVecNum*(int)sizeof(XrdProto::clone_list) != clVecLen) )
579  return Response.Send(kXR_ArgInvalid, "Clone vector is invalid");
580 
581 // Make sure that we can copy the clone vector to our local stack. We must impose
582 // a limit on it's size. We do this to be able to reuse the data buffer to
583 // prevent cross-cpu memory cache synchronization.
584 //
585  if (clVecNum > XrdProto::maxClonesz)
586  return Response.Send(kXR_ArgTooLong, "Clone vector is too long");
587 
588 // Allocate a new clone vector
589 //
590  std::vector<XrdOucCloneSeg> clVec(clVecNum);
591 
592 // Setup for clone vector initialisation
593 //
595 
596 // Create new clone vector
597 //
598  for (int i = 0; i < clVecNum; i++)
599  {fh.Set(clList[i].srcFH);
600  if (!srcFile || currFH != fh.handle)
601  {currFH = fh.handle;
602  if (!(fP = FTab->Get(currFH)))
604  "clone does not refer to an open src file");
605  srcFile = fP->XrdSfsp;
606  }
607 
608  int fdNum;
609  if (srcFile->fctl(SFS_FCTL_GETFD, 0, myError) != SFS_OK)
610  {int ecode;
611  const char *eMsg = myError.getErrText(ecode);
612  const int rc = XProtocol::mapError(ecode);
613  return Response.Send((XErrorCode)rc, eMsg);
614  }
615  else fdNum = myError.getErrInfo();
616 
617  if (fdNum<0)
619  "clone does not refer to an open src file");
620 
621  clVec[i].srcFD = fdNum;
622  n2hll(clList[i].srcOffs, clVec[i].srcOffs);
623  n2hll(clList[i].srcLen, clVec[i].srcLen);
624  n2hll(clList[i].dstOffs, clVec[i].dstOffs);
625  }
626 
627 // Now execute the clone request
628 //
629  int rc = dstFile->Clone(clVec);
630  if (SFS_OK != rc) return fsError(rc, 0, dstFile->error, 0, 0);
631 
632  return Response.Send();
633 }
634 
635 /******************************************************************************/
636 /* d o _ C l o s e */
637 /******************************************************************************/
638 
639 int XrdXrootdProtocol::do_Close()
640 {
641  static XrdXrootdCallBack closeCB("close", XROOTD_MON_CLOSE);
642  XrdXrootdFile *fp;
644  int rc;
645  bool doDel = true;
646 
647 // Keep statistics
648 //
649  SI->Bump(SI->miscCnt);
650 
651 // Find the file object
652 //
653  if (!FTab || !(fp = FTab->Get(fh.handle)))
655  "close does not refer to an open file");
656 
657 // Serialize the file to make sure all references due to async I/O and parallel
658 // stream operations have completed.
659 //
660  fp->Serialize();
661 
662 // If the file has a fob then it was subject to pgwrite and if uncorrected
663 // checksum errors exist do a forced close. This will trigger POSC or a restore.
664 //
665  if (fp->pgwFob && !do_PgClose(fp, rc))
666  {FTab->Del((Monitor.Files() ? Monitor.Agent : 0), fh.handle, true);
667  numFiles--;
668  return rc;
669  }
670 
671 // Setup the callback to allow close() to return SFS_STARTED so we can defer
672 // the response to the close request as it may be a lengthy operation. In
673 // this case the argument is the actual file pointer and the link reference
674 // is recorded in the file object.
675 //
676  fp->cbArg = ReqID.getID();
677  fp->XrdSfsp->error.setErrCB(&closeCB, (unsigned long long)fp);
678 
679 // Add a reference count to the file in case the close will be deferred. In
680 // the deferred case the reference is used to prevent the callback from
681 // deleting the file until we have done necessary processing of the object
682 // during its removal from the open table.
683 //
684  fp->Ref(1);
685 
686 // Do an explicit close of the file here; check for exceptions. Stall requests
687 // leave the file open as there will be a retry. Otherwise, we remove the
688 // file from our open table but a "started" return defers the the delete.
689 //
690  rc = fp->XrdSfsp->close();
691  TRACEP(FS, " fh=" <<fh.handle <<" close rc=" <<rc);
692  if (rc == SFS_STARTED) doDel = false;
693  else {fp->Ref(-1);
694  if (rc >= SFS_STALL)
695  return fsError(rc, 0, fp->XrdSfsp->error, 0, 0);
696  }
697 
698 // Before we potentially delete the file handle in FTab->Del, generate the
699 // appropriate error code (if necessary). Note that we delay the call
700 // to Response.Send() in the successful case to avoid holding on to the lock
701 // while the response is sent.
702 //
703  int retval = 0;
704  if (SFS_OK != rc) retval = fsError(rc, 0, fp->XrdSfsp->error, 0, 0);
705 
706 // Delete the file from the file table. If the file object is deleted then it
707 // will unlock the file In all cases, final monitoring records will be produced.
708 //
709  FTab->Del((Monitor.Files() ? Monitor.Agent : 0), fh.handle, doDel);
710  numFiles--;
711  if (!doDel) fp->Ref(-1);
712 
713 // Send back the right response
714 //
715  if (SFS_OK == rc) return Response.Send();
716  return retval;
717 }
718 
719 /******************************************************************************/
720 /* d o _ D i r l i s t */
721 /******************************************************************************/
722 
723 int XrdXrootdProtocol::do_Dirlist()
724 {
725  int bleft, rc = 0, dlen, cnt = 0;
726  char *opaque, *buff, ebuff[4096];
727  const char *dname;
728  XrdSfsDirectory *dp;
729  bool doDig;
730 
731 // Check if we are digging for data
732 //
733  doDig = (digFS && SFS_LCLROOT(argp->buff));
734 
735 // Check for static routing
736 //
737  if (!doDig) {STATIC_REDIRECT(RD_dirlist);}
738 
739 // Prescreen the path
740 //
741  if (rpCheck(argp->buff, &opaque)) return rpEmsg("Listing", argp->buff);
742  if (!doDig && !Squash(argp->buff))return vpEmsg("Listing", argp->buff);
743 
744 // Get a directory object
745 //
746  if (doDig) dp = digFS->newDir(Link->ID, Monitor.Did);
747  else dp = osFS->newDir(Link->ID, Monitor.Did);
748 
749 // Make sure we have the object
750 //
751  if (!dp)
752  {snprintf(ebuff,sizeof(ebuff)-1,"Insufficient memory to open %s",argp->buff);
753  eDest.Emsg("Xeq", ebuff);
754  return Response.Send(kXR_NoMemory, ebuff);
755  }
756 
757 // First open the directory
758 //
759  dp->error.setUCap(clientPV);
760  if ((rc = dp->open(argp->buff, CRED, opaque)))
761  {rc = fsError(rc, XROOTD_MON_OPENDIR, dp->error, argp->buff, opaque);
762  delete dp;
763  return rc;
764  }
765 
766 // Check if the caller wants stat information as well
767 //
769  return do_DirStat(dp, ebuff, opaque);
770 
771 // Start retreiving each entry and place in a local buffer with a trailing new
772 // line character (the last entry will have a null byte). If we cannot fit a
773 // full entry in the buffer, send what we have with an OKSOFAR and continue.
774 // This code depends on the fact that a directory entry will never be longer
775 // than sizeof( ebuff)-1; otherwise, an infinite loop will result. No errors
776 // are allowed to be reflected at this point.
777 //
778  dname = 0;
779  do {buff = ebuff; bleft = sizeof(ebuff);
780  while(dname || (dname = dp->nextEntry()))
781  {dlen = strlen(dname);
782  if (dlen > 2 || dname[0] != '.' || (dlen == 2 && dname[1] != '.'))
783  {if ((bleft -= (dlen+1)) < 0) break;
784  strcpy(buff, dname); buff += dlen; *buff = '\n'; buff++; cnt++;
785  }
786  dname = 0;
787  }
788  if (dname) rc = Response.Send(kXR_oksofar, ebuff, buff-ebuff);
789  } while(!rc && dname);
790 
791 // Send the ending packet if we actually have one to send
792 //
793  if (!rc)
794  {if (ebuff == buff) rc = Response.Send();
795  else {*(buff-1) = '\0';
796  rc = Response.Send((void *)ebuff, buff-ebuff);
797  }
798  }
799 
800 // Close the directory
801 //
802  dp->close();
803  delete dp;
804  if (!rc) {TRACEP(FS, "dirlist entries=" <<cnt <<" path=" <<argp->buff);}
805  return rc;
806 }
807 
808 /******************************************************************************/
809 /* d o _ D i r S t a t */
810 /******************************************************************************/
811 
812 int XrdXrootdProtocol::do_DirStat(XrdSfsDirectory *dp, char *pbuff,
813  char *opaque)
814 {
815  XrdOucErrInfo myError(Link->ID, Monitor.Did, clientPV);
816  struct stat Stat;
817  char *buff, *dLoc, *algT = 0;
818  const char *csData, *dname;
819  int bleft, rc = 0, dlen, cnt = 0, statSz = 160;
820  bool manStat;
821  struct {char ebuff[8192]; char epad[512];} XB;
822 
823 // Preprocess checksum request. If we don't support checksums or if the
824 // requested checksum type is not supported, ignore it.
825 //
826  if ((Request.dirlist.options[0] & kXR_dcksm) && JobLCL)
827  {char cksT[64];
828  algT = getCksType(opaque, cksT, sizeof(cksT));
829  if (!algT)
830  {char ebuf[1024];
831  snprintf(ebuf, sizeof(ebuf), "%s checksum not supported.", cksT);
832  return Response.Send(kXR_ServerError, ebuf);
833  }
834  statSz += XrdCksData::NameSize + (XrdCksData::ValuSize*2) + 8;
835  }
836 
837 // We always return stat information, see if we can use autostat
838 //
839  manStat = (dp->autoStat(&Stat) != SFS_OK);
840 
841 // Construct the path to the directory as we will be asking for stat calls
842 // if the interface does not support autostat or returning checksums.
843 //
844  if (manStat || algT)
845  {strcpy(pbuff, argp->buff);
846  dlen = strlen(pbuff);
847  if (pbuff[dlen-1] != '/') {pbuff[dlen] = '/'; dlen++;}
848  dLoc = pbuff+dlen;
849  } else dLoc = 0;
850 
851 // The initial leadin is a "dot" entry to indicate to the client that we
852 // support the dstat option (older servers will not do that). It's up to the
853 // client to issue individual stat requests in that case.
854 //
855  memset(&Stat, 0, sizeof(Stat));
856  strcpy(XB.ebuff, ".\n0 0 0 0\n");
857  buff = XB.ebuff+10; bleft = sizeof(XB.ebuff)-10;
858 
859 // Start retreiving each entry and place in a local buffer with a trailing new
860 // line character (the last entry will have a null byte). If we cannot fit a
861 // full entry in the buffer, send what we have with an OKSOFAR and continue.
862 // This code depends on the fact that a directory entry will never be longer
863 // than sizeof( ebuff)-1; otherwise, an infinite loop will result. No errors
864 // are allowed to be reflected at this point.
865 //
866  dname = 0;
867  do {while(dname || (dname = dp->nextEntry()))
868  {dlen = strlen(dname);
869  if (dlen > 2 || dname[0] != '.' || (dlen == 2 && dname[1] != '.'))
870  {if ((bleft -= (dlen+1)) < 0 || bleft < statSz) break;
871  if (dLoc) strcpy(dLoc, dname);
872  if (manStat)
873  {rc = osFS->stat(pbuff, &Stat, myError, CRED, opaque);
874  if (rc == SFS_ERROR && myError.getErrInfo() == ENOENT)
875  {dname = 0; continue;}
876  if (rc != SFS_OK)
877  return fsError(rc, XROOTD_MON_STAT, myError,
878  argp->buff, opaque);
879  }
880  strcpy(buff, dname); buff += dlen; *buff = '\n'; buff++; cnt++;
881  dlen = StatGen(Stat, buff, sizeof(XB.epad));
882  bleft -= dlen; buff += (dlen-1);
883  if (algT)
884  {int ec = osFS->chksum(XrdSfsFileSystem::csGet, algT,
885  pbuff, myError, CRED, opaque);
886  csData = myError.getErrText();
887  if (ec != SFS_OK || !(*csData) || *csData == '!')
888  csData = "none";
889  int n = snprintf(buff,sizeof(XB.epad)," [ %s:%s ]",
890  algT, csData);
891  buff += n; bleft -= n;
892  }
893  *buff = '\n'; buff++;
894  }
895  dname = 0;
896  }
897  if (dname)
898  {rc = Response.Send(kXR_oksofar, XB.ebuff, buff-XB.ebuff);
899  buff = XB.ebuff; bleft = sizeof(XB.ebuff);
900  TRACEP(FS, "dirstat sofar n=" <<cnt <<" path=" <<argp->buff);
901  }
902  } while(!rc && dname);
903 
904 // Send the ending packet if we actually have one to send
905 //
906  if (!rc)
907  {if (XB.ebuff == buff) rc = Response.Send();
908  else {*(buff-1) = '\0';
909  rc = Response.Send((void *)XB.ebuff, buff-XB.ebuff);
910  }
911  }
912 
913 // Close the directory
914 //
915  dp->close();
916  delete dp;
917  if (!rc) {TRACEP(FS, "dirstat entries=" <<cnt <<" path=" <<argp->buff);}
918  return rc;
919 }
920 
921 /******************************************************************************/
922 /* d o _ E n d s e s s */
923 /******************************************************************************/
924 
925 int XrdXrootdProtocol::do_Endsess()
926 {
927  XrdXrootdSessID sessID;
928  int rc;
929 
930 // Update misc stats count
931 //
932  SI->Bump(SI->miscCnt);
933 
934 // Extract out the FD and Instance from the session ID
935 //
936  memcpy((void*)&sessID, Request.endsess.sessid, sizeof(sessID));
937  sessID.UnMask();
938 
939 // Trace this request
940 //
941  TRACEP(LOGIN, "endsess " <<sessID.Pid <<':' <<sessID.FD <<'.' <<sessID.Inst);
942 
943 // If this session id does not refer to us, ignore the request
944 //
945  if (sessID.Pid != myPID) return Response.Send();
946 
947 // Terminate the indicated session, if possible. This could also be a self-termination.
948 //
949  if ((sessID.FD == 0 && sessID.Inst == 0)
950  || !(rc = Link->Terminate(0, sessID.FD, sessID.Inst))) return -1;
951 
952 // Trace this request
953 //
954  TRACEP(LOGIN, "endsess " <<sessID.Pid <<':' <<sessID.FD <<'.' <<sessID.Inst
955  <<" rc=" <<rc <<" (" <<XrdSysE2T(rc < 0 ? -rc : EAGAIN) <<")");
956 
957 // Return result. We only return obvious problems (exclude ESRCH and EPIPE).
958 //
959  if (rc > 0)
960  return (rc = Response.Send(kXR_wait, rc, "session still active")) ? rc:1;
961 
962  if (rc == -EACCES)return Response.Send(kXR_NotAuthorized, "not session owner");
963  if (rc == -ETIME) return Response.Send(kXR_Cancelled,"session not ended");
964 
965  return Response.Send();
966 }
967 
968 /******************************************************************************/
969 /* d o _ F A t t r */
970 /* */
971 /* Resides in XrdXrootdXeqFAttr.cc */
972 /******************************************************************************/
973 
974 /******************************************************************************/
975 /* d o _ g p F i l e */
976 /******************************************************************************/
977 
978 int XrdXrootdProtocol::do_gpFile()
979 {
980 // int gopts, buffsz;
981 
982 // Keep Statistics (TO DO: differentiate get vs put)
983 //
984  SI->Bump(SI->getfCnt);
985 // SI->Bump(SI->putfCnt);
986 
987 // Check if gpfile need to occur on a TLS connection
988 //
989  if ((doTLS & Req_TLSGPFile) && !isTLS && !Link->hasBridge())
990  return Response.Send(kXR_TLSRequired, "gpfile requires TLS");
991 
992  return Response.Send(kXR_Unsupported, "gpfile request is not supported");
993 }
994 
995 /******************************************************************************/
996 /* d o _ L o c a t e */
997 /******************************************************************************/
998 
999 int XrdXrootdProtocol::do_Locate()
1000 {
1001  static XrdXrootdCallBack locCB("locate", XROOTD_MON_LOCATE);
1002  int rc, opts, fsctl_cmd = SFS_FSCTL_LOCATE;
1003  char *opaque = 0, *Path, *fn = argp->buff, opt[8], *op=opt;
1004  XrdOucErrInfo myError(Link->ID,&locCB,ReqID.getID(),Monitor.Did,clientPV);
1005  bool doDig = false;
1006 
1007 // Unmarshall the data
1008 //
1009  opts = (int)ntohs(Request.locate.options);
1010 
1011 // Map the options
1012 //
1013  if (opts & kXR_nowait) {fsctl_cmd |= SFS_O_NOWAIT; *op++ = 'i';}
1014  if (opts & kXR_refresh) {fsctl_cmd |= SFS_O_RESET; *op++ = 's';}
1015  if (opts & kXR_force ) {fsctl_cmd |= SFS_O_FORCE; *op++ = 'f';}
1016  if (opts & kXR_prefname){fsctl_cmd |= SFS_O_HNAME; *op++ = 'n';}
1017  if (opts & kXR_compress){fsctl_cmd |= SFS_O_RAWIO; *op++ = 'u';}
1018  if (opts & kXR_4dirlist){fsctl_cmd |= SFS_O_DIRLIST;*op++ = 'D';}
1019  *op = '\0';
1020  TRACEP(FS, "locate " <<opt <<' ' <<fn);
1021 
1022 // Check if this is a non-specific locate
1023 //
1024  if (*fn != '*'){Path = fn;
1025  doDig = (digFS && SFS_LCLROOT(Path));
1026  }
1027  else if (*(fn+1)) {Path = fn+1;
1028  doDig = (digFS && SFS_LCLROOT(Path));
1029  }
1030  else {Path = 0;
1031  fn = XPList.Next()->Path();
1032  fsctl_cmd |= SFS_O_TRUNC;
1033  }
1034 
1035 // Check for static routing
1036 //
1037  if (!doDig) {STATIC_REDIRECT(RD_locate);}
1038 
1039 // Prescreen the path
1040 //
1041  if (Path)
1042  {if (rpCheck(Path, &opaque)) return rpEmsg("Locating", Path);
1043  if (!doDig && !Squash(Path))return vpEmsg("Locating", Path);
1044  }
1045 
1046 // Preform the actual function. For regular Fs add back any opaque info
1047 //
1048  if (doDig) rc = digFS->fsctl(fsctl_cmd, fn, myError, CRED);
1049  else {if (opaque)
1050  {int n = strlen(argp->buff); argp->buff[n] = '?';
1051  if ((argp->buff)+n != opaque-1)
1052  memmove(&argp->buff[n+1], opaque, strlen(opaque)+1);
1053  }
1054  rc = osFS->fsctl(fsctl_cmd, fn, myError, CRED);
1055  }
1056  TRACEP(FS, "rc=" <<rc <<" locate " <<fn);
1057  return fsError(rc, (doDig ? 0 : XROOTD_MON_LOCATE), myError, Path, opaque);
1058 }
1059 
1060 /******************************************************************************/
1061 /* d o _ L o g i n */
1062 /*.x***************************************************************************/
1063 
1064 int XrdXrootdProtocol::do_Login()
1065 {
1066  XrdXrootdSessID sessID;
1067  XrdNetAddrInfo *addrP;
1068  int i, pid, rc, sendSID = 0;
1069  char uname[sizeof(Request.login.username)+1];
1070 
1071 // Keep Statistics
1072 //
1073  SI->Bump(SI->LoginAT);
1074 
1075 // Check if login need to occur on a TLS connection
1076 //
1077  if ((doTLS & Req_TLSLogin) && !isTLS && !Link->hasBridge())
1078  {const char *emsg = "login requires TLS be enabled";
1079  if (!ableTLS)
1080  {emsg = "login requires TLS support";
1081  eDest.Emsg("Xeq","login requires TLS but",Link->ID,"is incapable.");
1082  }
1083  return Response.Send(kXR_TLSRequired, emsg);
1084  }
1085 
1086 // Unmarshall the pid and construct username using the POSIX.1-2008 standard
1087 //
1088  pid = (int)ntohl(Request.login.pid);
1089  strncpy(uname, (const char *)Request.login.username, sizeof(uname)-1);
1090  uname[sizeof(uname)-1] = 0;
1091  XrdOucUtils::Sanitize(uname);
1092 
1093 // Make sure the user is not already logged in
1094 //
1095  if (Status) return Response.Send(kXR_InvalidRequest,
1096  "duplicate login; already logged in");
1097 
1098 // Establish the ID for this link
1099 //
1100  Link->setID(uname, pid);
1101  CapVer = Request.login.capver[0];
1102 
1103 // Establish the session ID if the client can handle it (protocol version > 0)
1104 //
1105  if ((i = (CapVer & kXR_vermask)))
1106  {sessID.FD = Link->FDnum();
1107  sessID.Inst = Link->Inst();
1108  sessID.Pid = myPID;
1109  mySID = getSID();
1110  sessID.Sid = mySID;
1111  sessID.Mask();
1112  sendSID = 1;
1113  if (!clientPV)
1114  { if (i >= kXR_ver004) clientPV = (int)0x0310;
1115  else if (i == kXR_ver003) clientPV = (int)0x0300;
1116  else if (i == kXR_ver002) clientPV = (int)0x0290;
1117  else if (i == kXR_ver001) clientPV = (int)0x0200;
1118  else clientPV = (int)0x0100;
1119  }
1135  }
1136 
1137 // Mark the client as IPv4 if they came in as IPv4 or mapped IPv4 we can only
1138 // return IPv4 addresses. Of course, if the client is dual-stacked then we
1139 // simply indicate the client can accept either (the client better be honest).
1140 //
1141  addrP = Link->AddrInfo();
1142  if (addrP->isIPType(XrdNetAddrInfo::IPv4) || addrP->isMapped())
1144 // WORKAROUND: XrdCl 4.0.x often identifies worker nodes as being IPv6-only.
1145 // Rather than breaking a significant number of our dual-stack workers, we
1146 // automatically denote IPv6 connections as also supporting IPv4 - regardless
1147 // of what the remote client claims. This was fixed in 4.3.x but we can't
1148 // tell release differences until 4.5 when we can safely ignore this as we
1149 // also don't want to misidentify IPv6-only clients either.
1150  else if (i < kXR_ver004 && XrdInet::GetAssumeV4())
1152 
1153 // Mark the client as being on a private net if the address is private
1154 //
1155  if (addrP->isPrivate()) {clientPV |= XrdOucEI::uPrip; rdType = 1;}
1156  else rdType = 0;
1157 
1158 // Get the security token for this link. We will either get a token, a null
1159 // string indicating host-only authentication, or a null indicating no
1160 // authentication. We can then optimize of each case.
1161 //
1162  if (CIA)
1163  {const char *pp=CIA->getParms(i, Link->AddrInfo());
1164  if (pp && i ) {if (!sendSID) rc = Response.Send((void *)pp, i);
1165  else {struct iovec iov[3];
1166  iov[1].iov_base = (char *)&sessID;
1167  iov[1].iov_len = sizeof(sessID);
1168  iov[2].iov_base = (char *)pp;
1169  iov[2].iov_len = i;
1170  rc = Response.Send(iov,3,int(i+sizeof(sessID)));
1171  }
1173  }
1174  else {rc = (sendSID ? Response.Send((void *)&sessID, sizeof(sessID))
1175  : Response.Send());
1177  }
1178  }
1179  else {rc = (sendSID ? Response.Send((void *)&sessID, sizeof(sessID))
1180  : Response.Send());
1182  }
1183 
1184 // We always allow at least host-based authentication. This may be over-ridden
1185 // should strong authentication be enabled. Allocation of the protocol object
1186 // already supplied the protocol name and the host name. We supply the tident
1187 // and the connection details in addrInfo.
1188 //
1191  Client = &Entity;
1192 
1193 // Check if we need to process a login environment
1194 //
1195  if (Request.login.dlen > 8)
1196  {XrdOucEnv loginEnv(argp->buff+1, Request.login.dlen-1);
1197  char *rnumb = loginEnv.Get("xrd.rn");
1198  char *cCode = loginEnv.Get("xrd.cc");
1199  char *tzVal = loginEnv.Get("xrd.tz");
1200  char *appXQ = loginEnv.Get("xrd.appname");
1201  char *aInfo = loginEnv.Get("xrd.info");
1202  int tzNum = (tzVal ? atoi(tzVal) : 0);
1203  if (cCode && *cCode && tzNum >= -12 && tzNum <= 14)
1204  {XrdNetAddrInfo::LocInfo locInfo;
1205  locInfo.Country[0] = cCode[0]; locInfo.Country[1] = cCode[1];
1206  locInfo.TimeZone = tzNum & 0xff;
1207  Link->setLocation(locInfo);
1208  }
1209  if (Monitor.Ready() && (appXQ || aInfo))
1210  {char apBuff[1024];
1211  snprintf(apBuff, sizeof(apBuff), "&R=%s&x=%s&y=%s&I=%c",
1212  (rnumb ? rnumb : ""),
1213  (appXQ ? appXQ : ""), (aInfo ? aInfo : ""),
1214  (clientPV & XrdOucEI::uIPv4 ? '4' : '6'));
1215  Entity.moninfo = strdup(apBuff);
1216  }
1217 
1218  if (rnumb)
1219  {int majr, minr, pchr;
1220  if (sscanf(rnumb, "v%d.%d.%d", &majr, &minr, &pchr) == 3)
1221  clientRN = (majr<<16) | ((minr<<8) | pchr);
1222  else if (sscanf(rnumb, "v%d-%*x", &majr) == 1) clientRN = -1;
1223  }
1224  if (appXQ) AppName = strdup(appXQ);
1225  }
1226 
1227 // Allocate a monitoring object, if needed for this connection
1228 //
1229  if (Monitor.Ready())
1230  {Monitor.Register(Link->ID, Link->Host(), "xroot", mySID);
1231  if (Monitor.Logins() && (!Monitor.Auths() || !(Status & XRD_NEED_AUTH)))
1233  if (Entity.moninfo) {free(Entity.moninfo); Entity.moninfo = 0;}
1234  Entity.secMon = &Monitor;
1235  }
1236  }
1237 
1238 // Complete the rquestID object
1239 //
1241 
1242 // Document this login
1243 //
1244  if (!(Status & XRD_NEED_AUTH) && !logLogin()) return -1;
1245  return rc;
1246 }
1247 
1248 /******************************************************************************/
1249 /* d o _ M k d i r */
1250 /******************************************************************************/
1251 
1252 int XrdXrootdProtocol::do_Mkdir()
1253 {
1254  int mode, rc;
1255  char *opaque;
1256  XrdOucErrInfo myError(Link->ID, Monitor.Did, clientPV);
1257 
1258 // Check for static routing
1259 //
1260  STATIC_REDIRECT(RD_mkdir);
1261 
1262 // Unmarshall the data
1263 //
1264  mode = mapMode((int)ntohs(Request.mkdir.mode)) | S_IRWXU;
1265  if (Request.mkdir.options[0] & static_cast<unsigned char>(kXR_mkdirpath))
1266  mode |= SFS_O_MKPTH;
1267  if (rpCheck(argp->buff, &opaque)) return rpEmsg("Creating", argp->buff);
1268  if (!Squash(argp->buff)) return vpEmsg("Creating", argp->buff);
1269 
1270 // Preform the actual function
1271 //
1272  rc = osFS->mkdir(argp->buff, (XrdSfsMode)mode, myError, CRED, opaque);
1273  TRACEP(FS, "rc=" <<rc <<" mkdir " <<Xrd::oct1 <<mode <<' ' <<argp->buff);
1274  if (SFS_OK == rc) return Response.Send();
1275 
1276 // An error occurred
1277 //
1278  return fsError(rc, XROOTD_MON_MKDIR, myError, argp->buff, opaque);
1279 }
1280 
1281 /******************************************************************************/
1282 /* d o _ M v */
1283 /******************************************************************************/
1284 
1285 int XrdXrootdProtocol::do_Mv()
1286 {
1287  int rc;
1288  char *oldp, *newp, *Opaque, *Npaque;
1289  XrdOucErrInfo myError(Link->ID, Monitor.Did, clientPV);
1290 
1291 // Check for static routing
1292 //
1293  STATIC_REDIRECT(RD_mv);
1294 
1295 // Find the space separator between the old and new paths
1296 //
1297  oldp = newp = argp->buff;
1298  if (Request.mv.arg1len)
1299  {int n = ntohs(Request.mv.arg1len);
1300  if (n < 0 || n >= Request.mv.dlen || *(argp->buff+n) != ' ')
1301  return Response.Send(kXR_ArgInvalid, "invalid path specification");
1302  *(oldp+n) = 0;
1303  newp += n+1;
1304  } else {
1305  while(*newp && *newp != ' ') newp++;
1306  if (*newp) {*newp = '\0'; newp++;
1307  while(*newp && *newp == ' ') newp++;
1308  }
1309  }
1310 
1311 // Get rid of relative paths and multiple slashes
1312 //
1313  if (rpCheck(oldp, &Opaque)) return rpEmsg("Renaming", oldp);
1314  if (rpCheck(newp, &Npaque)) return rpEmsg("Renaming to", newp);
1315  if (!Squash(oldp)) return vpEmsg("Renaming", oldp);
1316  if (!Squash(newp)) return vpEmsg("Renaming to", newp);
1317 
1318 // Check if new path actually specified here
1319 //
1320  if (*newp == '\0')
1321  Response.Send(kXR_ArgMissing, "new path specified for mv");
1322 
1323 // Preform the actual function
1324 //
1325  rc = osFS->rename(oldp, newp, myError, CRED, Opaque, Npaque);
1326  TRACEP(FS, "rc=" <<rc <<" mv " <<oldp <<' ' <<newp);
1327  if (SFS_OK == rc) return Response.Send();
1328 
1329 // An error occurred
1330 //
1331  return fsError(rc, XROOTD_MON_MV, myError, oldp, Opaque);
1332 }
1333 
1334 /******************************************************************************/
1335 /* d o _ O f f l o a d */
1336 /******************************************************************************/
1337 
1338 int XrdXrootdProtocol::do_Offload(int (XrdXrootdProtocol::*Invoke)(),int pathID)
1339 {
1340  XrdSysSemaphore isAvail(0);
1341  XrdXrootdProtocol *pp;
1342  XrdXrootdPio *pioP;
1343  int rc;
1344  kXR_char streamID[2];
1345 
1346 // Verify that the path actually exists (note we will have the stream lock)
1347 //
1348  if (!(pp = VerifyStream(rc, pathID))) return rc;
1349 
1350 // Grab the stream ID
1351 //
1352  Response.StreamID(streamID);
1353 
1354 // Try to schedule this operation. In order to maximize the I/O overlap, we
1355 // will wait until the stream gets control and will have a chance to start
1356 // reading from the network. We handle refs for consistency.
1357 //
1358  do{if (!pp->isActive)
1359  {pp->IO = IO;
1360  pp->myBlen = 0;
1361  pp->Resume = &XrdXrootdProtocol::do_OffloadIO;
1362  pp->ResumePio= Invoke;
1363  pp->isActive = true;
1364  pp->newPio = true;
1365  pp->reTry = &isAvail;
1366  pp->Response.Set(streamID);
1367  pp->streamMutex.UnLock();
1368  Link->setRef(1);
1369  IO.File->Ref(1);
1370  Sched->Schedule((XrdJob *)(pp->Link));
1371  isAvail.Wait();
1372  return 0;
1373  }
1374 
1375  if ((pioP = pp->pioFree)) break;
1376  pp->reTry = &isAvail;
1377  pp->streamMutex.UnLock();
1378  TRACEP(FSZIO, "busy path " <<pathID <<" offs=" <<IO.Offset);
1379  isAvail.Wait();
1380  TRACEP(FSZIO, "retry path " <<pathID <<" offs=" <<IO.Offset);
1381  pp->streamMutex.Lock();
1382  if (pp->isNOP)
1383  {pp->streamMutex.UnLock();
1384  return Response.Send(kXR_ArgInvalid, "path ID is not connected");
1385  }
1386  } while(1);
1387 
1388 // Fill out the queue entry and add it to the queue
1389 //
1390  pp->pioFree = pioP->Next; pioP->Next = 0;
1391  pioP->Set(Invoke, IO, streamID);
1392  IO.File->Ref(1);
1393  if (pp->pioLast) pp->pioLast->Next = pioP;
1394  else pp->pioFirst = pioP;
1395  pp->pioLast = pioP;
1396  pp->streamMutex.UnLock();
1397  return 0;
1398 }
1399 
1400 /******************************************************************************/
1401 /* d o _ O f f l o a d I O */
1402 /******************************************************************************/
1403 
1404 int XrdXrootdProtocol::do_OffloadIO()
1405 {
1406  XrdXrootdPio *pioP;
1407  int rc;
1408 
1409 // Entry implies that we just got scheduled and are marked as active. Hence
1410 // we need to post the session thread so that it can pick up the next request.
1411 //
1412  streamMutex.Lock();
1413  isLinkWT = false;
1414  if (newPio)
1415  {newPio = false;
1416  if (reTry) {reTry->Post(); reTry = 0;}
1417  TRACEP(FSZIO, "dispatch new I/O path " <<PathID <<" offs=" <<IO.Offset);
1418  }
1419 
1420 // Perform all I/O operations on a parallel stream
1421 //
1422  if (!isNOP)
1423  do {streamMutex.UnLock();
1424  rc = (*this.*ResumePio)();
1425  streamMutex.Lock();
1426 
1427  if (rc > 0 && !isNOP)
1428  {ResumePio = Resume;
1429  Resume = &XrdXrootdProtocol::do_OffloadIO;
1430  isLinkWT = true;
1431  streamMutex.UnLock();
1432  return rc;
1433  }
1434 
1435  IO.File->Ref(-1); // Note: File was ref'd when request was queued
1436  if (rc || isNOP || !(pioP = pioFirst)) break;
1437  if (!(pioFirst = pioP->Next)) pioLast = 0;
1438 
1439  IO = pioP->IO;
1440  ResumePio = pioP->ResumePio;
1441  Response.Set(pioP->StreamID);
1442  pioP->Next = pioFree; pioFree = pioP;
1443  if (reTry) {reTry->Post(); reTry = 0;}
1444  } while(1);
1445  else {rc = -1; IO.File->Ref(-1);}
1446 
1447 // There are no pending operations or the link died
1448 //
1449  if (rc) isNOP = true;
1450  isActive = false;
1451  Stream[0]->Link->setRef(-1);
1452  if (reTry) {reTry->Post(); reTry = 0;}
1453  if (endNote) endNote->Signal();
1454  streamMutex.UnLock();
1455  TRACEP(FSZIO, "offload complete path "<<PathID<<" virt rc=" <<rc);
1456  return (rc ? rc : -EINPROGRESS);
1457 }
1458 
1459 /******************************************************************************/
1460 /* d o _ O p e n */
1461 /******************************************************************************/
1462 
1463 namespace
1464 {
1465 struct OpenHelper
1466  {XrdSfsFile *fp;
1467  XrdXrootdFile *xp;
1468  XrdXrootdFileLock *Locker;
1469  const char *path;
1470  char mode;
1471  bool isOK;
1472 
1473  OpenHelper(XrdXrootdFileLock *lkP, const char *fn)
1474  : fp(0), xp(0), Locker(lkP), path(fn), mode(0),
1475  isOK(false) {}
1476 
1477  ~OpenHelper()
1478  {if (!isOK)
1479  {if (xp) delete xp; // Deletes fp & unlocks
1480  else {if (fp) delete fp;
1481  if (mode) Locker->Unlock(path,mode);
1482  }
1483  }
1484  }
1485  };
1486 }
1487 
1488 int XrdXrootdProtocol::do_Open()
1489 {
1490  static XrdXrootdCallBack openCB("open file", XROOTD_MON_OPENR);
1491  int fhandle;
1492  int rc, mode, opts, optt, openopts, compchk = 0;
1493  int popt;
1494  char *opaque, usage, ebuff[2048], opC;
1495  bool doDig, doforce = false, isAsync = false, doClone = false;
1496  char *fn = argp->buff, opt[24], *op=opt;
1497  XrdSfsFile *fp;
1498  XrdXrootdFile *xp, *sameFS = 0;
1499  struct stat statbuf;
1500  struct ServerResponseBody_Open myResp;
1501  int resplen = sizeof(myResp.fhandle);
1502  struct iovec IOResp[3]; // Note that IOResp[0] is completed by Response
1503  int retStat = 0;
1504 
1505 // Keep Statistics
1506 //
1507  SI->Bump(SI->openCnt);
1508 
1509 // Unmarshall the data
1510 //
1511  mode = (int)ntohs(Request.open.mode);
1512  opts = (int)ntohs(Request.open.options);
1513  optt = (int)ntohs(Request.open.optiont);
1514 
1515 // Make sutre that retstat and retstatx are processed correctly
1516 //
1517  if (optt & kXR_retstatx) opts |= kXR_retstat;
1518 
1519 // Map the mode and options
1520 //
1521  mode = mapMode(mode) | S_IRUSR | S_IWUSR; usage = 'r';
1522  if (opts & kXR_open_read)
1523  {openopts = SFS_O_RDONLY; *op++ = 'r'; opC = XROOTD_MON_OPENR;}
1524  else if (opts & kXR_open_updt)
1525  {openopts = SFS_O_RDWR; *op++ = 'u'; usage = 'w';
1526  opC = XROOTD_MON_OPENW;}
1527  else if (opts & kXR_open_wrto)
1528  {openopts = SFS_O_WRONLY; *op++ = 'o'; usage = 'w';
1529  opC = XROOTD_MON_OPENW;}
1530  else {openopts = SFS_O_RDONLY; *op++ = 'r'; opC = XROOTD_MON_OPENR;}
1531 
1532  if (opts & kXR_new)
1533  {openopts |= SFS_O_CREAT; *op++ = 'n'; opC = XROOTD_MON_OPENC;
1534  if (opts & kXR_replica) {*op++ = '+';
1535  openopts |= SFS_O_REPLICA;
1536  }
1537  // Up until 3/28/19 we mistakenly used kXR_mkdir instead of
1538  // kXR_mkpath to allow path creation. That meant, path creation was
1539  // allowed if _mkpath|_async|_refresh|_open_apnd|_replica were set.
1540  // Since the client has always turned on _async that meant that
1541  // path creation was always enabled. We continue this boondogle
1542  // using the correct flag for backward compatibility reasons, sigh.
1543  //
1544  if (opts & (kXR_mkpath | kXR_async))
1545  {*op++ = 'm';
1546  mode |= SFS_O_MKPTH;
1547  }
1548  }
1549  else if (opts & kXR_delete)
1550  {openopts = SFS_O_TRUNC; *op++ = 'd'; opC = XROOTD_MON_OPENW;
1551  if (opts & (kXR_mkpath | kXR_async))
1552  {*op++ = 'm';
1553  mode |= SFS_O_MKPTH;
1554  }
1555  }
1556  if (opts & kXR_compress)
1557  {openopts |= SFS_O_RAWIO; *op++ = 'c'; compchk = 1;}
1558  if (opts & kXR_force) {*op++ = 'f'; doforce = true;}
1559  if ((opts & kXR_async || as_force) && as_aioOK)
1560  {*op++ = 'a'; isAsync = true;}
1561  if (opts & kXR_refresh) {*op++ = 's'; openopts |= SFS_O_RESET;
1562  SI->Bump(SI->Refresh);
1563  }
1564  if (opts & kXR_retstat) {*op++ = 't'; retStat = 1;}
1565  if (opts & kXR_posc) {*op++ = 'p'; openopts |= SFS_O_POSC;}
1566  if (opts & kXR_seqio) {*op++ = 'S'; openopts |= SFS_O_SEQIO;}
1567  if (optt & kXR_samefs || optt & kXR_dup)
1569  if (!(fsFeatures & XrdSfs::hasFICL))
1570  return Response.Send(kXR_Unsupported,(optt & kXR_dup) ?
1571  "file cloning is not supported" :
1572  "colocating with a specified file is not supported");
1573  if (optt & kXR_dup)
1574  {if (usage != 'w') return Response.Send(kXR_ArgInvalid,
1575  "cloned file is not being opened R/W");
1576  {*op++ = 'K'; doClone = true;}
1577  }
1578  if (!(opts & kXR_new)) return Response.Send(kXR_ArgInvalid,
1579  "file must be opened as a new file in order to colocate");
1580  if (openopts &= SFS_O_CREAT) {*op++ = 'L'; openopts |= SFS_O_CREATAT;}
1581 
1582  if (!FTab || !(sameFS = FTab->Get(fh.handle)))
1583  return Response.Send(kXR_FileNotOpen,
1584  "file template does not refer to an open file");
1585  }
1586 
1587  *op = '\0';
1588 
1589 // Do some tracing, avoid exposing any security token in the URL
1590 //
1591  if (TRACING(TRACE_FS))
1592  {char* cgiP = index(fn, '?');
1593  if (cgiP) *cgiP = 0;
1594  TRACEP(FS, "open " <<opt <<' ' <<fn);
1595  if (cgiP) *cgiP = '?';
1596  }
1597 
1598 // Check if opaque data has been provided
1599 //
1600  if (rpCheck(fn, &opaque)) return rpEmsg("Opening", fn);
1601 
1602 // Check if this is a local dig type file
1603 //
1604  doDig = (digFS && SFS_LCLPATH(fn));
1605 
1606 // Validate the path/req type and then check if static redirection applies
1607 //
1608  if (doDig) {popt = XROOTDXP_NOLK; opC = 0;}
1609  else {int ropt = -1;
1610  if (!(popt = Squash(fn))) return vpEmsg("Opening", fn);
1611  if (Route[RD_open1].Host[rdType])
1612  ropt = RPList.Validate(fn);
1613  else
1614  if (Route[RD_openw].Host[rdType] && ('w' == usage || strchr(op, 'd')))
1615  ropt = RD_openw;
1616  if (ropt > 0)
1617  return Response.Send(
1618  kXR_redirect, Route[ropt].Port[rdType],
1619  Route[ropt].Host[rdType]
1620  );
1621  }
1622 
1623 // Add the multi-write option if this path supports it
1624 //
1625  if (popt & XROOTDXP_NOMWCHK) openopts |= SFS_O_MULTIW;
1626 
1627 // Construct an open helper to release resources should we exit due to an error.
1628 //
1629  OpenHelper oHelp(Locker, fn);
1630 
1631 // Lock this file
1632 //
1633  if (!(popt & XROOTDXP_NOLK))
1634  {if ((rc = Locker->Lock(fn, usage, doforce)))
1635  {const char *who;
1636  if (rc > 0) who = (rc > 1 ? "readers" : "reader");
1637  else { rc = -rc;
1638  who = (rc > 1 ? "writers" : "writer");
1639  }
1640  snprintf(ebuff, sizeof(ebuff)-1,
1641  "%s file %s is already opened by %d %s; open denied.",
1642  ('r' == usage ? "Input" : "Output"), fn, rc, who);
1643  eDest.Emsg("Xeq", ebuff);
1644  return Response.Send(kXR_FileLocked, ebuff);
1645  } else oHelp.mode = usage;
1646  }
1647 
1648 // Get a file object
1649 //
1650  if (doDig) fp = digFS->newFile(Link->ID, Monitor.Did);
1651  else fp = osFS->newFile(Link->ID, Monitor.Did);
1652 
1653 // Make sure we got one
1654 //
1655  if (!fp)
1656  {snprintf(ebuff, sizeof(ebuff)-1,"Insufficient memory to open %s",fn);
1657  eDest.Emsg("Xeq", ebuff);
1658  return Response.Send(kXR_NoMemory, ebuff);
1659  }
1660  oHelp.fp = fp;
1661 
1662 // The open is elegible for a deferred response, indicate we're ok with that
1663 // unless a clone is required. Then this needs to be done synchrnously.
1664 //
1665  if (!doClone)
1666  {fp->error.setErrCB(&openCB, ReqID.getID());
1667  fp->error.setUCap(clientPV);
1668  }
1669 
1670 // If TPC opens require TLS but this is not a TLS connection, prohibit TPC
1671 //
1672  if ((doTLS & Req_TLSTPC) && !isTLS && !Link->hasBridge())
1673  openopts|= SFS_O_NOTPC;
1674 
1675 // If needed add the colocation information. This is the filesystem in
1676 // which the new file should be created.
1677 //
1678  std::string oinfo(opaque ? opaque : "");
1679  if ((openopts & SFS_O_CREATAT) == SFS_O_CREATAT)
1680  {std::string coloc = sameFS->XrdSfsp->FName();
1681  coloc = "oss.coloc=" + XrdOucUtils::UrlEncode(coloc);
1682  oinfo += (!oinfo.empty() ? "&" : "") + coloc;
1683  }
1684 
1685 // Open the file
1686 //
1687  if ((rc = fp->open(fn, (XrdSfsFileOpenMode)openopts,
1688  (mode_t)mode, CRED, oinfo.c_str())))
1689  return fsError(rc, opC, fp->error, fn, opaque);
1690 
1691 // If file needs to be cloned, do so now
1692 //
1693  if (doClone && (rc = fp->Clone(*(sameFS->XrdSfsp))))
1694  return fsError(rc, opC, fp->error, fn, opaque);
1695 
1696 // Obtain a hyper file object
1697 //
1698  xp = new XrdXrootdFile(Link->ID, fn, fp, usage, isAsync, &statbuf);
1699  if (!xp)
1700  {snprintf(ebuff, sizeof(ebuff)-1, "Insufficient memory to open %s", fn);
1701  eDest.Emsg("Xeq", ebuff);
1702  return Response.Send(kXR_NoMemory, ebuff);
1703  }
1704  oHelp.xp = xp;
1705 
1706 // Serialize the link
1707 //
1708  Link->Serialize();
1709  *ebuff = '\0';
1710 
1711 // Create a file table for this link if it does not have one
1712 //
1713  if (!FTab) FTab = new XrdXrootdFileTable(Monitor.Did);
1714 
1715 // Insert this file into the link's file table
1716 //
1717  if (!FTab || (fhandle = FTab->Add(xp)) < 0)
1718  {snprintf(ebuff, sizeof(ebuff)-1, "Insufficient memory to open %s", fn);
1719  eDest.Emsg("Xeq", ebuff);
1720  return Response.Send(kXR_NoMemory, ebuff);
1721  }
1722 
1723 // If the file supports exchange buffering, supply it with the object
1724 //
1725  if (fsFeatures & XrdSfs::hasSXIO) fp->setXio(this);
1726 
1727 // Document forced opens
1728 //
1729  if (doforce)
1730  {int rdrs, wrtrs;
1731  Locker->numLocks(fn, rdrs, wrtrs);
1732  if (('r' == usage && wrtrs) || ('w' == usage && rdrs) || wrtrs > 1)
1733  {snprintf(ebuff, sizeof(ebuff)-1,
1734  "%s file %s forced opened with %d reader(s) and %d writer(s).",
1735  ('r' == usage ? "Input" : "Output"), fn, rdrs, wrtrs);
1736  eDest.Emsg("Xeq", ebuff);
1737  }
1738  }
1739 
1740 // Determine if file is compressed
1741 //
1742  memset(&myResp, 0, sizeof(myResp));
1743  if (!compchk) resplen = sizeof(myResp.fhandle);
1744  else {int cpsize;
1745  fp->getCXinfo((char *)myResp.cptype, cpsize);
1746  myResp.cpsize = static_cast<kXR_int32>(htonl(cpsize));
1747  resplen = sizeof(myResp);
1748  }
1749 
1750 // If client wants a stat in open, return the stat information
1751 //
1752  if (retStat)
1753  {retStat = StatGen(statbuf, ebuff, sizeof(ebuff));
1754  IOResp[1].iov_base = (char *)&myResp; IOResp[1].iov_len = sizeof(myResp);
1755  IOResp[2].iov_base = ebuff; IOResp[2].iov_len = retStat;
1756  resplen = sizeof(myResp) + retStat;
1757  }
1758 
1759 // If we are monitoring, send off a path to dictionary mapping (must try 1st!)
1760 //
1761  if (Monitor.Files())
1762  {xp->Stats.FileID = Monitor.MapPath(fn);
1764  Monitor.Agent->Open(xp->Stats.FileID, statbuf.st_size);
1765  }
1766 
1767 // Since file monitoring is deprecated, a dictid may not have been assigned.
1768 // But if fstream monitoring is enabled it will assign the dictid.
1769 //
1770  if (Monitor.Fstat())
1771  XrdXrootdMonFile::Open(&(xp->Stats), fn, Monitor.Did, usage == 'w');
1772 
1773 // Insert the file handle
1774 //
1775  memcpy((void *)myResp.fhandle,(const void *)&fhandle,sizeof(myResp.fhandle));
1776  numFiles++;
1777 
1778 // If packet marking is enabled, notify that we have potentially started data.
1779 // We also need to extend the marking to any associated streams.
1780 //
1781  int eCode, aCode;
1782  if (PMark && !pmDone)
1783  {streamMutex.Lock();
1784  pmDone = true;
1785  if ((pmHandle = PMark->Begin(*Client, fn, opaque, AppName)))
1786  for (int i = 1; i < maxStreams; i++)
1787  {if (Stream[i] && !(Stream[i]->pmDone))
1788  {Stream[i]->pmDone = true;
1789  Stream[i]->pmHandle =
1790  PMark->Begin(*(Stream[i]->Link->AddrInfo()),
1791  *pmHandle, Stream[i]->Link->ID);
1792  }
1793  }
1794  streamMutex.UnLock();
1795 
1796  if (pmHandle && Monitor.Logins() && pmHandle->getEA(eCode, aCode))
1797  Monitor.Report(eCode, aCode);
1798  } else {
1799  if (!pmDone && Monitor.Logins()
1800  && XrdNetPMark::getEA(opaque, eCode, aCode))
1801  {Monitor.Report(eCode, aCode); pmDone = true;}
1802  }
1803 
1804 // Respond (failure is not an option now)
1805 //
1806  oHelp.isOK = true;
1807  if (retStat) return Response.Send(IOResp, 3, resplen);
1808  else return Response.Send((void *)&myResp, resplen);
1809 }
1810 
1811 /******************************************************************************/
1812 /* d o _ P i n g */
1813 /******************************************************************************/
1814 
1815 int XrdXrootdProtocol::do_Ping()
1816 {
1817 
1818 // Keep Statistics
1819 //
1820  SI->Bump(SI->miscCnt);
1821 
1822 // This is a basic nop
1823 //
1824  return Response.Send();
1825 }
1826 
1827 /******************************************************************************/
1828 /* d o _ P r e p a r e */
1829 /******************************************************************************/
1830 
1831 int XrdXrootdProtocol::do_Prepare(bool isQuery)
1832 {
1833  static XrdXrootdCallBack prpCB("query", XROOTD_MON_QUERY);
1834 
1835  XrdOucErrInfo myError(Link->ID, Monitor.Did, clientPV);
1836 
1837  XrdOucTokenizer pathlist(argp->buff);
1838  XrdOucTList *pFirst=0, *pP, *pLast = 0;
1839  XrdOucTList *oFirst=0, *oP, *oLast = 0;
1840  XrdOucTListHelper pHelp(&pFirst), oHelp(&oFirst);
1841  XrdXrootdPrepArgs pargs(0, 0);
1842  XrdSfsPrep fsprep;
1843 
1844  int rc, pathnum = 0;
1845  char reqid[128], nidbuff[512], *path, *opaque, *prpid = 0;
1846  unsigned short optX = ntohs(Request.prepare.optionX);
1847  char opts;
1848  bool isCancel, isEvict, isPrepare;
1849 
1850 // Check if this is an evict request (similar to stage)
1851 //
1852  isEvict = (optX & kXR_evict) != 0;
1853 
1854 // Establish what we are really doing here
1855 //
1856  if (isQuery)
1857  {opts = 0;
1858  isCancel = false;
1859  } else {
1861  {opts = 0;
1862  isCancel = true;
1863  } else {
1864  opts = (isEvict ? 0 : Request.prepare.options);
1865  isCancel = false;
1866  }
1867  }
1868  isPrepare = !(isCancel || isQuery);
1869 
1870 // Apply prepare limits, as necessary.
1871 //
1872  if (isPrepare && (PrepareLimit >= 0) && (++PrepareCount > PrepareLimit)) {
1873  if (LimitError) {
1874  return Response.Send( kXR_overQuota,
1875  "Surpassed this connection's prepare limit.");
1876  } else {
1877  return Response.Send();
1878  }
1879  }
1880 
1881 // Check for static routing
1882 //
1883  if ((opts & kXR_stage) || isCancel) {STATIC_REDIRECT(RD_prepstg);}
1884  STATIC_REDIRECT(RD_prepare);
1885 
1886 // Prehandle requests that must have a requestID. Otherwise, generate one.
1887 // Note that prepare request id's have two formats. The external format is
1888 // is qualifiaed by this host while the internal one removes the qualification.
1889 // The internal one is only used for the native prepare implementation.
1890 // To wit: prpid is the unqualified ID while reqid is the qualified one for
1891 // generated id's while prpid is always the specified request id.
1892 //
1893  if (isCancel || isQuery)
1894  {if (!(prpid = pathlist.GetLine()))
1895  return Response.Send(kXR_ArgMissing, "Prepare requestid not specified");
1896  fsprep.reqid = prpid;
1897  fsprep.opts = (isCancel ? Prep_CANCEL : Prep_QUERY);
1898  if (!PrepareAlt)
1899  {char hname[256];
1900  int hport;
1901  prpid = PrepID->isMine(prpid, hport, hname, sizeof(hname));
1902  if (!prpid)
1903  {if (!hport) return Response.Send(kXR_ArgInvalid,
1904  "Prepare requestid owned by an unknown server");
1905  TRACEI(REDIR, Response.ID() <<" redirecting prepare to "
1906  << hname <<':' <<hport);
1907  return Response.Send(kXR_redirect, hport, hname);
1908  }
1909  }
1910  } else {
1911  if (opts & kXR_stage)
1912  {prpid = PrepID->ID(reqid, sizeof(reqid));
1913  fsprep.reqid = reqid;
1914  fsprep.opts = Prep_STAGE | (opts & kXR_coloc ? Prep_COLOC : 0);
1915  } else {
1916  reqid[0]='*'; reqid[1]='\0';
1917  fsprep.reqid = prpid = reqid;
1918  fsprep.opts = (isEvict ? Prep_EVICT : 0);
1919  }
1920  }
1921 
1922 // Initialize the file system prepare arg list
1923 //
1924  fsprep.paths = 0;
1925  fsprep.oinfo = 0;
1926  fsprep.notify = 0;
1927 
1928 // Cycle through all of the paths in the list
1929 //
1930  while((path = pathlist.GetLine()))
1931  {if (rpCheck(path, &opaque)) return rpEmsg("Preparing", path);
1932  if (!Squash(path)) return vpEmsg("Preparing", path);
1933  pP = new XrdOucTList(path, pathnum);
1934  (pLast ? (pLast->next = pP) : (pFirst = pP)); pLast = pP;
1935  oP = new XrdOucTList(opaque, 0);
1936  (oLast ? (oLast->next = oP) : (oFirst = oP)); oLast = oP;
1937  pathnum++;
1938  }
1939  fsprep.paths = pFirst;
1940  fsprep.oinfo = oFirst;
1941 
1942 // We support callbacks but only for alternate prepare processing
1943 //
1944  if (PrepareAlt) myError.setErrCB(&prpCB, ReqID.getID());
1945 
1946 // Process cancel requests here; they are simple at this point.
1947 //
1948  if (isCancel)
1949  {if (SFS_OK != (rc = osFS->prepare(fsprep, myError, CRED)))
1950  return fsError(rc, XROOTD_MON_PREP, myError, path, 0);
1951  rc = Response.Send();
1952  if (!PrepareAlt) XrdXrootdPrepare::Logdel(prpid);
1953  return rc;
1954  }
1955 
1956 // Process query requests here; they are simple at this point.
1957 //
1958  if (isQuery)
1959  {if (PrepareAlt)
1960  {if (SFS_OK != (rc = osFS->prepare(fsprep, myError, CRED)))
1961  return fsError(rc, XROOTD_MON_PREP, myError, path, 0);
1962  rc = Response.Send();
1963  } else {
1964  char *mBuff = myError.getMsgBuff(rc);
1965  pargs.reqid = prpid;
1966  pargs.user = Link->ID;
1967  pargs.paths = pFirst;
1968  rc = XrdXrootdPrepare::List(pargs, mBuff, rc);
1969  if (rc < 0) rc = Response.Send("No information found.");
1970  else rc = Response.Send(mBuff);
1971  }
1972  return rc;
1973  }
1974 
1975 // Make sure we have at least one path
1976 //
1977  if (!pFirst)
1978  return Response.Send(kXR_ArgMissing, "No prepare paths specified");
1979 
1980 // Handle evict. We only support the evicts for alternate prepare handlers.
1981 //
1982  if (isEvict)
1983  {if (PrepareAlt
1984  && (SFS_OK != (rc = osFS->prepare(fsprep, myError, CRED))))
1985  return fsError(rc, XROOTD_MON_PREP, myError, path, 0);
1986  return Response.Send();
1987  }
1988 
1989 // Handle notification parameter. The notification depends on whether or not
1990 // we have a custom prepare handler.
1991 //
1992  if (opts & kXR_notify)
1993  {const char *nprot = (opts & kXR_usetcp ? "tcp" : "udp");
1994  fsprep.notify = nidbuff;
1995  if (PrepareAlt)
1996  {if (Request.prepare.port == 0) fsprep.notify = 0;
1997  else snprintf(nidbuff, sizeof(nidbuff), "%s://%s:%d/",
1998  nprot, Link->Host(), ntohs(Request.prepare.port));
1999  } else sprintf(nidbuff, Notify, nprot, Link->FDnum(), Link->ID);
2000  if (fsprep.notify)
2001  fsprep.opts |= (opts & kXR_noerrs ? Prep_SENDAOK : Prep_SENDACK);
2002  }
2003 
2004 // Complete prepare options
2005 //
2006  fsprep.opts |= (opts & kXR_fresh ? Prep_FRESH : 0);
2007  if (opts & kXR_wmode) fsprep.opts |= Prep_WMODE;
2008  if (PrepareAlt)
2009  {switch(Request.prepare.prty)
2010  {case 0: fsprep.opts |= Prep_PRTY0; break;
2011  case 1: fsprep.opts |= Prep_PRTY1; break;
2012  case 2: fsprep.opts |= Prep_PRTY2; break;
2013  case 3: fsprep.opts |= Prep_PRTY3; break;
2014  default: break;
2015  }
2016  } else {
2017  if (Request.prepare.prty == 0) fsprep.opts |= Prep_PRTY0;
2018  else fsprep.opts |= Prep_PRTY1;
2019  }
2020 
2021 // Issue the prepare request
2022 //
2023  if (SFS_OK != (rc = osFS->prepare(fsprep, myError, CRED)))
2024  return fsError(rc, XROOTD_MON_PREP, myError, pFirst->text, oFirst->text);
2025 
2026 // Perform final processing
2027 //
2028  if (!(opts & kXR_stage)) rc = Response.Send();
2029  else {rc = Response.Send(reqid, strlen(reqid));
2030  if (!PrepareAlt)
2031  {pargs.reqid = prpid;
2032  pargs.user = Link->ID;
2033  pargs.paths = pFirst;
2034  XrdXrootdPrepare::Log(pargs);
2035  }
2036  }
2037  return rc;
2038 }
2039 
2040 /******************************************************************************/
2041 /* d o _ P r o t o c o l */
2042 /******************************************************************************/
2043 
2044 namespace XrdXrootd
2045 {
2046 extern char *bifResp[2];
2047 extern int bifRLen[2];
2048 }
2049 
2050 int XrdXrootdProtocol::do_Protocol()
2051 {
2052  static kXR_int32 verNum = static_cast<kXR_int32>(htonl(kXR_PROTOCOLVERSION));
2053  static kXR_int32 theRle = static_cast<kXR_int32>(htonl(myRole));
2054  static kXR_int32 theRlf = static_cast<kXR_int32>(htonl(myRolf));
2055  static kXR_int32 theRlt = static_cast<kXR_int32>(htonl(myRole|kXR_gotoTLS));
2056 
2058  struct iovec ioVec[4] = {{0,0},{&theResp,kXR_ShortProtRespLen},{0,0},{0,0}};
2059 
2060  int rc, iovN = 2, RespLen = kXR_ShortProtRespLen;
2061  bool wantTLS = false;
2062 
2063 // Keep Statistics
2064 //
2065  SI->Bump(SI->miscCnt);
2066 
2067 // Determine which response to provide
2068 //
2070  {int cvn = XrdOucEI::uVMask & ntohl(Request.protocol.clientpv);
2071  if (!Status || !(clientPV & XrdOucEI::uVMask))
2072  clientPV = (clientPV & ~XrdOucEI::uVMask) | cvn;
2073  else cvn = (clientPV & XrdOucEI::uVMask);
2074 
2076  && XrdXrootd::bifResp[0])
2077  {int k =( Link->AddrInfo()->isPrivate() ? 1 : 0);
2078  ioVec[iovN ].iov_base = XrdXrootd::bifResp[k];
2079  ioVec[iovN++].iov_len = XrdXrootd::bifRLen[k];
2080  RespLen += XrdXrootd::bifRLen[k];
2081  }
2082 
2083  if (DHS && cvn >= kXR_PROTSIGNVERSION
2085  {int n = DHS->ProtResp(theResp.secreq, *(Link->AddrInfo()), cvn);
2086  ioVec[iovN ].iov_base = (void *)&theResp.secreq;
2087  ioVec[iovN++].iov_len = n;
2088  RespLen += n;
2089  }
2090 
2091  if ((myRole & kXR_haveTLS) != 0 && !(Link->hasTLS()))
2092  {wantTLS = (Request.protocol.flags &
2094  ableTLS = wantTLS || (Request.protocol.flags &
2096  if (ableTLS) doTLS = tlsCap;
2097  else doTLS = tlsNot;
2098  if (ableTLS && !wantTLS)
2101  wantTLS = (doTLS & Req_TLSData) != 0;
2102  break;
2104  wantTLS = (doTLS & Req_TLSLogin) != 0;
2105  break;
2107  wantTLS = (doTLS & Req_TLSTPC) != 0 ||
2108  (doTLS & Req_TLSLogin) != 0;
2109  break;
2110  default: break;
2111  }
2112  }
2113  theResp.flags = (wantTLS ? theRlt : theRle);
2114  } else {
2115  theResp.flags = theRlf;
2116  doTLS = tlsNot;
2117  }
2118 
2119 // Send the response
2120 //
2121  theResp.pval = verNum;
2122  rc = Response.Send(ioVec, iovN, RespLen);
2123 
2124 // If the client wants to start using TLS, enable it now. If we fail then we
2125 // have no choice but to terminate the connection. Note that incapable clients
2126 // don't want TLS but if we require TLS anyway, they will get an error either
2127 // pre-login or post-login or on a bind later on.
2128 //
2129  if (rc == 0 && wantTLS)
2130  {if (Link->setTLS(true, tlsCtx))
2131  {Link->setProtName("xroots");
2132  isTLS = true;
2133  } else {
2134  eDest.Emsg("Xeq", "Unable to enable TLS for", Link->ID);
2135  rc = -1;
2136  }
2137  }
2138  return rc;
2139 }
2140 
2141 /******************************************************************************/
2142 /* d o _ Q c o n f */
2143 /******************************************************************************/
2144 
2145 int XrdXrootdProtocol::do_Qconf()
2146 {
2147  static const int fsctl_cmd = SFS_FSCTL_STATCC|SFS_O_LOCAL;
2148  XrdOucTokenizer qcargs(argp->buff);
2149  char *val, buff[4096], *bp=buff;
2150  int n, bleft = sizeof(buff);
2151 
2152 // Get the first argument
2153 //
2154  if (!qcargs.GetLine() || !(val = qcargs.GetToken()))
2155  return Response.Send(kXR_ArgMissing, "query config argument not specified.");
2156 
2157 // The first item can be xrootd or cmsd to display the config file
2158 //
2159  if (!strcmp(val, "cmsd") || !strcmp(val, "xrootd"))
2160  return do_QconfCX(qcargs, val);
2161 
2162 // Trace this query variable
2163 //
2164  do {TRACEP(DEBUG, "query config " <<val);
2165 
2166  // Now determine what the user wants to query
2167  //
2168  if (!strcmp("bind_max", val))
2169  {n = snprintf(bp, bleft, "%d\n", maxStreams-1);
2170  bp += n; bleft -= n;
2171  }
2172  else if (!strcmp("chksum", val))
2173  {const char *csList = getenv("XRD_CSLIST");
2174  if (!JobCKT || !csList)
2175  {n = snprintf(bp, bleft, "chksum\n");
2176  bp += n; bleft -= n;
2177  continue;
2178  }
2179  n = snprintf(bp, bleft, "%s\n", csList);
2180  bp += n; bleft -= n;
2181  }
2182  else if (!strcmp("cid", val))
2183  {const char *cidval = getenv("XRDCMSCLUSTERID");
2184  if (!cidval || !(*cidval)) cidval = "cid";
2185  n = snprintf(bp, bleft, "%s\n", cidval);
2186  bp += n; bleft -= n;
2187  }
2188  else if (!strcmp("cms", val))
2189  {XrdOucErrInfo myError(Link->ID, Monitor.Did, clientPV);
2190  if (osFS->fsctl(fsctl_cmd, ".", myError, CRED) == SFS_DATA)
2191  n = snprintf(bp, bleft, "%s\n", myError.getErrText());
2192  else n = snprintf(bp, bleft, "%s\n", "cms");
2193  bp += n; bleft -= n;
2194  }
2195  else if (!strcmp("pio_max", val))
2196  {n = snprintf(bp, bleft, "%d\n", maxPio+1);
2197  bp += n; bleft -= n;
2198  }
2199  else if (!strcmp("proxy", val))
2200  {const char* pxyOrigin = "proxy";
2201  if (myRole & kXR_attrProxy)
2202  {pxyOrigin = getenv("XRDXROOTD_PROXY");
2203  if (!pxyOrigin) pxyOrigin = "proxy";
2204  }
2205  n = snprintf(bp,bleft,"%s\n",pxyOrigin);
2206  bp += n; bleft -= n;
2207  }
2208  else if (!strcmp("readv_ior_max", val))
2209  {n = snprintf(bp,bleft,"%d\n",maxReadv_ior);
2210  bp += n; bleft -= n;
2211  }
2212  else if (!strcmp("readv_iov_max", val))
2213  {n = snprintf(bp, bleft, "%d\n", XrdProto::maxRvecsz);
2214  bp += n; bleft -= n;
2215  }
2216  else if (!strcmp("role", val))
2217  {const char *theRole = getenv("XRDROLE");
2218  n = snprintf(bp, bleft, "%s\n", (theRole ? theRole : "none"));
2219  bp += n; bleft -= n;
2220  }
2221  else if (!strcmp("sitename", val))
2222  {const char *siteName = getenv("XRDSITE");
2223  n = snprintf(bp, bleft, "%s\n", (siteName ? siteName : "sitename"));
2224  bp += n; bleft -= n;
2225  }
2226  else if (!strcmp("start", val))
2227  {n = snprintf(bp, bleft, "%s\n", startUP);
2228  bp += n; bleft -= n;
2229  }
2230  else if (!strcmp("sysid", val))
2231  {const char *cidval = getenv("XRDCMSCLUSTERID");
2232  const char *nidval = getenv("XRDCMSVNID");
2233  if (!cidval || !(*cidval) || !nidval || !(*nidval))
2234  {cidval = "sysid"; nidval = "";}
2235  n = snprintf(bp, bleft, "%s %s\n", nidval, cidval);
2236  bp += n; bleft -= n;
2237  }
2238  else if (!strcmp("tpc", val))
2239  {char *tpcval = getenv("XRDTPC");
2240  n = snprintf(bp, bleft, "%s\n", (tpcval ? tpcval : "tpc"));
2241  bp += n; bleft -= n;
2242  }
2243  else if (!strcmp("tpcdlg", val))
2244  {char *tpcval = getenv("XRDTPCDLG");
2245  n = snprintf(bp, bleft, "%s\n", (tpcval ? tpcval : "tpcdlg"));
2246  bp += n; bleft -= n;
2247  }
2248  else if (!strcmp("tls_port", val) && tlsPort)
2249  {n = snprintf(bp, bleft, "%d\n", tlsPort);
2250  bp += n; bleft -= n;
2251  }
2252  else if (!strcmp("window", val) && Window)
2253  {n = snprintf(bp, bleft, "%d\n", Window);
2254  bp += n; bleft -= n;
2255  }
2256  else if (!strcmp("version", val))
2257  {n = snprintf(bp, bleft, "%s\n", XrdVSTRING);
2258  bp += n; bleft -= n;
2259  }
2260  else if (!strcmp("vnid", val))
2261  {const char *nidval = getenv("XRDCMSVNID");
2262  if (!nidval || !(*nidval)) nidval = "vnid";
2263  n = snprintf(bp, bleft, "%s\n", nidval);
2264  }
2265  else if (!strcmp("fattr", val))
2266  {n = snprintf(bp, bleft, "%s\n", usxParms);
2267  bp += n; bleft -= n;
2268  }
2269  else {n = strlen(val);
2270  if (bleft <= n) break;
2271  strcpy(bp, val); bp +=n; *bp = '\n'; bp++;
2272  bleft -= (n+1);
2273  }
2274  } while(bleft > 0 && (val = qcargs.GetToken()));
2275 
2276 // Make sure all ended well
2277 //
2278  if (val)
2279  return Response.Send(kXR_ArgTooLong, "too many query config arguments.");
2280 
2281 // All done
2282 //
2283  return Response.Send(buff, sizeof(buff) - bleft);
2284 }
2285 
2286 /******************************************************************************/
2287 /* d o _ Q c o n f C X */
2288 /******************************************************************************/
2289 
2290 int XrdXrootdProtocol::do_QconfCX(XrdOucTokenizer &qcargs, char *val)
2291 {
2292  extern XrdOucString *XrdXrootdCF;
2293  bool isCMSD = (*val == 'c');
2294 
2295 // Make sure there is nothing else following the token
2296 //
2297  if ((val = qcargs.GetToken()))
2298  return Response.Send(kXR_ArgInvalid, "too many query config arguments.");
2299 
2300 // If this is a cms just return a null for now
2301 //
2302  if (isCMSD) return Response.Send((void *)"\n", 2);
2303 
2304 // Display the xrootd configuration
2305 //
2306  if (XrdXrootdCF && isTLS && getenv("XROOTD_QCFOK"))
2307  return Response.Send((void *)XrdXrootdCF->c_str(), XrdXrootdCF->length());
2308 
2309 // Respond with a null
2310 //
2311  return Response.Send((void *)"\n", 2);
2312 }
2313 
2314 /******************************************************************************/
2315 /* d o _ Q f h */
2316 /******************************************************************************/
2317 
2318 int XrdXrootdProtocol::do_Qfh()
2319 {
2320  static XrdXrootdCallBack qryCB("query", XROOTD_MON_QUERY);
2322  XrdXrootdFile *fp;
2323  const char *fArg = 0, *qType = "";
2324  int rc;
2325  short qopt = (short)ntohs(Request.query.infotype);
2326 
2327 // Update misc stats count
2328 //
2329  SI->Bump(SI->miscCnt);
2330 
2331 // Find the file object
2332 //
2333  if (!FTab || !(fp = FTab->Get(fh.handle)))
2334  return Response.Send(kXR_FileNotOpen,
2335  "query does not refer to an open file");
2336 
2337 // The query is elegible for a deferred response, indicate we're ok with that
2338 //
2339  fp->XrdSfsp->error.setErrCB(&qryCB, ReqID.getID());
2340 
2341 // Perform the appropriate query
2342 //
2343  switch(qopt)
2344  {case kXR_QFinfo: qType = "QFinfo";
2345  fArg = (Request.query.dlen ? argp->buff : 0);
2346  rc = fp->XrdSfsp->fctl(SFS_FCTL_QFINFO,
2347  Request.query.dlen, fArg,
2348  CRED);
2349  break;
2350  case kXR_Qopaqug: qType = "Qopaqug";
2351  fArg = (Request.query.dlen ? argp->buff : 0);
2352  rc = fp->XrdSfsp->fctl(SFS_FCTL_SPEC1,
2353  Request.query.dlen, fArg,
2354  CRED);
2355  break;
2356  case kXR_Qvisa: qType = "Qvisa";
2357  rc = fp->XrdSfsp->fctl(SFS_FCTL_STATV, 0,
2358  fp->XrdSfsp->error);
2359  break;
2360  default: return Response.Send(kXR_ArgMissing,
2361  "Required query argument not present");
2362  }
2363 
2364 // Preform the actual function
2365 //
2366  TRACEP(FS, "fh=" <<fh.handle <<" query " <<qType <<" rc=" <<rc);
2367 
2368 // Return appropriately
2369 //
2370  if (SFS_OK != rc)
2371  return fsError(rc, XROOTD_MON_QUERY, fp->XrdSfsp->error, 0, 0);
2372  return Response.Send();
2373 }
2374 
2375 /******************************************************************************/
2376 /* d o _ Q o p a q u e */
2377 /******************************************************************************/
2378 
2379 int XrdXrootdProtocol::do_Qopaque(short qopt)
2380 {
2381  static XrdXrootdCallBack qpqCB("query", XROOTD_MON_QUERY);
2382  XrdOucErrInfo myError(Link->ID, Monitor.Did, clientPV);
2383  XrdSfsFSctl myData;
2384  const char *Act, *AData;
2385  char *opaque;
2386  int fsctl_cmd, rc, dlen = Request.query.dlen;
2387 
2388 // Process unstructured as well as structured (path/opaque) requests
2389 //
2390  if (qopt == kXR_Qopaque)
2391  {myData.Arg1 = argp->buff; myData.Arg1Len = dlen;
2392  myData.Arg2 = 0; myData.Arg2Len = 0;
2393  fsctl_cmd = SFS_FSCTL_PLUGIO;
2394  Act = " qopaque '"; AData = "...";
2395  } else {
2396  // Check for static routing (this falls under stat)
2397  //
2398  STATIC_REDIRECT(RD_stat);
2399 
2400  // Prescreen the path
2401  //
2402  if (rpCheck(argp->buff, &opaque)) return rpEmsg("Querying", argp->buff);
2403  if (!Squash(argp->buff)) return vpEmsg("Querying", argp->buff);
2404 
2405  // Setup arguments
2406  //
2407  myData.Arg1 = argp->buff;
2408  myData.Arg1Len = (opaque ? opaque - argp->buff - 1 : dlen);
2409  myData.Arg2 = opaque;
2410  myData.Arg2Len = (opaque ? argp->buff + dlen - opaque : 0);
2411  if (qopt == kXR_QFSinfo)
2412  {fsctl_cmd = SFS_FSCTL_PLUGFS;
2413  Act = " qfsinfo '";
2414  } else {
2415  fsctl_cmd = SFS_FSCTL_PLUGIN;
2416  Act = " qopaquf '";
2417  }
2418  AData = argp->buff;
2419  }
2420 
2421 // The query is elegible for a deferred response, indicate we're ok with that
2422 //
2423  myError.setErrCB(&qpqCB, ReqID.getID());
2424 
2425 // Preform the actual function using the supplied arguments
2426 //
2427  rc = osFS->FSctl(fsctl_cmd, myData, myError, CRED);
2428  TRACEP(FS, "rc=" <<rc <<Act <<AData <<"'");
2429  if (rc == SFS_OK) return Response.Send("");
2430  return fsError(rc, 0, myError, 0, 0);
2431 }
2432 
2433 /******************************************************************************/
2434 /* d o _ Q s p a c e */
2435 /******************************************************************************/
2436 
2437 int XrdXrootdProtocol::do_Qspace()
2438 {
2439  static const int fsctl_cmd = SFS_FSCTL_STATLS;
2440  XrdOucErrInfo myError(Link->ID, Monitor.Did, clientPV);
2441  char *opaque;
2442  int n, rc;
2443 
2444 // Check for static routing
2445 //
2446  STATIC_REDIRECT(RD_stat);
2447 
2448 // Prescreen the path
2449 //
2450  if (rpCheck(argp->buff, &opaque)) return rpEmsg("Stating", argp->buff);
2451  if (!Squash(argp->buff)) return vpEmsg("Stating", argp->buff);
2452 
2453 // Add back the opaque info
2454 //
2455  if (opaque)
2456  {n = strlen(argp->buff); argp->buff[n] = '?';
2457  if ((argp->buff)+n != opaque-1)
2458  memmove(&argp->buff[n+1], opaque, strlen(opaque)+1);
2459  }
2460 
2461 // Preform the actual function using the supplied logical FS name
2462 //
2463  rc = osFS->fsctl(fsctl_cmd, argp->buff, myError, CRED);
2464  TRACEP(FS, "rc=" <<rc <<" qspace '" <<argp->buff <<"'");
2465  if (rc == SFS_OK) return Response.Send("");
2466  return fsError(rc, XROOTD_MON_QUERY, myError, argp->buff, opaque);
2467 }
2468 
2469 /******************************************************************************/
2470 /* d o _ Q u e r y */
2471 /******************************************************************************/
2472 
2473 int XrdXrootdProtocol::do_Query()
2474 {
2475  short qopt = (short)ntohs(Request.query.infotype);
2476 
2477 // Perform the appropriate query
2478 //
2479  switch(qopt)
2480  {case kXR_QStats: return SI->Stats(Response,
2481  (Request.header.dlen ? argp->buff : "a"));
2482  case kXR_Qcksum: return do_CKsum(0);
2483  case kXR_Qckscan: return do_CKsum(1);
2484  case kXR_Qconfig: return do_Qconf();
2485  case kXR_Qspace: return do_Qspace();
2486  case kXR_Qxattr: return do_Qxattr();
2487  case kXR_QFSinfo:
2488  case kXR_Qopaque:
2489  case kXR_Qopaquf: return do_Qopaque(qopt);
2490 // case kXR_Qvisa:
2491  case kXR_QFinfo:
2492  case kXR_Qopaqug: return do_Qfh();
2493  case kXR_QPrep: return do_Prepare(true);
2494  default: break;
2495  }
2496 
2497 // Whatever we have, it's not valid
2498 //
2499  return Response.Send(kXR_ArgInvalid,
2500  "Invalid information query type code");
2501 }
2502 
2503 /******************************************************************************/
2504 /* d o _ Q x a t t r */
2505 /******************************************************************************/
2506 
2507 int XrdXrootdProtocol::do_Qxattr()
2508 {
2509  static XrdXrootdCallBack statCB("stat", XROOTD_MON_QUERY);
2510  static const int fsctl_cmd = SFS_FSCTL_STATXA;
2511  int rc;
2512  char *opaque;
2513  XrdOucErrInfo myError(Link->ID,&statCB,ReqID.getID(),Monitor.Did,clientPV);
2514 
2515 // Check for static routing
2516 //
2517  STATIC_REDIRECT(RD_stat);
2518 
2519 // Prescreen the path
2520 //
2521  if (rpCheck(argp->buff, &opaque)) return rpEmsg("Stating", argp->buff);
2522  if (!Squash(argp->buff)) return vpEmsg("Stating", argp->buff);
2523 
2524 // Add back opaque information is present
2525 //
2526  if (opaque)
2527  {int n = strlen(argp->buff); argp->buff[n] = '?';
2528  if ((argp->buff)+n != opaque-1)
2529  memmove(&argp->buff[n+1], opaque, strlen(opaque)+1);
2530  }
2531 
2532 // Preform the actual function
2533 //
2534  rc = osFS->fsctl(fsctl_cmd, argp->buff, myError, CRED);
2535  TRACEP(FS, "rc=" <<rc <<" qxattr " <<argp->buff);
2536  return fsError(rc, XROOTD_MON_QUERY, myError, argp->buff, opaque);
2537 }
2538 
2539 /******************************************************************************/
2540 /* d o _ R e a d */
2541 /******************************************************************************/
2542 
2543 int XrdXrootdProtocol::do_Read()
2544 {
2545  int pathID, retc = 0;
2547  numReads++;
2548 
2549 // We first handle the pre-read list, if any. We do it this way because of
2550 // a historical glitch in the protocol. One should really not piggy back a
2551 // pre-read on top of a read, though it is allowed.
2552 //
2553  if (!Request.header.dlen) pathID = 0;
2554  else if (do_ReadNone(retc, pathID)) return retc;
2555 
2556 // Unmarshall the data
2557 //
2558  IO.IOLen = ntohl(Request.read.rlen);
2559  n2hll(Request.read.offset, IO.Offset);
2560 
2561 // Find the file object
2562 //
2563  if (!FTab || !(IO.File = FTab->Get(fh.handle)))
2564  return Response.Send(kXR_FileNotOpen,
2565  "read does not refer to an open file");
2566 
2567 // Trace and verify read length is not negative
2568 //
2569  TRACEP(FSIO, pathID <<" fh=" <<fh.handle <<" read " <<IO.IOLen
2570  <<'@' <<IO.Offset);
2571  if ( IO.IOLen < 0) return Response.Send(kXR_ArgInvalid,
2572  "Read length is negative");
2573 
2574 // If we are monitoring, insert a read entry
2575 //
2576  if (Monitor.InOut())
2578  Request.read.offset);
2579 
2580 // Short circuit processing if read length is zero
2581 //
2582  if (!IO.IOLen) return Response.Send();
2583 
2584 // There are many competing ways to accomplish a read. Pick the one we
2585 // will use and if possible, do a fast dispatch.
2586 //
2588  else if (IO.File->sfEnabled && !isTLS && IO.IOLen >= as_minsfsz
2589  && IO.Offset+IO.IOLen <= IO.File->Stats.fSize)
2591  else if (IO.File->AsyncMode && IO.IOLen >= as_miniosz
2592  && IO.Offset+IO.IOLen <= IO.File->Stats.fSize+as_seghalf
2594  {XrdXrootdProtocol *pP;
2595  XrdXrootdNormAio *aioP=0;
2596 
2597  if (!pathID) pP = this;
2598  else {if (!(pP = VerifyStream(retc, pathID, false))) return retc;
2599  if (pP->linkAioReq >= as_maxperlnk) pP = 0;
2600  }
2601  if (pP)
2602  {// Use of TmpRsp here is to avoid modying pP. It is built
2603  // to contain the correct streamid for this request and the
2604  // right Link for the pathID. It's used by Alloc to call
2605  // XrdXrootdAioTask::Init which in turn makes a copy of TmpRsp
2606  // to its own response object and also keeps the Link pointer.
2607  XrdXrootdResponse TmpRsp;
2608  TmpRsp = Response;
2609  TmpRsp.Set(pP->Link);
2610  aioP = XrdXrootdNormAio::Alloc(pP,TmpRsp,IO.File);
2611  }
2612  if (aioP)
2613  {if (!IO.File->aioFob) IO.File->aioFob = new XrdXrootdAioFob;
2614  aioP->Read(IO.Offset, IO.IOLen);
2615  return 0;
2616  }
2617  SI->AsyncRej++;
2619  }
2621 
2622 // See if an alternate path is required, offload the read
2623 //
2624  if (pathID) return do_Offload(&XrdXrootdProtocol::do_ReadAll, pathID);
2625 
2626 // Now read all of the data (do pre-reads first)
2627 //
2628  return do_ReadAll();
2629 }
2630 
2631 /******************************************************************************/
2632 /* d o _ R e a d A l l */
2633 /******************************************************************************/
2634 
2635 // IO.File = file to be read
2636 // IO.Offset = Offset at which to read
2637 // IO.IOLen = Number of bytes to read from file and write to socket
2638 
2639 int XrdXrootdProtocol::do_ReadAll()
2640 {
2641  int rc, xframt, Quantum = (IO.IOLen > maxBuffsz ? maxBuffsz : IO.IOLen);
2642  char *buff;
2643 
2644 // If this file is memory mapped, short ciruit all the logic and immediately
2645 // transfer the requested data to minimize latency.
2646 //
2648  {if (IO.Offset >= IO.File->Stats.fSize) return Response.Send();
2649  if (IO.Offset+IO.IOLen <= IO.File->Stats.fSize)
2650  {IO.File->Stats.rdOps(IO.IOLen);
2651  return Response.Send(IO.File->mmAddr+IO.Offset, IO.IOLen);
2652  }
2653  xframt = IO.File->Stats.fSize -IO.Offset;
2654  IO.File->Stats.rdOps(xframt);
2655  return Response.Send(IO.File->mmAddr+IO.Offset, xframt);
2656  }
2657 
2658 // If we are sendfile enabled, then just send the file if possible
2659 //
2661  {IO.File->Stats.rdOps(IO.IOLen);
2662  if (IO.File->fdNum >= 0)
2663  return Response.Send(IO.File->fdNum, IO.Offset, IO.IOLen);
2664  rc = IO.File->XrdSfsp->SendData((XrdSfsDio *)this, IO.Offset, IO.IOLen);
2665  if (rc == SFS_OK)
2666  {if (!IO.IOLen) return 0;
2667  if (IO.IOLen < 0) return -1; // Otherwise retry using read()
2668  } else return fsError(rc, 0, IO.File->XrdSfsp->error, 0, 0);
2669  }
2670 
2671 // Make sure we have a large enough buffer
2672 //
2673  if (!argp || Quantum < halfBSize || Quantum > argp->bsize)
2674  {if ((rc = getBuff(1, Quantum)) <= 0) return rc;}
2675  else if (hcNow < hcNext) hcNow++;
2676  buff = argp->buff;
2677 
2678 // Now read all of the data. For statistics, we need to record the orignal
2679 // amount of the request even if we really do not get to read that much!
2680 //
2681  IO.File->Stats.rdOps(IO.IOLen);
2682  do {if ((xframt = IO.File->XrdSfsp->read(IO.Offset, buff, Quantum)) <= 0) break;
2683  if (xframt >= IO.IOLen) return Response.Send(buff, xframt);
2684  if (Response.Send(kXR_oksofar, buff, xframt) < 0) return -1;
2685  IO.Offset += xframt; IO.IOLen -= xframt;
2686  if (IO.IOLen < Quantum) Quantum = IO.IOLen;
2687  } while(IO.IOLen);
2688 
2689 // Determine why we ended here
2690 //
2691  if (xframt == 0) return Response.Send();
2692  return fsError(xframt, 0, IO.File->XrdSfsp->error, 0, 0);
2693 }
2694 
2695 /******************************************************************************/
2696 /* d o _ R e a d N o n e */
2697 /******************************************************************************/
2698 
2699 int XrdXrootdProtocol::do_ReadNone(int &retc, int &pathID)
2700 {
2701  XrdXrootdFHandle fh;
2702  int ralsz = Request.header.dlen;
2703  struct read_args *rargs=(struct read_args *)(argp->buff);
2704  struct readahead_list *ralsp = (readahead_list *)(rargs+1);
2705 
2706 // Return the pathid
2707 //
2708  pathID = static_cast<int>(rargs->pathid);
2709  if ((ralsz -= sizeof(read_args)) <= 0) return 0;
2710 
2711 // Make sure that we have a proper pre-read list
2712 //
2713  if (ralsz%sizeof(readahead_list))
2714  {Response.Send(kXR_ArgInvalid, "Invalid length for read ahead list");
2715  return 1;
2716  }
2717 
2718 // Run down the pre-read list
2719 //
2720  while(ralsz > 0)
2721  {IO.IOLen = ntohl(ralsp->rlen);
2722  n2hll(ralsp->offset, IO.Offset);
2723  memcpy((void *)&fh.handle, (const void *)ralsp->fhandle,
2724  sizeof(fh.handle));
2725  TRACEP(FSIO, "fh="<<fh.handle<<" read "<<IO.IOLen<<'@'<<IO.Offset);
2726  if (!FTab || !(IO.File = FTab->Get(fh.handle)))
2727  {retc = Response.Send(kXR_FileNotOpen,
2728  "preread does not refer to an open file");
2729  return 1;
2730  }
2731  IO.File->XrdSfsp->read(IO.Offset, IO.IOLen);
2732  ralsz -= sizeof(struct readahead_list);
2733  ralsp++;
2734  numReads++;
2735  };
2736 
2737 // All done
2738 //
2739  return 0;
2740 }
2741 
2742 /******************************************************************************/
2743 /* d o _ R e a d V */
2744 /******************************************************************************/
2745 
2746 int XrdXrootdProtocol::do_ReadV()
2747 {
2748 // This will read multiple buffers at the same time in an attempt to avoid
2749 // the latency in a network. The information with the offsets and lengths
2750 // of the information to read is passed as a data buffer... then we decode
2751 // it and put all the individual buffers in a single one it's up to the
2752 // client to interpret it. Code originally developed by Leandro Franco, CERN.
2753 // The readv file system code originally added by Brian Bockelman, UNL.
2754 //
2755  const int hdrSZ = sizeof(readahead_list);
2756  struct XrdOucIOVec rdVec[XrdProto::maxRvecsz+1];
2757  struct readahead_list *raVec, respHdr;
2758  long long totSZ;
2759  XrdSfsXferSize rdVAmt, rdVXfr, xfrSZ = 0;
2760  int rdVBeg, rdVBreak, rdVNow, rdVNum, rdVecNum;
2761  int currFH, i, k, Quantum, Qleft, rdVecLen = Request.header.dlen;
2762  int rvMon = Monitor.InOut();
2763  int ioMon = (rvMon > 1);
2764  char *buffp, vType = (ioMon ? XROOTD_MON_READU : XROOTD_MON_READV);
2765 
2766 // Compute number of elements in the read vector and make sure we have no
2767 // partial elements.
2768 //
2769  rdVecNum = rdVecLen / sizeof(readahead_list);
2770  if ( (rdVecNum <= 0) || (rdVecNum*hdrSZ != rdVecLen) )
2771  return Response.Send(kXR_ArgInvalid, "Read vector is invalid");
2772 
2773 // Make sure that we can copy the read vector to our local stack. We must impose
2774 // a limit on it's size. We do this to be able to reuse the data buffer to
2775 // prevent cross-cpu memory cache synchronization.
2776 //
2777  if (rdVecNum > XrdProto::maxRvecsz)
2778  return Response.Send(kXR_ArgTooLong, "Read vector is too long");
2779 
2780 // So, now we account for the number of readv requests and total segments
2781 //
2782  numReadV++; numSegsV += rdVecNum;
2783 
2784 // Run down the list and compute the total size of the read. No individual
2785 // read may be greater than the maximum transfer size. We also use this loop
2786 // to copy the read ahead list to our readv vector for later processing.
2787 //
2788  raVec = (readahead_list *)argp->buff;
2789  totSZ = rdVecLen; Quantum = maxReadv_ior;
2790  for (i = 0; i < rdVecNum; i++)
2791  {totSZ += (rdVec[i].size = ntohl(raVec[i].rlen));
2792  if (rdVec[i].size < 0) return Response.Send(kXR_ArgInvalid,
2793  "Readv length is negative");
2794  if (rdVec[i].size > Quantum) return Response.Send(kXR_NoMemory,
2795  "Single readv transfer is too large");
2796  rdVec[i].offset = ntohll(raVec[i].offset);
2797  memcpy(&rdVec[i].info, raVec[i].fhandle, sizeof(int));
2798  }
2799 
2800 // Now add an extra dummy element to force flushing of the read vector.
2801 //
2802  rdVec[i].offset = -1;
2803  rdVec[i].size = 0;
2804  rdVec[i].info = -1;
2805  rdVBreak = rdVecNum;
2806  rdVecNum++;
2807 
2808 // We limit the total size of the read to be 2GB for convenience
2809 //
2810  if (totSZ > 0x80000000LL)
2811  return Response.Send(kXR_NoMemory, "Total readv transfer is too large");
2812 
2813 // Calculate the transfer unit which will be the smaller of the maximum
2814 // transfer unit and the actual amount we need to transfer.
2815 //
2816  Quantum = totSZ < maxTransz ? totSZ : maxTransz;
2817 
2818 // Now obtain the right size buffer
2819 //
2820  if ((Quantum < halfBSize && Quantum > 1024) || Quantum > argp->bsize)
2821  {if ((k = getBuff(1, Quantum)) <= 0) return k;}
2822  else if (hcNow < hcNext) hcNow++;
2823 
2824 // Check that we really have at least one file open. This needs to be done
2825 // only once as this code runs in the control thread.
2826 //
2827  if (!FTab) return Response.Send(kXR_FileNotOpen,
2828  "readv does not refer to an open file");
2829 
2830 // Preset the previous and current file handle to be the handle of the first
2831 // element and make sure the file is actually open.
2832 //
2833  currFH = rdVec[0].info;
2834  memcpy(respHdr.fhandle, &currFH, sizeof(respHdr.fhandle));
2835  if (!(IO.File = FTab->Get(currFH))) return Response.Send(kXR_FileNotOpen,
2836  "readv does not refer to an open file");
2837 
2838 // Setup variables for running through the list.
2839 //
2840  Qleft = Quantum; buffp = argp->buff; rvSeq++;
2841  rdVBeg = rdVNow = 0; rdVXfr = rdVAmt = 0;
2842 
2843 // Now run through the elements
2844 //
2845  for (i = 0; i < rdVecNum; i++)
2846  {if (rdVec[i].info != currFH)
2847  {xfrSZ = IO.File->XrdSfsp->readv(&rdVec[rdVNow], i-rdVNow);
2848  if (xfrSZ != rdVAmt) break;
2849  rdVNum = i - rdVBeg; rdVXfr += rdVAmt;
2850  IO.File->Stats.rvOps(rdVXfr, rdVNum);
2851  if (rvMon)
2852  {Monitor.Agent->Add_rv(IO.File->Stats.FileID, htonl(rdVXfr),
2853  htons(rdVNum), rvSeq, vType);
2854  if (ioMon) for (k = rdVBeg; k < i; k++)
2856  htonl(rdVec[k].size), htonll(rdVec[k].offset));
2857  }
2858  rdVXfr = rdVAmt = 0;
2859  if (i == rdVBreak) break;
2860  rdVBeg = rdVNow = i; currFH = rdVec[i].info;
2861  memcpy(respHdr.fhandle, &currFH, sizeof(respHdr.fhandle));
2862  if (!(IO.File = FTab->Get(currFH)))
2863  return Response.Send(kXR_FileNotOpen,
2864  "readv does not refer to an open file");
2865  }
2866 
2867  if (Qleft < (rdVec[i].size + hdrSZ))
2868  {if (rdVAmt)
2869  {xfrSZ = IO.File->XrdSfsp->readv(&rdVec[rdVNow], i-rdVNow);
2870  if (xfrSZ != rdVAmt) break;
2871  }
2872  if (Response.Send(kXR_oksofar,argp->buff,Quantum-Qleft) < 0)
2873  return -1;
2874  Qleft = Quantum;
2875  buffp = argp->buff;
2876  rdVNow = i; rdVXfr += rdVAmt; rdVAmt = 0;
2877  }
2878 
2879  xfrSZ = rdVec[i].size; rdVAmt += xfrSZ;
2880  respHdr.rlen = htonl(xfrSZ);
2881  respHdr.offset = htonll(rdVec[i].offset);
2882  memcpy(buffp, &respHdr, hdrSZ);
2883  rdVec[i].data = buffp + hdrSZ;
2884  buffp += (xfrSZ+hdrSZ); Qleft -= (xfrSZ+hdrSZ);
2885  TRACEP(FSIO,"fh=" <<currFH<<" readV "<< xfrSZ <<'@'<<rdVec[i].offset);
2886  }
2887 
2888 // Check if we have an error here. This is indicated when rdVAmt is not zero.
2889 //
2890  if (rdVAmt)
2891  {if (xfrSZ >= 0)
2892  {xfrSZ = SFS_ERROR;
2893  IO.File->XrdSfsp->error.setErrInfo(-ENODATA,"readv past EOF");
2894  }
2895  return fsError(xfrSZ, 0, IO.File->XrdSfsp->error, 0, 0);
2896  }
2897 
2898 // All done, return result of the last segment or just zero
2899 //
2900  return (Quantum != Qleft ? Response.Send(argp->buff, Quantum-Qleft) : 0);
2901 }
2902 
2903 /******************************************************************************/
2904 /* d o _ R m */
2905 /******************************************************************************/
2906 
2907 int XrdXrootdProtocol::do_Rm()
2908 {
2909  int rc;
2910  char *opaque;
2911  XrdOucErrInfo myError(Link->ID, Monitor.Did, clientPV);
2912 
2913 // Check for static routing
2914 //
2915  STATIC_REDIRECT(RD_rm);
2916 
2917 // Prescreen the path
2918 //
2919  if (rpCheck(argp->buff, &opaque)) return rpEmsg("Removing", argp->buff);
2920  if (!Squash(argp->buff)) return vpEmsg("Removing", argp->buff);
2921 
2922 // Preform the actual function
2923 //
2924  rc = osFS->rem(argp->buff, myError, CRED, opaque);
2925  TRACEP(FS, "rc=" <<rc <<" rm " <<argp->buff);
2926  if (SFS_OK == rc) return Response.Send();
2927 
2928 // An error occurred
2929 //
2930  return fsError(rc, XROOTD_MON_RM, myError, argp->buff, opaque);
2931 }
2932 
2933 /******************************************************************************/
2934 /* d o _ R m d i r */
2935 /******************************************************************************/
2936 
2937 int XrdXrootdProtocol::do_Rmdir()
2938 {
2939  int rc;
2940  char *opaque;
2941  XrdOucErrInfo myError(Link->ID, Monitor.Did, clientPV);
2942 
2943 // Check for static routing
2944 //
2945  STATIC_REDIRECT(RD_rmdir);
2946 
2947 // Prescreen the path
2948 //
2949  if (rpCheck(argp->buff, &opaque)) return rpEmsg("Removing", argp->buff);
2950  if (!Squash(argp->buff)) return vpEmsg("Removing", argp->buff);
2951 
2952 // Preform the actual function
2953 //
2954  rc = osFS->remdir(argp->buff, myError, CRED, opaque);
2955  TRACEP(FS, "rc=" <<rc <<" rmdir " <<argp->buff);
2956  if (SFS_OK == rc) return Response.Send();
2957 
2958 // An error occurred
2959 //
2960  return fsError(rc, XROOTD_MON_RMDIR, myError, argp->buff, opaque);
2961 }
2962 
2963 /******************************************************************************/
2964 /* d o _ S e t */
2965 /******************************************************************************/
2966 
2967 int XrdXrootdProtocol::do_Set()
2968 {
2969  XrdOucTokenizer setargs(argp->buff);
2970  char *val, *rest;
2971 
2972 // Get the first argument
2973 //
2974  if (!setargs.GetLine() || !(val = setargs.GetToken(&rest)))
2975  return Response.Send(kXR_ArgMissing, "set argument not specified.");
2976 
2977 // Trace this set
2978 //
2979  TRACEP(DEBUG, "set " <<val <<' ' <<rest);
2980 
2981 // Now determine what the user wants to set
2982 //
2983  if (!strcmp("appid", val))
2984  {while(*rest && *rest == ' ') rest++;
2985  eDest.Emsg("Xeq", Link->ID, "appid", rest);
2986  return Response.Send();
2987  }
2988  else if (!strcmp("monitor", val)) return do_Set_Mon(setargs);
2989  else if (!strcmp("cache", val)) return do_Set_Cache(setargs);
2990 
2991 // All done
2992 //
2993  return Response.Send(kXR_ArgInvalid, "invalid set parameter");
2994 }
2995 
2996 /******************************************************************************/
2997 /* d o _ S e t _ C a c h e */
2998 /******************************************************************************/
2999 
3000 // Process: set cache <cmd> <args>
3001 
3002 int XrdXrootdProtocol::do_Set_Cache(XrdOucTokenizer &setargs)
3003 {
3004  XrdOucErrInfo myError(Link->ID, Monitor.Did, clientPV);
3005  XrdSfsFSctl myData;
3006  char *cmd, *cargs, *opaque = nullptr;
3007  const char *myArgs[2];
3008 
3009 // This set is valid only if we implement a cache
3010 //
3011  if ((fsFeatures & XrdSfs::hasCACH) == 0)
3012  return Response.Send(kXR_ArgInvalid, "invalid set parameter");
3013 
3014 // Get the command and argument
3015 //
3016  if (!(cmd = setargs.GetToken(&cargs)))
3017  return Response.Send(kXR_ArgMissing,"set cache argument not specified.");
3018 
3019 // Prescreen the path if the next token starts with a slash
3020 //
3021  if (cargs && *cargs == '/')
3022  {if (rpCheck(cargs, &opaque)) return rpEmsg("Setting", cargs);
3023  if (!Squash(cargs)) return vpEmsg("Setting", cargs);
3024  myData.ArgP = myArgs; myData.Arg2Len = -2;
3025  myArgs[0] = cargs;
3026  myArgs[1] = opaque;
3027  } else {
3028  myData.Arg2 = opaque; myData.Arg2Len = (opaque ? strlen(opaque) : 0);
3029  }
3030  myData.Arg1 = cmd; myData.Arg1Len = strlen(cmd);
3031 
3032 // Preform the actual function using the supplied arguments
3033 //
3034  int rc = osFS->FSctl(SFS_FSCTL_PLUGXC, myData, myError, CRED);
3035  TRACEP(FS, "rc=" <<rc <<"set cache " <<myData.Arg1 <<' ' <<cargs);
3036  if (rc == SFS_OK) return Response.Send("");
3037  return fsError(rc, 0, myError, 0, 0);
3038 }
3039 
3040 /******************************************************************************/
3041 /* d o _ S e t _ M o n */
3042 /******************************************************************************/
3043 
3044 // Process: set monitor {off | on} {[appid] | info [info]}
3045 
3046 int XrdXrootdProtocol::do_Set_Mon(XrdOucTokenizer &setargs)
3047 {
3048  char *val, *appid;
3049  kXR_unt32 myseq = 0;
3050 
3051 // Get the first argument
3052 //
3053  if (!(val = setargs.GetToken(&appid)))
3054  return Response.Send(kXR_ArgMissing,"set monitor argument not specified.");
3055 
3056 // For info requests, nothing changes. However, info events must have been
3057 // enabled for us to record them. Route the information via the static
3058 // monitor entry, since it knows how to forward the information.
3059 //
3060  if (!strcmp(val, "info"))
3061  {if (appid && Monitor.Info())
3062  {while(*appid && *appid == ' ') appid++;
3063  if (strlen(appid) > 1024) appid[1024] = '\0';
3064  if (*appid) myseq = Monitor.MapInfo(appid);
3065  }
3066  return Response.Send((void *)&myseq, sizeof(myseq));
3067  }
3068 
3069 // Determine if on do appropriate processing
3070 //
3071  if (!strcmp(val, "on"))
3072  {Monitor.Enable();
3073  if (appid && Monitor.InOut())
3074  {while(*appid && *appid == ' ') appid++;
3075  if (*appid) Monitor.Agent->appID(appid);
3076  }
3077  if (!Monitor.Did && Monitor.Logins()) MonAuth();
3078  return Response.Send();
3079  }
3080 
3081 // Determine if off and do appropriate processing
3082 //
3083  if (!strcmp(val, "off"))
3084  {if (appid && Monitor.InOut())
3085  {while(*appid && *appid == ' ') appid++;
3086  if (*appid) Monitor.Agent->appID(appid);
3087  }
3088  Monitor.Disable();
3089  return Response.Send();
3090  }
3091 
3092 // Improper request
3093 //
3094  return Response.Send(kXR_ArgInvalid, "invalid set monitor argument");
3095 }
3096 
3097 /******************************************************************************/
3098 /* d o _ S t a t */
3099 /******************************************************************************/
3100 
3101 int XrdXrootdProtocol::do_Stat()
3102 {
3103  static XrdXrootdCallBack statCB("stat", XROOTD_MON_STAT);
3104  static const int fsctl_cmd = SFS_FSCTL_STATFS;
3105  bool doDig;
3106  int rc;
3107  char *opaque, xxBuff[1024];
3108  struct stat buf;
3109  XrdOucErrInfo myError(Link->ID,&statCB,ReqID.getID(),Monitor.Did,clientPV);
3110 
3111 // Update misc stats count
3112 //
3113  SI->Bump(SI->miscCnt);
3114 
3115 // The stat request may refer to an open file handle. So, screen this out.
3116 //
3117  if (!argp || !Request.header.dlen)
3118  {XrdXrootdFile *fp;
3120  if (Request.stat.options & kXR_vfs)
3121  {Response.Send(kXR_ArgMissing, "Required argument not present");
3122  return 0;
3123  }
3124  if (!FTab || !(fp = FTab->Get(fh.handle)))
3125  return Response.Send(kXR_FileNotOpen,
3126  "stat does not refer to an open file");
3127  rc = fp->XrdSfsp->stat(&buf);
3128  TRACEP(FS, "fh=" <<fh.handle <<" stat rc=" <<rc);
3129  if (SFS_OK == rc) return Response.Send(xxBuff,
3130  StatGen(buf,xxBuff,sizeof(xxBuff)));
3131  return fsError(rc, 0, fp->XrdSfsp->error, 0, 0);
3132  }
3133 
3134 // Check if we are handling a dig type path
3135 //
3136  doDig = (digFS && SFS_LCLROOT(argp->buff));
3137 
3138 // Check for static routing
3139 //
3140  if (!doDig) {STATIC_REDIRECT(RD_stat);}
3141 
3142 // Prescreen the path
3143 //
3144  if (rpCheck(argp->buff, &opaque)) return rpEmsg("Stating", argp->buff);
3145  if (!doDig && !Squash(argp->buff))return vpEmsg("Stating", argp->buff);
3146 
3147 // Preform the actual function, we may been to add back the opaque info
3148 //
3149  if (Request.stat.options & kXR_vfs)
3150  {if (opaque)
3151  {int n = strlen(argp->buff); argp->buff[n] = '?';
3152  if ((argp->buff)+n != opaque-1)
3153  memmove(&argp->buff[n+1], opaque, strlen(opaque)+1);
3154  }
3155  rc = osFS->fsctl(fsctl_cmd, argp->buff, myError, CRED);
3156  TRACEP(FS, "rc=" <<rc <<" statfs " <<argp->buff);
3157  if (rc == SFS_OK) Response.Send("");
3158  } else {
3159  if (doDig) rc = digFS->stat(argp->buff, &buf, myError, CRED, opaque);
3160  else rc = osFS->stat(argp->buff, &buf, myError, CRED, opaque);
3161  TRACEP(FS, "rc=" <<rc <<" stat " <<argp->buff);
3162  if (rc == SFS_OK) return Response.Send(xxBuff,
3163  StatGen(buf,xxBuff,sizeof(xxBuff)));
3164  }
3165  return fsError(rc, (doDig ? 0 : XROOTD_MON_STAT),myError,argp->buff,opaque);
3166 }
3167 
3168 /******************************************************************************/
3169 /* d o _ S t a t x */
3170 /******************************************************************************/
3171 
3172 int XrdXrootdProtocol::do_Statx()
3173 {
3174  static XrdXrootdCallBack statxCB("xstat", XROOTD_MON_STAT);
3175  int rc;
3176  char *path, *opaque, *respinfo = argp->buff;
3177  mode_t mode;
3178  XrdOucErrInfo myError(Link->ID,&statxCB,ReqID.getID(),Monitor.Did,clientPV);
3179  XrdOucTokenizer pathlist(argp->buff);
3180 
3181 // Check for static routing
3182 //
3183  STATIC_REDIRECT(RD_stat);
3184 
3185 // Cycle through all of the paths in the list
3186 //
3187  while((path = pathlist.GetLine()))
3188  {if (rpCheck(path, &opaque)) return rpEmsg("Stating", path);
3189  if (!Squash(path)) return vpEmsg("Stating", path);
3190  rc = osFS->stat(path, mode, myError, CRED, opaque);
3191  TRACEP(FS, "rc=" <<rc <<" stat " <<path);
3192  if (rc != SFS_OK)
3193  return fsError(rc, XROOTD_MON_STAT, myError, path, opaque);
3194  else {if (mode == (mode_t)-1) *respinfo = (char)kXR_offline;
3195  else if (S_ISDIR(mode)) *respinfo = (char)kXR_isDir;
3196  else *respinfo = (char)kXR_file;
3197  }
3198  respinfo++;
3199  }
3200 
3201 // Return result
3202 //
3203  return Response.Send(argp->buff, respinfo-argp->buff);
3204 }
3205 
3206 /******************************************************************************/
3207 /* d o _ S y n c */
3208 /******************************************************************************/
3209 
3210 int XrdXrootdProtocol::do_Sync()
3211 {
3212  static XrdXrootdCallBack syncCB("sync", 0);
3213  int rc;
3214  XrdXrootdFile *fp;
3216 
3217 // Keep Statistics
3218 //
3219  SI->Bump(SI->syncCnt);
3220 
3221 // Find the file object
3222 //
3223  if (!FTab || !(fp = FTab->Get(fh.handle)))
3224  return Response.Send(kXR_FileNotOpen,"sync does not refer to an open file");
3225 
3226 // The sync is elegible for a deferred response, indicate we're ok with that
3227 //
3228  fp->XrdSfsp->error.setErrCB(&syncCB, ReqID.getID());
3229 
3230 // Sync the file
3231 //
3232  rc = fp->XrdSfsp->sync();
3233  TRACEP(FS, "fh=" <<fh.handle <<" sync rc=" <<rc);
3234  if (SFS_OK != rc) return fsError(rc, 0, fp->XrdSfsp->error, 0, 0);
3235 
3236 // Respond that all went well
3237 //
3238  return Response.Send();
3239 }
3240 
3241 /******************************************************************************/
3242 /* d o _ T r u n c a t e */
3243 /******************************************************************************/
3244 
3245 int XrdXrootdProtocol::do_Truncate()
3246 {
3247  static XrdXrootdCallBack truncCB("trunc", 0);
3248  XrdXrootdFile *fp;
3250  long long theOffset;
3251  int rc;
3252 
3253 // Unmarshall the data
3254 //
3255  n2hll(Request.truncate.offset, theOffset);
3256 
3257 // Check if this is a truncate for an open file (no path given)
3258 //
3259  if (!Request.header.dlen)
3260  {
3261  // Update misc stats count
3262  //
3263  SI->Bump(SI->miscCnt);
3264 
3265  // Find the file object
3266  //
3267  if (!FTab || !(fp = FTab->Get(fh.handle)))
3268  return Response.Send(kXR_FileNotOpen,
3269  "trunc does not refer to an open file");
3270 
3271  // Truncate the file (it is eligible for async callbacks)
3272  //
3273  fp->XrdSfsp->error.setErrCB(&truncCB, ReqID.getID());
3274  rc = fp->XrdSfsp->truncate(theOffset);
3275  TRACEP(FS, "fh=" <<fh.handle <<" trunc rc=" <<rc <<" sz=" <<theOffset);
3276  if (SFS_OK != rc) return fsError(rc, 0, fp->XrdSfsp->error, 0, 0);
3277 
3278  } else {
3279 
3280  XrdOucErrInfo myError(Link->ID, Monitor.Did, clientPV);
3281  char *opaque;
3282 
3283  // Check for static routing
3284  //
3285  STATIC_REDIRECT(RD_trunc);
3286 
3287  // Verify the path and extract out the opaque information
3288  //
3289  if (rpCheck(argp->buff,&opaque)) return rpEmsg("Truncating",argp->buff);
3290  if (!Squash(argp->buff)) return vpEmsg("Truncating",argp->buff);
3291 
3292  // Preform the actual function
3293  //
3294  rc = osFS->truncate(argp->buff, (XrdSfsFileOffset)theOffset, myError,
3295  CRED, opaque);
3296  TRACEP(FS, "rc=" <<rc <<" trunc " <<theOffset <<' ' <<argp->buff);
3297  if (SFS_OK != rc)
3298  return fsError(rc, XROOTD_MON_TRUNC, myError, argp->buff, opaque);
3299  }
3300 
3301 // Respond that all went well
3302 //
3303  return Response.Send();
3304 }
3305 
3306 /******************************************************************************/
3307 /* d o _ W r i t e */
3308 /******************************************************************************/
3309 
3310 int XrdXrootdProtocol::do_Write()
3311 {
3312  int pathID;
3314  numWrites++;
3315 
3316 // Unmarshall the data
3317 //
3319  n2hll(Request.write.offset, IO.Offset);
3320  pathID = static_cast<int>(Request.write.pathid);
3321 
3322 // Find the file object. We will drain socket data on the control path only!
3323 // .
3324  if (!FTab || !(IO.File = FTab->Get(fh.handle)))
3325  {IO.File = 0;
3326  return do_WriteNone(pathID);
3327  }
3328 
3329 // Trace and verify that length is not negative
3330 //
3331  TRACEP(FSIO, pathID<<" fh="<<fh.handle<<" write "<<IO.IOLen<<'@'<<IO.Offset);
3332  if ( IO.IOLen < 0) return Response.Send(kXR_ArgInvalid,
3333  "Write length is negative");
3334 
3335 // If we are monitoring, insert a write entry
3336 //
3337  if (Monitor.InOut())
3339  Request.write.offset);
3340 
3341 // If zero length write, simply return
3342 //
3343  if (!IO.IOLen) return Response.Send();
3344  IO.File->Stats.wrOps(IO.IOLen); // Optimistically correct
3345 
3346 // If async write allowed and it is a true write request (e.g. not chkpoint) and
3347 // current conditions permit async; schedule the write to occur asynchronously
3348 //
3351  {if (myStalls < as_maxstalls)
3352  {if (pathID) return do_Offload(&XrdXrootdProtocol::do_WriteAio,pathID);
3353  return do_WriteAio();
3354  }
3355  SI->AsyncRej++;
3356  myStalls--;
3357  }
3358 
3359 // See if an alternate path is required
3360 //
3361  if (pathID) return do_Offload(&XrdXrootdProtocol::do_WriteAll, pathID);
3362 
3363 // Just to the i/o now
3364 //
3365  return do_WriteAll();
3366 }
3367 
3368 /******************************************************************************/
3369 /* d o _ W r i t e A i o */
3370 /******************************************************************************/
3371 
3372 // IO.File = file to be written
3373 // IO.Offset = Offset at which to write
3374 // IO.IOLen = Number of bytes to read from socket and write to file
3375 
3376 int XrdXrootdProtocol::do_WriteAio()
3377 {
3378  XrdXrootdNormAio *aioP;
3379 
3380 // Allocate an aio request object if client hasn't exceeded the link limit
3381 //
3382  if (linkAioReq >= as_maxperlnk
3383  || !(aioP = XrdXrootdNormAio::Alloc(this, Response, IO.File)))
3384  {SI->AsyncRej++;
3385  if (myStalls > 0) myStalls--;
3386  return do_WriteAll();
3387  }
3388 
3389 // Issue the write request
3390 //
3391  return aioP->Write(IO.Offset, IO.IOLen);
3392 }
3393 
3394 /******************************************************************************/
3395 /* d o _ W r i t e A l l */
3396 /******************************************************************************/
3397 
3398 // IO.File = file to be written
3399 // IO.Offset = Offset at which to write
3400 // IO.IOLen = Number of bytes to read from socket and write to file
3401 
3402 int XrdXrootdProtocol::do_WriteAll()
3403 {
3404  int rc, Quantum = (IO.IOLen > maxBuffsz ? maxBuffsz : IO.IOLen);
3405 
3406 // Make sure we have a large enough buffer
3407 //
3408  if (!argp || Quantum < halfBSize || Quantum > argp->bsize)
3409  {if ((rc = getBuff(0, Quantum)) <= 0) return rc;}
3410  else if (hcNow < hcNext) hcNow++;
3411 
3412 // Now write all of the data (XrdXrootdProtocol.C defines getData())
3413 //
3414  while(IO.IOLen > 0)
3415  {if ((rc = getData("data", argp->buff, Quantum)))
3416  {if (rc > 0)
3417  {Resume = &XrdXrootdProtocol::do_WriteCont;
3418  myBlast = Quantum;
3419  }
3420  return rc;
3421  }
3422  if ((rc = IO.File->XrdSfsp->write(IO.Offset, argp->buff, Quantum)) < 0)
3423  {IO.IOLen = IO.IOLen-Quantum; IO.EInfo[0] = rc; IO.EInfo[1] = 0;
3424  return do_WriteNone();
3425  }
3426  IO.Offset += Quantum; IO.IOLen -= Quantum;
3427  if (IO.IOLen < Quantum) Quantum = IO.IOLen;
3428  }
3429 
3430 // All done
3431 //
3432  return Response.Send();
3433 }
3434 
3435 /******************************************************************************/
3436 /* d o _ W r i t e C o n t */
3437 /******************************************************************************/
3438 
3439 // IO.File = file to be written
3440 // IO.Offset = Offset at which to write
3441 // IO.IOLen = Number of bytes to read from socket and write to file
3442 // myBlast = Number of bytes already read from the socket
3443 
3444 int XrdXrootdProtocol::do_WriteCont()
3445 {
3446  int rc;
3447 
3448 // Write data that was finaly finished comming in
3449 //
3450  if ((rc = IO.File->XrdSfsp->write(IO.Offset, argp->buff, myBlast)) < 0)
3451  {IO.IOLen = IO.IOLen-myBlast; IO.EInfo[0] = rc; IO.EInfo[1] = 0;
3452  return do_WriteNone();
3453  }
3454  IO.Offset += myBlast; IO.IOLen -= myBlast;
3455 
3456 // See if we need to finish this request in the normal way
3457 //
3458  if (IO.IOLen > 0) return do_WriteAll();
3459  return Response.Send();
3460 }
3461 
3462 /******************************************************************************/
3463 /* d o _ W r i t e N o n e */
3464 /******************************************************************************/
3465 
3466 int XrdXrootdProtocol::do_WriteNone()
3467 {
3468  char *buff, dbuff[4096];
3469  int rlen, blen;
3470 
3471 // Determine which buffer we will use
3472 //
3473  if (argp && argp->bsize > (int)sizeof(dbuff))
3474  {buff = argp->buff;
3475  blen = argp->bsize;
3476  } else {
3477  buff = dbuff;
3478  blen = sizeof(dbuff);
3479  }
3480  if (IO.IOLen < blen) blen = IO.IOLen;
3481 
3482 // Discard any data being transmitted
3483 //
3484  TRACEP(REQ, "discarding " <<IO.IOLen <<" bytes");
3485  while(IO.IOLen > 0)
3486  {rlen = Link->Recv(buff, blen, readWait);
3487  if (rlen < 0) return Link->setEtext("link read error");
3488  IO.IOLen -= rlen;
3489  if (rlen < blen)
3490  {myBlen = 0;
3491  Resume = &XrdXrootdProtocol::do_WriteNone;
3492  return 1;
3493  }
3494  if (IO.IOLen < blen) blen = IO.IOLen;
3495  }
3496 
3497 // Send final message
3498 //
3499  return do_WriteNoneMsg();
3500 }
3501 
3502 /******************************************************************************/
3503 
3504 int XrdXrootdProtocol::do_WriteNone(int pathID, XErrorCode ec,
3505  const char *emsg)
3506 {
3507 // We can't recover when the data is arriving on a foriegn bound path as there
3508 // no way to properly drain the socket. So, we terminate the connection.
3509 //
3510  if (pathID != PathID)
3511  {if (ec && emsg) Response.Send(ec, emsg);
3512  else do_WriteNoneMsg();
3513  return Link->setEtext("write protocol violation");
3514  }
3515 
3516 // Set error code if present
3517 //
3518  if (ec != kXR_noErrorYet)
3519  {IO.EInfo[1] = ec;
3520  if (IO.File)
3521  {if (!emsg) emsg = XProtocol::errName(ec);
3523  }
3524  }
3525 
3526 // Otherwise, continue to darin the socket
3527 //
3528  return do_WriteNone();
3529 }
3530 
3531 /******************************************************************************/
3532 /* d o _ W r i t e N o n e M s g */
3533 /******************************************************************************/
3534 
3535 int XrdXrootdProtocol::do_WriteNoneMsg()
3536 {
3537 // Send our the error message and return
3538 //
3539  if (!IO.File) return
3540  Response.Send(kXR_FileNotOpen,"write does not refer to an open file");
3541 
3542  if (IO.EInfo[1])
3543  return Response.Send((XErrorCode)IO.EInfo[1],
3545 
3546  if (IO.EInfo[0]) return fsError(IO.EInfo[0], 0, IO.File->XrdSfsp->error, 0, 0);
3547 
3549 }
3550 
3551 /******************************************************************************/
3552 /* d o _ W r i t e S p a n */
3553 /******************************************************************************/
3554 
3556 {
3557  int rc;
3559  numWrites++;
3560 
3561 // Unmarshall the data
3562 //
3564  n2hll(Request.write.offset, IO.Offset);
3565 
3566 // Find the file object. We will only drain socket data on the control path.
3567 // .
3568  if (!FTab || !(IO.File = FTab->Get(fh.handle)))
3569  {IO.IOLen -= myBlast;
3570  IO.File = 0;
3571  return do_WriteNone(Request.write.pathid);
3572  }
3573 
3574 // If we are monitoring, insert a write entry
3575 //
3576  if (Monitor.InOut())
3578  Request.write.offset);
3579  IO.File->Stats.wrOps(IO.IOLen); // Optimistically correct
3580 
3581 // Trace this entry
3582 //
3583  TRACEP(FSIO, "fh=" <<fh.handle <<" write " <<IO.IOLen <<'@' <<IO.Offset);
3584 
3585 // Write data that was already read
3586 //
3587  if ((rc = IO.File->XrdSfsp->write(IO.Offset, myBuff, myBlast)) < 0)
3588  {IO.IOLen = IO.IOLen-myBlast; IO.EInfo[0] = rc; IO.EInfo[1] = 0;
3589  return do_WriteNone();
3590  }
3591  IO.Offset += myBlast; IO.IOLen -= myBlast;
3592 
3593 // See if we need to finish this request in the normal way
3594 //
3595  if (IO.IOLen > 0) return do_WriteAll();
3596  return Response.Send();
3597 }
3598 
3599 /******************************************************************************/
3600 /* d o _ W r i t e V */
3601 /******************************************************************************/
3602 
3603 int XrdXrootdProtocol::do_WriteV()
3604 {
3605 // This will write multiple buffers at the same time in an attempt to avoid
3606 // the disk latency. The information with the offsets and lengths of the data
3607 // to write is passed as a data buffer. We attempt to optimize as best as
3608 // possible, though certain combinations may result in multiple writes. Since
3609 // socket flushing is nearly impossible when an error occurs, most errors
3610 // simply terminate the connection.
3611 //
3612  const int wveSZ = sizeof(XrdProto::write_list);
3613  struct trackInfo
3614  {XrdXrootdWVInfo **wvInfo; bool doit;
3615  trackInfo(XrdXrootdWVInfo **wvP) : wvInfo(wvP), doit(true) {}
3616  ~trackInfo() {if (doit && *wvInfo) {free(*wvInfo); *wvInfo = 0;}}
3617  } freeInfo(&wvInfo);
3618 
3619  struct XrdProto::write_list *wrLst;
3620  XrdOucIOVec *wrVec;
3621  long long totSZ, maxSZ;
3622  int curFH, k, Quantum, wrVecNum, wrVecLen = Request.header.dlen;
3623 
3624 // Compute number of elements in the write vector and make sure we have no
3625 // partial elements.
3626 //
3627  wrVecNum = wrVecLen / wveSZ;
3628  if ( (wrVecLen <= 0) || (wrVecNum*wveSZ != wrVecLen) )
3629  {Response.Send(kXR_ArgInvalid, "Write vector is invalid");
3630  return -1;
3631  }
3632 
3633 // Make sure that we can make a copy of the read vector. So, we impose a limit
3634 // on it's size.
3635 //
3636  if (wrVecNum > XrdProto::maxWvecsz)
3637  {Response.Send(kXR_ArgTooLong, "Write vector is too long");
3638  return -1;
3639  }
3640 
3641 // Create the verctor write information structure sized as needed.
3642 //
3643  if (wvInfo) free(wvInfo);
3644  wvInfo = (XrdXrootdWVInfo *)malloc(sizeof(XrdXrootdWVInfo) +
3645  sizeof(XrdOucIOVec)*(wrVecNum-1));
3646  memset(wvInfo, 0, sizeof(XrdXrootdWVInfo) - sizeof(XrdOucIOVec));
3647  wvInfo->wrVec = wrVec = wvInfo->ioVec;
3648 
3649 // Run down the list and compute the total size of the write. No individual
3650 // write may be greater than the maximum transfer size. We also use this loop
3651 // to copy the write list to our writev vector for later processing.
3652 //
3653  wrLst = (XrdProto::write_list *)argp->buff;
3654  totSZ = 0; maxSZ = 0; k = 0; Quantum = maxTransz; curFH = 0;
3655  for (int i = 0; i < wrVecNum; i++)
3656  {if (wrLst[i].wlen == 0) continue;
3657  memcpy(&wrVec[k].info, wrLst[i].fhandle, sizeof(int));
3658  wrVec[k].size = ntohl(wrLst[i].wlen);
3659  if (wrVec[k].size < 0)
3660  {Response.Send(kXR_ArgInvalid, "Writev length is negtive");
3661  return -1;
3662  }
3663  if (wrVec[k].size > Quantum)
3664  {Response.Send(kXR_NoMemory,"Single writev transfer is too large");
3665  return -1;
3666  }
3667  wrVec[k].offset = ntohll(wrLst[i].offset);
3668  if (wrVec[k].info == curFH) totSZ += wrVec[k].size;
3669  else {if (maxSZ < totSZ) maxSZ = totSZ;
3670  totSZ = wrVec[k].size;
3671  }
3672  k++;
3673  }
3674 
3675 // Check if we are not actually writing anything, simply return success
3676 //
3677  if (maxSZ < totSZ) maxSZ = totSZ;
3678  if (maxSZ == 0) return Response.Send();
3679 
3680 // So, now we account for the number of writev requests and total segments
3681 //
3682  numWritV++; numSegsW += k; wrVecNum = k;
3683 
3684 // Calculate the transfer unit which will be the smaller of the maximum
3685 // transfer unit and the actual amount we need to transfer.
3686 //
3687  if (maxSZ > maxTransz) Quantum = maxTransz;
3688  else Quantum = static_cast<int>(maxSZ);
3689 
3690 // Now obtain the right size buffer
3691 //
3692  if ((Quantum < halfBSize && Quantum > 1024) || Quantum > argp->bsize)
3693  {if (getBuff(0, Quantum) <= 0) return -1;}
3694  else if (hcNow < hcNext) hcNow++;
3695 
3696 // Check that we really have at least the first file open (part of setup)
3697 //
3698  if (!FTab || !(IO.File = FTab->Get(wrVec[0].info)))
3699  {Response.Send(kXR_FileNotOpen, "writev does not refer to an open file");
3700  return -1;
3701  }
3702 
3703 // Setup to do the complete transfer
3704 //
3705  wvInfo->curFH = wrVec[0].info;
3706  wvInfo->vBeg = 0;
3707  wvInfo->vPos = 0;
3708  wvInfo->vEnd = wrVecNum;
3709  wvInfo->vMon = 0;
3711  wvInfo->wvMon = Monitor.InOut();
3712  wvInfo->ioMon = (wvInfo->vMon > 1);
3713 // wvInfo->vType = (wvInfo->ioMon ? XROOTD_MON_WRITEU : XROOTD_MON_WRITEV);
3714  IO.WVBytes = 0;
3715  IO.IOLen = wrVec[0].size;
3716  myBuff = argp->buff;
3717  myBlast = 0;
3718 
3719 // Now we simply start the write operations if this is a true writev request.
3720 // Otherwise return to the caller for additional processing.
3721 //
3722  freeInfo.doit = false;
3723  if (Request.header.requestid == kXR_writev) return do_WriteVec();
3724  return 0;
3725 }
3726 
3727 /******************************************************************************/
3728 /* d o _ W r i t e V e c */
3729 /******************************************************************************/
3730 
3731 int XrdXrootdProtocol::do_WriteVec()
3732 {
3733  XrdSfsXferSize xfrSZ;
3734  int rc, wrVNum, vNow = wvInfo->vPos;
3735  bool done, newfile;
3736 
3737 // Read the complete data from the socket for the current element. Note that
3738 // should we enter a resume state; upon re-entry all of the data will be read.
3739 //
3740 do{if (IO.IOLen > 0)
3741  {wvInfo->wrVec[vNow].data = argp->buff + myBlast;
3742  myBlast += IO.IOLen;
3743  if ((rc = getData("data", myBuff, IO.IOLen)))
3744  {if (rc < 0) return rc;
3745  IO.IOLen = 0;
3746  Resume = &XrdXrootdProtocol::do_WriteVec;
3747  return rc;
3748  }
3749  }
3750 
3751 // Establish the state at this point as this will tell us what to do next.
3752 //
3753  vNow++;
3754  done = newfile = false;
3755  if (vNow >= wvInfo->vEnd) done = true;
3756  else if (wvInfo->wrVec[vNow].info != wvInfo->curFH) newfile = true;
3757  else if (myBlast + wvInfo->wrVec[vNow].size <= argp->bsize)
3758  {IO.IOLen = wvInfo->wrVec[vNow].size;
3759  myBuff = argp->buff + myBlast;
3760  wvInfo->vPos = vNow;
3761  continue;
3762  }
3763 
3764 // We need to write out what we have.
3765 //
3766  wrVNum = vNow - wvInfo->vBeg;
3767  xfrSZ = IO.File->XrdSfsp->writev(&(wvInfo->wrVec[wvInfo->vBeg]), wrVNum);
3768  TRACEP(FSIO,"fh=" <<wvInfo->curFH <<" writeV " << xfrSZ <<':' <<wrVNum);
3769  if (xfrSZ != myBlast) break;
3770 
3771 // Check if we need to do monitoring or a sync with no deferal. Note that
3772 // we currently do not support detailed monitoring for vector writes!
3773 //
3774  if (done || newfile)
3775  {int monVnum = vNow - wvInfo->vMon;
3776  IO.File->Stats.wvOps(IO.WVBytes, monVnum);
3786  wvInfo->vMon = vNow;
3787  IO.WVBytes = 0;
3788  if (wvInfo->doSync)
3789  {IO.File->XrdSfsp->error.setErrCB(0,0);
3790  xfrSZ = IO.File->XrdSfsp->sync();
3791  if (xfrSZ< 0) break;
3792  }
3793  }
3794 
3795 // If we are done, the finish up
3796 //
3797  if (done)
3798  {if (wvInfo) {free(wvInfo); wvInfo = 0;}
3799  return Response.Send();
3800  }
3801 
3802 // Sequence to a new file if we need to do so
3803 //
3804  if (newfile)
3805  {if (!FTab || !(IO.File = FTab->Get(wvInfo->wrVec[vNow].info)))
3806  {Response.Send(kXR_FileNotOpen,"writev does not refer to an open file");
3807  return -1;
3808  }
3809  wvInfo->curFH = wvInfo->wrVec[vNow].info;
3810  }
3811 
3812 // Setup to resume transfer
3813 //
3814  myBlast = 0;
3815  myBuff = argp->buff;
3816  IO.IOLen = wvInfo->wrVec[vNow].size;
3817  wvInfo->vBeg = vNow;
3818  wvInfo->vPos = vNow;
3819 
3820 } while(true);
3821 
3822 // If we got here then there was a write error (file pointer is valid).
3823 //
3824  if (wvInfo) {free(wvInfo); wvInfo = 0;}
3825  return fsError((int)xfrSZ, 0, IO.File->XrdSfsp->error, 0, 0);
3826 }
3827 
3828 /******************************************************************************/
3829 /* S e n d F i l e */
3830 /******************************************************************************/
3831 
3833 {
3834 
3835 // Make sure we have some data to send
3836 //
3837  if (!IO.IOLen) return 1;
3838 
3839 // Send off the data
3840 //
3841  IO.IOLen = Response.Send(fildes, IO.Offset, IO.IOLen);
3842  return IO.IOLen;
3843 }
3844 
3845 /******************************************************************************/
3846 
3848 {
3849  int i, xframt = 0;
3850 
3851 // Make sure we have some data to send
3852 //
3853  if (!IO.IOLen) return 1;
3854 
3855 // Verify the length, it can't be greater than what the client wants
3856 //
3857  for (i = 1; i < sfvnum; i++) xframt += sfvec[i].sendsz;
3858  if (xframt > IO.IOLen) return 1;
3859 
3860 // Send off the data
3861 //
3862  if (xframt) IO.IOLen = Response.Send(sfvec, sfvnum, xframt);
3863  else {IO.IOLen = 0; Response.Send();}
3864  return IO.IOLen;
3865 }
3866 
3867 /******************************************************************************/
3868 /* S e t F D */
3869 /******************************************************************************/
3870 
3872 {
3873  if (fildes < 0) IO.File->sfEnabled = 0;
3874  else IO.File->fdNum = fildes;
3875 }
3876 
3877 /******************************************************************************/
3878 /* U t i l i t y M e t h o d s */
3879 /******************************************************************************/
3880 /******************************************************************************/
3881 /* f s E r r o r */
3882 /******************************************************************************/
3883 
3884 int XrdXrootdProtocol::fsError(int rc, char opC, XrdOucErrInfo &myError,
3885  const char *Path, char *Cgi)
3886 {
3887  int ecode, popt, rs;
3888  const char *eMsg = myError.getErrText(ecode);
3889 
3890 // Process standard errors
3891 //
3892  if (rc == SFS_ERROR)
3893  {SI->errorCnt++;
3894  rc = XProtocol::mapError(ecode);
3895 
3896  if (Path && (rc == kXR_Overloaded) && (opC == XROOTD_MON_OPENR
3897  || opC == XROOTD_MON_OPENW || opC == XROOTD_MON_OPENC))
3898  {if (myError.extData()) myError.Reset();
3899  return fsOvrld(opC, Path, Cgi);
3900  }
3901 
3902  if (Path && (rc == kXR_NotFound) && RQLxist && opC
3903  && (popt = RQList.Validate(Path)))
3906  Route[popt].Host[rdType],
3907  Route[popt].Port[rdType],
3908  opC|XROOTD_MON_REDLOCAL, Path);
3909  if (Cgi) rs = fsRedirNoEnt(eMsg, Cgi, popt);
3910  else rs = Response.Send(kXR_redirect,
3911  Route[popt].Port[rdType],
3912  Route[popt].Host[rdType]);
3913  } else rs = Response.Send((XErrorCode)rc, eMsg);
3914  if (myError.extData()) myError.Reset();
3915  return rs;
3916  }
3917 
3918 // Process the redirection (error msg is host:port)
3919 //
3920  if (rc == SFS_REDIRECT)
3921  {SI->redirCnt++;
3922  // if the plugin set some redirect flags but the client does not
3923  // support them, clear the flags (set -1)
3924  if( ecode < -1 && !( clientPV & XrdOucEI::uRedirFlgs ) )
3925  ecode = -1;
3926  if (XrdXrootdMonitor::Redirect() && Path && opC)
3928  if (TRACING(TRACE_REDIR))
3929  {if (ecode < 0)
3930  {TRACEI(REDIR, Response.ID() <<"redirecting to " << eMsg);}
3931  else {TRACEI(REDIR, Response.ID() <<"redirecting to "
3932  << eMsg <<':' <<ecode);
3933  }
3934  }
3935  if (RedirPI) rs = fsRedirPI(eMsg, ecode, myError.getErrTextLen());
3936  else rs = Response.Send(kXR_redirect, ecode, eMsg,
3937  myError.getErrTextLen());
3938  if (myError.extData()) myError.Reset();
3939  return rs;
3940  }
3941 
3942 // Process the deferal. We also synchronize sending the deferal response with
3943 // sending the actual deferred response by calling Done() in the callback object.
3944 // This allows the requestor of he callback know that we actually send the
3945 // kXR_waitresp to the end client and avoid violating time causality.
3946 //
3947  if (rc == SFS_STARTED)
3948  {SI->stallCnt++;
3949  if (ecode <= 0) ecode = 1800;
3950  TRACEI(STALL, Response.ID() <<"delaying client up to " <<ecode <<" sec");
3951  rc = Response.Send(kXR_waitresp, ecode, eMsg);
3952  if (myError.getErrCB()) myError.getErrCB()->Done(ecode, &myError);
3953  if (myError.extData()) myError.Reset();
3954  return (rc ? rc : 1);
3955  }
3956 
3957 // Process the data response
3958 //
3959  if (rc == SFS_DATA)
3960  {if (ecode) rs = Response.Send((void *)eMsg, ecode);
3961  else rs = Response.Send();
3962  if (myError.extData()) myError.Reset();
3963  return rs;
3964  }
3965 
3966 // Process the data response via an iovec
3967 //
3968  if (rc == SFS_DATAVEC)
3969  {if (ecode < 2) rs = Response.Send();
3970  else rs = Response.Send((struct iovec *)eMsg, ecode);
3971  if (myError.getErrCB()) myError.getErrCB()->Done(ecode, &myError);
3972  if (myError.extData()) myError.Reset();
3973  return rs;
3974  }
3975 
3976 // Process the deferal
3977 //
3978  if (rc >= SFS_STALL)
3979  {SI->stallCnt++;
3980  TRACEI(STALL, Response.ID() <<"stalling client for " <<rc <<" sec");
3981  rs = Response.Send(kXR_wait, rc, eMsg);
3982  if (myError.extData()) myError.Reset();
3983  return rs;
3984  }
3985 
3986 // Unknown conditions, report it
3987 //
3988  {char buff[32];
3989  SI->errorCnt++;
3990  sprintf(buff, "%d", rc);
3991  eDest.Emsg("Xeq", "Unknown error code", buff, eMsg);
3993  if (myError.extData()) myError.Reset();
3994  return rs;
3995  }
3996 }
3997 
3998 /******************************************************************************/
3999 /* f s O v r l d */
4000 /******************************************************************************/
4001 
4002 int XrdXrootdProtocol::fsOvrld(char opC, const char *Path, char *Cgi)
4003 {
4004  static const char *prot = "root://";
4005  static int negOne = -1;
4006  static char quest = '?', slash = '/';
4007 
4008  struct iovec rdrResp[8];
4009  char *destP=0, dest[512];
4010  int iovNum=0, pOff, port;
4011 
4012 // If this is a forwarded path and the client can handle full url's then
4013 // redirect the client to the destination in the path. Otherwise, if there is
4014 // an alternate destination, send client there. Otherwise, stall the client.
4015 //
4017  && (pOff = XrdOucUtils::isFWD(Path, &port, dest, sizeof(dest))))
4018  { rdrResp[1].iov_base = (char *)&negOne;
4019  rdrResp[1].iov_len = sizeof(negOne);
4020  rdrResp[2].iov_base = (char *)prot;
4021  rdrResp[2].iov_len = 7; // root://
4022  rdrResp[3].iov_base = (char *)dest;
4023  rdrResp[3].iov_len = strlen(dest); // host:port
4024  rdrResp[4].iov_base = (char *)&slash;
4025  rdrResp[4].iov_len = (*Path == '/' ? 1 : 0); // / or nil for objid
4026  rdrResp[5].iov_base = (char *)(Path+pOff);
4027  rdrResp[5].iov_len = strlen(Path+pOff); // path
4028  if (Cgi && *Cgi)
4029  {rdrResp[6].iov_base = (char *)&quest;
4030  rdrResp[6].iov_len = sizeof(quest); // ?
4031  rdrResp[7].iov_base = (char *)Cgi;
4032  rdrResp[7].iov_len = strlen(Cgi); // cgi
4033  iovNum = 8;
4034  } else iovNum = 6;
4035  destP = dest;
4036  } else if ((destP = Route[RD_ovld].Host[rdType]))
4037  port = Route[RD_ovld].Port[rdType];
4038 
4039 // If a redirect happened, then trace it.
4040 //
4041  if (destP)
4042  {SI->redirCnt++;
4044  XrdXrootdMonitor::Redirect(Monitor.Did, destP, port,
4045  opC|XROOTD_MON_REDLOCAL, Path);
4046  if (iovNum)
4047  {TRACEI(REDIR, Response.ID() <<"redirecting to "<<dest);
4048  return Response.Send(kXR_redirect, rdrResp, iovNum);
4049  } else {
4050  TRACEI(REDIR, Response.ID() <<"redirecting to "<<destP<<':'<<port);
4051  return Response.Send(kXR_redirect, port, destP);
4052  }
4053  }
4054 
4055 // If there is a stall value, then delay the client
4056 //
4057  if (OD_Stall)
4058  {TRACEI(STALL, Response.ID()<<"stalling client for "<<OD_Stall<<" sec");
4059  SI->stallCnt++;
4060  return Response.Send(kXR_wait, OD_Stall, "server is overloaded");
4061  }
4062 
4063 // We were unsuccessful, return overload as an error
4064 //
4065  return Response.Send(kXR_Overloaded, "server is overloaded");
4066 }
4067 
4068 /******************************************************************************/
4069 /* f s R e d i r N o E n t */
4070 /******************************************************************************/
4071 
4072 int XrdXrootdProtocol::fsRedirNoEnt(const char *eMsg, char *Cgi, int popt)
4073 {
4074  struct iovec ioV[4];
4075  char *tried, *trend, *ptried = 0;
4076  kXR_int32 pnum = htonl(static_cast<kXR_int32>(Route[popt].Port[rdType]));
4077  int tlen;
4078 
4079 // Try to find the last tried token in the cgi
4080 //
4081  if ((trend = Cgi))
4082  {do {if (!(tried = strstr(Cgi, "tried="))) break;
4083  if (tried == trend || *(tried-1) == '&')
4084  {if (!ptried || (*(tried+6) && *(tried+6) != '&')) ptried=tried;}
4085  Cgi = index(tried+6, '&');
4086  } while(Cgi);
4087  }
4088 
4089 // If we did find a tried, bracket it out with a leading comma (we can modify
4090 // the passed cgi string here because this is the last time it will be used.
4091 //
4092  if ((tried = ptried))
4093  {tried += 5;
4094  while(*(tried+1) && *(tried+1) == ',') tried++;
4095  trend = index(tried, '&');
4096  if (trend) {tlen = trend - tried; *trend = 0;}
4097  else tlen = strlen(tried);
4098  *tried = ',';
4099  } else tlen = 0;
4100 
4101 // Check if we are in a redirect loop (i.e. we are listed in the client's cgi).
4102 // If so, then treat this and file not found as we've been here before.
4103 //
4104  if ((trend = tried) && eMsg)
4105  do {if ((trend = strstr(trend, myCName)))
4106  {if (*(trend+myCNlen) == '\0' || *(trend+myCNlen) == ',')
4107  return Response.Send(kXR_NotFound, eMsg);
4108  trend = index(trend+myCNlen, ',');
4109  }
4110  } while(trend);
4111 
4112 
4113 // If we have not found a tried token or that token far too large to propogate
4114 // (i.e. it's likely we have an undetected loop), then do a simple redirect.
4115 //
4116  if (!tried || !tlen || tlen > 16384)
4117  return Response.Send(kXR_redirect,
4118  Route[popt].Port[rdType],
4119  Route[popt].Host[rdType]);
4120 
4121 // We need to append the client's tried list to the one we have to avoid loops
4122 //
4123 
4124  ioV[1].iov_base = (char *)&pnum;
4125  ioV[1].iov_len = sizeof(pnum);
4126  ioV[2].iov_base = Route[popt].Host[rdType];
4127  ioV[2].iov_len = Route[popt].RDSz[rdType];
4128  ioV[3].iov_base = tried;
4129  ioV[3].iov_len = tlen;
4130 
4131 // Compute total length
4132 //
4133  tlen += sizeof(pnum) + Route[popt].RDSz[rdType];
4134 
4135 // Send off the redirect
4136 //
4137  return Response.Send(kXR_redirect, ioV, 4, tlen);
4138 }
4139 
4140 /******************************************************************************/
4141 /* f s R e d i r P I */
4142 /******************************************************************************/
4143 
4144 // Protocol-level glue around the redirect plugin. The plugin call itself,
4145 // its target-netaddr cache, the host[?cgi] vs URL dispatch and parsing, and
4146 // the "" / "<target>" / "!<msg>" return-string contract all live in
4147 // XrdXrootdRedirHelper, which is shared with the HTTP TPC handler (issue
4148 // #2767). This function only forwards the target and translates the helper's
4149 // tri-state Outcome into a kXR_redirect or kXR_ServerError frame on the wire.
4150 
4151 int XrdXrootdProtocol::fsRedirPI(const char *trg, int port, int trglen)
4152 {
4153  std::string outTarget;
4154  std::string errMsg;
4155  int newPort = port; // wire port; the helper may rewrite it below
4156 
4157 // Run the target through the redirect plugin. The helper dispatches on the
4158 // sign of newPort: >= 0 selects the host[?cgi] form (newPort is the port and
4159 // may be rewritten); < 0 selects the URL form (newPort is left unmodified).
4160 //
4162  XrdXrootdRedirHelper::Redirect(trg, newPort, *(Link->AddrInfo()),
4163  outTarget, errMsg);
4164 
4165 // Translate the helper's outcome into the wire response. Replaced and Error
4166 // are early-return cases; Unchanged falls through to the original-target
4167 // kXR_redirect at the bottom.
4168 //
4170  {TRACEI(REDIR, Response.ID() << "plugin redirects to "
4171  << outTarget.c_str()
4172  << " portarg=" << newPort);
4173  return Response.Send(kXR_redirect, newPort,
4174  outTarget.c_str(), outTarget.size());
4175  }
4176 
4177  if (outcome == XrdXrootdRedirHelper::Outcome::Error)
4178  {
4179  char mbuff[1024];
4180  snprintf(mbuff, sizeof(mbuff), "Redirect failed; %s", errMsg.c_str());
4181  eDest.Emsg("Xeq_RedirPI", mbuff);
4182  return Response.Send(kXR_ServerError, mbuff);
4183  }
4184 
4185 // Outcome::Unchanged: emit the original target unmodified.
4186 //
4187  return Response.Send(kXR_redirect, port, trg, trglen);
4188 }
4189 
4190 /******************************************************************************/
4191 /* g e t B u f f */
4192 /******************************************************************************/
4193 
4194 int XrdXrootdProtocol::getBuff(const int isRead, int Quantum)
4195 {
4196 
4197 // Check if we need to really get a new buffer
4198 //
4199  if (!argp || Quantum > argp->bsize) hcNow = hcPrev;
4200  else if (Quantum >= halfBSize || hcNow-- > 0) return 1;
4201  else if (hcNext >= hcMax) hcNow = hcMax;
4202  else {int tmp = hcPrev;
4203  hcNow = hcNext;
4204  hcPrev = hcNext;
4205  hcNext = tmp+hcNext;
4206  }
4207 
4208 // Get a new buffer
4209 //
4210  if (argp) BPool->Release(argp);
4211  if ((argp = BPool->Obtain(Quantum))) halfBSize = argp->bsize >> 1;
4212  else return Response.Send(kXR_NoMemory, (isRead ?
4213  "insufficient memory to read file" :
4214  "insufficient memory to write file"));
4215 
4216 // Success
4217 //
4218  return 1;
4219 }
4220 
4221 /******************************************************************************/
4222 /* Private: g e t C k s T y p e */
4223 /******************************************************************************/
4224 
4225 char *XrdXrootdProtocol::getCksType(char *opaque, char *cspec, int cslen)
4226 {
4227  char *cksT;
4228 
4229 // Get match for user specified checksum type, if any. Otherwise return default.
4230 //
4231  if (opaque && *opaque)
4232  {XrdOucEnv jobEnv(opaque);
4233  if ((cksT = jobEnv.Get("cks.type")))
4234  {XrdOucTList *tP = JobCKTLST;
4235  while(tP && strcasecmp(tP->text, cksT)) tP = tP->next;
4236  if (!tP && cspec) snprintf(cspec, cslen, "%s", cksT);
4237  return (tP ? tP->text : 0);
4238  }
4239  }
4240 
4241 // Return default
4242 //
4243  return JobCKT;
4244 }
4245 
4246 /******************************************************************************/
4247 /* Private: l o g L o g i n */
4248 /******************************************************************************/
4249 
4250 bool XrdXrootdProtocol::logLogin(bool xauth)
4251 {
4252  const char *uName, *ipName, *tMsg, *zMsg = "";
4253  char lBuff[512], pBuff[512];
4254 
4255 // Determine ip type
4256 //
4257  if (clientPV & XrdOucEI::uIPv4)
4258  ipName = (clientPV & XrdOucEI::uIPv64 ? "IP46" : "IPv4");
4259  else ipName = (clientPV & XrdOucEI::uIPv64 ? "IP64" : "IPv6");
4260 
4261 // Determine client name
4262 //
4263  if (xauth) uName = (Client->name ? Client->name : "nobody");
4264  else uName = 0;
4265 
4266 // Check if TLS was or will be used
4267 //
4268  tMsg = Link->verTLS();
4269  if (*tMsg) zMsg = " ";
4270 
4271 // Format the line
4272 //
4273  snprintf(lBuff, sizeof(lBuff), "%s %s %s%slogin%s%s",
4274  (clientPV & XrdOucEI::uPrip ? "pvt" : "pub"), ipName,
4275  tMsg, zMsg,
4276  (xauth ? " as " : ""),
4277  (uName ? uName : ""));
4278 
4279 // Document the login
4280 //
4281  if (Client->tident != Client->pident)
4282  {snprintf(pBuff, sizeof(pBuff), "via %s auth for %s",
4283  Client->prot, Client->pident);
4284  } else *pBuff = 0;
4285  eDest.Log(SYS_LOG_01, "Xeq", Link->ID, lBuff, (*pBuff ? pBuff : 0));
4286 
4287 // Enable TLS if we need to (note sess setting is off if login setting is on).
4288 // If we need to but the client is not TLS capable, send an error and terminate.
4289 //
4290  if ((doTLS & Req_TLSSess) && !Link->hasBridge())
4291  {if (ableTLS)
4292  {if (Link->setTLS(true, tlsCtx))
4293  {Link->setProtName("xroots");
4294  isTLS = true;
4295  } else {
4296  eDest.Emsg("Xeq", "Unable to require TLS for", Link->ID);
4297  return false;
4298  }
4299  } else {
4300  eDest.Emsg("Xeq","session requires TLS but",Link->ID,"is incapable.");
4301  Response.Send(kXR_TLSRequired, "session requires TLS support");
4302  return false;
4303  }
4304  }
4305 
4306 // Record the appname in the final SecEntity object
4307 //
4308  if (AppName) Client->eaAPI->Add("xrd.appname", (std::string)AppName);
4309 
4310 // Assign unique identifier to the final SecEntity object
4311 //
4312  Client->ueid = mySID;
4313 
4314 // Propogate a connect through the whole system
4315 //
4316  osFS->Connect(Client);
4317  return true;
4318 }
4319 
4320 /******************************************************************************/
4321 /* m a p M o d e */
4322 /******************************************************************************/
4323 
4324 #define Map_Mode(x,y) if (Mode & kXR_ ## x) newmode |= S_I ## y
4325 
4326 int XrdXrootdProtocol::mapMode(int Mode)
4327 {
4328  int newmode = 0;
4329 
4330 // Map the mode in the obvious way
4331 //
4332  Map_Mode(ur, RUSR); Map_Mode(uw, WUSR); Map_Mode(ux, XUSR);
4333  Map_Mode(gr, RGRP); Map_Mode(gw, WGRP); Map_Mode(gx, XGRP);
4334  Map_Mode(or, ROTH); Map_Mode(ox, XOTH);
4335 
4336 // All done
4337 //
4338  return newmode;
4339 }
4340 
4341 /******************************************************************************/
4342 /* M o n A u t h */
4343 /******************************************************************************/
4344 
4346 {
4347  char Buff[4096];
4348  const char *bP = Buff;
4349 
4350  if (Client == &Entity) bP = Entity.moninfo;
4351  else {snprintf(Buff,sizeof(Buff),
4352  "&p=%s&n=%s&h=%s&o=%s&r=%s&g=%s&m=%s%s&I=%c",
4353  Client->prot,
4354  (Client->name ? Client->name : ""),
4355  (Client->host ? Client->host : ""),
4356  (Client->vorg ? Client->vorg : ""),
4357  (Client->role ? Client->role : ""),
4358  (Client->grps ? Client->grps : ""),
4359  (Client->moninfo ? Client->moninfo : ""),
4360  (Entity.moninfo ? Entity.moninfo : ""),
4361  (clientPV & XrdOucEI::uIPv4 ? '4' : '6')
4362  );
4363  Client->secMon = &Monitor;
4364  }
4365 
4366  Monitor.Report(bP);
4367  if (Entity.moninfo) {free(Entity.moninfo); Entity.moninfo = 0;}
4368 }
4369 
4370 /******************************************************************************/
4371 /* r p C h e c k */
4372 /******************************************************************************/
4373 
4374 int XrdXrootdProtocol::rpCheck(char *fn, char **opaque)
4375 {
4376  char *cp;
4377 
4378  if (*fn != '/')
4379  {if (!(XPList.Opts() & XROOTDXP_NOSLASH)) return 1;
4380  if ( XPList.Opts() & XROOTDXP_NOCGI) {*opaque = 0; return 0;}
4381  }
4382 
4383  if (!(cp = index(fn, '?'))) *opaque = 0;
4384  else {*cp = '\0'; *opaque = cp+1;
4385  if (!**opaque) *opaque = 0;
4386  }
4387 
4388  if (*fn != '/') return 0;
4389 
4390  while ((cp = index(fn, '/')))
4391  {fn = cp+1;
4392  if (fn[0] == '.' && fn[1] == '.' && (fn[2] == '/' || fn[2] == '\0'))
4393  return 1;
4394  }
4395  return 0;
4396 }
4397 
4398 /******************************************************************************/
4399 /* r p E m s g */
4400 /******************************************************************************/
4401 
4402 int XrdXrootdProtocol::rpEmsg(const char *op, char *fn)
4403 {
4404  char buff[2048];
4405  snprintf(buff,sizeof(buff)-1,"%s relative path '%s' is disallowed.",op,fn);
4406  buff[sizeof(buff)-1] = '\0';
4407  return Response.Send(kXR_NotAuthorized, buff);
4408 }
4409 
4410 /******************************************************************************/
4411 /* S e t S F */
4412 /******************************************************************************/
4413 
4414 int XrdXrootdProtocol::SetSF(kXR_char *fhandle, bool seton)
4415 {
4416  XrdXrootdFHandle fh(fhandle);
4417  XrdXrootdFile *theFile;
4418 
4419  if (!FTab || !(theFile = FTab->Get(fh.handle))) return -EBADF;
4420 
4421 // Turn it off or on if so wanted
4422 //
4423  if (!seton) theFile->sfEnabled = 0;
4424  else if (theFile->fdNum >= 0) theFile->sfEnabled = 1;
4425 
4426 // All done
4427 //
4428  return 0;
4429 }
4430 
4431 /******************************************************************************/
4432 /* S q u a s h */
4433 /******************************************************************************/
4434 
4435 int XrdXrootdProtocol::Squash(char *fn)
4436 {
4437  char *ofn, *ifn = fn;
4438 
4439  if (*fn != '/') return XPList.Opts();
4440 
4441  while(*ifn)
4442  {if (*ifn == '/')
4443  if (*(ifn+1) == '/'
4444  || (*(ifn+1) == '.' && *(ifn+1) && *(ifn+2) == '/')) break;
4445  ifn++;
4446  }
4447 
4448  if (!*ifn) return XPList.Validate(fn, ifn-fn);
4449 
4450  ofn = ifn;
4451  while(*ifn) {*ofn = *ifn++;
4452  while(*ofn == '/')
4453  {while(*ifn == '/') ifn++;
4454  if (ifn[0] == '.' && ifn[1] == '/') ifn += 2;
4455  else break;
4456  }
4457  ofn++;
4458  }
4459  *ofn = '\0';
4460 
4461  return XPList.Validate(fn, ofn-fn);
4462 }
4463 
4464 /******************************************************************************/
4465 /* v p E m s g */
4466 /******************************************************************************/
4467 
4468 int XrdXrootdProtocol::vpEmsg(const char *op, char *fn)
4469 {
4470  char buff[2048];
4471  snprintf(buff,sizeof(buff)-1,"%s path '%s' is disallowed.",op,fn);
4472  buff[sizeof(buff)-1] = '\0';
4473  return Response.Send(kXR_NotAuthorized, buff);
4474 }
kXR_char options[1]
Definition: XProtocol.hh:278
XErrorCode
Definition: XProtocol.hh:1031
@ kXR_ArgInvalid
Definition: XProtocol.hh:1032
@ kXR_InvalidRequest
Definition: XProtocol.hh:1038
@ kXR_ArgMissing
Definition: XProtocol.hh:1033
@ kXR_TLSRequired
Definition: XProtocol.hh:1060
@ kXR_AuthFailed
Definition: XProtocol.hh:1062
@ kXR_NotAuthorized
Definition: XProtocol.hh:1042
@ kXR_NotFound
Definition: XProtocol.hh:1043
@ kXR_FileLocked
Definition: XProtocol.hh:1035
@ kXR_noErrorYet
Definition: XProtocol.hh:1069
@ kXR_ChkSumErr
Definition: XProtocol.hh:1051
@ kXR_overQuota
Definition: XProtocol.hh:1053
@ kXR_FileNotOpen
Definition: XProtocol.hh:1036
@ kXR_Unsupported
Definition: XProtocol.hh:1045
@ kXR_Cancelled
Definition: XProtocol.hh:1049
@ kXR_ServerError
Definition: XProtocol.hh:1044
@ kXR_Overloaded
Definition: XProtocol.hh:1056
@ kXR_ArgTooLong
Definition: XProtocol.hh:1034
@ kXR_FSError
Definition: XProtocol.hh:1037
@ kXR_NoMemory
Definition: XProtocol.hh:1040
kXR_int16 arg1len
Definition: XProtocol.hh:460
struct ClientTruncateRequest truncate
Definition: XProtocol.hh:917
@ kXR_ecredir
Definition: XProtocol.hh:401
#define kXR_ShortProtRespLen
Definition: XProtocol.hh:1242
kXR_char fhandle[4]
Definition: XProtocol.hh:823
#define kXR_gotoTLS
Definition: XProtocol.hh:1222
struct ClientCloseRequest close
Definition: XProtocol.hh:893
kXR_char fhandle[4]
Definition: XProtocol.hh:848
#define kXR_haveTLS
Definition: XProtocol.hh:1221
kXR_char streamid[2]
Definition: XProtocol.hh:158
kXR_char fhandle[4]
Definition: XProtocol.hh:812
struct ClientMkdirRequest mkdir
Definition: XProtocol.hh:900
kXR_int32 dlen
Definition: XProtocol.hh:461
struct ClientAuthRequest auth
Definition: XProtocol.hh:888
kXR_int64 offset
Definition: XProtocol.hh:682
kXR_char fhtemplt[4]
Definition: XProtocol.hh:516
kXR_unt16 options
Definition: XProtocol.hh:513
#define kXR_PROTSIGNVERSION
Definition: XProtocol.hh:75
struct ClientDirlistRequest dirlist
Definition: XProtocol.hh:894
kXR_char pathid
Definition: XProtocol.hh:689
kXR_char credtype[4]
Definition: XProtocol.hh:172
kXR_char username[8]
Definition: XProtocol.hh:426
@ kXR_open_wrto
Definition: XProtocol.hh:499
@ kXR_compress
Definition: XProtocol.hh:482
@ kXR_async
Definition: XProtocol.hh:488
@ kXR_delete
Definition: XProtocol.hh:483
@ kXR_prefname
Definition: XProtocol.hh:491
@ kXR_nowait
Definition: XProtocol.hh:497
@ kXR_open_read
Definition: XProtocol.hh:486
@ kXR_open_updt
Definition: XProtocol.hh:487
@ kXR_mkpath
Definition: XProtocol.hh:490
@ kXR_seqio
Definition: XProtocol.hh:498
@ kXR_replica
Definition: XProtocol.hh:495
@ kXR_posc
Definition: XProtocol.hh:496
@ kXR_refresh
Definition: XProtocol.hh:489
@ kXR_new
Definition: XProtocol.hh:485
@ kXR_force
Definition: XProtocol.hh:484
@ kXR_4dirlist
Definition: XProtocol.hh:494
@ kXR_retstat
Definition: XProtocol.hh:493
struct ClientOpenRequest open
Definition: XProtocol.hh:902
@ kXR_waitresp
Definition: XProtocol.hh:948
@ kXR_redirect
Definition: XProtocol.hh:946
@ kXR_oksofar
Definition: XProtocol.hh:942
@ kXR_ok
Definition: XProtocol.hh:941
@ kXR_authmore
Definition: XProtocol.hh:944
@ kXR_wait
Definition: XProtocol.hh:947
@ kXR_dstat
Definition: XProtocol.hh:269
@ kXR_dcksm
Definition: XProtocol.hh:270
struct ClientRequestHdr header
Definition: XProtocol.hh:887
kXR_unt16 optiont
Definition: XProtocol.hh:514
kXR_unt16 infotype
Definition: XProtocol.hh:667
kXR_char fhandle[4]
Definition: XProtocol.hh:681
kXR_char fhandle[4]
Definition: XProtocol.hh:695
struct ClientWriteVRequest writev
Definition: XProtocol.hh:919
kXR_char fhandle[4]
Definition: XProtocol.hh:258
struct ClientLoginRequest login
Definition: XProtocol.hh:899
kXR_unt16 requestid
Definition: XProtocol.hh:159
kXR_char fhandle[4]
Definition: XProtocol.hh:669
kXR_char sessid[16]
Definition: XProtocol.hh:183
@ kXR_writev
Definition: XProtocol.hh:144
@ kXR_write
Definition: XProtocol.hh:132
struct ClientChmodRequest chmod
Definition: XProtocol.hh:891
struct ClientQueryRequest query
Definition: XProtocol.hh:908
struct ClientReadRequest read
Definition: XProtocol.hh:909
struct ClientMvRequest mv
Definition: XProtocol.hh:901
kXR_int32 rlen
Definition: XProtocol.hh:696
kXR_char sessid[16]
Definition: XProtocol.hh:289
struct ClientBindRequest bind
Definition: XProtocol.hh:889
kXR_char fhandle[4]
Definition: XProtocol.hh:835
kXR_unt16 mode
Definition: XProtocol.hh:512
@ kXR_vermask
Definition: XProtocol.hh:407
@ kXR_asyncap
Definition: XProtocol.hh:408
#define kXR_attrProxy
Definition: XProtocol.hh:1202
kXR_char options[1]
Definition: XProtocol.hh:446
#define kXR_PROTOCOLVERSION
Definition: XProtocol.hh:70
struct ClientEndsessRequest endsess
Definition: XProtocol.hh:895
struct ClientSyncRequest sync
Definition: XProtocol.hh:916
kXR_int64 offset
Definition: XProtocol.hh:697
@ kXR_vfs
Definition: XProtocol.hh:799
struct ClientPrepareRequest prepare
Definition: XProtocol.hh:906
@ kXR_mkdirpath
Definition: XProtocol.hh:440
@ kXR_wmode
Definition: XProtocol.hh:625
@ kXR_evict
Definition: XProtocol.hh:630
@ kXR_usetcp
Definition: XProtocol.hh:628
@ kXR_cancel
Definition: XProtocol.hh:621
@ kXR_fresh
Definition: XProtocol.hh:627
@ kXR_notify
Definition: XProtocol.hh:622
@ kXR_coloc
Definition: XProtocol.hh:626
@ kXR_stage
Definition: XProtocol.hh:624
@ kXR_noerrs
Definition: XProtocol.hh:623
struct ClientStatRequest stat
Definition: XProtocol.hh:915
kXR_int64 offset
Definition: XProtocol.hh:849
@ kXR_dup
Definition: XProtocol.hh:503
@ kXR_samefs
Definition: XProtocol.hh:504
@ kXR_retstatx
Definition: XProtocol.hh:505
struct ClientWriteRequest write
Definition: XProtocol.hh:918
ServerResponseReqs_Protocol secreq
Definition: XProtocol.hh:1236
kXR_char options
Definition: XProtocol.hh:809
kXR_char capver[1]
Definition: XProtocol.hh:429
kXR_int32 rlen
Definition: XProtocol.hh:683
struct ClientProtocolRequest protocol
Definition: XProtocol.hh:907
@ kXR_file
Definition: XProtocol.hh:1261
@ kXR_isDir
Definition: XProtocol.hh:1263
@ kXR_offline
Definition: XProtocol.hh:1265
@ kXR_QPrep
Definition: XProtocol.hh:650
@ kXR_Qopaqug
Definition: XProtocol.hh:661
@ kXR_Qconfig
Definition: XProtocol.hh:655
@ kXR_Qopaquf
Definition: XProtocol.hh:660
@ kXR_QFSinfo
Definition: XProtocol.hh:658
@ kXR_Qckscan
Definition: XProtocol.hh:654
@ kXR_Qxattr
Definition: XProtocol.hh:652
@ kXR_Qspace
Definition: XProtocol.hh:653
@ kXR_Qvisa
Definition: XProtocol.hh:656
@ kXR_QStats
Definition: XProtocol.hh:649
@ kXR_Qcksum
Definition: XProtocol.hh:651
@ kXR_QFinfo
Definition: XProtocol.hh:657
@ kXR_Qopaque
Definition: XProtocol.hh:659
struct ClientLocateRequest locate
Definition: XProtocol.hh:898
kXR_char fhandle[4]
Definition: XProtocol.hh:231
@ kXR_ver001
Definition: XProtocol.hh:415
@ kXR_ver003
Definition: XProtocol.hh:417
@ kXR_ver004
Definition: XProtocol.hh:418
@ kXR_ver002
Definition: XProtocol.hh:416
@ kXR_readrdok
Definition: XProtocol.hh:390
@ kXR_fullurl
Definition: XProtocol.hh:388
@ kXR_lclfile
Definition: XProtocol.hh:394
@ kXR_multipr
Definition: XProtocol.hh:389
@ kXR_redirflags
Definition: XProtocol.hh:395
@ kXR_hasipv64
Definition: XProtocol.hh:391
kXR_int32 dlen
Definition: XProtocol.hh:161
struct ClientCloneRequest clone
Definition: XProtocol.hh:892
int kXR_int32
Definition: XPtypes.hh:89
unsigned int kXR_unt32
Definition: XPtypes.hh:90
unsigned char kXR_char
Definition: XPtypes.hh:65
#define DEBUG(x)
Definition: XrdBwmTrace.hh:54
struct stat Stat
Definition: XrdCks.cc:49
void usage()
#define TRACE_AUTH
Definition: XrdHttpTrace.hh:48
#define TRACE_REDIR
Definition: XrdHttpTrace.hh:52
#define stat(a, b)
Definition: XrdPosix.hh:105
int Mode
XrdOucString Path
#define eMsg(x)
struct myOpts opts
int emsg(int rc, char *msg)
#define Prep_EVICT
int XrdSfsMode
#define SFS_DATAVEC
#define SFS_O_HNAME
#define Prep_FRESH
const char * Arg1
PLUGFS, PLUGIN, PLUGIO, PLUGXC.
#define SFS_DATA
int Arg2Len
Length or -count of args in extension.
#define SFS_FSCTL_PLUGFS
#define Prep_CANCEL
#define SFS_O_RESET
#define SFS_O_CREATAT
#define SFS_O_DIRLIST
#define SFS_FSCTL_STATFS
#define Prep_QUERY
char * notify
Notification path or 0.
XrdOucTList * paths
List of paths.
XrdOucTList * oinfo
1-to-1 correspondence of opaque info
#define SFS_ERROR
#define Prep_WMODE
#define SFS_LCLROOT(x)
#define SFS_O_SEQIO
#define SFS_O_NOTPC
#define SFS_O_FORCE
#define SFS_O_POSC
#define SFS_FCTL_QFINFO
#define SFS_FCTL_STATV
#define SFS_REDIRECT
#define Prep_PRTY3
#define Prep_PRTY0
#define SFS_O_MKPTH
#define Prep_PRTY2
#define SFS_STALL
#define SFS_O_RDONLY
#define SFS_STARTED
#define Prep_COLOC
#define SFS_O_MULTIW
#define SFS_FSCTL_STATLS
#define Prep_STAGE
#define SFS_FSCTL_STATCC
char * reqid
Request ID.
#define SFS_O_WRONLY
#define SFS_FCTL_GETFD
#define SFS_O_CREAT
#define SFS_FSCTL_STATXA
#define SFS_FSCTL_LOCATE
#define SFS_O_RAWIO
#define SFS_O_RDWR
#define Prep_PRTY1
#define Prep_SENDACK
#define SFS_FSCTL_PLUGIO
#define SFS_O_LOCAL
int XrdSfsFileOpenMode
int Arg1Len
Length.
#define SFS_FCTL_SPEC1
#define SFS_OK
long long XrdSfsFileOffset
#define SFS_LCLPATH(x)
#define SFS_O_NOWAIT
#define SFS_FSCTL_PLUGXC
int opts
Prep_xxx.
#define SFS_O_REPLICA
#define SFS_FSCTL_PLUGIN
#define SFS_O_TRUNC
int XrdSfsXferSize
#define Prep_SENDAOK
< Prepare parameters
< SFS_FSCTL_PLUGIN/PLUGIO/PLUGXC/PLUGFS parms
const char * XrdSysE2T(int errcode)
Definition: XrdSysE2T.cc:104
const int SYS_LOG_01
Definition: XrdSysError.hh:100
if(Avsz)
#define TRACING(x)
Definition: XrdTrace.hh:70
#define TRACEI(act, x)
Definition: XrdTrace.hh:66
XrdOucString * XrdXrootdCF
#define JOB_Sync
Definition: XrdXrootdJob.hh:48
const kXR_char XROOTD_MON_OPENW
const kXR_char XROOTD_MON_STAT
const kXR_char XROOTD_MON_REDLOCAL
const kXR_char XROOTD_MON_PREP
const kXR_char XROOTD_MON_OPENC
const kXR_char XROOTD_MON_TRUNC
const kXR_char XROOTD_MON_CLOSE
const kXR_char XROOTD_MON_CHMOD
const kXR_char XROOTD_MON_LOCATE
const kXR_char XROOTD_MON_OPENR
const kXR_char XROOTD_MON_MV
const kXR_char XROOTD_MON_RMDIR
const kXR_char XROOTD_MON_RM
const kXR_char XROOTD_MON_OPENDIR
const kXR_char XROOTD_MON_QUERY
const kXR_char XROOTD_MON_MKDIR
#define XRD_BOUNDPATH
#define XRD_LOGGEDIN
#define XRD_NEED_AUTH
#define TRACE_FS
#define TRACEP(act, x)
XrdOucIOVec ioVec[1]
XrdOucIOVec * wrVec
#define XROOTDXP_NOLK
#define XROOTDXP_NOSLASH
#define XROOTDXP_NOMWCHK
#define XROOTDXP_NOCGI
#define ENODATA
Definition: XrdXrootdXeq.cc:84
XrdSysTrace XrdXrootdTrace
#define ETIME
Definition: XrdXrootdXeq.cc:88
#define Map_Mode(x, y)
#define STATIC_REDIRECT(xfnc)
Definition: XrdXrootdXeq.hh:38
#define CRED
Definition: XrdXrootdXeq.hh:34
static const char * errName(kXR_int32 errCode)
Definition: XProtocol.cc:131
static int mapError(int rc)
Definition: XProtocol.hh:1404
void Release(XrdBuffer *bp)
Definition: XrdBuffer.cc:221
XrdBuffer * Obtain(int bsz)
Definition: XrdBuffer.cc:140
int bsize
Definition: XrdBuffer.hh:46
char * buff
Definition: XrdBuffer.hh:45
static const int ValuSize
Definition: XrdCksData.hh:42
static const int NameSize
Definition: XrdCksData.hh:41
static XrdCryptoLite_BFecb * Instance(const unsigned char *key=0, unsigned int klen=0)
void Decrypt(const unsigned char *in8, unsigned char *out8)
void Encrypt(const unsigned char *in8, unsigned char *out8)
static bool GetAssumeV4()
Definition: XrdInet.hh:65
Definition: XrdJob.hh:43
static XrdLink * fd2link(int fd)
Definition: XrdLinkCtl.hh:72
static bool RegisterCloseRequestCb(XrdLink *lp, XrdProtocol *pp, bool(*cb)(void *), void *cbarg)
Definition: XrdLinkCtl.cc:407
bool isMapped() const
bool isIPType(IPType ipType) const
bool getEA(int &ec, int &ac)
Definition: XrdNetPMark.hh:47
static bool getEA(const char *cgi, int &ecode, int &acode)
Definition: XrdNetPMark.cc:40
virtual Handle * Begin(XrdSecEntity &Client, const char *path=0, const char *cgi=0, const char *app=0)=0
virtual void Done(int &Result, XrdOucErrInfo *eInfo, const char *Path=0)=0
XrdOucEICB * getErrCB()
void setErrCB(XrdOucEICB *cb, unsigned long long cbarg=0)
const char * getErrText()
int setErrInfo(int code, const char *emsg)
void setUCap(int ucval)
Set user capabilties.
void Reset()
Reset object to no message state. Call this method to release appendages.
char * ID(char *buff, int blen)
Definition: XrdOucReqID.cc:139
char * isMine(char *reqid, int &hport, char *hname, int hlen)
Definition: XrdOucReqID.cc:100
void Bump(int &val)
Definition: XrdOucStats.hh:47
const char * c_str() const
int length() const
XrdOucTList * next
Definition: XrdOucTList.hh:45
char * text
Definition: XrdOucTList.hh:46
char * GetToken(char **rest=0, int lowcase=0)
static void Sanitize(char *instr, char subc='_')
static int isFWD(const char *path, int *port=0, char *hBuff=0, int hBLen=0, bool pTrim=false)
Definition: XrdOucUtils.cc:890
static std::string UrlEncode(const std::string &input)
void Schedule(XrdJob *jp)
bool Add(XrdSecAttr &attr)
XrdSecAttr * Get(const void *sigkey)
char * vorg
Entity's virtual organization(s)
Definition: XrdSecEntity.hh:71
const char * pident
Trace identifier (originator)
Definition: XrdSecEntity.hh:82
XrdNetAddrInfo * addrInfo
Entity's connection details.
Definition: XrdSecEntity.hh:80
XrdSecEntityAttr * eaAPI
non-const API to attributes
Definition: XrdSecEntity.hh:92
const char * tident
Trace identifier always preset.
Definition: XrdSecEntity.hh:81
char prot[XrdSecPROTOIDSIZE]
Auth protocol used (e.g. krb5)
Definition: XrdSecEntity.hh:67
XrdSecMonitor * secMon
If !0 security monitoring enabled.
Definition: XrdSecEntity.hh:89
char * grps
Entity's group name(s)
Definition: XrdSecEntity.hh:73
char * name
Entity's name.
Definition: XrdSecEntity.hh:69
unsigned int ueid
Unique ID of entity instance.
Definition: XrdSecEntity.hh:79
char * role
Entity's role(s)
Definition: XrdSecEntity.hh:72
void Display(XrdSysError &mDest)
Definition: XrdSecEntity.cc:58
char * moninfo
Information for monitoring.
Definition: XrdSecEntity.hh:76
char * host
Entity's host name dnr dependent.
Definition: XrdSecEntity.hh:70
virtual XrdSecProtect * New4Server(XrdSecProtocol &aprot, int plvl)
virtual int ProtResp(ServerResponseReqs_Protocol &resp, XrdNetAddrInfo &nai, int pver)
XrdSecEntity Entity
virtual void Delete()=0
Delete the protocol object. DO NOT use C++ delete() on this object.
virtual int Authenticate(XrdSecCredentials *cred, XrdSecParameters **parms, XrdOucErrInfo *einfo=0)=0
virtual const char * getParms(int &size, XrdNetAddrInfo *endPoint=0)=0
virtual bool PostProcess(XrdSecEntity &entity, XrdOucErrInfo &einfo)
virtual XrdSecProtocol * getProtocol(const char *host, XrdNetAddrInfo &endPoint, const XrdSecCredentials *cred, XrdOucErrInfo &einfo)=0
virtual int autoStat(struct stat *buf)
virtual const char * nextEntry()=0
virtual int open(const char *path, const XrdSecEntity *client=0, const char *opaque=0)=0
XrdOucErrInfo & error
virtual int close()=0
virtual XrdSfsDirectory * newDir(char *user=0, int MonID=0)=0
virtual void Connect(const XrdSecEntity *client=0)
virtual int chmod(const char *path, XrdSfsMode mode, XrdOucErrInfo &eInfo, const XrdSecEntity *client=0, const char *opaque=0)=0
virtual int fsctl(const int cmd, const char *args, XrdOucErrInfo &eInfo, const XrdSecEntity *client=0)=0
virtual int rename(const char *oPath, const char *nPath, XrdOucErrInfo &eInfo, const XrdSecEntity *client=0, const char *opaqueO=0, const char *opaqueN=0)=0
virtual int mkdir(const char *path, XrdSfsMode mode, XrdOucErrInfo &eInfo, const XrdSecEntity *client=0, const char *opaque=0)=0
virtual int FSctl(const int cmd, XrdSfsFSctl &args, XrdOucErrInfo &eInfo, const XrdSecEntity *client=0)
virtual int truncate(const char *path, XrdSfsFileOffset fsize, XrdOucErrInfo &eInfo, const XrdSecEntity *client=0, const char *opaque=0)=0
virtual int chksum(csFunc Func, const char *csName, const char *path, XrdOucErrInfo &eInfo, const XrdSecEntity *client=0, const char *opaque=0)
virtual int remdir(const char *path, XrdOucErrInfo &eInfo, const XrdSecEntity *client=0, const char *opaque=0)=0
virtual int prepare(XrdSfsPrep &pargs, XrdOucErrInfo &eInfo, const XrdSecEntity *client=0)=0
virtual int stat(const char *Name, struct stat *buf, XrdOucErrInfo &eInfo, const XrdSecEntity *client=0, const char *opaque=0)=0
virtual XrdSfsFile * newFile(char *user=0, int MonID=0)=0
virtual int rem(const char *path, XrdOucErrInfo &eInfo, const XrdSecEntity *client=0, const char *opaque=0)=0
virtual XrdSfsXferSize writev(XrdOucIOVec *writeV, int wdvCnt)
virtual int sync()=0
XrdOucErrInfo & error
virtual int SendData(XrdSfsDio *sfDio, XrdSfsFileOffset offset, XrdSfsXferSize size)
virtual int open(const char *fileName, XrdSfsFileOpenMode openMode, mode_t createMode, const XrdSecEntity *client=0, const char *opaque=0)=0
virtual XrdSfsXferSize read(XrdSfsFileOffset offset, XrdSfsXferSize size)=0
virtual XrdSfsXferSize readv(XrdOucIOVec *readV, int rdvCnt)
virtual int Clone(XrdSfsFile &srcFile)
virtual int truncate(XrdSfsFileOffset fsize)=0
virtual const char * FName()=0
virtual int getCXinfo(char cxtype[4], int &cxrsz)=0
virtual int stat(struct stat *buf)=0
virtual void setXio(XrdSfsXio *xioP)
virtual int fctl(const int cmd, const char *args, XrdOucErrInfo &eInfo)=0
virtual XrdSfsXferSize write(XrdSfsFileOffset offset, const char *buffer, XrdSfsXferSize size)=0
int Emsg(const char *esfx, int ecode, const char *text1, const char *text2=0)
Definition: XrdSysError.cc:116
void Log(int mask, const char *esfx, const char *text1, const char *text2=0, const char *text3=0)
Definition: XrdSysError.hh:167
static void Snooze(int seconds)
Definition: XrdSysTimer.cc:168
virtual void numLocks(const char *path, int &rcnt, int &wcnt)=0
virtual int Unlock(const char *path, char mode)=0
virtual int Lock(const char *path, char mode, bool force)=0
void rvOps(int rsz, int ssz)
void wvOps(int wsz, int ssz)
int Add(XrdXrootdFile *fp)
XrdXrootdFile * Get(int fnum)
XrdXrootdFile * Del(XrdXrootdMonitor *monP, int fnum, bool dodel=true)
void Ref(int num)
XrdXrootdPgwFob * pgwFob
XrdSfsFile * XrdSfsp
XrdXrootdAioFob * aioFob
XrdXrootdFileStats Stats
int Schedule(const char *jkey, const char **args, XrdXrootdResponse *resp, int Opts=0)
int Cancel(const char *jkey=0, XrdXrootdResponse *resp=0)
static void Open(XrdXrootdFileStats *fsP, const char *Path, unsigned int uDID, bool isRW)
kXR_unt32 MapInfo(const char *Info)
kXR_unt32 MapPath(const char *Path)
void Register(const char *Uname, const char *Hname, const char *Pname, unsigned int xSID=0)
void Report(const char *Info)
XrdXrootdMonitor * Agent
void appID(char *id)
void Add_rv(kXR_unt32 dictid, kXR_int32 rlen, kXR_int16 vcnt, kXR_char vseq, kXR_char vtype)
void Add_rd(kXR_unt32 dictid, kXR_int32 rlen, kXR_int64 offset)
static int Redirect()
void Add_wr(kXR_unt32 dictid, kXR_int32 wlen, kXR_int64 offset)
void Open(kXR_unt32 dictid, off_t fsize)
int Write(long long offs, int dlen) override
void Read(long long offs, int dlen) override
static XrdXrootdNormAio * Alloc(XrdXrootdProtocol *protP, XrdXrootdResponse &resp, XrdXrootdFile *fP)
XrdXrootdPio * Next
Definition: XrdXrootdPio.hh:43
XrdXrootd::IOParms IO
Definition: XrdXrootdPio.hh:45
int(XrdXrootdProtocol::* ResumePio)()
Definition: XrdXrootdPio.hh:44
static XrdXrootdPio * Alloc(int n=1)
Definition: XrdXrootdPio.cc:45
kXR_char StreamID[2]
Definition: XrdXrootdPio.hh:46
void Set(int(XrdXrootdProtocol::*Invoke)(), XrdXrootd::IOParms &io, const kXR_char *theSID)
Definition: XrdXrootdPio.hh:59
static int List(XrdXrootdPrepArgs &pargs, char *resp, int resplen)
static void Log(XrdXrootdPrepArgs &pargs)
static void Logdel(char *reqid)
static XrdXrootdStats * SI
int SendFile(int fildes) override
XrdXrootdProtocol * VerifyStream(int &rc, int pID, bool lok=true)
static XrdSfsFileSystem * digFS
int SetSF(kXR_char *fhandle, bool seton=false)
XrdSecProtect * Protect
XrdNetPMark::Handle * pmHandle
static XrdNetPMark * PMark
XrdXrootdProtocol * Stream[maxStreams]
XrdXrootd::IOParms IO
static XrdXrootdXPath RPList
XrdSecEntity * Client
static const char Req_TLSGPFile
static bool CloseRequestCb(void *cbarg)
void SetFD(int fildes) override
static const char Req_TLSSess
XrdXrootdWVInfo * wvInfo
XrdSysSemaphore * reTry
XrdXrootdFileTable * FTab
static XrdXrootdJob * JobCKS
static XrdSysError & eDest
static unsigned int getSID()
XrdSecProtocol * AuthProt
int getData(gdCallBack *gdcbP, const char *dtype, char *buff, int blen)
static char * usxParms
XrdXrootdMonitor::User Monitor
static XrdXrootdRedirPI * RedirPI
static const char * myCName
XrdXrootdPio * pioFree
static const char Req_TLSData
static XrdXrootdFileLock * Locker
static const int maxPio
int(XrdXrootdProtocol::* Resume)()
static const char Req_TLSTPC
static XrdTlsContext * tlsCtx
XrdXrootdPio * pioLast
static XrdXrootdXPath XPList
static XrdScheduler * Sched
static const char Req_TLSLogin
XrdXrootdResponse Response
int(XrdXrootdProtocol::* ResumePio)()
static const int maxStreams
static XrdOucTList * JobCKTLST
static XrdXrootdXPath RQList
static XrdSecProtector * DHS
static XrdBuffManager * BPool
XrdSysSemaphore * boundRecycle
static XrdSecService * CIA
static RAtomic_int srvrAioOps
static uint64_t fsFeatures
XrdXrootdReqID ReqID
static XrdOucReqID * PrepID
XrdXrootdPio * pioFirst
XrdSysCondVar2 * endNote
static struct XrdXrootdProtocol::RD_Table Route[RD_Num]
static XrdSfsFileSystem * osFS
static Outcome Redirect(const char *trg, int &port, XrdNetAddrInfo &clientAddr, std::string &outTarget, std::string &errMsg)
void setID(unsigned long long id)
unsigned long long getID()
void StreamID(kXR_char *sid)
void Set(XrdLink *lp)
long long AsyncRej
long long redirCnt
int Stats(char *buff, int blen, int do_sync=0)
int Validate(const char *pd, const int pl=0)
XrdXrootdXPath * Next()
kXR_char fhandle[4]
Definition: XProtocol.hh:873
static const int maxRvecsz
Definition: XProtocol.hh:722
static const int maxClonesz
Definition: XProtocol.hh:248
static const int maxWvecsz
Definition: XProtocol.hh:879
static const uint64_t hasCACH
Feature: Implements a data cache.
Definition: XrdSfsFlags.hh:74
static const uint64_t hasSXIO
Feature: Supports SfsXio.
Definition: XrdSfsFlags.hh:68
static const uint64_t hasFICL
Feature: Supports file cloning and samefs.
Definition: XrdSfsFlags.hh:80
ssize_t Send(int fd, KernelBuffer &buffer)
char * bifResp[2]
@ oct1
Definition: XrdSysTrace.hh:42
static const kXR_int32 doSync
Definition: XProtocol.hh:867
char TimeZone
+/- hours from GMT (-128 if not set)
unsigned char Country[2]
Two letter TLD country code.
static const int uRedirFlgs
ucap: Client supports "file://"
static const int uVMask
static const int uUrlOK
ucap: Supports async responses
static const int uIPv64
ucap: Supports only IPv4 info
static const int uReadR
ucap: Supports multiple protocols
static const int uEcRedir
ucap: Client supports redirect flags
static const int uMProt
ucap: Supports url redirects
static const int uLclF
ucap: Client is on a private net
static const int uAsync
ucap: Extract protocol version
static const int uIPv4
ucap: Supports read redirects
static const int uPrip
long long offset
Definition: XrdOucIOVec.hh:42
char * data
Definition: XrdOucIOVec.hh:45
Generic structure to pass security information back and forth.
char * buffer
Pointer to the buffer.
int size
Size of the buffer or length of data in the buffer.
kXR_int32 handle
Definition: XrdXrootdXeq.hh:48
unsigned int Sid
unsigned int Inst
static const int useSF
static const int useBasic
XrdXrootdFile * File
static const int useMMap