00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include <stdio.h>
00011
00012 #include "XrdSfs/XrdSfsInterface.hh"
00013 #include "XrdSys/XrdSysError.hh"
00014 #include "XrdSys/XrdSysPlatform.hh"
00015 #include "XrdSys/XrdSysTimer.hh"
00016 #include "XrdOuc/XrdOucReqID.hh"
00017 #include "XrdOuc/XrdOucTList.hh"
00018 #include "XrdOuc/XrdOucStream.hh"
00019 #include "XrdOuc/XrdOucTokenizer.hh"
00020 #include "XrdSec/XrdSecInterface.hh"
00021 #include "Xrd/XrdBuffer.hh"
00022 #include "Xrd/XrdLink.hh"
00023 #include "XrdXrootd/XrdXrootdAio.hh"
00024 #include "XrdXrootd/XrdXrootdCallBack.hh"
00025 #include "XrdXrootd/XrdXrootdFile.hh"
00026 #include "XrdXrootd/XrdXrootdFileLock.hh"
00027 #include "XrdXrootd/XrdXrootdJob.hh"
00028 #include "XrdXrootd/XrdXrootdMonitor.hh"
00029 #include "XrdXrootd/XrdXrootdPio.hh"
00030 #include "XrdXrootd/XrdXrootdPrepare.hh"
00031 #include "XrdXrootd/XrdXrootdProtocol.hh"
00032 #include "XrdXrootd/XrdXrootdStats.hh"
00033 #include "XrdXrootd/XrdXrootdTrace.hh"
00034 #include "XrdXrootd/XrdXrootdXPath.hh"
00035
00036
00037
00038
00039
00040 extern XrdOucTrace *XrdXrootdTrace;
00041
00042
00043
00044
00045
00046 struct XrdXrootdFHandle
00047 {kXR_int32 handle;
00048
00049 void Set(kXR_char *ch)
00050 {memcpy((void *)&handle, (const void *)ch, sizeof(handle));}
00051 XrdXrootdFHandle() {}
00052 XrdXrootdFHandle(kXR_char *ch) {Set(ch);}
00053 ~XrdXrootdFHandle() {}
00054 };
00055
00056 struct XrdXrootdSessID
00057 {unsigned int Sid;
00058 int Pid;
00059 int FD;
00060 unsigned int Inst;
00061
00062 XrdXrootdSessID() {}
00063 ~XrdXrootdSessID() {}
00064 };
00065
00066
00067
00068
00069
00070 #define CRED (const XrdSecEntity *)Client
00071
00072 #define TRACELINK Link
00073
00074 #define UPSTATS(x) SI->statsMutex.Lock(); SI->x++; SI->statsMutex.UnLock()
00075
00076
00077
00078
00079
00080 int XrdXrootdProtocol::do_Admin()
00081 {
00082 return Response.Send(kXR_Unsupported, "admin request is not supported");
00083 }
00084
00085
00086
00087
00088
00089 int XrdXrootdProtocol::do_Auth()
00090 {
00091 struct sockaddr netaddr;
00092 XrdSecCredentials cred;
00093 XrdSecParameters *parm = 0;
00094 XrdOucErrInfo eMsg;
00095 const char *eText;
00096 int rc, n;
00097
00098
00099
00100 if (!CIA) return Response.Send();
00101 cred.size = Request.header.dlen;
00102 cred.buffer = argp->buff;
00103
00104
00105
00106
00107
00108
00109
00110
00111 if (!AuthProt
00112 || strncmp(Entity.prot, (const char *)Request.auth.credtype,
00113 sizeof(Request.auth.credtype)))
00114 {if (AuthProt) AuthProt->Delete();
00115 strncpy(Entity.prot, (const char *)Request.auth.credtype,
00116 sizeof(Request.auth.credtype));
00117 Link->Name(&netaddr);
00118 if (!(AuthProt = CIA->getProtocol(Link->Host(),netaddr,&cred,&eMsg)))
00119 {eText = eMsg.getErrText(rc);
00120 eDest.Emsg("Xeq", "User authentication failed;", eText);
00121 return Response.Send(kXR_NotAuthorized, eText);
00122 }
00123 AuthProt->Entity.tident = Link->ID; numReads++;
00124 }
00125
00126
00127
00128 if (!(rc = AuthProt->Authenticate(&cred, &parm, &eMsg)))
00129 {const char *msg = (Status & XRD_ADMINUSER ? "admin login as"
00130 : "login as");
00131 rc = Response.Send(); Status &= ~XRD_NEED_AUTH;
00132 Client = &AuthProt->Entity; numReads = 0; strcpy(Entity.prot, "host");
00133 if (Client->name)
00134 eDest.Log(SYS_LOG_01, "Xeq", Link->ID, msg, Client->name);
00135 else
00136 eDest.Log(SYS_LOG_01, "Xeq", Link->ID, msg, "nobody");
00137 return rc;
00138 }
00139
00140
00141
00142 if (rc > 0)
00143 {TRACEP(LOGIN, "more auth requested; sz=" <<(parm ? parm->size : 0));
00144 if (parm) {rc = Response.Send(kXR_authmore, parm->buffer, parm->size);
00145 delete parm;
00146 return rc;
00147 }
00148 eDest.Emsg("Xeq", "Security requested additional auth w/o parms!");
00149 return Response.Send(kXR_ServerError,"invalid authentication exchange");
00150 }
00151
00152
00153
00154
00155
00156
00157 if (AuthProt) {AuthProt->Delete(); AuthProt = 0;}
00158 if ((n = numReads - 2) > 0) XrdSysTimer::Snooze(n > 5 ? 5 : n);
00159
00160
00161
00162 eText = eMsg.getErrText(rc);
00163 eDest.Emsg("Xeq", "User authentication failed;", eText);
00164 return Response.Send(kXR_NotAuthorized, eText);
00165 }
00166
00167
00168
00169
00170
00171 int XrdXrootdProtocol::do_Bind()
00172 {
00173 XrdXrootdSessID *sp = (XrdXrootdSessID *)Request.bind.sessid;
00174 XrdXrootdProtocol *pp;
00175 XrdLink *lp;
00176 int i, pPid, rc;
00177 char buff[64], *cp, *dp;
00178
00179
00180
00181 UPSTATS(miscCnt);
00182
00183
00184
00185 if (sp->FD <= 0 || !(lp = XrdLink::fd2link(sp->FD, sp->Inst)))
00186 return Response.Send(kXR_NotFound, "session not found");
00187
00188
00189
00190 lp->Hold(1);
00191 if (lp != XrdLink::fd2link(sp->FD, sp->Inst))
00192 {lp->Hold(0);
00193 return Response.Send(kXR_NotFound, "session just closed");
00194 }
00195
00196
00197
00198 if (!(pp=dynamic_cast<XrdXrootdProtocol *>(lp->getProtocol()))||lp != pp->Link)
00199 {lp->Hold(0);
00200 return Response.Send(kXR_ArgInvalid, "session protocol not xroot");
00201 }
00202
00203
00204
00205 if (!(pp->Status & XRD_LOGGEDIN) || (pp->Status & XRD_NEED_AUTH))
00206 {lp->Hold(0);
00207 return Response.Send(kXR_ArgInvalid, "session not logged in");
00208 }
00209
00210
00211
00212 if (sp->Pid != myPID || sp->Sid != pp->mySID)
00213 {lp->Hold(0);
00214 return Response.Send(kXR_ArgInvalid, "invalid session ID");
00215 }
00216
00217
00218
00219 if (strcmp(Link->Host(), lp->Host()))
00220 {lp->Hold(0);
00221 return Response.Send(kXR_NotAuthorized, "cross-host bind not allowed");
00222 }
00223
00224
00225
00226 for (i = 1; i < maxStreams && pp->Stream[i]; i++) {}
00227 if (i >= maxStreams)
00228 {lp->Hold(0);
00229 return Response.Send(kXR_NoMemory, "bind limit exceeded");
00230 }
00231
00232
00233
00234 pp->Stream[i] = this;
00235 Stream[0] = pp;
00236 pp->isBound = 1;
00237 PathID = i;
00238 sprintf(buff, "FD %d#%d bound", Link->FDnum(), i);
00239 eDest.Log(SYS_LOG_01, "Xeq", buff, lp->ID);
00240
00241
00242
00243 cp = strdup(lp->ID);
00244 if ( (dp = rindex(cp, '@'))) *dp = '\0';
00245 if (!(dp = rindex(cp, '.'))) pPid = 0;
00246 else {*dp++ = '\0'; pPid = strtol(dp, (char **)NULL, 10);}
00247 Link->setID(cp, pPid);
00248 free(cp);
00249 CapVer = pp->CapVer;
00250 Status = XRD_BOUNDPATH;
00251
00252
00253
00254 pioFree = XrdXrootdPio::Alloc(maxPio);
00255
00256
00257
00258 buff[0] = static_cast<char>(i);
00259 if (!(rc = Response.Send(kXR_ok, buff, 1))) rc = -EINPROGRESS;
00260
00261
00262
00263 lp->Hold(0);
00264 return rc;
00265 }
00266
00267
00268
00269
00270
00271 int XrdXrootdProtocol::do_Chmod()
00272 {
00273 int mode, rc;
00274 const char *opaque;
00275 XrdOucErrInfo myError(Link->ID);
00276
00277
00278
00279 if (Route[RD_chmod].Port)
00280 return Response.Send(kXR_redirect,Route[RD_chmod].Port,Route[RD_chmod].Host);
00281
00282
00283
00284 mode = mapMode((int)ntohs(Request.chmod.mode));
00285 if (rpCheck(argp->buff, &opaque)) return rpEmsg("Modifying", argp->buff);
00286 if (!Squash(argp->buff)) return vpEmsg("Modifying", argp->buff);
00287
00288
00289
00290 rc = osFS->chmod(argp->buff, (XrdSfsMode)mode, myError, CRED, opaque);
00291 TRACEP(FS, "chmod rc=" <<rc <<" mode=" <<std::oct <<mode <<std::dec <<' ' <<argp->buff);
00292 if (SFS_OK == rc) return Response.Send();
00293
00294
00295
00296 return fsError(rc, myError);
00297 }
00298
00299
00300
00301
00302
00303 int XrdXrootdProtocol::do_CKsum(int canit)
00304 {
00305 const char *opaque;
00306 char *args[3];
00307
00308
00309
00310 if (!JobCKS)
00311 return Response.Send(kXR_Unsupported, "query chksum is not supported");
00312
00313
00314
00315 if (rpCheck(argp->buff, &opaque)) return rpEmsg("Check summing", argp->buff);
00316 if (!Squash(argp->buff)) return vpEmsg("Check summing", argp->buff);
00317
00318
00319
00320 if (canit)
00321 {JobCKS->Cancel(argp->buff, &Response);
00322 return Response.Send();
00323 }
00324
00325
00326
00327 args[0] = JobCKT;
00328 args[1] = argp->buff;
00329 args[2] = 0;
00330
00331
00332
00333 return JobCKS->Schedule(argp->buff, (const char **)args, &Response,
00334 ((CapVer & kXR_vermask) >= kXR_ver002 ? 0 : JOB_Sync));
00335 }
00336
00337
00338
00339
00340
00341 int XrdXrootdProtocol::do_Close()
00342 {
00343 XrdXrootdFile *fp;
00344 XrdXrootdFHandle fh(Request.close.fhandle);
00345 int rc;
00346
00347
00348
00349 UPSTATS(miscCnt);
00350
00351
00352
00353 if (!FTab || !(fp = FTab->Get(fh.handle)))
00354 return Response.Send(kXR_FileNotOpen,
00355 "close does not refer to an open file");
00356
00357
00358
00359
00360 Link->Serialize();
00361
00362
00363
00364 if (monFILE && Monitor) Monitor->Close(fp->FileID,fp->readCnt,fp->writeCnt);
00365
00366
00367
00368 rc = fp->XrdSfsp->close();
00369 TRACEP(FS, "close rc=" <<rc <<" fh=" <<fh.handle);
00370 if (SFS_OK != rc)
00371 return Response.Send(kXR_FSError, fp->XrdSfsp->error.getErrText());
00372
00373
00374
00375 FTab->Del(fh.handle);
00376 numFiles--;
00377 return Response.Send();
00378 }
00379
00380
00381
00382
00383
00384 int XrdXrootdProtocol::do_Dirlist()
00385 {
00386 int bleft, rc = 0, dlen, cnt = 0;
00387 char *buff, ebuff[4096];
00388 const char *opaque, *dname;
00389 XrdSfsDirectory *dp;
00390
00391
00392
00393 if (Route[RD_dirlist].Port)
00394 return Response.Send(kXR_redirect,Route[RD_dirlist].Port,Route[RD_dirlist].Host);
00395
00396
00397
00398 if (rpCheck(argp->buff, &opaque)) return rpEmsg("Listing", argp->buff);
00399 if (!Squash(argp->buff)) return vpEmsg("Listing", argp->buff);
00400
00401
00402
00403 if (!(dp = osFS->newDir(Link->ID)))
00404 {snprintf(ebuff,sizeof(ebuff)-1,"Insufficient memory to open %s",argp->buff);
00405 eDest.Emsg("Xeq", ebuff);
00406 return Response.Send(kXR_NoMemory, ebuff);
00407 }
00408
00409
00410
00411 if ((rc = dp->open(argp->buff, CRED, opaque)))
00412 {rc = fsError(rc, dp->error); delete dp; return rc;}
00413
00414
00415
00416
00417
00418
00419
00420
00421 dname = 0;
00422 do {buff = ebuff; bleft = sizeof(ebuff);
00423 while(dname || (dname = dp->nextEntry()))
00424 {dlen = strlen(dname);
00425 if (dlen > 2 || dname[0] != '.' || (dlen == 2 && dname[1] != '.'))
00426 {if ((bleft -= (dlen+1)) < 0) break;
00427 strcpy(buff, dname); buff += dlen; *buff = '\n'; buff++; cnt++;
00428 }
00429 dname = 0;
00430 }
00431 if (dname) rc = Response.Send(kXR_oksofar, ebuff, buff-ebuff);
00432 } while(!rc && dname);
00433
00434
00435
00436 if (!rc)
00437 {if (ebuff == buff) rc = Response.Send();
00438 else {*(buff-1) = '\0';
00439 rc = Response.Send((void *)ebuff, buff-ebuff);
00440 }
00441 }
00442
00443
00444
00445 dp->close();
00446 delete dp;
00447 if (!rc) {TRACEP(FS, "dirlist entries=" <<cnt <<" path=" <<argp->buff);}
00448 return rc;
00449 }
00450
00451
00452
00453
00454
00455 int XrdXrootdProtocol::do_Endsess()
00456 {
00457 XrdXrootdSessID *sp, sessID;
00458 int rc;
00459
00460
00461
00462 UPSTATS(miscCnt);
00463
00464
00465
00466 sp = (XrdXrootdSessID *)Request.endsess.sessid;
00467 memcpy((void *)&sessID.Pid, &sp->Pid, sizeof(sessID.Pid));
00468 memcpy((void *)&sessID.FD, &sp->FD, sizeof(sessID.FD));
00469 memcpy((void *)&sessID.Inst, &sp->Inst, sizeof(sessID.Inst));
00470
00471
00472
00473 TRACEP(LOGIN, "endsess " <<sessID.Pid <<':' <<sessID.FD <<'.' <<sessID.Inst);
00474
00475
00476
00477 if (sessID.Pid != myPID) return Response.Send();
00478
00479
00480
00481 if ((sessID.FD == 0 && sessID.Inst == 0)
00482 || !(rc = Link->Terminate(Link, sessID.FD, sessID.Inst))) return -1;
00483
00484
00485
00486 TRACEP(LOGIN, "endsess " <<sessID.Pid <<':' <<sessID.FD <<'.' <<sessID.Inst
00487 <<" rc=" <<rc <<" (" <<strerror(rc < 0 ? -rc : EAGAIN) <<")");
00488
00489
00490
00491 if (rc > 0)
00492 return (rc = Response.Send(kXR_wait, rc, "session still active")) ? rc:1;
00493
00494 if (rc == -EACCES)return Response.Send(kXR_NotAuthorized, "not session owner");
00495 if (rc == -ESRCH) return Response.Send(kXR_NotFound, "session not found");
00496 if (rc == -ETIME) return Response.Send(kXR_Cancelled,"session not ended");
00497
00498 return Response.Send();
00499 }
00500
00501
00502
00503
00504
00505 int XrdXrootdProtocol::do_Getfile()
00506 {
00507 int gopts, buffsz;
00508
00509
00510
00511 UPSTATS(getfCnt);
00512
00513
00514
00515 gopts = int(ntohl(Request.getfile.options));
00516 buffsz = int(ntohl(Request.getfile.buffsz));
00517
00518 return Response.Send(kXR_Unsupported, "getfile request is not supported");
00519 }
00520
00521
00522
00523
00524
00525 int XrdXrootdProtocol::do_Locate()
00526 {
00527 static XrdXrootdCallBack locCB("locate");
00528 int rc, opts, fsctl_cmd = SFS_FSCTL_LOCATE;
00529 const char *opaque;
00530 char *Path, *fn = argp->buff, opt[8], *op=opt;
00531 XrdOucErrInfo myError(Link->ID, &locCB, ReqID.getID());
00532
00533
00534
00535 opts = (int)ntohs(Request.locate.options);
00536
00537
00538
00539 if (opts & kXR_nowait) {fsctl_cmd |= SFS_O_NOWAIT; *op++ = 'i';}
00540 if (opts & kXR_refresh) {fsctl_cmd |= SFS_O_RESET; *op++ = 's';}
00541 *op = '\0';
00542 TRACEP(FS, "locate " <<opt <<' ' <<fn);
00543
00544
00545
00546 if (Route[RD_locate].Port)
00547 return Response.Send(kXR_redirect, Route[RD_locate].Port,
00548 Route[RD_locate].Host);
00549
00550
00551
00552 if (*fn != '*') Path = fn;
00553 else if (*(fn+1)) Path = fn+1;
00554 else {Path = 0;
00555 fn = XPList.Next()->Path();
00556 fsctl_cmd |= SFS_O_TRUNC;
00557 }
00558
00559
00560
00561 if (Path)
00562 {if (rpCheck(Path, &opaque)) return rpEmsg("Locating", Path);
00563 if (!Squash(Path)) return vpEmsg("Locating", Path);
00564 }
00565
00566
00567
00568 rc = osFS->fsctl(fsctl_cmd, fn, myError, CRED);
00569 TRACEP(FS, "rc=" <<rc <<" locate " <<fn);
00570 return fsError(rc, myError);
00571 }
00572
00573
00574
00575
00576
00577 int XrdXrootdProtocol::do_Login()
00578 {
00579 static XrdSysMutex sessMutex;
00580 static unsigned int Sid = 0;
00581 XrdXrootdSessID sessID;
00582 int i, pid, rc, sendSID = 0;
00583 char uname[sizeof(Request.login.username)+1];
00584
00585
00586
00587 UPSTATS(miscCnt);
00588
00589
00590
00591 pid = (int)ntohl(Request.login.pid);
00592 for (i = 0; i < (int)sizeof(Request.login.username); i++)
00593 {if (Request.login.username[i] == '\0' ||
00594 Request.login.username[i] == ' ') break;
00595 uname[i] = Request.login.username[i];
00596 }
00597 uname[i] = '\0';
00598
00599
00600
00601 if (Status) return Response.Send(kXR_InvalidRequest,
00602 "duplicate login; already logged in");
00603
00604
00605
00606 Link->setID(uname, pid);
00607 CapVer = Request.login.capver[0];
00608
00609
00610
00611 if (CapVer && kXR_vermask)
00612 {sessID.FD = Link->FDnum();
00613 sessID.Inst = Link->Inst();
00614 sessID.Pid = myPID;
00615 sessMutex.Lock(); mySID = ++Sid; sessMutex.UnLock();
00616 sessID.Sid = mySID;
00617 sendSID = 1;
00618 }
00619
00620
00621
00622 if (*(Request.login.role) & (kXR_char)kXR_useradmin)
00623 Status = XRD_ADMINUSER;
00624
00625
00626
00627
00628
00629 if (CIA)
00630 {const char *pp=CIA->getParms(i, Link->Host());
00631 if (pp && i ) {if (!sendSID) rc = Response.Send((void *)pp, i);
00632 else {struct iovec iov[3];
00633 iov[1].iov_base = (char *)&sessID;
00634 iov[1].iov_len = sizeof(sessID);
00635 iov[2].iov_base = (char *)pp;
00636 iov[2].iov_len = i;
00637 rc = Response.Send(iov,3,int(i+sizeof(sessID)));
00638 }
00639 Status = (XRD_LOGGEDIN | XRD_NEED_AUTH);
00640 }
00641 else {rc = (sendSID ? Response.Send((void *)&sessID, sizeof(sessID))
00642 : Response.Send());
00643 Status = XRD_LOGGEDIN;
00644 if (pp) {Entity.tident = Link->ID; Client = &Entity;}
00645 }
00646 }
00647 else {rc = (sendSID ? Response.Send((void *)&sessID, sizeof(sessID))
00648 : Response.Send());
00649 Status = XRD_LOGGEDIN;
00650 }
00651
00652
00653
00654 if ((Monitor = XrdXrootdMonitor::Alloc()))
00655 {monFILE = XrdXrootdMonitor::monFILE;
00656 monIO = XrdXrootdMonitor::monIO;
00657 if (XrdXrootdMonitor::monUSER)
00658 monUID = XrdXrootdMonitor::Map(XROOTD_MON_MAPUSER, Link->ID, 0);
00659 }
00660
00661
00662
00663 ReqID.setID(Request.header.streamid, Link->FDnum(), Link->Inst());
00664
00665
00666
00667 if (!(Status & XRD_NEED_AUTH))
00668 eDest.Log(SYS_LOG_01, "Xeq", Link->ID, (Status & XRD_ADMINUSER
00669 ? "admin login" : "login"));
00670 return rc;
00671 }
00672
00673
00674
00675
00676
00677 int XrdXrootdProtocol::do_Mkdir()
00678 {
00679 int mode, rc;
00680 const char *opaque;
00681 XrdOucErrInfo myError(Link->ID);
00682
00683
00684
00685 if (Route[RD_mkdir].Port)
00686 return Response.Send(kXR_redirect,Route[RD_mkdir].Port,Route[RD_mkdir].Host);
00687
00688
00689
00690 mode = mapMode((int)ntohs(Request.mkdir.mode)) | S_IRWXU;
00691 if (Request.mkdir.options[0] & static_cast<unsigned char>(kXR_mkdirpath))
00692 mode |= SFS_O_MKPTH;
00693 if (rpCheck(argp->buff, &opaque)) return rpEmsg("Creating", argp->buff);
00694 if (!Squash(argp->buff)) return vpEmsg("Creating", argp->buff);
00695
00696
00697
00698 rc = osFS->mkdir(argp->buff, (XrdSfsMode)mode, myError, CRED, opaque);
00699 TRACEP(FS, "rc=" <<rc <<" mkdir " <<std::oct <<mode <<std::dec <<' ' <<argp->buff);
00700 if (SFS_OK == rc) return Response.Send();
00701
00702
00703
00704 return fsError(rc, myError);
00705 }
00706
00707
00708
00709
00710
00711 int XrdXrootdProtocol::do_Mv()
00712 {
00713 int rc;
00714 const char *Opaque, *Npaque;
00715 char *oldp, *newp;
00716 XrdOucErrInfo myError(Link->ID);
00717
00718
00719
00720 if (Route[RD_mv].Port)
00721 return Response.Send(kXR_redirect,Route[RD_mv].Port,Route[RD_mv].Host);
00722
00723
00724
00725 oldp = newp = argp->buff;
00726 while(*newp && *newp != ' ') newp++;
00727 if (*newp) {*newp = '\0'; newp++;
00728 while(*newp && *newp == ' ') newp++;
00729 }
00730
00731
00732
00733 if (rpCheck(oldp, &Opaque)) return rpEmsg("Renaming", oldp);
00734 if (rpCheck(newp, &Npaque)) return rpEmsg("Renaming to", newp);
00735 if (!Squash(oldp)) return vpEmsg("Renaming", oldp);
00736 if (!Squash(newp)) return vpEmsg("Renaming to", newp);
00737
00738
00739
00740 if (*newp == '\0')
00741 Response.Send(kXR_ArgMissing, "new path specfied for mv");
00742
00743
00744
00745 rc = osFS->rename(oldp, newp, myError, CRED, Opaque, Npaque);
00746 TRACEP(FS, "rc=" <<rc <<" mv " <<oldp <<' ' <<newp);
00747 if (SFS_OK == rc) return Response.Send();
00748
00749
00750
00751 return fsError(rc, myError);
00752 }
00753
00754
00755
00756
00757
00758 int XrdXrootdProtocol::do_Offload(int pathID, int isWrite)
00759 {
00760 XrdSysSemaphore isAvail(0);
00761 XrdXrootdProtocol *pp;
00762 XrdXrootdPio *pioP;
00763 kXR_char streamID[2];
00764
00765
00766
00767 if (pathID >= maxStreams || !(pp = Stream[pathID]))
00768 return Response.Send(kXR_ArgInvalid, "invalid path ID");
00769
00770
00771
00772 pp->streamMutex.Lock();
00773 if (pp->isDead || pp->isNOP)
00774 {pp->streamMutex.UnLock();
00775 return Response.Send(kXR_ArgInvalid,
00776 (pp->isDead ? "path ID is not functional"
00777 : "path ID is not connected"));
00778 }
00779
00780
00781
00782 Response.StreamID(streamID);
00783
00784
00785
00786
00787
00788 do{if (!pp->isActive)
00789 {pp->myFile = myFile;
00790 pp->myOffset = myOffset;
00791 pp->myIOLen = myIOLen;
00792 pp->myBlen = 0;
00793 pp->doWrite = static_cast<char>(isWrite);
00794 pp->doWriteC = 0;
00795 pp->Resume = &XrdXrootdProtocol::do_OffloadIO;
00796 pp->isActive = 1;
00797 pp->reTry = &isAvail;
00798 pp->Response.Set(streamID);
00799 pp->streamMutex.UnLock();
00800 Link->setRef(1);
00801 Sched->Schedule((XrdJob *)(pp->Link));
00802 isAvail.Wait();
00803 return 0;
00804 }
00805
00806 if ((pioP = pp->pioFree)) break;
00807 pp->reTry = &isAvail;
00808 pp->streamMutex.UnLock();
00809 TRACEP(FS, (isWrite ? 'w' : 'r') <<" busy path " <<pathID <<" offs=" <<myOffset);
00810 isAvail.Wait();
00811 TRACEP(FS, (isWrite ? 'w' : 'r') <<" free path " <<pathID <<" offs=" <<myOffset);
00812 pp->streamMutex.Lock();
00813 if (pp->isNOP)
00814 {pp->streamMutex.UnLock();
00815 return Response.Send(kXR_ArgInvalid, "path ID is not connected");
00816 }
00817 } while(1);
00818
00819
00820
00821 pp->pioFree = pioP->Next; pioP->Next = 0;
00822 pioP->Set(myFile, myOffset, myIOLen, streamID, static_cast<char>(isWrite));
00823 if (pp->pioLast) pp->pioLast->Next = pioP;
00824 else pp->pioFirst = pioP;
00825 pp->pioLast = pioP;
00826 pp->streamMutex.UnLock();
00827 return 0;
00828 }
00829
00830
00831
00832
00833
00834 int XrdXrootdProtocol::do_OffloadIO()
00835 {
00836 XrdSysSemaphore *sesSem;
00837 XrdXrootdPio *pioP;
00838 int rc;
00839
00840
00841
00842
00843
00844
00845 if (!doWriteC && (sesSem = reTry)) {reTry = 0; sesSem->Post();}
00846
00847
00848
00849 do {if (!doWrite) rc = do_ReadAll(0);
00850 else if ( (rc = (doWriteC ? do_WriteCont() : do_WriteAll()) ) > 0)
00851 {Resume = &XrdXrootdProtocol::do_OffloadIO;
00852 doWriteC = 1;
00853 return rc;
00854 }
00855 streamMutex.Lock();
00856 if (rc || !(pioP = pioFirst)) break;
00857 if (!(pioFirst = pioP->Next)) pioLast = 0;
00858 myFile = pioP->myFile;
00859 myOffset = pioP->myOffset;
00860 myIOLen = pioP->myIOLen;
00861 doWrite = pioP->isWrite;
00862 doWriteC = 0;
00863 Response.Set(pioP->StreamID);
00864 pioP->Next = pioFree; pioFree = pioP;
00865 if (reTry) {reTry->Post(); reTry = 0;}
00866 streamMutex.UnLock();
00867 } while(1);
00868
00869
00870
00871 if (rc) isNOP = 1;
00872 isActive = 0;
00873 Stream[0]->Link->setRef(-1);
00874 if (reTry) {reTry->Post(); reTry = 0;}
00875 streamMutex.UnLock();
00876 return -EINPROGRESS;
00877 }
00878
00879
00880
00881
00882
00883 int XrdXrootdProtocol::do_Open()
00884 {
00885 static XrdXrootdCallBack openCB("open file");
00886 int fhandle;
00887 int rc, mode, opts, openopts, mkpath = 0, doforce = 0, compchk = 0;
00888 int popt, retStat = 0;
00889 const char *opaque;
00890 char usage, ebuff[2048];
00891 char *fn = argp->buff, opt[16], *op=opt, isAsync = '\0';
00892 XrdSfsFile *fp;
00893 XrdXrootdFile *xp;
00894 struct stat statbuf;
00895 struct ServerResponseBody_Open myResp;
00896 int resplen = sizeof(myResp.fhandle);
00897 struct iovec IOResp[3];
00898
00899
00900
00901 UPSTATS(openCnt);
00902
00903
00904
00905 mode = (int)ntohs(Request.open.mode);
00906 opts = (int)ntohs(Request.open.options);
00907
00908
00909
00910 mode = mapMode(mode) | S_IRUSR | S_IWUSR; usage = 'r';
00911 if (opts & kXR_open_read)
00912 {openopts = SFS_O_RDONLY; *op++ = 'r';}
00913 else if (opts & kXR_open_updt)
00914 {openopts = SFS_O_RDWR; *op++ = 'u'; usage = 'w';}
00915 else {openopts = SFS_O_RDONLY; *op++ = 'r';}
00916
00917 if (opts & kXR_new)
00918 {openopts |= SFS_O_CREAT; *op++ = 'n';
00919 if (opts & kXR_replica) {*op++ = '+';
00920 openopts |= SFS_O_REPLICA;
00921 }
00922 if (opts & kXR_mkdir) {*op++ = 'm'; mkpath = 1;
00923 mode |= SFS_O_MKPTH;
00924 }
00925 }
00926 else if (opts & kXR_delete)
00927 {openopts = SFS_O_TRUNC; *op++ = 'd';
00928 if (opts & kXR_mkdir) {*op++ = 'm'; mkpath = 1;
00929 mode |= SFS_O_MKPTH;
00930 }
00931 }
00932 if (opts & kXR_compress)
00933 {openopts |= SFS_O_RAWIO; *op++ = 'c'; compchk = 1;}
00934 if (opts & kXR_force) {*op++ = 'f'; doforce = 1;}
00935 if ((opts & kXR_async || as_force) && !as_noaio)
00936 {*op++ = 'a'; isAsync = '1';}
00937 if (opts & kXR_refresh) {*op++ = 's'; openopts |= SFS_O_RESET;
00938 UPSTATS(Refresh);
00939 }
00940 if (opts & kXR_retstat) {*op++ = 't'; retStat = 1;}
00941 if (opts & kXR_posc) {*op++ = 'p'; openopts |= SFS_O_POSC;}
00942 *op = '\0';
00943 TRACEP(FS, "open " <<opt <<' ' <<fn);
00944
00945
00946
00947 if (rpCheck(fn, &opaque)) return rpEmsg("Opening", fn);
00948
00949
00950
00951 if (Route[RD_open1].Host && (popt = RPList.Validate(fn)))
00952 return Response.Send(kXR_redirect,Route[popt].Port,Route[popt].Host);
00953
00954
00955
00956 if (!(popt = Squash(fn))) return vpEmsg("Opening", fn);
00957
00958
00959
00960 if (!(fp = osFS->newFile(Link->ID)))
00961 {snprintf(ebuff, sizeof(ebuff)-1,"Insufficient memory to open %s",fn);
00962 eDest.Emsg("Xeq", ebuff);
00963 return Response.Send(kXR_NoMemory, ebuff);
00964 }
00965
00966
00967
00968 fp->error.setErrCB(&openCB, ReqID.getID());
00969
00970
00971
00972 if ((rc = fp->open(fn, (XrdSfsFileOpenMode)openopts,
00973 (mode_t)mode, CRED, opaque)))
00974 {rc = fsError(rc, fp->error); delete fp; return rc;}
00975
00976
00977
00978 if (!(xp=new XrdXrootdFile(Link->ID,fp,usage,isAsync,Link->sfOK,&statbuf)))
00979 {delete fp;
00980 snprintf(ebuff, sizeof(ebuff)-1, "Insufficient memory to open %s", fn);
00981 eDest.Emsg("Xeq", ebuff);
00982 return Response.Send(kXR_NoMemory, ebuff);
00983 }
00984
00985
00986
00987 Link->Serialize();
00988 *ebuff = '\0';
00989
00990
00991
00992 if (!(popt & XROOTDXP_NOLK) && (rc = Locker->Lock(xp, doforce)))
00993 {const char *who;
00994 if (rc > 0) who = (rc > 1 ? "readers" : "reader");
00995 else { rc = -rc;
00996 who = (rc > 1 ? "writers" : "writer");
00997 }
00998 snprintf(ebuff, sizeof(ebuff)-1,
00999 "%s file %s is already opened by %d %s; open denied.",
01000 ('r' == usage ? "Input" : "Output"), fn, rc, who);
01001 delete fp; xp->XrdSfsp = 0; delete xp;
01002 eDest.Emsg("Xeq", ebuff);
01003 return Response.Send(kXR_FileLocked, ebuff);
01004 }
01005
01006
01007
01008 if (!FTab) FTab = new XrdXrootdFileTable();
01009
01010
01011
01012 if (!FTab || (fhandle = FTab->Add(xp)) < 0)
01013 {delete xp;
01014 snprintf(ebuff, sizeof(ebuff)-1, "Insufficient memory to open %s", fn);
01015 eDest.Emsg("Xeq", ebuff);
01016 return Response.Send(kXR_NoMemory, ebuff);
01017 }
01018
01019
01020
01021 if (doforce)
01022 {int rdrs, wrtrs;
01023 Locker->numLocks(xp, rdrs, wrtrs);
01024 if (('r' == usage && wrtrs) || ('w' == usage && rdrs) || wrtrs > 1)
01025 {snprintf(ebuff, sizeof(ebuff)-1,
01026 "%s file %s forced opened with %d reader(s) and %d writer(s).",
01027 ('r' == usage ? "Input" : "Output"), fn, rdrs, wrtrs);
01028 eDest.Emsg("Xeq", ebuff);
01029 }
01030 }
01031
01032
01033
01034 if (!compchk)
01035 {resplen = sizeof(myResp.fhandle);
01036 memset(&myResp, 0, sizeof(myResp));
01037 }
01038 else {int cpsize;
01039 fp->getCXinfo((char *)myResp.cptype, cpsize);
01040 if (cpsize) {myResp.cpsize = static_cast<kXR_int32>(htonl(cpsize));
01041 resplen = sizeof(myResp);
01042 } else myResp.cpsize = 0;
01043 }
01044
01045
01046
01047 if (retStat)
01048 {retStat = StatGen(statbuf, ebuff);
01049 IOResp[1].iov_base = (char *)&myResp; IOResp[1].iov_len = sizeof(myResp);
01050 IOResp[2].iov_base = ebuff; IOResp[2].iov_len = retStat;
01051 resplen = sizeof(myResp) + retStat;
01052 }
01053
01054
01055
01056 if (monFILE && Monitor)
01057 {xp->FileID = Monitor->Map(XROOTD_MON_MAPPATH, Link->ID, fn);
01058 Monitor->Open(xp->FileID, statbuf.st_size);
01059 }
01060
01061
01062
01063 memcpy((void *)myResp.fhandle,(const void *)&fhandle,sizeof(myResp.fhandle));
01064 numFiles++;
01065
01066
01067
01068 if (retStat) return Response.Send(IOResp, 3, resplen);
01069 else return Response.Send((void *)&myResp, resplen);
01070 }
01071
01072
01073
01074
01075
01076 int XrdXrootdProtocol::do_Ping()
01077 {
01078
01079
01080
01081 UPSTATS(miscCnt);
01082
01083
01084
01085 return Response.Send();
01086 }
01087
01088
01089
01090
01091
01092 int XrdXrootdProtocol::do_Prepare()
01093 {
01094 int rc, hport, pathnum = 0;
01095 const char *opaque;
01096 char opts, hname[32], reqid[64], nidbuff[512], *path;
01097 XrdOucErrInfo myError(Link->ID);
01098 XrdOucTokenizer pathlist(argp->buff);
01099 XrdOucTList *pFirst=0, *pP, *pLast = 0;
01100 XrdOucTList *oFirst=0, *oP, *oLast = 0;
01101 XrdOucTListHelper pHelp(&pFirst), oHelp(&oFirst);
01102 XrdXrootdPrepArgs pargs(0, 0);
01103 XrdSfsPrep fsprep;
01104
01105
01106
01107 opts = Request.prepare.options;
01108
01109
01110
01111 if (Route[RD_prepstg].Port && ((opts & kXR_stage) || (opts & kXR_cancel)))
01112 return Response.Send(kXR_redirect,Route[RD_prepstg].Port,Route[RD_prepstg].Host);
01113 if (Route[RD_prepare].Port)
01114 return Response.Send(kXR_redirect,Route[RD_prepare].Port,Route[RD_prepare].Host);
01115
01116
01117
01118 if (opts & kXR_stage && !(opts & kXR_cancel))
01119 {XrdOucReqID::ID(reqid, sizeof(reqid));
01120 fsprep.opts = Prep_STAGE | (opts & kXR_coloc ? Prep_COLOC : 0);
01121 }
01122 else {reqid[0] = '*'; reqid[1] = '\0'; fsprep.opts = 0;}
01123
01124
01125
01126 fsprep.reqid = reqid;
01127 fsprep.paths = 0;
01128 fsprep.oinfo = 0;
01129 fsprep.opts |= Prep_PRTY0 | (opts & kXR_fresh ? Prep_FRESH : 0);
01130 fsprep.notify = 0;
01131
01132
01133
01134 if (opts & kXR_cancel)
01135 {if (!(path = pathlist.GetLine()))
01136 return Response.Send(kXR_ArgMissing, "Prepare requestid not specified");
01137 if (!XrdOucReqID::isMine(path, hport, hname, sizeof(hname)))
01138 {if (!hport) return Response.Send(kXR_ArgInvalid,
01139 "Prepare requestid owned by an unknown server");
01140 TRACEI(REDIR, Response.ID() <<"redirecting to " << hname <<':' <<hport);
01141 return Response.Send(kXR_redirect, hport, hname);
01142 }
01143 fsprep.reqid = path;
01144 if (SFS_OK != (rc = osFS->prepare(fsprep, myError, CRED)))
01145 return fsError(rc, myError);
01146 rc = Response.Send();
01147 XrdXrootdPrepare::Logdel(path);
01148 return rc;
01149 }
01150
01151
01152
01153 while((path = pathlist.GetLine()))
01154 {if (rpCheck(path, &opaque)) return rpEmsg("Preparing", path);
01155 if (!Squash(path)) return vpEmsg("Preparing", path);
01156 pP = new XrdOucTList(path, pathnum);
01157 (pLast ? (pLast->next = pP) : (pFirst = pP)); pLast = pP;
01158 oP = new XrdOucTList(opaque, 0);
01159 (oLast ? (oLast->next = oP) : (oFirst = oP)); oLast = oP;
01160 pathnum++;
01161 }
01162
01163
01164
01165 if (!pFirst)
01166 return Response.Send(kXR_ArgMissing, "No prepare paths specified");
01167
01168
01169
01170 if (opts & kXR_notify)
01171 {fsprep.notify = nidbuff;
01172 sprintf(nidbuff, Notify, Link->FDnum(), Link->ID);
01173 fsprep.opts = (opts & kXR_noerrs ? Prep_SENDAOK : Prep_SENDACK);
01174 }
01175 if (opts & kXR_wmode) fsprep.opts |= Prep_WMODE;
01176 fsprep.paths = pFirst;
01177 fsprep.oinfo = oFirst;
01178 if (SFS_OK != (rc = osFS->prepare(fsprep, myError, CRED)))
01179 return fsError(rc, myError);
01180
01181
01182
01183 if (!(opts & kXR_stage)) rc = Response.Send();
01184 else {rc = Response.Send(reqid, strlen(reqid));
01185 pargs.reqid=reqid;
01186 pargs.user=Link->ID;
01187 pargs.paths=pFirst;
01188 XrdXrootdPrepare::Log(pargs);
01189 pargs.reqid = 0;
01190 }
01191 return rc;
01192 }
01193
01194
01195
01196
01197
01198 int XrdXrootdProtocol::do_Protocol()
01199 {
01200 static ServerResponseBody_Protocol Resp
01201 = {static_cast<kXR_int32>(htonl(XROOTD_VERSBIN)),
01202 static_cast<kXR_int32>(htonl(kXR_DataServer))};
01203
01204
01205
01206 UPSTATS(miscCnt);
01207
01208
01209
01210 if (isRedir) Resp.flags = static_cast<kXR_int32>(htonl(kXR_LBalServer));
01211 return Response.Send((void *)&Resp, sizeof(Resp));
01212 }
01213
01214
01215
01216
01217
01218 int XrdXrootdProtocol::do_Putfile()
01219 {
01220 int popts, buffsz;
01221
01222
01223
01224 UPSTATS(putfCnt);
01225
01226
01227
01228 popts = int(ntohl(Request.putfile.options));
01229 buffsz = int(ntohl(Request.putfile.buffsz));
01230
01231 return Response.Send(kXR_Unsupported, "putfile request is not supported");
01232 }
01233
01234
01235
01236
01237
01238 int XrdXrootdProtocol::do_Qconf()
01239 {
01240 XrdOucTokenizer qcargs(argp->buff);
01241 char *val, buff[1024], *bp=buff;
01242 int n, bleft = sizeof(buff);
01243
01244
01245
01246 if (!qcargs.GetLine() || !(val = qcargs.GetToken()))
01247 return Response.Send(kXR_ArgMissing, "query config argument not specified.");
01248
01249
01250
01251 do {TRACEP(DEBUG, "query config " <<val);
01252 if (bleft < 32) break;
01253
01254
01255
01256 if (!strcmp("bind_max", val))
01257 {n = sprintf(bp, "%d\n", maxStreams-1);
01258 bp += n; bleft -= n;
01259 }
01260 else if (!strcmp("pio_max", val))
01261 {n = sprintf(bp, "%d\n", maxPio+1);
01262 bp += n; bleft -= n;
01263 }
01264 else if (!strcmp("readv_ior_max", val))
01265 {n = sprintf(bp, "%d\n", maxTransz - (int)sizeof(readahead_list));
01266 bp += n; bleft -= n;
01267 }
01268 else if (!strcmp("readv_iov_max", val))
01269 {n = sprintf(bp, "%d\n", maxRvecsz);
01270 bp += n; bleft -= n;
01271 }
01272 else if (!strcmp("wan_port", val) && WANPort)
01273 {n = sprintf(bp, "%d\n", WANPort);
01274 bp += n; bleft -= n;
01275 }
01276 else if (!strcmp("wan_window", val) && WANPort)
01277 {n = sprintf(bp, "%d\n", WANWindow);
01278 bp += n; bleft -= n;
01279 }
01280 else if (!strcmp("window", val) && Window)
01281 {n = sprintf(bp, "%d\n", Window);
01282 bp += n; bleft -= n;
01283 }
01284 else {n = strlen(val);
01285 if (bleft <= n) break;
01286 strcpy(bp, val); bp +=n; *bp = '\n'; bp++;
01287 bleft -= (n+1);
01288 }
01289 } while((val = qcargs.GetToken()));
01290
01291
01292
01293 if (val)
01294 return Response.Send(kXR_ArgTooLong, "too many query config arguments.");
01295
01296
01297
01298 return Response.Send(buff, sizeof(buff) - bleft);
01299 }
01300
01301
01302
01303
01304
01305 int XrdXrootdProtocol::do_Qfh()
01306 {
01307 static const int fsctl_cmd1 = SFS_FCTL_STATV;
01308 static XrdXrootdCallBack qryCB("query");
01309 XrdOucErrInfo myError(Link->ID, &qryCB, ReqID.getID());
01310 XrdXrootdFHandle fh(Request.query.fhandle);
01311 XrdXrootdFile *fp;
01312 short qopt = (short)ntohs(Request.query.infotype);
01313 int rc, fsctl_cmd;
01314
01315
01316
01317 UPSTATS(miscCnt);
01318
01319
01320
01321 switch(qopt)
01322 {case kXR_Qvisa: fsctl_cmd = fsctl_cmd1;
01323 break;
01324 default: return Response.Send(kXR_ArgMissing,
01325 "Required query argument not present");
01326 }
01327
01328
01329
01330 if (!FTab || !(fp = FTab->Get(fh.handle)))
01331 return Response.Send(kXR_FileNotOpen,
01332 "query does not refer to an open file");
01333
01334
01335
01336 rc = fp->XrdSfsp->fctl(fsctl_cmd, 0, myError);
01337 TRACEP(FS, "query rc=" <<rc <<" fh=" <<fh.handle);
01338
01339
01340
01341 if (SFS_OK != rc) return fsError(rc, myError);
01342 return Response.Send();
01343 }
01344
01345
01346
01347
01348
01349 int XrdXrootdProtocol::do_Qopaque(short qopt)
01350 {
01351 XrdOucErrInfo myError(Link->ID);
01352 XrdSfsFSctl myData;
01353 const char *opaque, *Act, *AData;
01354 int fsctl_cmd, rc, dlen = Request.query.dlen;
01355
01356
01357
01358 if (qopt == kXR_Qopaque)
01359 {myData.Arg1 = argp->buff; myData.Arg1Len = dlen;
01360 myData.Arg2 = 0; myData.Arg1Len = 0;
01361 fsctl_cmd = SFS_FSCTL_PLUGIO;
01362 Act = " qopaque '"; AData = "...";
01363 } else {
01364
01365
01366 if (Route[RD_stat].Port)
01367 return Response.Send(kXR_redirect,Route[RD_stat].Port,Route[RD_stat].Host);
01368
01369
01370
01371 if (rpCheck(argp->buff, &opaque)) return rpEmsg("Querying", argp->buff);
01372 if (!Squash(argp->buff)) return vpEmsg("Querying", argp->buff);
01373
01374
01375
01376 myData.Arg1 = argp->buff;
01377 myData.Arg1Len = (opaque ? opaque - argp->buff - 1 : dlen);
01378 myData.Arg2 = opaque;
01379 myData.Arg2Len = (opaque ? argp->buff + dlen - opaque : 0);
01380 fsctl_cmd = SFS_FSCTL_PLUGIN;
01381 Act = " qopaquf '"; AData = argp->buff;
01382 }
01383
01384
01385
01386 rc = osFS->FSctl(fsctl_cmd, myData, myError, CRED);
01387 TRACEP(FS, "rc=" <<rc <<Act <<AData <<"'");
01388 if (rc == SFS_OK) Response.Send("");
01389 return fsError(rc, myError);
01390 }
01391
01392
01393
01394
01395
01396 int XrdXrootdProtocol::do_Qspace()
01397 {
01398 static const int fsctl_cmd = SFS_FSCTL_STATLS;
01399 XrdOucErrInfo myError(Link->ID);
01400 const char *opaque;
01401 int n, rc;
01402
01403
01404
01405 if (Route[RD_stat].Port)
01406 return Response.Send(kXR_redirect,Route[RD_stat].Port,Route[RD_stat].Host);
01407
01408
01409
01410 if (rpCheck(argp->buff, &opaque)) return rpEmsg("Stating", argp->buff);
01411 if (!Squash(argp->buff)) return vpEmsg("Stating", argp->buff);
01412
01413
01414
01415 if (opaque)
01416 {n = strlen(argp->buff); argp->buff[n] = '?';
01417 if ((argp->buff)+n != opaque-1) strcpy(&argp->buff[n+1], opaque);
01418 }
01419
01420
01421
01422 rc = osFS->fsctl(fsctl_cmd, argp->buff, myError, CRED);
01423 TRACEP(FS, "rc=" <<rc <<" qspace '" <<argp->buff <<"'");
01424 if (rc == SFS_OK) Response.Send("");
01425 return fsError(rc, myError);
01426 }
01427
01428
01429
01430
01431
01432 int XrdXrootdProtocol::do_Query()
01433 {
01434 short qopt = (short)ntohs(Request.query.infotype);
01435
01436
01437
01438 switch(qopt)
01439 {case kXR_QStats: return SI->Stats(Response,
01440 (Request.header.dlen ? argp->buff : "a"));
01441 case kXR_Qcksum: return do_CKsum(0);
01442 case kXR_Qckscan: return do_CKsum(1);
01443 case kXR_Qconfig: return do_Qconf();
01444 case kXR_Qspace: return do_Qspace();
01445 case kXR_Qxattr: return do_Qxattr();
01446 case kXR_Qopaque:
01447 case kXR_Qopaquf: return do_Qopaque(qopt);
01448 default: break;
01449 }
01450
01451
01452
01453 return Response.Send(kXR_ArgInvalid,
01454 "Invalid information query type code");
01455 }
01456
01457
01458
01459
01460
01461 int XrdXrootdProtocol::do_Qxattr()
01462 {
01463 static XrdXrootdCallBack statCB("stat");
01464 static const int fsctl_cmd = SFS_FSCTL_STATXA;
01465 int rc;
01466 const char *opaque;
01467 XrdOucErrInfo myError(Link->ID, &statCB, ReqID.getID());
01468
01469
01470
01471 if (Route[RD_stat].Port)
01472 return Response.Send(kXR_redirect,Route[RD_stat].Port,Route[RD_stat].Host);
01473
01474
01475
01476 if (rpCheck(argp->buff, &opaque)) return rpEmsg("Stating", argp->buff);
01477 if (!Squash(argp->buff)) return vpEmsg("Stating", argp->buff);
01478
01479
01480
01481 rc = osFS->fsctl(fsctl_cmd, argp->buff, myError, CRED);
01482 TRACEP(FS, "rc=" <<rc <<" qxattr " <<argp->buff);
01483 return fsError(rc, myError);
01484 }
01485
01486
01487
01488
01489
01490 int XrdXrootdProtocol::do_Read()
01491 {
01492 int pathID, retc;
01493 XrdXrootdFHandle fh(Request.read.fhandle);
01494 numReads++;
01495
01496
01497
01498
01499
01500 if (!Request.header.dlen) pathID = 0;
01501 else if (do_ReadNone(retc, pathID)) return retc;
01502
01503
01504
01505 myIOLen = ntohl(Request.read.rlen);
01506 n2hll(Request.read.offset, myOffset);
01507
01508
01509
01510 if (!FTab || !(myFile = FTab->Get(fh.handle)))
01511 return Response.Send(kXR_FileNotOpen,
01512 "read does not refer to an open file");
01513
01514
01515
01516 TRACEP(FS, pathID <<" fh=" <<fh.handle <<" read " <<myIOLen <<'@' <<myOffset);
01517 if (!myIOLen) return Response.Send();
01518
01519
01520
01521 if (monIO && Monitor) Monitor->Add_rd(myFile->FileID, Request.read.rlen,
01522 Request.read.offset);
01523
01524
01525
01526 if (pathID) return do_Offload(pathID, 0);
01527
01528
01529
01530 return do_ReadAll();
01531 }
01532
01533
01534
01535
01536
01537
01538
01539
01540
01541 int XrdXrootdProtocol::do_ReadAll(int asyncOK)
01542 {
01543 int rc, xframt, Quantum = (myIOLen > maxBuffsz ? maxBuffsz : myIOLen);
01544 char *buff;
01545
01546
01547
01548
01549 if (myFile->isMMapped)
01550 { if (myOffset >= myFile->fSize) return Response.Send();
01551 else if (myOffset+myIOLen <= myFile->fSize)
01552 return Response.Send(myFile->mmAddr+myOffset, myIOLen);
01553 else return Response.Send(myFile->mmAddr+myOffset,
01554 myFile->fSize -myOffset);
01555 }
01556
01557
01558
01559 if (myFile->sfEnabled && myIOLen >= as_minsfsz
01560 && myOffset+myIOLen <= myFile->fSize)
01561 return Response.Send(myFile->fdNum, myOffset, myIOLen);
01562
01563
01564
01565 if (asyncOK && myFile->AsyncMode)
01566 {if (myIOLen >= as_miniosz && Link->UseCnt() < as_maxperlnk)
01567 if ((rc = aio_Read()) != -EAGAIN) return rc;
01568 SI->AsyncRej++;
01569 }
01570
01571
01572
01573 if (!argp || Quantum < halfBSize || Quantum > argp->bsize)
01574 {if ((rc = getBuff(1, Quantum)) <= 0) return rc;}
01575 else if (hcNow < hcNext) hcNow++;
01576 buff = argp->buff;
01577
01578
01579
01580 do {if ((xframt = myFile->XrdSfsp->read(myOffset, buff, Quantum)) <= 0) break;
01581 myFile->readCnt += xframt;
01582 if (xframt >= myIOLen) return Response.Send(buff, xframt);
01583 if (Response.Send(kXR_oksofar, buff, xframt) < 0) return -1;
01584 myOffset += xframt; myIOLen -= xframt;
01585 if (myIOLen < Quantum) Quantum = myIOLen;
01586 } while(myIOLen);
01587
01588
01589
01590 if (xframt == 0) return Response.Send();
01591 return Response.Send(kXR_FSError, myFile->XrdSfsp->error.getErrText());
01592 }
01593
01594
01595
01596
01597
01598 int XrdXrootdProtocol::do_ReadNone(int &retc, int &pathID)
01599 {
01600 XrdXrootdFHandle fh;
01601 int ralsz = Request.header.dlen;
01602 struct read_args *rargs=(struct read_args *)(argp->buff);
01603 struct readahead_list *ralsp = (readahead_list *)(rargs+sizeof(read_args));
01604
01605
01606
01607 pathID = static_cast<int>(rargs->pathid);
01608 if ((ralsz -= sizeof(read_args)) <= 0) return 0;
01609
01610
01611
01612 if (ralsz%sizeof(readahead_list))
01613 {Response.Send(kXR_ArgInvalid, "Invalid length for read ahead list");
01614 return 1;
01615 }
01616
01617
01618
01619 while(ralsz > 0)
01620 {myIOLen = ntohl(ralsp->rlen);
01621 n2hll(ralsp->offset, myOffset);
01622 memcpy((void *)&fh.handle, (const void *)ralsp->fhandle,
01623 sizeof(fh.handle));
01624 TRACEP(FS, "fh=" <<fh.handle <<" read " <<myIOLen <<'@' <<myOffset);
01625 if (!FTab || !(myFile = FTab->Get(fh.handle)))
01626 {retc = Response.Send(kXR_FileNotOpen,
01627 "preread does not refer to an open file");
01628 return 1;
01629 }
01630 myFile->XrdSfsp->read(myOffset, myIOLen);
01631 ralsz -= sizeof(struct readahead_list);
01632 ralsp++;
01633 numReads++;
01634 };
01635
01636
01637
01638 return 0;
01639 }
01640
01641
01642
01643
01644
01645 int XrdXrootdProtocol::do_ReadV()
01646 {
01647
01648
01649
01650
01651
01652
01653 const int hdrSZ = sizeof(readahead_list);
01654 XrdXrootdFHandle currFH, lastFH((kXR_char *)"\xff\xff\xff\xff");
01655 struct readahead_list rdVec[maxRvecsz];
01656 long long totLen;
01657 int rdVecNum, rdVecLen = Request.header.dlen;
01658 int i, rc, xframt, Quantum, Qleft;
01659 char *buffp;
01660
01661
01662
01663
01664 rdVecNum = rdVecLen / sizeof(readahead_list);
01665 if ( (rdVecLen <= 0) || (rdVecNum*hdrSZ != rdVecLen) )
01666 {Response.Send(kXR_ArgInvalid, "Read vector is invalid");
01667 return 0;
01668 }
01669
01670
01671
01672
01673
01674 if (rdVecLen > static_cast<int>(sizeof(rdVec)))
01675 {Response.Send(kXR_ArgTooLong, "Read vector is too long");
01676 return 0;
01677 }
01678 memcpy(rdVec, argp->buff, rdVecLen);
01679
01680
01681
01682
01683 totLen = rdVecLen; xframt = maxTransz - hdrSZ;
01684 for (i = 0; i < rdVecNum; i++)
01685 {totLen += (rdVec[i].rlen = ntohl(rdVec[i].rlen));
01686 if (rdVec[i].rlen > xframt)
01687 {Response.Send(kXR_NoMemory, "Single readv transfer is too large");
01688 return 0;
01689 }
01690 }
01691
01692
01693
01694 if (totLen > 0x7fffffffLL)
01695 {Response.Send(kXR_NoMemory, "Total readv transfer is too large");
01696 return 0;
01697 }
01698 if ((Quantum = static_cast<int>(totLen)) > maxTransz) Quantum = maxTransz;
01699
01700
01701
01702 if ((Quantum < halfBSize && Quantum > 1024) || Quantum > argp->bsize)
01703 {if ((rc = getBuff(1, Quantum)) <= 0) return rc;}
01704 else if (hcNow < hcNext) hcNow++;
01705
01706
01707
01708
01709 if (!FTab) return Response.Send(kXR_FileNotOpen,
01710 "readv does not refer to an open file");
01711
01712
01713
01714
01715 Qleft = Quantum; buffp = argp->buff;
01716 for (i = 0; i < rdVecNum; i++)
01717 {
01718
01719
01720 currFH.Set(rdVec[i].fhandle);
01721 if (currFH.handle != lastFH.handle)
01722 {if (!(myFile = FTab->Get(currFH.handle)))
01723 return Response.Send(kXR_FileNotOpen,
01724 "readv does not refer to an open file");
01725 else lastFH.handle = currFH.handle;
01726 }
01727
01728
01729
01730
01731 myIOLen = rdVec[i].rlen;
01732 n2hll(rdVec[i].offset, myOffset);
01733 if (Qleft < (myIOLen + hdrSZ))
01734 {if (Response.Send(kXR_oksofar,argp->buff,Quantum-Qleft) < 0)
01735 return -1;
01736 Qleft = Quantum;
01737 buffp = argp->buff;
01738 }
01739 TRACEP(FS,"fh=" <<currFH.handle <<" readV " << myIOLen <<'@' <<myOffset);
01740 if ((xframt = myFile->XrdSfsp->read(myOffset,buffp+hdrSZ,myIOLen)) < 0)
01741 break;
01742 myFile->readCnt += xframt; numReads++;
01743 rdVec[i].rlen = htonl(xframt);
01744 memcpy(buffp, &rdVec[i], hdrSZ);
01745 buffp += (xframt+hdrSZ); Qleft -= (xframt+hdrSZ);
01746 }
01747
01748
01749
01750 if (i >= rdVecNum)
01751 return Response.Send(argp->buff, Quantum-Qleft);
01752 return Response.Send(kXR_FSError, myFile->XrdSfsp->error.getErrText());
01753 }
01754
01755
01756
01757
01758
01759 int XrdXrootdProtocol::do_Rm()
01760 {
01761 int rc;
01762 const char *opaque;
01763 XrdOucErrInfo myError(Link->ID);
01764
01765
01766
01767 if (Route[RD_rm].Port)
01768 return Response.Send(kXR_redirect,Route[RD_rm].Port,Route[RD_rm].Host);
01769
01770
01771
01772 if (rpCheck(argp->buff, &opaque)) return rpEmsg("Removing", argp->buff);
01773 if (!Squash(argp->buff)) return vpEmsg("Removing", argp->buff);
01774
01775
01776
01777 rc = osFS->rem(argp->buff, myError, CRED, opaque);
01778 TRACEP(FS, "rc=" <<rc <<" rm " <<argp->buff);
01779 if (SFS_OK == rc) return Response.Send();
01780
01781
01782
01783 return fsError(rc, myError);
01784 }
01785
01786
01787
01788
01789
01790 int XrdXrootdProtocol::do_Rmdir()
01791 {
01792 int rc;
01793 const char *opaque;
01794 XrdOucErrInfo myError(Link->ID);
01795
01796
01797
01798 if (Route[RD_rmdir].Port)
01799 return Response.Send(kXR_redirect,Route[RD_rmdir].Port,Route[RD_rmdir].Host);
01800
01801
01802
01803 if (rpCheck(argp->buff, &opaque)) return rpEmsg("Removing", argp->buff);
01804 if (!Squash(argp->buff)) return vpEmsg("Removing", argp->buff);
01805
01806
01807
01808 rc = osFS->remdir(argp->buff, myError, CRED, opaque);
01809 TRACEP(FS, "rc=" <<rc <<" rmdir " <<argp->buff);
01810 if (SFS_OK == rc) return Response.Send();
01811
01812
01813
01814 return fsError(rc, myError);
01815 }
01816
01817
01818
01819
01820
01821 int XrdXrootdProtocol::do_Set()
01822 {
01823 XrdOucTokenizer setargs(argp->buff);
01824 char *val, *rest;
01825
01826
01827
01828 if (!setargs.GetLine() || !(val = setargs.GetToken(&rest)))
01829 return Response.Send(kXR_ArgMissing, "set argument not specified.");
01830
01831
01832
01833 TRACEP(DEBUG, "set " <<val <<' ' <<rest);
01834
01835
01836
01837 if (!strcmp("appid", val))
01838 {while(*rest && *rest == ' ') rest++;
01839 eDest.Emsg("Xeq", Link->ID, "appid", rest);
01840 return Response.Send();
01841 }
01842 else if (!strcmp("monitor", val)) return do_Set_Mon(setargs);
01843
01844
01845
01846 return Response.Send(kXR_ArgInvalid, "invalid set parameter");
01847 }
01848
01849
01850
01851
01852
01853
01854
01855 int XrdXrootdProtocol::do_Set_Mon(XrdOucTokenizer &setargs)
01856 {
01857 char *val, *appid;
01858 kXR_unt32 myseq = 0;
01859
01860
01861
01862 if (!(val = setargs.GetToken(&appid)))
01863 return Response.Send(kXR_ArgMissing,"set monitor argument not specified.");
01864
01865
01866
01867
01868
01869 if (!strcmp(val, "info"))
01870 {if (appid && XrdXrootdMonitor::monINFO)
01871 {while(*appid && *appid == ' ') appid++;
01872 if (strlen(appid) > 1024) appid[1024] = '\0';
01873 if (*appid) myseq = XrdXrootdMonitor::Map(XROOTD_MON_MAPINFO,
01874 Link->ID, appid);
01875 }
01876 return Response.Send((void *)&myseq, sizeof(myseq));
01877 }
01878
01879
01880
01881 if (!strcmp(val, "on"))
01882 {if (Monitor || (Monitor = XrdXrootdMonitor::Alloc(1)))
01883 {if (appid && XrdXrootdMonitor::monIO)
01884 {while(*appid && *appid == ' ') appid++;
01885 if (*appid) Monitor->appID(appid);
01886 }
01887 monIO = XrdXrootdMonitor::monIO;
01888 monFILE = XrdXrootdMonitor::monFILE;
01889 if (XrdXrootdMonitor::monUSER && !monUID)
01890 monUID = XrdXrootdMonitor::Map(XROOTD_MON_MAPUSER, Link->ID, 0);
01891 }
01892 return Response.Send();
01893 }
01894
01895
01896
01897 if (!strcmp(val, "off"))
01898 {if (Monitor)
01899 {if (appid && XrdXrootdMonitor::monIO)
01900 {while(*appid && *appid == ' ') appid++;
01901 if (*appid) Monitor->appID(appid);
01902 }
01903 Monitor->unAlloc(Monitor); Monitor = 0; monIO = monFILE = 0;
01904 }
01905 return Response.Send();
01906 }
01907
01908
01909
01910 return Response.Send(kXR_ArgInvalid, "invalid set monitor argument");
01911 }
01912
01913
01914
01915
01916
01917 int XrdXrootdProtocol::do_Stat()
01918 {
01919 static XrdXrootdCallBack statCB("stat");
01920 static const int fsctl_cmd = SFS_FSCTL_STATFS;
01921 int rc;
01922 const char *opaque;
01923 char xxBuff[256];
01924 struct stat buf;
01925 XrdOucErrInfo myError(Link->ID, &statCB, ReqID.getID());
01926
01927
01928
01929 if (Route[RD_stat].Port)
01930 return Response.Send(kXR_redirect,Route[RD_stat].Port,Route[RD_stat].Host);
01931
01932
01933
01934 if (rpCheck(argp->buff, &opaque)) return rpEmsg("Stating", argp->buff);
01935 if (!Squash(argp->buff)) return vpEmsg("Stating", argp->buff);
01936
01937
01938
01939 if (Request.stat.options & kXR_vfs)
01940 {rc = osFS->fsctl(fsctl_cmd, argp->buff, myError, CRED);
01941 TRACEP(FS, "rc=" <<rc <<" statfs " <<argp->buff);
01942 if (rc == SFS_OK) Response.Send("");
01943 } else {
01944 rc = osFS->stat(argp->buff, &buf, myError, CRED, opaque);
01945 TRACEP(FS, "rc=" <<rc <<" stat " <<argp->buff);
01946 if (rc == SFS_OK) return Response.Send(xxBuff, StatGen(buf, xxBuff));
01947 }
01948 return fsError(rc, myError);
01949 }
01950
01951
01952
01953
01954
01955 int XrdXrootdProtocol::do_Statx()
01956 {
01957 static XrdXrootdCallBack statxCB("xstat");
01958 int rc;
01959 const char *opaque;
01960 char *path, *respinfo = argp->buff;
01961 mode_t mode;
01962 XrdOucErrInfo myError(Link->ID, &statxCB, ReqID.getID());
01963 XrdOucTokenizer pathlist(argp->buff);
01964
01965
01966
01967 while((path = pathlist.GetLine()))
01968 {if (rpCheck(path, &opaque)) return rpEmsg("Stating", path);
01969 if (!Squash(path)) return vpEmsg("Stating", path);
01970 rc = osFS->stat(path, mode, myError, CRED, opaque);
01971 TRACEP(FS, "rc=" <<rc <<" stat " <<path);
01972 if (rc != SFS_OK) return fsError(rc, myError);
01973 else {if (mode == (mode_t)-1) *respinfo = (char)kXR_offline;
01974 else if (S_ISDIR(mode)) *respinfo = (char)kXR_isDir;
01975 else *respinfo = (char)kXR_file;
01976 }
01977 respinfo++;
01978 }
01979
01980
01981
01982 return Response.Send(argp->buff, respinfo-argp->buff);
01983 }
01984
01985
01986
01987
01988
01989 int XrdXrootdProtocol::do_Sync()
01990 {
01991 int rc;
01992 XrdXrootdFile *fp;
01993 XrdXrootdFHandle fh(Request.sync.fhandle);
01994
01995
01996
01997 UPSTATS(syncCnt);
01998
01999
02000
02001 if (!FTab || !(fp = FTab->Get(fh.handle)))
02002 return Response.Send(kXR_FileNotOpen,"sync does not refer to an open file");
02003
02004
02005
02006 rc = fp->XrdSfsp->sync();
02007 TRACEP(FS, "sync rc=" <<rc <<" fh=" <<fh.handle);
02008 if (SFS_OK != rc)
02009 return Response.Send(kXR_FSError, fp->XrdSfsp->error.getErrText());
02010
02011
02012
02013 return Response.Send();
02014 }
02015
02016
02017
02018
02019
02020 int XrdXrootdProtocol::do_Truncate()
02021 {
02022 XrdXrootdFile *fp;
02023 XrdXrootdFHandle fh(Request.truncate.fhandle);
02024 long long theOffset;
02025 int rc;
02026
02027
02028
02029 n2hll(Request.truncate.offset, theOffset);
02030
02031
02032
02033 if (!Request.header.dlen)
02034 {
02035
02036
02037 UPSTATS(miscCnt);
02038
02039
02040
02041 if (!FTab || !(fp = FTab->Get(fh.handle)))
02042 return Response.Send(kXR_FileNotOpen,
02043 "trunc does not refer to an open file");
02044
02045
02046
02047 rc = fp->XrdSfsp->truncate(theOffset);
02048 TRACEP(FS, "trunc rc=" <<rc <<" sz=" <<theOffset <<" fh=" <<fh.handle);
02049 if (SFS_OK != rc)
02050 return Response.Send(kXR_FSError, fp->XrdSfsp->error.getErrText());
02051
02052 } else {
02053
02054 XrdOucErrInfo myError(Link->ID);
02055 const char *opaque;
02056
02057
02058
02059 if (rpCheck(argp->buff,&opaque)) return rpEmsg("Truncating",argp->buff);
02060 if (!Squash(argp->buff)) return vpEmsg("Truncating",argp->buff);
02061
02062
02063
02064 rc = osFS->truncate(argp->buff, (XrdSfsFileOffset)theOffset, myError,
02065 CRED, opaque);
02066 TRACEP(FS, "rc=" <<rc <<" trunc " <<theOffset <<' ' <<argp->buff);
02067 if (SFS_OK != rc) return fsError(rc, myError);
02068 }
02069
02070
02071
02072 return Response.Send();
02073 }
02074
02075
02076
02077
02078
02079 int XrdXrootdProtocol::do_Write()
02080 {
02081 int retc, pathID;
02082 XrdXrootdFHandle fh(Request.write.fhandle);
02083 numWrites++;
02084
02085
02086
02087 myIOLen = Request.header.dlen;
02088 n2hll(Request.write.offset, myOffset);
02089 pathID = static_cast<int>(Request.write.pathid);
02090
02091
02092
02093 if (!FTab || !(myFile = FTab->Get(fh.handle)))
02094 {if (argp) return do_WriteNone();
02095 Response.Send(kXR_FileNotOpen,"write does not refer to an open file");
02096 return Link->setEtext("write protcol violation");
02097 }
02098
02099
02100
02101 if (monIO && Monitor) Monitor->Add_wr(myFile->FileID, Request.write.dlen,
02102 Request.write.offset);
02103
02104
02105
02106 TRACEP(FS, "fh=" <<fh.handle <<" write " <<myIOLen <<'@' <<myOffset);
02107 if (myIOLen <= 0) return Response.Send();
02108
02109
02110
02111 if (pathID) return do_Offload(pathID, 1);
02112
02113
02114
02115 if (myFile->AsyncMode && !as_syncw)
02116 {if (myStalls > as_maxstalls) myStalls--;
02117 else if (myIOLen >= as_miniosz && Link->UseCnt() < as_maxperlnk)
02118 {if ((retc = aio_Write()) != -EAGAIN)
02119 {if (retc == -EIO) return do_WriteNone();
02120 else return retc;
02121 }
02122 }
02123 SI->AsyncRej++;
02124 }
02125
02126
02127
02128 myFile->writeCnt += myIOLen;
02129 return do_WriteAll();
02130 }
02131
02132
02133
02134
02135
02136
02137
02138
02139
02140 int XrdXrootdProtocol::do_WriteAll()
02141 {
02142 int rc, Quantum = (myIOLen > maxBuffsz ? maxBuffsz : myIOLen);
02143
02144
02145
02146 if (!argp || Quantum < halfBSize || Quantum > argp->bsize)
02147 {if ((rc = getBuff(0, Quantum)) <= 0) return rc;}
02148 else if (hcNow < hcNext) hcNow++;
02149
02150
02151
02152 while(myIOLen > 0)
02153 {if ((rc = getData("data", argp->buff, Quantum)))
02154 {if (rc > 0)
02155 {Resume = &XrdXrootdProtocol::do_WriteCont;
02156 myBlast = Quantum;
02157 myStalls++;
02158 }
02159 return rc;
02160 }
02161 if (myFile->XrdSfsp->write(myOffset, argp->buff, Quantum) < 0)
02162 {myIOLen = myIOLen-Quantum;
02163 return do_WriteNone();
02164 }
02165 myOffset += Quantum; myIOLen -= Quantum;
02166 if (myIOLen < Quantum) Quantum = myIOLen;
02167 }
02168
02169
02170
02171 return Response.Send();
02172 }
02173
02174
02175
02176
02177
02178
02179
02180
02181
02182
02183 int XrdXrootdProtocol::do_WriteCont()
02184 {
02185
02186
02187
02188 if (myFile->XrdSfsp->write(myOffset, argp->buff, myBlast) < 0)
02189 {myIOLen = myIOLen-myBlast;
02190 return do_WriteNone();
02191 }
02192 myOffset += myBlast; myIOLen -= myBlast;
02193
02194
02195
02196 if (myIOLen > 0) return do_WriteAll();
02197 return Response.Send();
02198 }
02199
02200
02201
02202
02203
02204 int XrdXrootdProtocol::do_WriteNone()
02205 {
02206 int rlen, blen = (myIOLen > argp->bsize ? argp->bsize : myIOLen);
02207
02208
02209
02210 TRACEP(REQ, "discarding " <<myIOLen <<" bytes");
02211 while(myIOLen > 0)
02212 {rlen = Link->Recv(argp->buff, blen, readWait);
02213 if (rlen < 0) return Link->setEtext("link read error");
02214 myIOLen -= rlen;
02215 if (rlen < blen)
02216 {myBlen = 0;
02217 Resume = &XrdXrootdProtocol::do_WriteNone;
02218 return 1;
02219 }
02220 if (myIOLen < blen) blen = myIOLen;
02221 }
02222
02223
02224
02225 return Response.Send(kXR_FSError, myFile->XrdSfsp->error.getErrText());
02226 }
02227
02228
02229
02230
02231
02232
02233
02234
02235 int XrdXrootdProtocol::fsError(int rc, XrdOucErrInfo &myError)
02236 {
02237 int ecode;
02238 const char *eMsg = myError.getErrText(ecode);
02239
02240
02241
02242 if (rc == SFS_ERROR)
02243 {SI->errorCnt++;
02244 rc = mapError(ecode);
02245 return Response.Send((XErrorCode)rc, eMsg);
02246 }
02247
02248
02249
02250 if (rc == SFS_REDIRECT)
02251 {SI->redirCnt++;
02252 if (ecode <= 0) ecode = (ecode ? -ecode : Port);
02253 TRACEI(REDIR, Response.ID() <<"redirecting to " << eMsg <<':' <<ecode);
02254 return Response.Send(kXR_redirect, ecode, eMsg);
02255 }
02256
02257
02258
02259
02260
02261
02262 if (rc == SFS_STARTED)
02263 {SI->stallCnt++;
02264 if (ecode <= 0) ecode = 1800;
02265 TRACEI(STALL, Response.ID() <<"delaying client up to " <<ecode <<" sec");
02266 rc = Response.Send(kXR_waitresp, ecode, eMsg);
02267 if (myError.getErrCB()) myError.getErrCB()->Done(ecode, &myError);
02268 return (rc ? rc : 1);
02269 }
02270
02271
02272
02273 if (rc == SFS_DATA)
02274 {if (ecode) return Response.Send((void *)eMsg, ecode);
02275 else return Response.Send();
02276 }
02277
02278
02279
02280 if (rc >= SFS_STALL)
02281 {SI->stallCnt++;
02282 TRACEI(STALL, Response.ID() <<"stalling client for " <<rc <<" sec");
02283 return (rc = Response.Send(kXR_wait, rc, eMsg)) ? rc : 1;
02284 }
02285
02286
02287
02288 {char buff[32];
02289 SI->errorCnt++;
02290 sprintf(buff, "%d", rc);
02291 eDest.Emsg("Xeq", "Unknown error code", buff, eMsg);
02292 return Response.Send(kXR_ServerError, eMsg);
02293 }
02294 }
02295
02296
02297
02298
02299
02300 int XrdXrootdProtocol::getBuff(const int isRead, int Quantum)
02301 {
02302
02303
02304
02305 if (!argp || Quantum > argp->bsize) hcNow = hcPrev;
02306 else if (Quantum >= halfBSize || hcNow-- > 0) return 1;
02307 else if (hcNext >= hcMax) hcNow = hcMax;
02308 else {int tmp = hcPrev;
02309 hcNow = hcNext;
02310 hcPrev = hcNext;
02311 hcNext = tmp+hcNext;
02312 }
02313
02314
02315
02316 if (argp) BPool->Release(argp);
02317 if ((argp = BPool->Obtain(Quantum))) halfBSize = argp->bsize >> 1;
02318 else return Response.Send(kXR_NoMemory, (isRead ?
02319 "insufficient memory to read file" :
02320 "insufficient memory to write file"));
02321
02322
02323
02324 return 1;
02325 }
02326
02327
02328
02329
02330
02331 int XrdXrootdProtocol::mapError(int rc)
02332 {
02333 if (rc < 0) rc = -rc;
02334 switch(rc)
02335 {case ENOENT: return kXR_NotFound;
02336 case EPERM: return kXR_NotAuthorized;
02337 case EACCES: return kXR_NotAuthorized;
02338 case EIO: return kXR_IOError;
02339 case ENOMEM: return kXR_NoMemory;
02340 case ENOBUFS: return kXR_NoMemory;
02341 case ENOSPC: return kXR_NoSpace;
02342 case ENAMETOOLONG: return kXR_ArgTooLong;
02343 case ENETUNREACH: return kXR_noserver;
02344 case ENOTBLK: return kXR_NotFile;
02345 case EISDIR: return kXR_isDirectory;
02346 case EEXIST: return kXR_InvalidRequest;
02347 case ETXTBSY: return kXR_inProgress;
02348 default: return kXR_FSError;
02349 }
02350 }
02351
02352
02353
02354
02355
02356 #define Map_Mode(x,y) if (Mode & kXR_ ## x) newmode |= S_I ## y
02357
02358 int XrdXrootdProtocol::mapMode(int Mode)
02359 {
02360 int newmode = 0;
02361
02362
02363
02364 Map_Mode(ur, RUSR); Map_Mode(uw, WUSR); Map_Mode(ux, XUSR);
02365 Map_Mode(gr, RGRP); Map_Mode(gw, WGRP); Map_Mode(gx, XGRP);
02366 Map_Mode(or, ROTH); Map_Mode(ox, XOTH);
02367
02368
02369
02370 return newmode;
02371 }
02372
02373
02374
02375
02376
02377 int XrdXrootdProtocol::rpCheck(char *fn, const char **opaque)
02378 {
02379 char *cp;
02380
02381 if (*fn != '/') return 1;
02382
02383 if (!(cp = index(fn, '?'))) *opaque = 0;
02384 else {*cp = '\0'; *opaque = cp+1;
02385 if (!**opaque) *opaque = 0;
02386 }
02387
02388 while ((cp = index(fn, '/')))
02389 {fn = cp+1;
02390 if (fn[0] == '.' && fn[1] == '.' && fn[2] == '/') return 1;
02391 }
02392 return 0;
02393 }
02394
02395
02396
02397
02398
02399 int XrdXrootdProtocol::rpEmsg(const char *op, char *fn)
02400 {
02401 char buff[2048];
02402 snprintf(buff,sizeof(buff)-1,"%s relative path '%s' is disallowed.",op,fn);
02403 buff[sizeof(buff)-1] = '\0';
02404 return Response.Send(kXR_NotAuthorized, buff);
02405 }
02406
02407
02408
02409
02410
02411 int XrdXrootdProtocol::Squash(char *fn)
02412 {
02413 char *ofn, *ifn = fn;
02414
02415 while(*ifn)
02416 {if (*ifn == '/')
02417 if (*(ifn+1) == '/'
02418 || (*(ifn+1) == '.' && *(ifn+1) && *(ifn+2) == '/')) break;
02419 ifn++;
02420 }
02421
02422 if (!*ifn) return XPList.Validate(fn, ifn-fn);
02423
02424 ofn = ifn;
02425 while(*ifn) {*ofn = *ifn++;
02426 while(*ofn == '/')
02427 {while(*ifn == '/') ifn++;
02428 if (ifn[0] == '.' && ifn[1] == '/') ifn += 2;
02429 else break;
02430 }
02431 ofn++;
02432 }
02433 *ofn = '\0';
02434
02435 return XPList.Validate(fn, ofn-fn);
02436 }
02437
02438
02439
02440
02441
02442 #define XRDXROOTD_STAT_CLASSNAME XrdXrootdProtocol
02443 #include "XrdXrootd/XrdXrootdStat.icc"
02444
02445
02446
02447
02448
02449 int XrdXrootdProtocol::vpEmsg(const char *op, char *fn)
02450 {
02451 char buff[2048];
02452 snprintf(buff,sizeof(buff)-1,"%s path '%s' is disallowed.",op,fn);
02453 buff[sizeof(buff)-1] = '\0';
02454 return Response.Send(kXR_NotAuthorized, buff);
02455 }