/******************************************************************************/
/* */
/* X r d P o s i x X r o o t d P a t h . c c */
/* */
/* (c) 2011 by the Board of Trustees of the Leland Stanford, Jr., University */
/* All Rights Reserved */
/* Produced by Andrew Hanushevsky for Stanford University under contract */
/* DE-AC02-76-SFO0515 with the Department of Energy */
/* */
/* This file is part of the XRootD software suite. */
/* */
/* XRootD is free software: you can redistribute it and/or modify it under */
/* the terms of the GNU Lesser General Public License as published by the */
/* Free Software Foundation, either version 3 of the License, or (at your */
/* option) any later version. */
/* */
/* XRootD is distributed in the hope that it will be useful, but WITHOUT */
/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
/* License for more details. */
/* */
/* You should have received a copy of the GNU Lesser General Public License */
/* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
/* COPYING (GPL license). If not, see . */
/* */
/* The copyright holder's institutional names and contributor's names may not */
/* be used to endorse or promote products derived from this software without */
/* specific prior written permission of the institution or contributor. */
/******************************************************************************/
#include
#include
#include
#include
#include
#include "XrdOuc/XrdOucName2Name.hh"
#include "XrdOuc/XrdOucTokenizer.hh"
#include "XrdPosix/XrdPosixTrace.hh"
#include "XrdPosix/XrdPosixXrootdPath.hh"
#include "XrdSys/XrdSysHeaders.hh"
/******************************************************************************/
/* S t a t i c s */
/******************************************************************************/
namespace
{
struct ProtoTable
{const char *name;
int nlen;
};
static const int ptEnts = 8; // Number of protocol entries we support
}
namespace XrdPosixGlobals
{
extern XrdOucName2Name *theN2N;
extern bool oidsOK;
ProtoTable protoTab[ptEnts] = {{"root://", 7}, {"xroot://", 8}};
}
/******************************************************************************/
/* 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 */
/******************************************************************************/
XrdPosixXrootPath::XrdPosixXrootPath()
: xplist(0),
pBase(0)
{
XrdOucTokenizer thePaths(0);
char *plist = 0, *colon = 0, *subs = 0, *lp = 0, *tp = 0;
int aOK = 0;
cwdPath = 0; cwdPlen = 0;
if (!(plist = getenv("XROOTD_VMP")) || !*plist) return;
pBase = strdup(plist);
thePaths.Attach(pBase);
if ((lp = thePaths.GetLine())) while((tp = thePaths.GetToken()))
{aOK = 1;
if ((colon = rindex(tp, (int)':')) && *(colon+1) == '/')
{if (!(subs = index(colon, (int)'='))) subs = 0;
else if (*(subs+1) == '/') {*subs = '\0'; subs++;}
else if (*(subs+1)) aOK = 0;
else {*subs = '\0'; subs = (char*)"";}
} else aOK = 0;
if (aOK)
{*colon++ = '\0';
while(*(colon+1) == '/') colon++;
xplist = new xpath(xplist, tp, colon, subs);
} else DMSG("Path", "Invalid XROOTD_VMP token '" <next; delete xpnow;}
}
/******************************************************************************/
/* X r d P o s i x P a t h : : A d d P r o t o */
/******************************************************************************/
bool XrdPosixXrootPath::AddProto(const char *proto)
{
int i;
// Check if we already have this protocol entry. The proto argument must be
// in the form "pname://", where pname is the protocol name.
//
for (i = 0; i < ptEnts && XrdPosixGlobals::protoTab[i].name; i++)
if (!strcmp(proto, XrdPosixGlobals::protoTab[i].name)) return true;
// Add the entry if we have room
//
if (i >= ptEnts) return false;
XrdPosixGlobals::protoTab[i].name = strdup(proto);
XrdPosixGlobals::protoTab[i].nlen = strlen(proto);
return true;
}
/******************************************************************************/
/* X r d P o s i x P a t h : : C W D */
/******************************************************************************/
void XrdPosixXrootPath::CWD(const char *path)
{
if (cwdPath) free(cwdPath);
cwdPlen = strlen(path);
if (*(path+cwdPlen-1) == '/') cwdPath = strdup(path);
else if (cwdPlen <= MAXPATHLEN)
{char buff[MAXPATHLEN+8];
strcpy(buff, path);
*(buff+cwdPlen ) = '/';
*(buff+cwdPlen+1) = '\0';
cwdPath = strdup(buff); cwdPlen++;
}
}
/******************************************************************************/
/* 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)
{
EPNAME("P2L");
const char *urlP, *slash, *quest;
char *outP, pfnBuff[1032], lfnBuff[1032];
int cgiLen, lfnLen, pfnLen, pfxLen, n;
bool notOurs = true;
// Preset repP to zero to indicate no translation required, nothing to free
//
relP = 0;
// Check if we need to do any translation at all
//
if (!XrdPosixGlobals::theN2N && !ponly) return inP;
// If this is a protocol we support, then we can convert the path
//
for (int i = 0; i < ptEnts && XrdPosixGlobals::protoTab[i].name; i++)
if (!strncmp(inP, XrdPosixGlobals::protoTab[i].name,
XrdPosixGlobals::protoTab[i].nlen))
{urlP = inP + XrdPosixGlobals::protoTab[i].nlen;
notOurs = false;
break;
}
if (notOurs) return inP;
// Search for the next slash which must be followed by another slash unless we
// are allowing object ids.
//
if (!(slash = index(urlP, '/'))) return inP;
if (*(slash+1) != '/' && !XrdPosixGlobals::oidsOK) 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
//
DEBUG(who <<' ' <path, xpnow->plen)) break;
else xpnow = xpnow->next;
// If we did not match a path, this is not our path.
//
if (!xpnow) return 0;
if (!buff) return (char *)1;
// Verify that we won't overflow the buffer
//
if (!pathlen) pathlen = strlen(path);
plen = pathlen + xpnow->servln + 2;
if (xpnow->nath) plen = plen - xpnow->plen + xpnow->nlen;
if (plen >= blen) return 0;
// Build the url
//
strcpy(buff, XrdPosixGlobals::protoTab[0].name);
strcat(buff, xpnow->server);
strcat(buff, "/");
if (xpnow->nath) {strcat(buff, xpnow->nath); path += xpnow->plen;}
if (*path != '/') strcat(buff, "/");
strcat(buff, path);
return buff;
}