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