/******************************************************************************/
/* */
/* X r d O s s P a t h . c c */
/* */
/* (c) 2008 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
#include
#include
#include "XrdOss/XrdOssPath.hh"
#include "XrdOss/XrdOssSpace.hh"
#include "XrdSys/XrdSysPthread.hh"
#include "XrdNet/XrdNetAddr.hh"
#include "XrdNet/XrdNetUtils.hh"
/******************************************************************************/
/* L o c a l M a c r o s */
/******************************************************************************/
#define XrdOssTAMP(dst, src) \
while(*src) {*dst = (*src == '/' ? xChar : *src); src++; dst++;}; *dst='\0'
/******************************************************************************/
/* S t a t i c O b j e c t s */
/******************************************************************************/
char XrdOssPath::h2c[16] = {'0','1','2','3','4','5','6','7',
'8','9','A','B','C','D','E','F'};
char XrdOssPath::pfnPfx[60] = {'\0'};
const char XrdOssPath::xChar;
// The initialization must be in 1-to-1 order with theSfx enum!
//
const char *XrdOssPath::Sfx[XrdOssPath::sfxNum] =
{".anew", ".fail", ".lock", ".pin",
".mmap", ".mkeep", ".mlock",".pfn", 0};
/******************************************************************************/
/* C o n v e r t */
/******************************************************************************/
int XrdOssPath::Convert(char *dst, int dln, const char *oldP, const char *newP)
{
int i;
// Copy all the char up to the first % into the new link buffer
//
for (i = 0; oldP[i] && oldP[i] != xChar; i++) *dst++ = oldP[i];
// Now make sure the resulting name will fit
//
if ((i + static_cast(strlen(newP))) >= dln) return -ENAMETOOLONG;
// Complete the name
//
XrdOssTAMP(dst, newP);
return 0;
}
/******************************************************************************/
/* E x t r a c t */
/******************************************************************************/
const char *XrdOssPath::Extract(char *path, char *lbuf, int &lbsz)
{
struct stat Stat;
char *pP;
int j, lnklen = 0;
// If path is 0, the caller already has read the link; else read it.
//
if (!path) lnklen = lbsz;
else if (!lstat(path, &Stat) && S_ISLNK(Stat.st_mode))
{if ((lnklen = readlink(path, lbuf, lbsz-1)) < 0) *lbuf = 0;
else *(lbuf+lnklen) = 0;
}
else {lnklen = strlen(path);
if (lnklen >= lbsz) lnklen = lbsz-1;
strncpy(lbuf, path, lnklen); *(lbuf+lnklen) = '\0';
}
// Extract out the cache group name from "/cgroup/nn/fn" if possible
//
if (lnklen >= 4 && lbuf[lnklen-1] == xChar && (pP=posCname(lbuf,lnklen,j)))
{*(pP+j) = '\0';
if (pP != lbuf) *(pP-1) = '\0';
return pP;
}
// This is not a normal cache, so do something reasonable
//
if ((pP = index(lbuf, xChar))) *pP = '\0';
else *(lbuf+1) = '\0';
return "public";
}
/******************************************************************************/
/* g e n P a t h */
/******************************************************************************/
char *XrdOssPath::genPath(const char *inPath, const char *cgrp, char *sfx)
{
char *dirP, cgbuff[XrdOssSpace::minSNbsz], pbuff[MAXPATHLEN+64], *pP = pbuff;
int n;
// Check if the group name is already in the path
//
strcpy(pbuff, inPath); strcpy(cgbuff, cgrp); strcat(cgbuff, "/");
do {if ((dirP = index(pP, '/')) && !strcmp(dirP+1, cgbuff)) break;
pP = dirP+1;
} while(dirP);
// If the group name is not in the path, add the group name to it.
//
if (!dirP)
{dirP = pbuff + strlen(inPath) - 1;
strcpy(dirP+1, cgbuff);
}
// Construct a suffix that will allow us to quickly find the group name
// We rely on the fact that group names are typically less than 16 characters
// and cache group paths are less than 240 characters
//
if ((n = strlen(cgrp)) > 15) sfx[2] = 'f';
else sfx[2] = h2c[n];
n = (dirP - pbuff + 1) & 0xff;
sfx[1] = h2c[(n & 0x0f)]; n = n >> 4; sfx[0] = h2c[(n & 0x0f)];
sfx[3] = xChar;
// Return the path
//
return strdup(pbuff);
}
/******************************************************************************/
/* g e n P F N */
/******************************************************************************/
char *XrdOssPath::genPFN(fnInfo &Info, char *buff, int blen, const char *Path)
{
static XrdSysMutex myMutex;
static int mySeq = 0;
union {int bin;
char chr[4];} Seq;
char *bP = buff;
// Construct old style path if we have a path present (i.e., non-xa path)
//
if (Path)
{const char *pap = Path;
if ((Info.Plen + static_cast(strlen(Path))) >= blen)
{*buff = '\0'; return 0;}
memcpy(bP, Info.Path, Info.Plen);
bP += Info.Plen;
XrdOssTAMP(bP, pap);
Info.Slash = buff;
return 0;
}
if (! *pfnPfx) {
*bP = '\0';
return bP;
}
// Increment the sequence number
//
myMutex.Lock();
Seq.bin = mySeq++;
myMutex.UnLock();
// Construct the path (buffer will be big enough)
//
memcpy(bP, Info.Path, Info.Plen);
bP += Info.Plen;
*bP++ = h2c[((Seq.bin>>4) & 0x0f)];
*bP++ = h2c[( Seq.bin & 0x0f)];
Info.Slash= bP;
*bP++ = '/';
strcpy(bP, pfnPfx);
bP = bin2hex(Seq.chr, sizeof(Seq.chr), bP+strlen(pfnPfx));
memcpy(bP, Info.Sfx, sfxLen);
bP += sfxLen;
*bP = '\0';
// All done
//
return bP;
}
/******************************************************************************/
char *XrdOssPath::genPFN(char *dst, int dln, const char *src)
{
char *pP;
if (!(pP = (char *) index(src, xChar))|| dln <= (int)strlen(pP)) return 0;
while(*pP) {*dst++ = (*pP == xChar ? '/' : *pP); pP++;}
*dst = '\0';
return dst;
}
/******************************************************************************/
/* g e t C n a m e */
/******************************************************************************/
int XrdOssPath::getCname(const char *path, char *Cache,
char *lbuf, int lbsz)
{
struct stat lbuff;
char *xP, lnkbuff[MAXPATHLEN+64];
int j, lnklen = 0;
// Set up local buffer or remote buffer
//
if (!lbuf) {lbuf = lnkbuff; lbsz = MAXPATHLEN;}
// If path is 0, the caller already has read the link; else read it.
//
if (!path) lnklen = lbsz;
else if (!lstat(path, &lbuff) && S_ISLNK(lbuff.st_mode))
lnklen = readlink(path, lbuf, lbsz);
// Check if the symlink references a new cache. If not then the cache group is
// always deemed to be public.
//
if (lnklen < 4 || lbuf[lnklen-1] != xChar)
{strcpy(Cache, "public"); return (lnklen < 0 ? 0 : lnklen);}
// Extract out the cache group name from "/cgroup/nn/fn"
//
if (!(xP = posCname(lbuf, lnklen, j))) strcpy(Cache, "public");
else {strncpy(Cache, xP, j); *(Cache+j)='\0';}
// All done
//
return lnklen;
}
/******************************************************************************/
/* p a t h T y p e */
/******************************************************************************/
XrdOssPath::theSfx XrdOssPath::pathType(const char *Path, int chkWhat)
{
static const int chkMM = chkMem | chkMig;
char *Dot;
int i, iBeg, iEnd;
// Compute ending test
//
if ( chkWhat & chkAll) {iBeg = 0; iEnd = int(sfxLast);}
else if ((chkWhat & chkMM ) == chkMM) {iBeg = 1; iEnd = int(sfxMemL);}
else if ( chkWhat & chkMig) {iBeg = 1; iEnd = int(sfxMigL);}
else if ( chkWhat & chkMem) {iBeg = int(sfxMemF);iEnd = int(sfxMigL);}
else {iBeg = 0; iEnd = 0;}
// Convert path to suffix number
//
if ((Dot = (char *) rindex(Path, '.')))
for (i = iBeg; i < iEnd; i++) if (!strcmp(Dot,Sfx[i])) return theSfx(i+1);
return isBase;
}
/******************************************************************************/
/* T r i m 2 B a s e */
/******************************************************************************/
void XrdOssPath::Trim2Base(char *eP)
{
int oneMore = (*eP == xChar);
// Trim to the cache group name in "/cgroup/nn/fn" or "/fn"
//
do {eP--;} while(*eP != '/');
if (oneMore) do {eP--;} while(*eP != '/');
*(eP+1) = '\0';
}
/******************************************************************************/
/* P r i v a t e M e t h o d s */
/******************************************************************************/
/******************************************************************************/
/* b i n 2 h e x */
/******************************************************************************/
char *XrdOssPath::bin2hex(char *inbuff, int dlen, char *buff)
{
int i;
for (i = 0; i < dlen; i++) {
*buff++ = h2c[(inbuff[i] >> 4) & 0x0f];
*buff++ = h2c[ inbuff[i] & 0x0f];
}
return buff;
}
/******************************************************************************/
/* I n i t P r e f i x */
/******************************************************************************/
// Create a prefix for files in a cache. It is create only once when oss is
// configured. It is unique using: