39#include "XrdVersion.hh"
55#define EMSG(x) std::cerr <<PName <<": " <<x <<std::endl
57#define FMSG(x,y) {EMSG(x);exit(y);}
59#define UMSG(x) {EMSG(x);Usage(22);}
61#define ZMSG(x) {EMSG(x);return 0;}
66#define OPT_TYPE (char *)
93const char *XrdCpConfig::opLetters =
":C:d:D:EfFhH:I:NpPrRsS:t:T:vVX:y:z:ZA";
142 if ((PName = rindex(pgm,
'/'))) PName++;
177 if (
const auto value = getenv(
"BEARER_TOKEN_FILE"); value !=
nullptr)
190 if (inFile) free(inFile);
192 if (parmVal) free(parmVal);
199 while((pNow = pFile)) {pFile = pFile->Next;
delete pNow;}
213 extern int optind, opterr;
214 static int pgmSet = 0;
215 char Buff[128], *
Path, opC;
221 if (parmVal) free(parmVal);
222 parmVal = (
char **)malloc(aCnt*
sizeof(
char *));
236 {
char *Slash = rindex(aVec[0],
'/');
238 Pgm = (Slash ? Slash+1 : aVec[0]);
245 if ((opC = getopt_long(Argc, Argv, opLetters, opVec, &i)) != (
char)-1)
252 if (!a2i(optarg, &
Dlvl, 0, 3)) Usage(22);
267 case OpIfile:
if (inFile) free(inFile);
268 inFile = strdup(optarg);
289 if (!a2i(optarg, &
Retry, 0, -1)) Usage(22);
302 if (!a2i(optarg, &
nSrcs, 1, 32)) Usage(22);
305 if (!a2i(optarg, &
nStrm, 1, 15)) Usage(22);
312 if (!strcmp(
"delegate", optarg))
315 {
UMSG(
"Missing tpc qualifier after "
320 if (!strcmp(
"push", optarg))
323 {
UMSG(
"Missing tpc qualifier after "
329 else if (strcmp(
"first", optarg))
331 UMSG(
"Invalid option, '" <<OpName()
332 <<
' ' <<optarg <<
"' ");
342 case OpVersion: std::cerr <<XrdVERSION <<std::endl; exit(0);
345 if (!a2z(optarg, &
xRate, 10*1024LL, -1)) Usage(22);
351 if (!a2i(optarg, &
Parallel, 1, 128)) Usage(22);
361 case ':':
UMSG(
"'" <<OpName() <<
"' argument missing.");
363 case '?':
if (!Legacy(
optind-1))
364 UMSG(
"Invalid option, '" <<OpName() <<
"'.");
366 default:
UMSG(
"Internal error processing '" <<OpName() <<
"'.");
369 }
while(opC != (
char)-1 &&
optind < Argc);
373 if (inFile) {
if (!parmCnt )
UMSG(
"Destination not specified.");}
374 else {
if (!parmCnt )
UMSG(
"No files specified.");
375 if ( parmCnt == 1 )
UMSG(
"Destination not specified.");
381 UMSG(
"Third party copy requires a single source.");
386 UMSG(
"Cannot calculate source checksum for a file in ZIP archive.");
389 UMSG(
"Cannot calculate source checksum for a file in ZIP archive.");
431 for (i = 0; i < parmCnt; i++) ProcFile(parmVal[i]);
438 int inFD =
open(inFile, O_RDONLY);
439 if (inFD < 0)
FMSG(
XrdSysE2T(errno) <<
" opening infiles " <<inFile, 2);
441 while((fname =
inList.GetLine()))
if (*fname) ProcFile(fname);
449 UMSG(
"Source not specified.");
452 FMSG(
"Only a single source is allowed.", 2);
458 FMSG(
"Destination is neither remote nor a directory.", 2);
463 FMSG(
"All files are local; use 'cp' instead!", 1);
469 UMSG(
"'--header' requires an http or https source or destination.");
476 FMSG(
"Checksum with fixed value requires a single input file.", 2);
478 FMSG(
"Checksum with fixed value conflicts with '--recursive'.", 2);
485 while((pFile = pPrev->Next))
487 else {
Path = pFile->Path;
488 pPrev->Next = pFile->Next;
494 {pLast->Next = pPrev->Next;
495 pPrev->Next = pFile->Next;
501 FMSG(
"No regular files found to copy!", 2);
504 <<(
numFiles != 1 ?
" files." :
" file."));
515int XrdCpConfig::a2i(
const char *item,
int *val,
int minv,
int maxv)
522 *val = strtol(item, &eP, 10);
523 if (errno || *eP)
ZMSG(
"'" <<OpName() <<
"' argument is not a number.");
528 ZMSG(
"'" <<OpName() <<
"' argument must be >= " <<minv <<
'.');
529 if (maxv >= 0 && *val > maxv)
530 ZMSG(
"'" <<OpName() <<
"' argument must be <= " <<maxv <<
'.');
537int XrdCpConfig::a2l(
const char *item,
long long *val,
538 long long minv,
long long maxv)
545 *val = strtoll(item, &eP, 10);
546 if (errno || *eP)
ZMSG(
"'" <<OpName() <<
"' argument is not a number.");
551 ZMSG(
"'" <<OpName() <<
"' argument must be >= " <<minv <<
'.');
552 if (maxv >= 0 && *val > maxv)
553 ZMSG(
"'" <<OpName() <<
"' argument must be <= " <<maxv <<
'.');
561int XrdCpConfig::a2t(
const char *item,
int *val,
int minv,
int maxv)
563 char *eP, *fP = (
char *)item + strlen(item) - 1;
567 if (*fP ==
's' || *fP ==
'S') qmult = 1;
568 else if (*fP ==
'm' || *fP ==
'M') qmult = 60;
569 else if (*fP ==
'h' || *fP ==
'H') qmult = 60*60;
570 else if (*fP ==
'd' || *fP ==
'D') qmult = 60*60*24;
571 else {qmult = 1; fP++;}
576 *val = strtoll(item, &eP, 10) * qmult;
577 if (errno || eP != fP)
578 ZMSG(
"'" <<OpName() <<
"' argument is not a valid time.");
583 ZMSG(
"'" <<OpName() <<
"' argument must be >= " <<minv <<
'.');
584 if (maxv >= 0 && *val > maxv)
585 ZMSG(
"'" <<OpName() <<
"' argument must be <= " <<maxv <<
'.');
593int XrdCpConfig::a2x(
const char *Val,
char *Buff,
int Vlen)
595 int n, i = 0, Odd = 0;
596 if (Vlen & 0x01)
return 0;
598 {
if (*Val >=
'0' && *Val <=
'9') n = *Val-48;
599 else if (*Val >=
'a' && *Val <=
'f') n = *Val-87;
600 else if (*Val >=
'A' && *Val <=
'F') n = *Val-55;
602 if (Odd) Buff[i++] |= n;
603 else Buff[i ] = n << 4;
613int XrdCpConfig::a2z(
const char *item,
long long *val,
614 long long minv,
long long maxv)
616 char *eP, *fP = (
char *)item + strlen(item) - 1;
620 if (*fP ==
'k' || *fP ==
'K') qmult = 1024LL;
621 else if (*fP ==
'm' || *fP ==
'M') qmult = 1024LL*1024LL;
622 else if (*fP ==
'g' || *fP ==
'G') qmult = 1024LL*1024LL*1024LL;
623 else if (*fP ==
't' || *fP ==
'T') qmult = 1024LL*1024LL*1024LL*1024LL;
624 else {qmult = 1; fP++;}
629 *val = strtoll(item, &eP, 10) * qmult;
630 if (errno || eP != fP)
631 ZMSG(
"'" <<OpName() <<
"' argument is not a valid time.");
636 ZMSG(
"'" <<OpName() <<
"' argument must be >= " <<minv <<
'.');
637 if (maxv >= 0 && *val > maxv)
638 ZMSG(
"'" <<OpName() <<
"' argument must be <= " <<maxv <<
'.');
646int XrdCpConfig::defCks(
const char *opval)
650 std::string cksum( opval );
651 size_t pos = cksum.find(
':' );
652 std::string mode = cksum.substr( pos + 1 );
653 if( mode !=
"source" )
654 FMSG(
"Additional checksum must be of mode 'source'.", 13);
655 AddCksVal.push_back( cksum.substr( 0, pos ) );
660 const char *Colon = index(opval,
':');
670 FMSG(
"Unable to initialize checksum processing.", 13);
676 n = (Colon ? Colon - opval : strlen(opval));
678 UMSG(
"Invalid checksum type, '" <<opval <<
"'.");
679 strncpy(csName, opval, n); csName[n] = 0;
684 if( strcmp( csName,
"auto" ) )
688 UMSG(
"Invalid checksum type, '" <<csName <<
"'.");
704 else {n = strlen(Colon);
721int XrdCpConfig::defOpq(
const char *theOp)
723 const char *oVal = theOp+3;
727 if (!(*oVal))
UMSG(
"'" <<theOp <<
"' opaque data not specified.");
731 if (*(theOp+2) ==
'S')
srcOpq = oVal;
743int XrdCpConfig::defOpt(
const char *theOp,
const char *theArg)
746 int opval, isInt = (*(theOp+2) ==
'I');
747 const char *vName = theOp+3;
752 if (!(*vName))
UMSG(
"'" <<theOp <<
"' variable not specified.");
756 if (!theArg)
UMSG(
"'" <<theOp <<
"' argument not specified.");
762 opval = strtol(theArg, &eP, 10);
763 if (errno || *eP)
UMSG(
"'" <<theOp <<
"' argument is not a number.");
764 dP =
new defVar(vName, opval);
765 if (!intDend)
intDefs = intDend = dP;
766 else {intDend->Next = dP; intDend = dP;}
768 dP =
new defVar(vName, theArg);
769 if (!strDend)
strDefs = strDend = dP;
770 else {strDend->Next = dP; strDend = dP;}
782void XrdCpConfig::defPxy(
const char *opval)
784 const char *Colon = index(opval,
':');
790 if (Colon == opval)
UMSG(
"Proxy host not specified.");
794 if (!Colon || !(*(Colon+1)))
UMSG(
"Proxy port not specified.");
799 pPort = strtol(Colon+1, &eP, 10);
801 UMSG(
"Invalid proxy port, '" <<opval <<
"'.");
806 n = Colon - opval + 1;
807 pHost = (
char *)malloc(n);
808 strncpy(
pHost, opval, n-1);
817const char *XrdCpConfig::Human(
long long inval,
char *Buff,
int Blen)
819 static const char *sfx[] = {
" bytes",
"KB",
"MB",
"GB",
"TB",
"PB"};
822 for (i = 0; i <
sizeof(sfx)/
sizeof(sfx[0]) - 1 && inval >= 1024; i++)
825 snprintf(Buff, Blen,
"%lld%s", inval, sfx[i]);
833int XrdCpConfig::Legacy(
int oIndex)
841 while(oIndex < Argc && (*Argv[oIndex] !=
'-' || *(Argv[oIndex]+1) ==
'\0'))
842 parmVal[parmCnt++] = Argv[oIndex++];
843 if (oIndex >= Argc)
return 0;
845 if (oIndex+1 >= Argc || *Argv[oIndex+1] ==
'-') oArg = 0;
846 else oArg = Argv[oIndex+1];
847 if (!(rc = Legacy(Argv[oIndex], oArg)))
return 0;
855int XrdCpConfig::Legacy(
const char *theOp,
const char *theArg)
857 if (!strcmp(theOp,
"-adler"))
return defCks(
"adler32:source");
859 if (!strncmp(theOp,
"-DI", 3) || !strncmp(theOp,
"-DS", 3))
860 return defOpt(theOp, theArg);
862 if (!strcmp(theOp,
"-extreme") || !strcmp(theOp,
"-x"))
869 if (!strcmp(theOp,
"-md5"))
return defCks(
"md5:source");
871 if (!strncmp(theOp,
"-OD",3) || !strncmp(theOp,
"-OS",3))
return defOpq(theOp);
873 if (!strcmp(theOp,
"-version")) {std::cerr <<XrdVERSION <<std::endl; exit(0);}
875 if (!strcmp(theOp,
"-force"))
876 FMSG(
"-force is no longer supported; use --retry instead!",22);
885void XrdCpConfig::License()
887 const char *theLicense =
888#include "../../LICENSE"
891 std::cerr <<theLicense;
899const char *XrdCpConfig::OpName()
902 static char oName[4] = {
'-', 0, 0, 0};
914void XrdCpConfig::ProcFile(
const char *fname)
920 pLast->Next = pFile =
new XrdCpFile(fname, rc);
921 if (rc)
FMSG(
"Invalid url, '" <<fname <<
"'.", 22);
933 FMSG(pFile->Path <<
" is a directory.", 2);
937 FMSG(
"Using stdin as a source is disallowed.", 22);
939 FMSG(
"Multiple sources disallowed with stdin.", 22);
947 {
FMSG(pFile->ProtName <<
" file protocol is not supported.", 22)}
949 {
FMSG(
"Recursive copy from a remote host is not supported.",22)}
962void XrdCpConfig::Usage(
int rc)
964 static const char *Syntax =
"\n"
965 "Usage: xrdcp [<options>] <src> [<src> [. . .]] <dest>\n";
967 static const char *Syntax1=
"\n"
968 "Usage: xrdcp [<options>] <src> <dest>\n";
970 static const char *Options=
"\n"
971 "Options: [--cksum <args>] [--coerce] [--continue]\n"
972 " [--debug <lvl>] [--dynamic-src] [--force] [--header <name: value>]\n"
973 " [--help] [--infiles <fn>] [--license] [--nopbar] [--notlsok]\n"
974 " [--parallel <n>] [--posc] [--proxy <host>:<port>]\n"
975 " [--recursive] [--retry <n>] [--retry-policy <force|continue>]\n"
976 " [--rm-bad-cksum] [--server] [--silent] [--sources <n>]\n"
977 " [--streams <n>] [--tlsmetalink] [--tlsnodata]\n"
978 " [--tpc [delegate] [push] {first|only}] [--verbose] [--version]\n"
979 " [--tpc-token-file <file>]\n"
980 " [--xattr] [--xrate <rate>] [--xrate-threshold <rate>]\n"
981 " [--zip <file>] [--zip-append] [--zip-mtln-cksum]\n";
983 static const char *Syntax2=
"\n"
984 "<src>: [[x]root[s]://<host>[:<port>]/]<path> | -";
986 static const char *Syntay2=
"\n"
987 "<src>: [[x]root[s]://<host>[:<port>]/]<path>";
989 static const char *Syntax3=
"\n"
990 "<dest>: [[x]root[s]://<host>[:<port>]/]<path> | -";
992 static const char *Detail =
"\n"
993 "Note: using a dash (-) for <src> uses stdin and for <dest> stdout\n\n"
994 "-C | --cksum <args> verifies the checksum at the destination as provided\n"
995 " by the source server or locally computed. The args are\n"
996 " <ckstype>[:{<value>|print|source}]\n"
997 " where <ckstype> is one of adler32, crc32, crc32c, md5,\n"
998 " zcrc32 or auto. If 'auto' is chosen, xrdcp will try to\n"
999 " automatically infer the right checksum type based on the\n"
1000 " source/destination configuration, source file type\n"
1001 " (e.g. metalink, ZIP), and available checksum plug-ins.\n"
1002 " If the hex value of the checksum is given, it is used.\n"
1003 " Otherwise, the server's checksum is used for remote files\n"
1004 " and computed for local files. Specifying print merely\n"
1005 " prints the checksum but does not verify it.\n"
1006 "-F | --coerce coerces the copy by ignoring file locking semantics\n"
1007 " --continue continue copying a file from the point where the previous\n"
1008 " copy was interrupted\n"
1009 "-d | --debug <lvl> sets the debug level: 0 off, 1 low, 2 medium, 3 high\n"
1010 "-Z | --dynamic-src file size may change during the copy\n"
1011 "-f | --force replaces any existing output file\n"
1012 "-H | --header <name: value> adds the given header to the requests sent to an\n"
1013 " http or https endpoint. May be repeated to add more\n"
1014 " than one header. Requires an http or https source or\n"
1015 " destination. The hop-by-hop and message framing\n"
1016 " headers are reserved and cannot be overridden.\n"
1017 " With --tpc, the headers go to the server the client\n"
1018 " connects to: the destination server in 'pull' mode,\n"
1019 " or the source server in 'push' mode. To send a header\n"
1020 " to the other server, prepend 'TransferHeader' to the\n"
1021 " header name. Example, in 'pull' mode:\n"
1022 " -H \"X-Request-Id: <destination-id>\"\n"
1023 " -H \"TransferHeaderX-Request-Id: <source-id>\"\n"
1024 " The destination server gets the X-Request-Id header,\n"
1025 " and sends the value of TransferHeaderX-Request-Id as\n"
1026 " the X-Request-Id header of its request to the source.\n"
1027 " If the option is not specified, the XRD_HTTPHEADERS\n"
1028 " environment variable is used instead. It holds the\n"
1029 " headers as a newline separated list of\n"
1030 " '<name>: <value>' entries.\n"
1031 "-h | --help prints this information\n"
1032 "-I | --infiles <fname> specifies the file that contains a list of input files\n"
1033 " --license prints license terms and conditions\n"
1034 "-N | --nopbar does not print the progress bar\n"
1035 " --notlsok if server is too old to support TLS encryption fallback\n"
1036 " to unencrypted communication\n"
1037 " --parallel <n> number of files to copy at the same time\n"
1038 "-P | --posc enables persist on successful close semantics\n"
1039 "-D | --proxy <host>:<port> uses the specified SOCKS4 proxy connection\n"
1040 "-r | --recursive recursively copies all source files\n"
1041 "-t | --retry <n> maximum number of times to retry failed copy-jobs\n"
1042 " --retry-policy <policy> retry policy: force or continue\n"
1043 " --rm-bad-cksum remove the target file if checksum verification failed\n"
1044 " (enables also POSC semantics)\n"
1045 " --server runs in a server environment with added operations\n"
1046 "-s | --silent produces no output other than error messages\n"
1047 "-y | --sources <n> uses up to the number of sources specified in parallel\n"
1048 "-S | --streams <n> copies using the specified number of TCP connections\n"
1049 " --tlsmetalink convert [x]root to [x]roots protocol in metalinks\n"
1050 "-E | --tlsnodata in case of [x]roots protocol, encrypt only the control\n"
1051 " stream and leave the data streams unencrypted\n"
1052 "-T | --tpc <args> uses third party copy mode between the src and dest.\n"
1053 " Both the src and dest must allow tpc mode. Argument\n"
1054 " 'first' tries tpc and if it fails, does a normal copy;\n"
1055 " while 'only' fails the copy unless tpc succeeds.\n"
1056 " Argument 'push' drives the copy from the source server,\n"
1057 " which pushes the data to the destination; by default the\n"
1058 " destination server pulls the data from the source. A push\n"
1059 " copy only applies to tpc over HTTP(S).\n"
1060 " --tpc-token-file <file> Specify a token file containing in the first line the\n"
1061 " <src> token and in the second line the <dst> token. In\n"
1062 " case the file is a JSON object, the <src> and <dst>\n"
1063 " tokens are taken from its 'src' and 'dst' properties.\n"
1064 " Either token may be left out, by an empty line or by an\n"
1065 " omitted property, but not both.\n"
1066 " In case no file is specified the BEARER_TOKEN_FILE env\n"
1067 " variable will be used.\n"
1068 "-v | --verbose produces more information about the copy\n"
1069 "-V | --version prints the version number\n"
1070 " --xattr preserve extended attributes\n"
1071 "-X | --xrate <rate> limits the transfer to the specified rate. You can\n"
1072 " suffix the value with 'k', 'm', or 'g'\n"
1073 " --xrate-threshold <rate> If the transfer rate drops below given threshold force\n"
1074 " the client to use different source or if no more sources\n"
1075 " are available fail the transfer. You can suffix the value\n"
1076 " with 'k', 'm', or 'g'\n"
1077 "-z | --zip <file> treat the source as a ZIP archive containing given file\n"
1078 " --zip-append append file to existing zip archive\n"
1079 " --zip-mtln-cksum use the checksum available in a metalink file even if\n"
1080 " a file is being extracted from a ZIP archive\n"
1082 "Legacy options: [-adler] [-DI<var> <val>] [-DS<var> <val>] [-np]\n"
1083 " [-md5] [-OD<cgi>] [-OS<cgi>] [-version] [-x]";
1085 std::cerr <<(Opts &
opt1Src ? Syntax1 : Syntax) <<Options;
1086 std::cerr <<(Opts &
optNoStdIn ? Syntay2 : Syntax2) <<Syntax3 <<std::endl;
1087 if (!rc) std::cerr <<Detail <<std::endl;
int inList(const char *var, const char **Vec)
XrdSysError eDest(0, "HttpMon")
const char * XrdSysE2T(int errcode)
virtual const char * Type(int &csSize)=0
int Set(const char *csName)
static const int NameSize
XrdCksManager(XrdSysError *erP, int iosz, XrdVersionInfo &vInfo, bool autoload=false)
virtual int Init(const char *ConfigFN, const char *DfltCalc=0)=0
virtual XrdCksCalc * Object(const char *name)
static const uint64_t OpVerbose
static const uint64_t OpXAttr
static const uint64_t DoProxy
void Config(int argc, char **argv, int Opts=0)
static const uint64_t OpRecurse
static const uint64_t OpContinue
static const uint64_t DoRetry
static const uint64_t DoStreams
std::vector< std::string > AddCksVal
static const uint64_t OpParallel
static const uint64_t OpZipAppend
static const uint64_t DoZipMtlnCksum
static const uint64_t OpSilent
static const uint64_t OpTlsMLF
static const uint64_t OpNoTlsOK
static const uint64_t OpRetryPolicy
static const uint64_t OpDebug
XrdCpConfig(const char *pgname)
static const uint64_t OpRetry
static const uint64_t DoNoPbar
static const uint64_t OpXrateThreshold
static const uint64_t DoCoerce
static const uint64_t OpServer
static const uint64_t DoForce
static const uint64_t OpVersion
static const uint64_t OpTpc
static const uint64_t DoParallel
static const uint64_t DoRmOnBadCksum
static const uint64_t DoNoTlsOK
static const uint64_t OpPath
static const uint64_t OpRecursv
static const uint64_t OpProxy
static const uint64_t DoTpc
static const uint64_t DoDebug
static const uint64_t OpSources
std::vector< std::string > HttpHeaders
static const uint64_t DoCksum
static const uint64_t OpPosc
static const uint64_t DoXrate
static const uint64_t DoCksrc
static const uint64_t DoTpcModePush
static const uint64_t OpZipMtlnCksum
static const uint64_t DoHttpHeader
static const uint64_t OpXrate
static const uint64_t DoTpcDlgt
static const uint64_t DoZip
static const uint64_t DoVerbose
static const uint64_t DoContinue
static const uint64_t OpCksum
static const uint64_t DoRecurse
static const uint64_t OpTlsNoData
static const int optNoLclCp
static const uint64_t DoXrateThreshold
static const uint64_t DoTpcTokenFile
static const uint64_t DoZipAppend
static const uint64_t OpIfile
static const uint64_t DoDynaSrc
static const uint64_t OpHttpHeader
static const int optNoStdIn
static const uint64_t OpNoPbar
static const uint64_t DoSources
static const uint64_t DoSilent
static const uint64_t OpForce
static const uint64_t OpRmOnBadCksum
static const uint64_t OpDynaSrc
static const uint64_t DoXAttr
static const int optNoXtnd
static const uint64_t DoTlsMLF
static const uint64_t OpZip
static const uint64_t OpLicense
static const uint64_t DoIfile
static const uint64_t OpHelp
static const int optRmtRec
static const uint64_t DoRetryPolicy
static const uint64_t DoPath
static const uint64_t DoPosc
static const uint64_t OpStreams
static const uint64_t OpCoerce
static const uint64_t DoTpcOnly
static const uint64_t DoTlsNoData
static const uint64_t OpTpcTokenFile
static const uint64_t DoServer
static const uint64_t DoCkprt
static void SetMsgPfx(const char *pfx)
const char * SetPrefix(const char *prefix)
XrdVERSIONINFODEF(myVersion, cmsclient, XrdVNUMBER, XrdVERSION)
static XrdSysLogger Logger
static bool isHttpProt(XrdCpFile::PType pType)
defVar(const char *vn, const char *vl)