/******************************************************************************/
/* */
/* X r d C k s A s s i s t . c c */
/* */
/* (c) 2017 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 "XrdCks/XrdCksData.hh"
/******************************************************************************/
/* S t a t i c s */
/******************************************************************************/
namespace
{
struct csTable {const char *csName; int csLenC; int csLenB;} csTab[]
= {{"adler32", 8, 4},
{"crc32", 8, 4},
{"crc64", 16, 8},
{"md5", 32, 16},
{"sha1", 40, 20},
{"sha2", 64, 32},
{"sha256", 64, 32},
{"sha512", 128, 64}
};
static const int csNum = sizeof(csTab)/sizeof(csTable);
bool LowerCase(const char *src, char *dst, int dstlen)
{
int n = strlen(src);
// Verify that the result will fit in the supplied buffer with a null
//
if (n >= dstlen) return false;
// Convert to ower case with trailing nulls
//
memset(dst+n, 0, dstlen-n);
for (int i = 0; i < n; i++) dst[i] = tolower(src[i]);
return true;
}
}
/******************************************************************************/
/* X r d C k s A t t r D a t a */
/******************************************************************************/
// Return the data portion of a checksum attribute so that it can be use
// to set an attribute value.
std::vector XrdCksAttrData(const char *cstype,
const char *csval, time_t mtime)
{
std::vector cksError; // Null vector
XrdCksData cksData;
char csName[XrdCksData::NameSize];
int n = strlen(cstype);
// Convert the checksum type to lower case
//
if (!LowerCase(cstype, csName, sizeof(csName)))
{errno = ENAMETOOLONG; return cksError;}
// For cheksums we know, verify that the legnth of the input string
// corresponds to the checksum type.
//
n = strlen(csval);
for (int i = 0; i < csNum; i++)
{if (!strcmp(csTab[i].csName, csName) && csTab[i].csLenC != n)
{errno = EINVAL; return cksError;}
}
// we simply fill out the cksdata structure with the provided information
//
if (!cksData.Set(csName)) {errno = ENAMETOOLONG; return cksError;}
if (!cksData.Set(csval, n)) {errno = EOVERFLOW; return cksError;}
cksData.fmTime = mtime;
cksData.csTime = time(0) - mtime;
// Convert the checksum data to a string of bytes and return the vector
//
return std::vector( (char *)&cksData,
((char *)&cksData) + sizeof(cksData));
}
/******************************************************************************/
/* X r d C k s A t t r N a m e */
/******************************************************************************/
// Return the extended attribute variable name for a particular checksum type.
std::string XrdCksAttrName(const char *cstype, const char *nspfx)
{
std::string xaName;
char csName[XrdCksData::NameSize];
int pfxlen = strlen(nspfx);
// Do some easy checks for this we know are common
//
if (!pfxlen)
{if (!strcmp(cstype, "adler32")) return std::string("XrdCks.adler32");
if (!strcmp(cstype, "md5" )) return std::string("XrdCks.md5");
if (!strcmp(cstype, "crc32" )) return std::string("XrdCks.crc32");
}
// Convert the checksum type to lower case
//
if (!LowerCase(cstype, csName, sizeof(csName)))
{errno = ENAMETOOLONG; return xaName;}
// Reserve storage for the string and construct the variable name
//
xaName.reserve(strlen(nspfx) + strlen(cstype) + 8);
if (pfxlen)
{xaName = nspfx;
if (nspfx[pfxlen-1] != '.') xaName += '.';
}
xaName += "XrdCks.";
xaName += csName;
// Return the variable name
//
return xaName;
}
/******************************************************************************/
/* X r d C k s A t t r V a l u e */
/******************************************************************************/
std::string XrdCksAttrValue(const char *cstype,
const char *csbuff, int csblen)
{
XrdCksData cksData;
std::string csError;
char csBuff[XrdCksData::ValuSize*2+1];
// Verify that the length matches our object length
//
if (csblen != (int)sizeof(cksData)) {errno = EMSGSIZE; return csError;}
// Copy the buffer into the object
//
memcpy(&cksData, csbuff, sizeof(cksData));
// Now verify that all the fields are consistent
//
if (strncasecmp(cksData.Name, cstype, XrdCksData::NameSize))
{errno = ENOENT; return csError;}
if (cksData.Length <= 0 || cksData.Length > XrdCksData::ValuSize)
{errno = EINVAL; return csError;}
// For known checksum values make sure the length matches
//
for (int i = 0; i < csNum; i++)
{if (!strcmp(csTab[i].csName, cstype)
&& csTab[i].csLenB != int(cksData.Length))
{errno = EINVAL; return csError;}
}
// Convert value to a hex string
//
if (!cksData.Get(csBuff, sizeof(csBuff)))
{errno = EOVERFLOW; return csError;}
// Return string version of the hex string
//
return std::string(csBuff);
}