XRootD
XrdOucN2No2p.cc
Go to the documentation of this file.
1 /******************************************************************************/
2 /* */
3 /* X r d O u c N 2 N o 2 p . c c */
4 /* */
5 /* (c) 2017 by the Board of Trustees of the Leland Stanford, Jr., University */
6 /* Produced by Andrew Hanushevsky for Stanford University under contract */
7 /* DE-AC02-76-SFO0515 with the Department of Energy */
8 /* */
9 /* This file is part of the XRootD software suite. */
10 /* */
11 /* XRootD is free software: you can redistribute it and/or modify it under */
12 /* the terms of the GNU Lesser General Public License as published by the */
13 /* Free Software Foundation, either version 3 of the License, or (at your */
14 /* option) any later version. */
15 /* */
16 /* XRootD is distributed in the hope that it will be useful, but WITHOUT */
17 /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
18 /* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
19 /* License for more details. */
20 /* */
21 /* You should have received a copy of the GNU Lesser General Public License */
22 /* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
23 /* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */
24 /* */
25 /* The copyright holder's institutional names and contributor's names may not */
26 /* be used to endorse or promote products derived from this software without */
27 /* specific prior written permission of the institution or contributor. */
28 /******************************************************************************/
29 /******************************************************************************/
30 /* i n c l u d e f i l e s */
31 /******************************************************************************/
32 
33 #include <algorithm>
34 #include <cerrno>
35 #include <cstdio>
36 #include <string>
37 #include <cstring>
38 #include <unistd.h>
39 
40 #include "XrdVersion.hh"
41 
44 #include "XrdSys/XrdSysError.hh"
45 
46 /******************************************************************************/
47 /* S t a t i c s */
48 /******************************************************************************/
49 
51 
52 namespace
53 {
54 char h2c[16] = {'0','1','2','3','4','5','6','7',
55  '8','9','A','B','C','D','E','F'};
56 }
57 
58 /******************************************************************************/
59 /* E x t e r n a l F u n c t i o n s */
60 /******************************************************************************/
61 
62 extern unsigned long XrdOucHashVal2(const char *KeyVal, int KeyLen);
63 
64 /******************************************************************************/
65 /* C l a s s D e f i n i t i o n */
66 /******************************************************************************/
67 
69 {
70 public:
71 
72 virtual int lfn2pfn(const char* lfn, char* buff, int blen);
73 
74 virtual int lfn2rfn(const char* lfn, char* buff, int blen) {return -ENOTSUP;}
75 
76 virtual int pfn2lfn(const char* pfn, char* buff, int blen);
77 
78  XrdOucN2No2p(XrdSysError *erp, const char *lroot,
79  const char* pfx, int fnmax, char sc)
80  : eDest(erp), sChar(sc),
81  oidPfx(strdup(pfx)), oidPsz(strlen(pfx)), oidMax(fnmax)
82  {if (!lroot) {lRoot = 0; lRLen = 0;}
83  else {lRoot = strdup(lroot);
84  lRLen = strlen(lroot);
85  if (lRoot[lRLen-1] == '/')
86  {lRoot[lRLen-1] = 0; lRLen--;}
87  }
88  }
89 
90 virtual ~XrdOucN2No2p() {if (oidPfx) free(oidPfx);
91  if (lRoot) free(lRoot);
92  }
93 
94 private:
95 XrdSysError *eDest;
96 char *lRoot;
97 int lRLen;
98 char sChar;
99 char *oidPfx;
100 int oidPsz;
101 int oidMax;
102 };
103 
104 /******************************************************************************/
105 /* l f n 2 p f n */
106 /******************************************************************************/
107 
108 int XrdOucN2No2p::lfn2pfn(const char* lfn, char* buff, int blen)
109 {
110 // If have a local root then prefix result with it (make sure it fits)
111 //
112  if (lRoot)
113  {if (lRLen >= blen-1) return ENAMETOOLONG;
114  strcpy(buff, lRoot);
115  buff += lRLen; blen -= lRLen;
116  }
117 
118 // Now just to the transformation so that we can ref the oid as a file
119 //
120  return pfn2lfn(lfn, buff, blen);
121 }
122 
123 /******************************************************************************/
124 /* p f n 2 l f n */
125 /******************************************************************************/
126 
127 int XrdOucN2No2p::pfn2lfn(const char* pfn, char* buff, int blen)
128 {
129  const char *sP;
130  char *bP;
131  std::string pstr;
132  int pfnLen = strlen(pfn);
133 
134 // If the pfn starts with a slash then do nothing
135 //
136  if (*pfn == '/')
137  {if (pfnLen >= blen) return ENAMETOOLONG;
138  strcpy(buff, pfn);
139  return 0;
140  }
141 
142 // If there are any slashes in the object id we need to remove them
143 //
144  if ((sP = index(pfn, '/')))
145  {pstr = pfn;
146  std::replace(pstr.begin(), pstr.end(), '/', sChar);
147  pfn = pstr.c_str();
148  }
149 
150 // Create the object distribution subpath. The format is based on the
151 // actual length of the object id and what we can use in this file system.
152 // We make special allowances for short object ID's that can screw this up.
153 //
154  if (pfnLen <= oidMax)
155  {unsigned long hVal = XrdOucHashVal2(pfn, pfnLen);
156  unsigned long sVal = ((int)sizeof(unsigned long) > 4 ? 32 : 16);
157  char subP[8];
158  if (pfnLen <= (int)sizeof(unsigned long)) hVal = hVal ^ (hVal >> sVal);
159  subP[1] = h2c[(hVal & 0x0f)]; hVal >>= 4; subP[0] = h2c[(hVal & 0x0f)];
160  subP[2] = '/'; hVal >>= 4;
161  subP[4] = h2c[(hVal & 0x0f)]; hVal >>= 4; subP[3] = h2c[(hVal & 0x0f)];
162  subP[5] = '/'; subP[6] = 0;
163  int n = snprintf(buff, blen, "%s%s%s", oidPfx, subP, pfn);
164  return (n < blen ? 0 : ENAMETOOLONG);
165  }
166 
167 // The object id is longer than what is allowed for a file name. So, we
168 // convert the name to a number of directories using object id fragments.
169 // Check if we even have a chance here (note we may be one byte too many).
170 //
171  if ((oidPsz + pfnLen + (pfnLen/oidMax)) >= blen) return ENAMETOOLONG;
172 
173 // Prepare to segement the oid
174 //
175  strcpy(buff, oidPfx); bP = buff + oidPsz; blen -= oidPsz;
176 
177 // Copy over segments separated by a slash
178 //
179  while(blen > oidMax && pfnLen > oidMax)
180  {strncpy(bP, pfn, oidMax);
181  bP += oidMax; blen -= oidMax;
182  pfn += oidMax; pfnLen -= oidMax;
183  if (blen > 0) {*bP++ = '/'; blen--;}
184  }
185 
186 // Copy the final segment if we have room
187 //
188  if (blen <= pfnLen) return ENAMETOOLONG;
189  strcpy(bP, pfn);
190  return 0;
191 }
192 
193 /******************************************************************************/
194 /* X r d O u c g e t N a m e 2 N a m e */
195 /******************************************************************************/
196 
198 {
199  struct bHelper {char *p; bHelper(const char *bP) : p(bP ? strdup(bP) : 0) {}
200  ~bHelper() {if (p) free(p);}
201  };
202  bHelper prms(parms);
203  const char *oPfx;
204  char *val, *eP;
205  std::string ostr;
206  int fnMax = 0, n;
207  char sChar = '\\';
208 
209 // Process options
210 //
211  XrdOucTokenizer toks(prms.p);
212  toks.GetLine();
213  while((val = toks.GetToken()) && *val)
214  { if (!strcmp(val, "-slash"))
215  {if (!(val = toks.GetToken()) || !(*val))
216  {eDest->Emsg("N2No2p", "-slash argument not specified.");
217  return 0;
218  }
219  if (strlen(val) == 1) {sChar = *val; continue;}
220  n = strtol(val, &eP, 16);
221  if (n & 0xff || *eP)
222  {eDest->Emsg("N2No2p", "Invalid -slash argument -",val);
223  return 0;
224  }
225  sChar = static_cast<char>(n);
226  }
227  else if (!strcmp(val, "-maxfnlen"))
228  {if (!(val = toks.GetToken()) || !(*val))
229  {eDest->Emsg("N2No2p", "-maxfnlen argument not specified.");
230  return 0;
231  }
232  fnMax = strtol(val, &eP, 16);
233  if (fnMax <= 0 || *eP)
234  {eDest->Emsg("N2No2p", "Invalid -maxfnlen argument -",val);
235  return 0;
236  }
237  }
238  else break;
239  }
240 
241 // Obtain the objectid prefix we are to use (default is '/')
242 //
243  if (!val || !(*val)) oPfx = "/";
244  else {if (*val != '/')
245  {eDest->Emsg("N2No2p", "Invalid object ID path prefix -", val);
246  return 0;
247  }
248  oPfx = val;
249  n = strlen(val);
250  if (val[n-1] != '/') {ostr = val; ostr += '/'; oPfx = ostr.c_str();}
251  }
252 
253 // Now determine what the maximum filename length if not specified
254 //
255  if (!fnMax)
256  if ((fnMax = pathconf("/", _PC_NAME_MAX)) < 0)
257  {eDest->Emsg("N2No2p", errno, "determine -fnmaxlen for '/'; using 255.");
258  fnMax = 255;
259  }
260 
261 // Return a new n2n object
262 //
263  return new XrdOucN2No2p(eDest, lroot, oPfx, fnMax, sChar);
264 }
static XrdSysError eDest(0,"crypto_")
XrdOucName2Name * XrdOucgetName2Name(XrdOucgetName2NameArgs)
unsigned long XrdOucHashVal2(const char *KeyVal, int KeyLen)
XrdVERSIONINFO(XrdOucgetName2Name, "XrdN2No2p")
#define XrdOucgetName2NameArgs
long pathconf(const char *path, int name)
XrdOucN2No2p(XrdSysError *erp, const char *lroot, const char *pfx, int fnmax, char sc)
Definition: XrdOucN2No2p.cc:78
virtual int pfn2lfn(const char *pfn, char *buff, int blen)
virtual ~XrdOucN2No2p()
Definition: XrdOucN2No2p.cc:90
virtual int lfn2pfn(const char *lfn, char *buff, int blen)
virtual int lfn2rfn(const char *lfn, char *buff, int blen)
Definition: XrdOucN2No2p.cc:74
char * GetToken(char **rest=0, int lowcase=0)
int Emsg(const char *esfx, int ecode, const char *text1, const char *text2=0)
Definition: XrdSysError.cc:95