XRootD
Loading...
Searching...
No Matches
XrdCksManager.cc
Go to the documentation of this file.
1/******************************************************************************/
2/* */
3/* X r d O s s C k s M a n a g e r . c c */
4/* */
5/* (c) 2011 by the Board of Trustees of the Leland Stanford, Jr., University */
6/* All Rights Reserved */
7/* Produced by Andrew Hanushevsky for Stanford University under contract */
8/* DE-AC02-76-SFO0515 with the Department of Energy */
9/* */
10/* This file is part of the XRootD software suite. */
11/* */
12/* XRootD is free software: you can redistribute it and/or modify it under */
13/* the terms of the GNU Lesser General Public License as published by the */
14/* Free Software Foundation, either version 3 of the License, or (at your */
15/* option) any later version. */
16/* */
17/* XRootD is distributed in the hope that it will be useful, but WITHOUT */
18/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
19/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
20/* License for more details. */
21/* */
22/* You should have received a copy of the GNU Lesser General Public License */
23/* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
24/* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */
25/* */
26/* The copyright holder's institutional names and contributor's names may not */
27/* be used to endorse or promote products derived from this software without */
28/* specific prior written permission of the institution or contributor. */
29/******************************************************************************/
30
31#include <cerrno>
32#include <fcntl.h>
33#include <cstring>
34#include <ctime>
35#include <cstdio>
36#include <unistd.h>
37#include <sys/mman.h>
38#include <sys/types.h>
39#include <sys/stat.h>
40
41#include "XrdCks/XrdCksCalc.hh"
48#include "XrdCks/XrdCksXAttr.hh"
51#include "XrdOuc/XrdOucUtils.hh"
52#include "XrdOuc/XrdOucXAttr.hh"
53#include "XrdSys/XrdSysError.hh"
54#include "XrdSys/XrdSysFAttr.hh"
57
58#ifndef ENOATTR
59#define ENOATTR ENODATA
60#endif
61
62/******************************************************************************/
63/* C o n s t r u c t o r */
64/******************************************************************************/
65
66XrdCksManager::XrdCksManager(XrdSysError *erP, int rdsz, XrdVersionInfo &vInfo,
67 bool autoload)
68 : XrdCks(erP), myVersion(vInfo)
69{
70
71// Get a dynamic loader if so wanted
72//
73 if (autoload) cksLoader = new XrdCksLoader(vInfo);
74 else cksLoader = 0;
75
76// Prefill the native digests we support
77//
78 strcpy(csTab[0].Name, "adler32");
79 strcpy(csTab[1].Name, "crc32");
80 strcpy(csTab[2].Name, "crc32c");
81 strcpy(csTab[3].Name, "md5");
82 csLast = 3;
83
84// Compute the i/o size
85//
86 if (rdsz <= 65536) segSize = 67108864;
87 else segSize = ((rdsz/65536) + (rdsz%65536 != 0)) * 65536;
88}
89
90/******************************************************************************/
91/* D e s t r u c t o r */
92/******************************************************************************/
93
95{
96 int i;
97 for (i = 0; i <= csLast; i++)
98 {if (csTab[i].Obj && csTab[i].doDel) csTab[i].Obj->Recycle();
99 if (csTab[i].Path) free( csTab[i].Path);
100 if (csTab[i].Parms) free( csTab[i].Parms);
101 if (csTab[i].Plugin) delete csTab[i].Plugin;
102 }
103 if (cksLoader) delete cksLoader;
104}
105
106/******************************************************************************/
107/* C a l c */
108/******************************************************************************/
109
110int XrdCksManager::Calc(const char *Pfn, XrdCksData &Cks, int doSet)
111{
112 XrdCksCalc *csP;
113 csInfo *csIP = &csTab[0];
114 time_t MTime;
115 int rc;
116
117// Determine which checksum to get
118//
119 if (csLast < 0) return -ENOTSUP;
120 if (!(*Cks.Name)) Cks.Set(csIP->Name);
121 else if (!(csIP = Find(Cks.Name))) return -ENOTSUP;
122
123// If we need not set the checksum then see if we can get it from the
124// extended attributes.
125
126// Obtain a new checksum object
127//
128 if (!(csP = csIP->Obj->New())) return -ENOMEM;
129
130// Use the calculator to get and possibly set the checksum
131//
132 if (!(rc = Calc(Pfn, MTime, csP)))
133 {memcpy(Cks.Value, csP->Final(), csIP->Len);
134 Cks.fmTime = static_cast<long long>(MTime);
135 Cks.csTime = static_cast<int>(time(0) - MTime);
136 Cks.Length = csIP->Len;
137 csP->Recycle();
138 if (doSet)
140 memcpy(&xCS.Attr.Cks, &Cks, sizeof(xCS.Attr.Cks));
141 if ((rc = xCS.Set(Pfn))) return -rc;
142 }
143 }
144
145// All done
146//
147 return rc;
148}
149
150/******************************************************************************/
151
152int XrdCksManager::Calc(const char *Pfn, time_t &MTime, XrdCksCalc *csP)
153{
154 class ioFD
155 {public:
156 int FD;
157 ioFD() : FD(-1) {}
158 ~ioFD() {if (FD >= 0) close(FD);}
159 } In;
160 struct stat Stat;
161 char *inBuff;
162 off_t Offset=0, fileSize;
163 size_t ioSize, calcSize;
164 int rc;
165
166// Open the input file
167//
168 if ((In.FD = open(Pfn, O_RDONLY)) < 0) return -errno;
169
170// Get the file characteristics
171//
172 if (fstat(In.FD, &Stat)) return -errno;
173 if (!(Stat.st_mode & S_IFREG)) return -EPERM;
174 calcSize = fileSize = Stat.st_size;
175 MTime = Stat.st_mtime;
176
177// We now compute checksum 64MB at a time using mmap I/O
178//
179 ioSize = (fileSize < (off_t)segSize ? fileSize : segSize); rc = 0;
180 while(calcSize)
181 {if ((inBuff = (char *)mmap(0, ioSize, PROT_READ,
182#if defined(__FreeBSD__)
183 MAP_RESERVED0040|MAP_PRIVATE, In.FD, Offset)) == MAP_FAILED)
184#elif defined(__GNU__)
185 MAP_PRIVATE, In.FD, Offset)) == MAP_FAILED)
186#else
187 MAP_NORESERVE|MAP_PRIVATE, In.FD, Offset)) == MAP_FAILED)
188#endif
189 {rc = errno; eDest->Emsg("Cks", rc, "memory map", Pfn); break;}
190 madvise(inBuff, ioSize, MADV_SEQUENTIAL);
191 csP->Update(inBuff, ioSize);
192 calcSize -= ioSize; Offset += ioSize;
193 if (munmap(inBuff, ioSize) < 0)
194 {rc = errno; eDest->Emsg("Cks",rc,"unmap memory for",Pfn); break;}
195 if (calcSize < (size_t)segSize) ioSize = calcSize;
196 }
197
198// Return if we failed
199//
200 if (calcSize) return (rc ? -rc : -EIO);
201 return 0;
202}
203
204/******************************************************************************/
205/* C o n f i g */
206/******************************************************************************/
207/*
208 Purpose: To parse the directive: ckslib <digest> <path> [<parms>]
209
210 <digest> the name of the checksum.
211 <path> the path of the checksum library to be used.
212 <parms> optional parms to be passed
213
214 Output: 0 upon success or !0 upon failure.
215*/
216int XrdCksManager::Config(const char *Token, char *Line)
217{
218 XrdOucTokenizer Cfg(Line);
219 char *val, *path = 0, name[XrdCksData::NameSize], *parms;
220 int i;
221
222// Get the the checksum name
223//
224 Cfg.GetLine();
225 if (!(val = Cfg.GetToken()) || !val[0])
226 {eDest->Emsg("Config", "checksum name not specified"); return 1;}
227 if (int(strlen(val)) >= XrdCksData::NameSize)
228 {eDest->Emsg("Config", "checksum name too long"); return 1;}
229 strcpy(name, val); XrdOucUtils::toLower(name);
230
231// Get the path and optional parameters
232//
233 val = Cfg.GetToken(&parms);
234 if (val && val[0]) path = strdup(val);
235 else {eDest->Emsg("Config","library path missing for ckslib digest",name);
236 return 1;
237 }
238
239// Check if this replaces an existing checksum
240//
241 for (i = 0; i < csMax; i++)
242 if (!(*csTab[i].Name) || !strcmp(csTab[i].Name, name)) break;
243
244// See if we can insert a new checksum (or replace one)
245//
246 if (i >= csMax)
247 {eDest->Emsg("Config", "too many checksums specified");
248 if (path) free(path);
249 return 1;
250 } else if (!(*csTab[i].Name)) csLast = i;
251
252// Insert the new checksum
253//
254 strcpy(csTab[i].Name, name);
255 if (csTab[i].Path) free(csTab[i].Path);
256 csTab[i].Path = path;
257 if (csTab[i].Parms) free(csTab[i].Parms);
258 csTab[i].Parms = (parms && *parms ? strdup(parms) : 0);
259
260// All done
261//
262 return 0;
263}
264
265/******************************************************************************/
266/* I n i t */
267/******************************************************************************/
268
269int XrdCksManager::Init(const char *ConfigFN, const char *DfltCalc)
270{
271 int i;
272
273// See if we need to set the default calculation
274//
275 if (DfltCalc)
276 {for (i = 0; i < csLast; i++) if (!strcmp(csTab[i].Name, DfltCalc)) break;
277 if (i >= csMax)
278 {eDest->Emsg("Config", DfltCalc, "cannot be made the default; "
279 "not supported.");
280 return 0;
281 }
282 if (i) {csInfo Temp = csTab[i]; csTab[i] = csTab[0]; csTab[0] = Temp;}
283 }
284
285// See if there are any checksums to configure
286//
287 if (csLast < 0)
288 {eDest->Emsg("Config", "No checksums defined; cannot configure!");
289 return 0;
290 }
291
292// Complete the checksum table
293//
294 for (i = 0; i <= csLast; i++)
295 {if (csTab[i].Path) {if (!(Config(ConfigFN, csTab[i]))) return 0;}
296 else { if (!strcmp("adler32", csTab[i].Name))
297 csTab[i].Obj = new XrdCksCalcadler32;
298 else if (!strcmp("crc32", csTab[i].Name))
299 csTab[i].Obj = new XrdCksCalccrc32;
300 else if (!strcmp("crc32c", csTab[i].Name))
301 csTab[i].Obj = new XrdCksCalccrc32C;
302 else if (!strcmp("md5", csTab[i].Name))
303 csTab[i].Obj = new XrdCksCalcmd5;
304 else {eDest->Emsg("Config", "Invalid native checksum -",
305 csTab[i].Name);
306 return 0;
307 }
308 csTab[i].Obj->Type(csTab[i].Len);
309 }
310 }
311
312// All done
313//
314 return 1;
315}
316
317/******************************************************************************/
318
319#define XRDOSSCKSLIBARGS XrdSysError *, const char *, const char *, const char *
320
321int XrdCksManager::Config(const char *cFN, csInfo &Info)
322{
323 XrdOucPinLoader myPin(eDest, &myVersion, "ckslib", Info.Path);
325 int n;
326
327// Find the entry point
328//
329 Info.Plugin = 0;
330 if (!(ep = (XrdCksCalc *(*)(XRDOSSCKSLIBARGS))
331 (myPin.Resolve("XrdCksCalcInit"))))
332 {eDest->Emsg("Config", "Unable to configure cksum", Info.Name);
333 myPin.Unload();
334 return 0;
335 }
336
337// Get the initial object
338//
339 if (!(Info.Obj = ep(eDest,cFN,Info.Name,(Info.Parms ? Info.Parms : ""))))
340 {eDest->Emsg("Config", Info.Name, "checksum initialization failed");
341 myPin.Unload();
342 return 0;
343 }
344
345// Verify the object
346//
347 if (strcmp(Info.Name, Info.Obj->Type(n)))
348 {eDest->Emsg("Config",Info.Name,"cksum plugin returned wrong name -",
349 Info.Obj->Type(n));
350 myPin.Unload();
351 return 0;
352 }
353 if (n > XrdCksData::ValuSize || n <= 0)
354 {eDest->Emsg("Config",Info.Name,"cksum plugin has an unsupported "
355 "checksum length");
356 myPin.Unload();
357 return 0;
358 }
359
360// All is well
361//
362 Info.Plugin = myPin.Export();
363 Info.Len = n;
364 return 1;
365}
366
367/******************************************************************************/
368/* F i n d */
369/******************************************************************************/
370
371XrdCksManager::csInfo *XrdCksManager::Find(const char *Name)
372{
373 static XrdSysMutex myMutex;
374 XrdCksCalc *myCalc;
375 int i;
376
377// Find the pre-loaded checksum
378//
379 for (i = 0; i <= csLast; i++)
380 if (!strcmp(Name, csTab[i].Name)) return &csTab[i];
381
382// If we have loader see if we can auto-load this object
383//
384 if (!cksLoader) return 0;
385 myMutex.Lock();
386
387// An entry could have been added as we were running unlocked
388//
389 for (i = 0; i <= csLast; i++)
390 if (!strcmp(Name, csTab[i].Name))
391 {myMutex.UnLock();
392 return &csTab[i];
393 }
394
395// Check if we have room in the table
396//
397 if (csLast >= csMax)
398 {myMutex.UnLock();
399 eDest->Emsg("CksMan","Unable to load",Name,"; checksum limit reached.");
400 return 0;
401 }
402
403// Attempt to dynamically load this object
404//
405{ char buff[2048];
406 *buff = 0;
407 if (!(myCalc = cksLoader->Load(Name, 0, buff, sizeof(buff), true)))
408 {myMutex.UnLock();
409 eDest->Emsg("CksMan", "Unable to load", Name);
410 if (*buff) eDest->Emsg("CksMan", buff);
411 return 0;
412 }
413}
414
415// Fill out the table
416//
417 i = csLast + 1;
418 strncpy(csTab[i].Name, Name, XrdCksData::NameSize);
419 csTab[i].Obj = myCalc;
420 csTab[i].Path = 0;
421 csTab[i].Parms = 0;
422 csTab[i].Plugin = 0;
423 csTab[i].doDel = false;
424 myCalc->Type(csTab[i].Len);
425
426// Return the result
427//
428 csLast = i;
429 myMutex.UnLock();
430 return &csTab[i];
431}
432
433/******************************************************************************/
434/* D e l */
435/******************************************************************************/
436
437int XrdCksManager::Del(const char *Pfn, XrdCksData &Cks)
438{
440
441// Set the checksum name
442//
443 xCS.Attr.Cks.Set(Cks.Name);
444
445// Delete the attribute and return the result
446//
447 return xCS.Del(Pfn);
448}
449
450/******************************************************************************/
451/* G e t */
452/******************************************************************************/
453
454int XrdCksManager::Get(const char *Pfn, XrdCksData &Cks)
455{
457 time_t MTime;
458 int rc, nFault;
459
460// Determine which checksum to get (we will accept unsupported ones as well)
461//
462 if (csLast < 0) return -ENOTSUP;
463 if (!*Cks.Name) Cks.Set(csTab[0].Name);
464 if (!xCS.Attr.Cks.Set(Cks.Name)) return -ENOTSUP;
465
466// Retreive the attribute
467//
468 if ((rc = xCS.Get(Pfn)) <= 0) return (rc && rc != -ENOATTR ? rc : -ESRCH);
469
470// Mark state of the name and copy the attribute over
471//
472 nFault = strcmp(xCS.Attr.Cks.Name, Cks.Name);
473 Cks = xCS.Attr.Cks;
474
475// Verify the file
476//
477 if ((rc = ModTime(Pfn, MTime))) return rc;
478
479// Return result
480//
481 return (Cks.fmTime != MTime || nFault
482 || Cks.Length > XrdCksData::ValuSize || Cks.Length <= 0
483 ? -ESTALE : int(Cks.Length));
484}
485
486/******************************************************************************/
487/* L i s t */
488/******************************************************************************/
489
490char *XrdCksManager::List(const char *Pfn, char *Buff, int Blen, char Sep)
491{
492 static const char *vPfx = "XrdCks.";
493 static const int vPln = strlen(vPfx);
494 XrdSysFAttr::AList *vP, *axP = 0;
495 char *bP = Buff;
496 int i, n;
497
498// Verify that the buffer is large enough
499//
500 if (Blen < 2) return 0;
501
502// Check if the default list is wanted
503//
504 if (!Pfn)
505 {if (csLast < 0) return 0;
506 i = 0;
507 while(i <= csLast && Blen > 1)
508 {n = strlen(csTab[i].Name);
509 if (n >= Blen) break;
510 if (bP != Buff) *bP++ = Sep;
511 strcpy(bP, csTab[i].Name); bP += n; *bP = 0;
512 }
513 return (bP == Buff ? 0 : Buff);
514 }
515
516// Get a list of attributes for this file
517//
518 if (XrdSysFAttr::Xat->List(&axP, Pfn) < 0 || !axP) return 0;
519
520// Go through the list extracting what we are looking for
521//
522 vP = axP;
523 while(vP)
524 {if (vP->Nlen > vPln && !strncmp(vP->Name, vPfx, vPln))
525 {n = vP->Nlen - vPln;
526 if (n >= Blen) break;
527 if (bP != Buff) *bP++ = Sep;
528 strcpy(bP, vP->Name + vPln); bP += n; *bP = 0;
529 }
530 vP = vP->Next;
531 }
532
533// All done
534//
536 return (bP == Buff ? 0 : Buff);
537}
538
539/******************************************************************************/
540/* M o d T i m e */
541/******************************************************************************/
542
543int XrdCksManager::ModTime(const char *Pfn, time_t &MTime)
544{
545 struct stat Stat;
546
547 if (stat(Pfn, &Stat)) return -errno;
548
549 MTime = Stat.st_mtime;
550 return 0;
551}
552
553/******************************************************************************/
554/* N a m e */
555/******************************************************************************/
556
557const char *XrdCksManager::Name(int seqNum)
558{
559
560 return (seqNum < 0 || seqNum > csLast ? 0 : csTab[seqNum].Name);
561}
562
563/******************************************************************************/
564/* O b j e c t */
565/******************************************************************************/
566
568{
569 csInfo *csIP = &csTab[0];
570
571// Return an object it at all possible
572//
573 if (name && !(csIP = Find(name))) return 0;
574 return csIP->Obj->New();
575}
576
577/******************************************************************************/
578/* S i z e */
579/******************************************************************************/
580
581int XrdCksManager::Size(const char *Name)
582{
583 csInfo *iP = (Name != 0 ? Find(Name) : &csTab[0]);
584 return (iP != 0 ? iP->Len : 0);
585}
586
587/******************************************************************************/
588/* S e t */
589/******************************************************************************/
590
591int XrdCksManager::Set(const char *Pfn, XrdCksData &Cks, int myTime)
592{
594 csInfo *csIP = &csTab[0];
595
596// Verify the incoming checksum for correctness
597//
598 if (csLast < 0 || (*Cks.Name && !(csIP = Find(Cks.Name)))) return -ENOTSUP;
599 if (Cks.Length != csIP->Len) return -EDOM;
600 memcpy(&xCS.Attr.Cks, &Cks, sizeof(xCS.Attr.Cks));
601
602// Set correct times if need be
603//
604 if (!myTime)
605 {time_t MTime;
606 int rc = ModTime(Pfn, MTime);
607 if (rc) return rc;
608 xCS.Attr.Cks.fmTime = static_cast<long long>(MTime);
609 xCS.Attr.Cks.csTime = static_cast<int>(time(0) - MTime);
610 }
611
612// Now set the checksum information in the extended attribute object
613//
614 return xCS.Set(Pfn);
615}
616
617/******************************************************************************/
618/* V e r */
619/******************************************************************************/
620
621int XrdCksManager::Ver(const char *Pfn, XrdCksData &Cks)
622{
624 time_t MTime;
625 csInfo *csIP = &csTab[0];
626 int rc;
627
628// Determine which checksum to get
629//
630 if (csLast < 0 || (*Cks.Name && !(csIP = Find(Cks.Name)))) return -ENOTSUP;
631 xCS.Attr.Cks.Set(csIP->Name);
632
633// Verify the file
634//
635 if ((rc = ModTime(Pfn, MTime))) return rc;
636
637// Retreive the attribute. Return upon fatal error.
638//
639 if ((rc = xCS.Get(Pfn)) < 0) return rc;
640
641// Verify the checksum and see if we need to recalculate it
642//
643 if (!rc || xCS.Attr.Cks.fmTime != MTime
644 || strcmp(xCS.Attr.Cks.Name, csIP->Name)
645 || xCS.Attr.Cks.Length != csIP->Len)
646 {strcpy(xCS.Attr.Cks.Name, Cks.Name);
647 if ((rc = Calc(Pfn, xCS.Attr.Cks, 1)) < 0) return rc;
648 }
649
650// Compare the checksums
651//
652 return (xCS.Attr.Cks.Length == Cks.Length
653 && !memcmp(xCS.Attr.Cks.Value, Cks.Value, csIP->Len));
654}
#define ENOATTR
#define XRDOSSCKSLIBARGS
struct stat Stat
Definition XrdCks.cc:49
XrdOucXAttr< XrdCksXAttr > xCS
Definition XrdCks.cc:48
#define close(a)
Definition XrdPosix.hh:43
#define fstat(a, b)
Definition XrdPosix.hh:57
#define open
Definition XrdPosix.hh:71
#define stat(a, b)
Definition XrdPosix.hh:96
XrdOucString Path
virtual void Update(const char *Buff, int BLen)=0
virtual void Recycle()
Recycle the checksum object as it is no longer needed. A default is given.
Definition XrdCksCalc.hh:95
virtual XrdCksCalc * New()=0
virtual const char * Type(int &csSize)=0
virtual char * Final()=0
char Value[ValuSize]
Definition XrdCksData.hh:53
static const int ValuSize
Definition XrdCksData.hh:42
int Set(const char *csName)
Definition XrdCksData.hh:81
static const int NameSize
Definition XrdCksData.hh:41
char Name[NameSize]
Definition XrdCksData.hh:44
XrdCksCalc * Load(const char *csName, const char *csParms=0, char *eBuff=0, int eBlen=0, bool orig=false)
virtual int Config(const char *Token, char *Line)
virtual int Get(const char *Pfn, XrdCksData &Cks)
virtual int Del(const char *Pfn, XrdCksData &Cks)
virtual int Size(const char *Name=0)
virtual const char * Name(int seqNum=0)
virtual ~XrdCksManager()
XrdCksManager(XrdSysError *erP, int iosz, XrdVersionInfo &vInfo, bool autoload=false)
virtual int Calc(const char *Pfn, XrdCksData &Cks, int doSet=1)
virtual int ModTime(const char *Pfn, time_t &MTime)
virtual char * List(const char *Pfn, char *Buff, int Blen, char Sep=' ')
virtual XrdCksCalc * Object(const char *name)
virtual int Ver(const char *Pfn, XrdCksData &Cks)
virtual int Set(const char *Pfn, XrdCksData &Cks, int myTime=0)
virtual int Init(const char *ConfigFN, const char *AddCalc=0)
XrdSysError * eDest
Definition XrdCks.hh:289
void * Resolve(const char *symbl, int mcnt=1)
void Unload(bool dodel=false)
XrdSysPlugin * Export()
static void toLower(char *str)
int Emsg(const char *esfx, int ecode, const char *text1, const char *text2=0)
static XrdSysXAttr * Xat
char Name[1]
Start of the name (size of struct is dynamic)
int Nlen
The length of the attribute name that follows.
virtual void Free(AList *aPL)=0
AList * Next
-> next element.