XRootD
Loading...
Searching...
No Matches
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
52namespace
53{
54char 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
62extern 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{
70public:
71
72virtual int lfn2pfn(const char* lfn, char* buff, int blen);
73
74virtual int lfn2rfn(const char* lfn, char* buff, int blen) {return -ENOTSUP;}
75
76virtual 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
90virtual ~XrdOucN2No2p() {if (oidPfx) free(oidPfx);
91 if (lRoot) free(lRoot);
92 }
93
94private:
96char *lRoot;
97int lRLen;
98char sChar;
99char *oidPfx;
100int oidPsz;
101int oidMax;
102};
103
104/******************************************************************************/
105/* l f n 2 p f n */
106/******************************************************************************/
107
108int 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
127int 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_")
unsigned long XrdOucHashVal2(const char *KeyVal, int KeyLen)
XrdOucName2Name * XrdOucgetName2Name(XrdOucgetName2NameArgs)
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)
virtual int pfn2lfn(const char *pfn, char *buff, int blen)
virtual ~XrdOucN2No2p()
virtual int lfn2pfn(const char *lfn, char *buff, int blen)
virtual int lfn2rfn(const char *lfn, char *buff, int blen)
XrdOucName2Name()
Constructor.
char * GetToken(char **rest=0, int lowcase=0)