diff --git a/src/XrdPosix/XrdPosixFile.cc b/src/XrdPosix/XrdPosixFile.cc index baae9cf027c..1d64f97a84d 100644 --- a/src/XrdPosix/XrdPosixFile.cc +++ b/src/XrdPosix/XrdPosixFile.cc @@ -38,10 +38,12 @@ #include #include +#include "XrdOuc/XrdOucName2Name.hh" #include "XrdPosix/XrdPosixCallBack.hh" #include "XrdPosix/XrdPosixFile.hh" #include "XrdPosix/XrdPosixFileRH.hh" #include "XrdPosix/XrdPosixPrepIO.hh" +#include "XrdPosix/XrdPosixXrootdPath.hh" #include "XrdSys/XrdSysTimer.hh" @@ -51,8 +53,9 @@ namespace XrdPosixGlobals { -extern XrdOucCache2 *theCache; -extern bool psxDBG; +extern XrdOucCache2 *theCache; +extern XrdOucName2Name *theN2N; +extern bool psxDBG; }; namespace @@ -81,14 +84,20 @@ int XrdPosixFile::ddNum = 0; /* C o n s t r u c t o r */ /******************************************************************************/ -XrdPosixFile::XrdPosixFile(const char *path, XrdPosixCallBack *cbP, int Opts) +XrdPosixFile::XrdPosixFile(bool &aOK, const char *path, XrdPosixCallBack *cbP, + int Opts) : XCio((XrdOucCacheIO2 *)this), PrepIO(0), mySize(0), myMtime(0), myInode(0), myMode(0), - theCB(cbP), - fPath(strdup(path)), fLoc(0), - cOpt(0), + theCB(cbP), fLoc(0), cOpt(0), isStream(Opts & isStrm ? 1 : 0) { +// Handle path generation. This is trickt as we may have two namespaces. One +// for the origin and one for the cache. +// + fOpen = strdup(path); aOK = true; + if (!XrdPosixGlobals::theN2N || !XrdPosixGlobals::theCache) fPath = fOpen; + else if (!XrdPosixXrootPath::P2L("new file",path,fPath)) aOK = false; + else if (!fPath) fPath = fOpen; // Check for structured file check // @@ -124,6 +133,7 @@ XrdPosixFile::~XrdPosixFile() // Free the path and location information // if (fPath) free(fPath); + if (fOpen != fPath) free(fOpen); if (fLoc) free(fLoc); } @@ -188,7 +198,7 @@ do{if (doWait) {numLost++; ddCount--; snprintf(eBuff, sizeof(eBuff), "PosixFile: %s timeout closing %s; %d objects lost!\n", - eTxt, fCurr->Path(), numLost); + eTxt, fCurr->Origin(), numLost); std::cerr <nextFile = ddLost; ddLost = fCurr; @@ -237,7 +247,7 @@ void XrdPosixFile::DelayedDestroy(XrdPosixFile *fp) {char eBuff[2048]; snprintf(eBuff, sizeof(eBuff), "PosixFile: DLY destory %s %d objects; added %s.\n", - (doPost ? "post" : "has "), ddCount, fp->Path()); + (doPost ? "post" : "has "), ddCount, fp->Origin()); std::cerr <clFile.Open((std::string)fileP->Path(), clFlags, clMode); + Status = fileP->clFile.Open((std::string)fileP->Origin(), clFlags, clMode); // If all went well, then we need to do a Stat() call on the underlying file // @@ -87,7 +87,7 @@ bool XrdPosixPrepIO::Init(XrdOucCacheIOCB *iocbP) if (XrdPosixGlobals::psxDBG && errno != ENOENT && errno != ELOOP) {char eBuff[2048]; snprintf(eBuff, sizeof(eBuff), "%s deferred open %s\n", - Status.ToString().c_str(), fileP->Path()); + Status.ToString().c_str(), fileP->Origin()); std::cerr <Path()); + Status.ToString().c_str(), fP->Origin()); std::cerr <Path()); + Status.ToString().c_str(), fp->Origin()); std::cerr <Rename(urlp.c_str(), nurlp.c_str()); + if (XrdPosixGlobals::theCache) + {LfnPath oldF("rename", oldpath); + LfnPath newF("rename", newpath); + if (!oldF.path || !newF.path) return -1; + XrdPosixGlobals::theCache->Rename(oldF.path, newF.path); + } - return res; +// Issue the rename +// + return XrdPosixMap::Result(admin.Xrd.Mv(admin.Url.GetPathWithParams(), + newUrl.GetPathWithParams())); } /******************************************************************************/ @@ -967,20 +1004,23 @@ void XrdPosixXrootd::Rewinddir(DIR *dirp) int XrdPosixXrootd::Rmdir(const char *path) { - XrdPosixAdmin admin(path); + XrdPosixAdmin admin(path); // Make sure the admin is OK // - if (!admin.isOK()) return -1; + if (!admin.isOK()) return -1; -// Issue the rmdir +// Remove directory from the cache first // - std::string urlp = admin.Url.GetPathWithParams(); - int res = XrdPosixMap::Result(admin.Xrd.RmDir(urlp)); - if (!res && XrdPosixGlobals::theCache) - XrdPosixGlobals::theCache->Rmdir(urlp.c_str()); + if (XrdPosixGlobals::theCache) + {LfnPath rmd("rmdir", path); + if (!rmd.path) return -1; + XrdPosixGlobals::theCache->Rmdir(rmd.path); + } - return res; +// Issue the rmdir +// + return XrdPosixMap::Result(admin.Xrd.RmDir(admin.Url.GetPathWithParams())); } /******************************************************************************/ @@ -1030,8 +1070,9 @@ int XrdPosixXrootd::Stat(const char *path, struct stat *buf) // Check if we can get the stat informatation from the cache // if (myCache2) - {std::string urlp = admin.Url.GetPathWithParams(); - int rc = myCache2->Stat(urlp.c_str(), *buf); + {LfnPath statX("stat", path, false); + if (!statX.path) return -1; + int rc = myCache2->Stat(statX.path, *buf); if (!rc) return 0; if (rc < 0) {errno = -rc; return -1;} } @@ -1186,18 +1227,20 @@ int XrdPosixXrootd::Truncate(const char *path, off_t Size) // Make sure the admin is OK // - if (!admin.isOK()) return -1; + if (!admin.isOK()) return -1; -// Issue the truncate +// Truncate in the cache first // - std::string urlp = admin.Url.GetPathWithParams(); - int res = XrdPosixMap::Result(admin.Xrd.Truncate(urlp,tSize)); - - if (!res && XrdPosixGlobals::theCache) { - XrdPosixGlobals::theCache->Truncate(urlp.c_str(), tSize); - } + if (XrdPosixGlobals::theCache) + {LfnPath trunc("truncate", path); + if (!trunc.path) return -1; + XrdPosixGlobals::theCache->Truncate(trunc.path, tSize); + } - return res; +// Issue the truncate to the origin +// + std::string urlp = admin.Url.GetPathWithParams(); + return XrdPosixMap::Result(admin.Xrd.Truncate(urlp,tSize)); } /******************************************************************************/ @@ -1206,20 +1249,23 @@ int XrdPosixXrootd::Truncate(const char *path, off_t Size) int XrdPosixXrootd::Unlink(const char *path) { - XrdPosixAdmin admin(path); + XrdPosixAdmin admin(path); // Make sure the admin is OK // - if (!admin.isOK()) return -1; + if (!admin.isOK()) return -1; -// Issue the UnLink +// Unlink the cache first // - std::string urlp = admin.Url.GetPathWithParams(); - int res = XrdPosixMap::Result(admin.Xrd.Rm(urlp)); - if (!res && XrdPosixGlobals::theCache) - XrdPosixGlobals::theCache->Unlink(urlp.c_str()); + if (XrdPosixGlobals::theCache) + {LfnPath remf("unlink", path); + if (!remf.path) return -1; + XrdPosixGlobals::theCache->Unlink(remf.path); + } - return res; +// Issue the UnLink +// + return XrdPosixMap::Result(admin.Xrd.Rm(admin.Url.GetPathWithParams())); } /******************************************************************************/ @@ -1556,6 +1602,15 @@ void XrdPosixXrootd::setNumCB(int numcb) if (numcb >= 0) XrdPosixFileRH::SetMax(numcb); } +/******************************************************************************/ +/* S e t N 2 N */ +/******************************************************************************/ + +void XrdPosixXrootd::setN2N(XrdOucName2Name *pN2N, int opts) +{ + XrdPosixGlobals::theN2N = pN2N; +} + /******************************************************************************/ /* s e t S c h e d */ /******************************************************************************/ diff --git a/src/XrdPosix/XrdPosixXrootd.hh b/src/XrdPosix/XrdPosixXrootd.hh index 92dce68f2e4..c7738d2741f 100644 --- a/src/XrdPosix/XrdPosixXrootd.hh +++ b/src/XrdPosix/XrdPosixXrootd.hh @@ -53,6 +53,7 @@ class XrdScheduler; class XrdOucCache; class XrdOucCache2; class XrdOucEnv; +class XrdOucName2Name; class XrdPosixCallBack; class XrdPosixCallBackIO; class XrdPosixFile; @@ -367,6 +368,8 @@ static void setIPV4(bool userv4); static void setNumCB(int numcb); +static void setN2N(XrdOucName2Name *pN2N, int opts=0); + static void setSched(XrdScheduler *sP); /* There must be one instance of this object per executable image. Typically, diff --git a/src/XrdPosix/XrdPosixXrootdPath.cc b/src/XrdPosix/XrdPosixXrootdPath.cc index a3bf1023d96..c71f2dc1a58 100644 --- a/src/XrdPosix/XrdPosixXrootdPath.cc +++ b/src/XrdPosix/XrdPosixXrootdPath.cc @@ -28,14 +28,35 @@ /* specific prior written permission of the institution or contributor. */ /******************************************************************************/ +#include +#include #include #include #include #include +#include "XrdOuc/XrdOucName2Name.hh" #include "XrdOuc/XrdOucTokenizer.hh" #include "XrdPosix/XrdPosixXrootdPath.hh" #include "XrdSys/XrdSysHeaders.hh" + +/******************************************************************************/ +/* S t a t i c s */ +/******************************************************************************/ + +namespace +{ +const char *rproto = "root://"; +const char *xproto = "xroot://"; +const int rprlen = strlen(rproto); +const int xprlen = strlen(xproto); +} + +namespace XrdPosixGlobals +{ +extern XrdOucName2Name *theN2N; +extern bool psxDBG; +} /******************************************************************************/ /* X r d P o s i x X r o o t P a t h C o n s t r u c t o r */ @@ -103,16 +124,99 @@ void XrdPosixXrootPath::CWD(const char *path) } } +/******************************************************************************/ +/* X r d P o s i x P a t h : : P 2 L */ +/******************************************************************************/ + +const char *XrdPosixXrootPath::P2L(const char *who, + const char *inP, + char *&relP, + bool ponly) +{ + const char *urlP, *slash, *quest; + char *outP, pfnBuff[1032], lfnBuff[1032]; + int cgiLen, lfnLen, pfnLen, pfxLen, n; + +// Preset repP to zero to indicate no translation required, nothing to free +// + relP = 0; + +// If this starts with "root" or "xroot", then we can convert the path +// + if (!XrdPosixGlobals::theN2N && !ponly) return inP; + else if (!strncmp(rproto, inP, rprlen)) urlP = inP + rprlen; + else if (!strncmp(xproto, inP, xprlen)) urlP = inP + xprlen; + else return inP; + +// Search for the next slash which must be followed by another slash +// + if (!(slash = index(urlP, '/')) || *(slash+1) != '/') return inP; + slash++; + pfxLen = slash - inP; + +// Search for start of the cgi +// + if ((quest = index(slash, '?'))) + {cgiLen = strlen(quest); + pfnLen = quest - slash; + } else { + cgiLen = 0; + pfnLen = strlen(slash); + } + +// Copy out the pfn. It must fit our buffer +// + if (pfnLen >= (int)sizeof(pfnBuff)) + {errno = ENAMETOOLONG; + return 0; + } + strncpy(pfnBuff, slash, pfnLen); + *(pfnBuff+pfnLen) = 0; + +// Invoke the name2name translator if we have one +// + if (XrdPosixGlobals::theN2N) + {if ((n = XrdPosixGlobals::theN2N->pfn2lfn(pfnBuff,lfnBuff,sizeof(lfnBuff)))) + {errno = n; + return 0; + } + } + +// If only the path is wanted, then adjust lengths +// + if (ponly) pfxLen = cgiLen = 0; + +// Allocate storage to assemble the new url +// + lfnLen = strlen(lfnBuff); + if (!(relP = (char *)malloc(pfxLen + lfnLen + cgiLen + 1))) + {errno = ENOMEM; + return 0; + } + outP = relP; + +// Assemble the new url, we know we have room to do this +// + if (pfxLen) {strncpy(outP, inP, pfxLen); outP += pfxLen;} + strcpy( outP, lfnBuff); + if (cgiLen) strcpy(outP+lfnLen, quest); + +// Do some debugging +// + if (XrdPosixGlobals::psxDBG) + std::cerr<<"Posix: "<lfn2pfn(path, Apath, sizeof(Apath)))) - return 0; + {if (retc > 0) retc = -retc; return 0;} fname = Apath; } pathln = strlen(fname); diff --git a/src/XrdPss/XrdPss.hh b/src/XrdPss/XrdPss.hh index d4d1fc00be1..3373fc6d060 100644 --- a/src/XrdPss/XrdPss.hh +++ b/src/XrdPss/XrdPss.hh @@ -151,7 +151,7 @@ static char *P2OUT(int &retc, char *pbuff, int pblen, static char *P2URL(int &retc, char *pbuff, int pblen, const char *path, int Split=0, const char *Cgi=0, int CgiLn=0, - const char *tIdent=0, int doN2N=1); + const char *tIdent=0, bool doN2N=true); static int T2UID(const char *Ident); static const char *ConfigFN; // -> Pointer to the config file name @@ -173,6 +173,9 @@ static int Streams; static int Workers; static int Trace; +static bool xLfn2Pfn; +static bool xPfn2Lfn; + static bool outProxy; // True means outgoing proxy static bool pfxProxy; // True means outgoing proxy is prefixed @@ -183,6 +186,7 @@ static char allRmdir; static char allRm; static char allTrunc; +static bool mCache; static char cfgDone; // Configuration completed XrdPssSys(); diff --git a/src/XrdPss/XrdPssConfig.cc b/src/XrdPss/XrdPssConfig.cc index f77183e33f3..ef4c82f9775 100644 --- a/src/XrdPss/XrdPssConfig.cc +++ b/src/XrdPss/XrdPssConfig.cc @@ -108,11 +108,15 @@ char XrdPssSys::allRm = 0; char XrdPssSys::allRmdir = 0; char XrdPssSys::allTrunc = 0; -char XrdPssSys::cfgDone = 0; +bool XrdPssSys::xLfn2Pfn = true; +bool XrdPssSys::xPfn2Lfn = false; bool XrdPssSys::outProxy = false; bool XrdPssSys::pfxProxy = false; +bool XrdPssSys::mCache = false; +char XrdPssSys::cfgDone = 0; + namespace XrdProxy { static XrdPosixXrootd *Xroot; @@ -403,13 +407,26 @@ int XrdPssSys::ConfigN2N() // Skip all of this we are not doing name mapping // - if (!N2NLib && !LocalRoot) return 0; + if (!N2NLib && !LocalRoot) + {xLfn2Pfn = xPfn2Lfn = false; return 0;} + +// Check if the n2n is applicable +// + if (xPfn2Lfn && !(mCache || cPath)) + {const char *txt = (xLfn2Pfn ? "-lfncache option" : "directive"); + eDest.Say("Config warning: ignoring namelib ", txt, + "; caching not in effect!"); + if (!xLfn2Pfn) return 0; + } // Get the plugin // - if ((theN2N = n2nLoader.Load(N2NLib, *myVersion))) - return 0; - return 1; + if (!(theN2N = n2nLoader.Load(N2NLib, *myVersion))) return 1; + +// Check if this also applies to the posix layer +// + if (xPfn2Lfn) XrdPosixXrootd::setN2N(theN2N); + return 0; } /******************************************************************************/ @@ -550,6 +567,7 @@ int XrdPssSys::xcach(XrdSysError *Eroute, XrdOucStream &Config) // If we have no parameters, then we just use the defaults // + mCache = true; if (!(val = Config.GetWord())) {XrdOucEnv::Export("XRDPOSIX_CACHE", "mode=s&optwr=0"); return 0;} *pBuff = 0; @@ -841,8 +859,9 @@ int XrdPssSys::xinet(XrdSysError *Eroute, XrdOucStream &Config) /* Function: xnml - Purpose: To parse the directive: namelib [] + Purpose: To parse the directive: namelib [] pfn [] + one or more: [-lfn2pfn] [-lfncache] the path of the filesystem library to be used. optional parms to be passed @@ -852,10 +871,22 @@ int XrdPssSys::xinet(XrdSysError *Eroute, XrdOucStream &Config) int XrdPssSys::xnml(XrdSysError *Eroute, XrdOucStream &Config) { char *val, parms[1024]; + bool l2p = false, p2l = false; + +// Parse options, if any +// + while((val = Config.GetWord()) && val[0]) + { if (!strcmp(val, "-lfn2pfn")) l2p = true; + else if (!strcmp(val, "-lfncache")) p2l = true; + else break; + } + if (!l2p && !p2l) l2p = true; + xLfn2Pfn = l2p; + xPfn2Lfn = p2l; // Get the path // - if (!(val = Config.GetWord()) || !val[0]) + if (!val || !val[0]) {Eroute->Emsg("Config", "namelib not specified"); return 1;} // Record the path