37 #include <sys/types.h>
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 *)
83 const char *XrdCpConfig::opLetters =
":C:d:D:EfFhHI:NpPrRsS:t:T:vVX:y:z:ZA";
131 if ((PName = rindex(pgm,
'/'))) PName++;
175 if (inFile) free(inFile);
177 if (parmVal) free(parmVal);
183 while((pNow = pFile)) {pFile = pFile->
Next;
delete pNow;}
197 extern int optind, opterr;
198 static int pgmSet = 0;
199 char Buff[128], *
Path, opC;
205 if (parmVal) free(parmVal);
206 parmVal = (
char **)malloc(aCnt*
sizeof(
char *));
220 {
char *Slash = rindex(aVec[0],
'/');
222 Pgm = (Slash ? Slash+1 : aVec[0]);
229 if ((opC = getopt_long(Argc, Argv, opLetters, opVec, &i)) != (char)-1)
236 if (!a2i(optarg, &
Dlvl, 0, 3)) Usage(22);
248 case OpIfile:
if (inFile) free(inFile);
249 inFile = strdup(optarg);
270 if (!a2i(optarg, &
Retry, 0, -1)) Usage(22);
283 if (!a2i(optarg, &
nSrcs, 1, 32)) Usage(22);
286 if (!a2i(optarg, &
nStrm, 1, 15)) Usage(22);
293 if (!strcmp(
"delegate", optarg))
296 {
UMSG(
"Missing tpc qualifier after "
302 else if (strcmp(
"first", optarg))
304 UMSG(
"Invalid option, '" <<OpName()
305 <<
' ' <<optarg <<
"' ");
311 case OpVersion: std::cerr <<XrdVERSION <<std::endl; exit(0);
314 if (!a2z(optarg, &
xRate, 10*1024LL, -1)) Usage(22);
320 if (!a2i(optarg, &
Parallel, 1, 128)) Usage(22);
332 case ':':
UMSG(
"'" <<OpName() <<
"' argument missing.");
334 case '?':
if (!Legacy(
optind-1))
335 UMSG(
"Invalid option, '" <<OpName() <<
"'.");
337 default:
UMSG(
"Internal error processing '" <<OpName() <<
"'.");
340 }
while(opC != (
char)-1 &&
optind < Argc);
344 if (inFile) {
if (!parmCnt )
UMSG(
"Destination not specified.");}
345 else {
if (!parmCnt )
UMSG(
"No files specified.");
346 if ( parmCnt == 1 )
UMSG(
"Destination not specified.");
352 UMSG(
"Third party copy requires a single source.");
357 UMSG(
"Cannot calculate source checksum for a file in ZIP archive.");
360 UMSG(
"Cannot calculate source checksum for a file in ZIP archive.");
379 if (getenv(
"XRDCP_ALLOW_HTTP")) {
405 for (i = 0; i < parmCnt; i++) ProcFile(parmVal[i]);
412 int inFD =
open(inFile, O_RDONLY);
413 if (inFD < 0)
FMSG(
XrdSysE2T(errno) <<
" opening infiles " <<inFile, 2);
415 while((fname =
inList.GetLine()))
if (*fname) ProcFile(fname);
422 FMSG(
"Only a single source is allowed.", 2);
429 FMSG(
"Destination is neither remote nor a directory.", 2);
434 FMSG(
"All files are local; use 'cp' instead!", 1);
440 FMSG(
"Checksum with fixed value requires a single input file.", 2);
442 FMSG(
"Checksum with fixed value conflicts with '--recursive'.", 2);
449 while((pFile = pPrev->
Next))
465 FMSG(
"No regular files found to copy!", 2);
468 <<(
numFiles != 1 ?
" files." :
" file."));
479 int XrdCpConfig::a2i(
const char *item,
int *val,
int minv,
int maxv)
486 *val = strtol(item, &eP, 10);
487 if (errno || *eP)
ZMSG(
"'" <<OpName() <<
"' argument is not a number.");
492 ZMSG(
"'" <<OpName() <<
"' argument must be >= " <<minv <<
'.');
493 if (maxv >= 0 && *val > maxv)
494 ZMSG(
"'" <<OpName() <<
"' argument must be <= " <<maxv <<
'.');
501 int XrdCpConfig::a2l(
const char *item,
long long *val,
502 long long minv,
long long maxv)
509 *val = strtoll(item, &eP, 10);
510 if (errno || *eP)
ZMSG(
"'" <<OpName() <<
"' argument is not a number.");
515 ZMSG(
"'" <<OpName() <<
"' argument must be >= " <<minv <<
'.');
516 if (maxv >= 0 && *val > maxv)
517 ZMSG(
"'" <<OpName() <<
"' argument must be <= " <<maxv <<
'.');
525 int XrdCpConfig::a2t(
const char *item,
int *val,
int minv,
int maxv)
527 char *eP, *fP = (
char *)item + strlen(item) - 1;
531 if (*fP ==
's' || *fP ==
'S') qmult = 1;
532 else if (*fP ==
'm' || *fP ==
'M') qmult = 60;
533 else if (*fP ==
'h' || *fP ==
'H') qmult = 60*60;
534 else if (*fP ==
'd' || *fP ==
'D') qmult = 60*60*24;
535 else {qmult = 1; fP++;}
540 *val = strtoll(item, &eP, 10) * qmult;
541 if (errno || eP != fP)
542 ZMSG(
"'" <<OpName() <<
"' argument is not a valid time.");
547 ZMSG(
"'" <<OpName() <<
"' argument must be >= " <<minv <<
'.');
548 if (maxv >= 0 && *val > maxv)
549 ZMSG(
"'" <<OpName() <<
"' argument must be <= " <<maxv <<
'.');
557 int XrdCpConfig::a2x(
const char *Val,
char *Buff,
int Vlen)
559 int n, i = 0, Odd = 0;
560 if (Vlen & 0x01)
return 0;
562 {
if (*Val >=
'0' && *Val <=
'9') n = *Val-48;
563 else if (*Val >=
'a' && *Val <=
'f') n = *Val-87;
564 else if (*Val >=
'A' && *Val <=
'F') n = *Val-55;
566 if (Odd) Buff[i++] |= n;
567 else Buff[i ] = n << 4;
577 int XrdCpConfig::a2z(
const char *item,
long long *val,
578 long long minv,
long long maxv)
580 char *eP, *fP = (
char *)item + strlen(item) - 1;
584 if (*fP ==
'k' || *fP ==
'K') qmult = 1024LL;
585 else if (*fP ==
'm' || *fP ==
'M') qmult = 1024LL*1024LL;
586 else if (*fP ==
'g' || *fP ==
'G') qmult = 1024LL*1024LL*1024LL;
587 else if (*fP ==
't' || *fP ==
'T') qmult = 1024LL*1024LL*1024LL*1024LL;
588 else {qmult = 1; fP++;}
593 *val = strtoll(item, &eP, 10) * qmult;
594 if (errno || eP != fP)
595 ZMSG(
"'" <<OpName() <<
"' argument is not a valid time.");
600 ZMSG(
"'" <<OpName() <<
"' argument must be >= " <<minv <<
'.');
601 if (maxv >= 0 && *val > maxv)
602 ZMSG(
"'" <<OpName() <<
"' argument must be <= " <<maxv <<
'.');
610 int XrdCpConfig::defCks(
const char *opval)
614 std::string cksum( opval );
615 size_t pos = cksum.find(
':' );
616 std::string mode = cksum.substr( pos + 1 );
617 if( mode !=
"source" )
618 FMSG(
"Additional checksum must be of mode 'source'.", 13);
619 AddCksVal.push_back( cksum.substr( 0, pos ) );
624 const char *Colon = index(opval,
':');
634 FMSG(
"Unable to initialize checksum processing.", 13);
640 n = (Colon ? Colon - opval : strlen(opval));
642 UMSG(
"Invalid checksum type, '" <<opval <<
"'.");
643 strncpy(csName, opval, n); csName[n] = 0;
648 if( strcmp( csName,
"auto" ) )
652 UMSG(
"Invalid checksum type, '" <<csName <<
"'.");
668 else {n = strlen(Colon);
685 int XrdCpConfig::defOpq(
const char *theOp)
687 const char *oVal = theOp+3;
691 if (!(*oVal))
UMSG(
"'" <<theOp <<
"' opaque data not specified.");
695 if (*(theOp+2) ==
'S')
srcOpq = oVal;
707 int XrdCpConfig::defOpt(
const char *theOp,
const char *theArg)
710 int opval, isInt = (*(theOp+2) ==
'I');
711 const char *vName = theOp+3;
716 if (!(*vName))
UMSG(
"'" <<theOp <<
"' variable not specified.");
720 if (!theArg)
UMSG(
"'" <<theOp <<
"' argument not specified.");
726 opval = strtol(theArg, &eP, 10);
727 if (errno || *eP)
UMSG(
"'" <<theOp <<
"' argument is not a number.");
728 dP =
new defVar(vName, opval);
729 if (!intDend)
intDefs = intDend = dP;
730 else {intDend->
Next = dP; intDend = dP;}
732 dP =
new defVar(vName, theArg);
733 if (!strDend)
strDefs = strDend = dP;
734 else {strDend->
Next = dP; strDend = dP;}
746 void XrdCpConfig::defPxy(
const char *opval)
748 const char *Colon = index(opval,
':');
754 if (Colon == opval)
UMSG(
"Proxy host not specified.");
758 if (!Colon || !(*(Colon+1)))
UMSG(
"Proxy port not specified.");
763 pPort = strtol(Colon+1, &eP, 10);
764 if (errno || *eP || pPort < 1 || pPort > 65535)
765 UMSG(
"Invalid proxy port, '" <<opval <<
"'.");
770 n = Colon - opval + 1;
771 pHost = (
char *)malloc(n);
772 strncpy(
pHost, opval, n-1);
781 const char *XrdCpConfig::Human(
long long inval,
char *Buff,
int Blen)
783 static const char *sfx[] = {
" bytes",
"KB",
"MB",
"GB",
"TB",
"PB"};
786 for (i = 0; i <
sizeof(sfx)/
sizeof(sfx[0]) - 1 && inval >= 1024; i++)
789 snprintf(Buff, Blen,
"%lld%s", inval, sfx[i]);
797 int XrdCpConfig::Legacy(
int oIndex)
805 while(oIndex < Argc && (*Argv[oIndex] !=
'-' || *(Argv[oIndex]+1) ==
'\0'))
806 parmVal[parmCnt++] = Argv[oIndex++];
807 if (oIndex >= Argc)
return 0;
809 if (oIndex+1 >= Argc || *Argv[oIndex+1] ==
'-') oArg = 0;
810 else oArg = Argv[oIndex+1];
811 if (!(rc = Legacy(Argv[oIndex], oArg)))
return 0;
819 int XrdCpConfig::Legacy(
const char *theOp,
const char *theArg)
821 if (!strcmp(theOp,
"-adler"))
return defCks(
"adler32:source");
823 if (!strncmp(theOp,
"-DI", 3) || !strncmp(theOp,
"-DS", 3))
824 return defOpt(theOp, theArg);
826 if (!strcmp(theOp,
"-extreme") || !strcmp(theOp,
"-x"))
833 if (!strcmp(theOp,
"-md5"))
return defCks(
"md5:source");
835 if (!strncmp(theOp,
"-OD",3) || !strncmp(theOp,
"-OS",3))
return defOpq(theOp);
837 if (!strcmp(theOp,
"-version")) {std::cerr <<XrdVERSION <<std::endl; exit(0);}
839 if (!strcmp(theOp,
"-force"))
840 FMSG(
"-force is no longer supported; use --retry instead!",22);
849 void XrdCpConfig::License()
851 const char *theLicense =
852 #include "../../LICENSE"
855 std::cerr <<theLicense;
863 const char *XrdCpConfig::OpName()
866 static char oName[4] = {
'-', 0, 0, 0};
878 void XrdCpConfig::ProcFile(
const char *fname)
885 if (rc)
FMSG(
"Invalid url, '" <<fname <<
"'.", 22);
897 FMSG(pFile->
Path <<
" is a directory.", 2);
901 FMSG(
"Using stdin as a source is disallowed.", 22);
903 FMSG(
"Multiple sources disallowed with stdin.", 22);
910 {
FMSG(pFile->
ProtName <<
" file protocol is not supported.", 22)}
912 {
FMSG(
"Recursive copy from a remote host is not supported.",22)}
925 void XrdCpConfig::Usage(
int rc)
927 static const char *Syntax =
"\n"
928 "Usage: xrdcp [<options>] <src> [<src> [. . .]] <dest>\n";
930 static const char *Syntax1=
"\n"
931 "Usage: xrdcp [<options>] <src> <dest>\n";
933 static const char *Options=
"\n"
934 "Options: [--allow-http] [--cksum <args>] [--coerce] [--continue]\n"
935 " [--debug <lvl>] [--dynamic-src] [--force] [--help]\n"
936 " [--infiles <fn>] [--license] [--nopbar] [--notlsok]\n"
937 " [--parallel <n>] [--posc] [--proxy <host>:<port>]\n"
938 " [--recursive] [--retry <n>] [--retry-policy <force|continue>]\n"
939 " [--rm-bad-cksum] [--server] [--silent] [--sources <n>]\n"
940 " [--streams <n>] [--tlsmetalink] [--tlsnodata]\n"
941 " [--tpc [delegate] {first|only}] [--verbose] [--version]\n"
942 " [--xattr] [--xrate <rate>] [--xrate-threshold <rate>]\n"
943 " [--zip <file>] [--zip-append] [--zip-mtln-cksum]\n";
945 static const char *Syntax2=
"\n"
946 "<src>: [[x]root[s]://<host>[:<port>]/]<path> | -";
948 static const char *Syntay2=
"\n"
949 "<src>: [[x]root[s]://<host>[:<port>]/]<path>";
951 static const char *Syntax3=
"\n"
952 "<dest>: [[x]root[s]://<host>[:<port>]/]<path> | -";
954 static const char *Detail =
"\n"
955 "Note: using a dash (-) for <src> uses stdin and for <dest> stdout\n\n"
956 "-A | --allow-http allow HTTP as source or destination protocol. Requires\n"
957 " the XrdClHttp client plugin\n"
958 "-C | --cksum <args> verifies the checksum at the destination as provided\n"
959 " by the source server or locally computed. The args are\n"
960 " <ckstype>[:{<value>|print|source}]\n"
961 " where <ckstype> is one of adler32, crc32, crc32c, md5,\n"
962 " zcrc32 or auto. If 'auto' is chosen, xrdcp will try to\n"
963 " automatically infer the right checksum type based on the\n"
964 " source/destination configuration, source file type\n"
965 " (e.g. metalink, ZIP), and available checksum plug-ins.\n"
966 " If the hex value of the checksum is given, it is used.\n"
967 " Otherwise, the server's checksum is used for remote files\n"
968 " and computed for local files. Specifying print merely\n"
969 " prints the checksum but does not verify it.\n"
970 "-F | --coerce coerces the copy by ignoring file locking semantics\n"
971 " --continue continue copying a file from the point where the previous\n"
972 " copy was interrupted\n"
973 "-d | --debug <lvl> sets the debug level: 0 off, 1 low, 2 medium, 3 high\n"
974 "-Z | --dynamic-src file size may change during the copy\n"
975 "-f | --force replaces any existing output file\n"
976 "-h | --help prints this information\n"
977 "-I | --infiles <fname> specifies the file that contains a list of input files\n"
978 "-H | --license prints license terms and conditions\n"
979 "-N | --nopbar does not print the progress bar\n"
980 " --notlsok if server is too old to support TLS encryption fallback\n"
981 " to unencrypted communication\n"
982 " --parallel <n> number of files to copy at the same time\n"
983 "-P | --posc enables persist on successful close semantics\n"
984 "-D | --proxy <host>:<port> uses the specified SOCKS4 proxy connection\n"
985 "-r | --recursive recursively copies all source files\n"
986 "-t | --retry <n> maximum number of times to retry failed copy-jobs\n"
987 " --retry-policy <policy> retry policy: force or continue\n"
988 " --rm-bad-cksum remove the target file if checksum verification failed\n"
989 " (enables also POSC semantics)\n"
990 " --server runs in a server environment with added operations\n"
991 "-s | --silent produces no output other than error messages\n"
992 "-y | --sources <n> uses up to the number of sources specified in parallel\n"
993 "-S | --streams <n> copies using the specified number of TCP connections\n"
994 " --tlsmetalink convert [x]root to [x]roots protocol in metalinks\n"
995 "-E | --tlsnodata in case of [x]roots protocol, encrypt only the control\n"
996 " stream and leave the data streams unencrypted\n"
997 "-T | --tpc <args> uses third party copy mode between the src and dest.\n"
998 " Both the src and dest must allow tpc mode. Argument\n"
999 " 'first' tries tpc and if it fails, does a normal copy;\n"
1000 " while 'only' fails the copy unless tpc succeeds.\n"
1001 "-v | --verbose produces more information about the copy\n"
1002 "-V | --version prints the version number\n"
1003 " --xattr preserve extended attributes\n"
1004 "-X | --xrate <rate> limits the transfer to the specified rate. You can\n"
1005 " suffix the value with 'k', 'm', or 'g'\n"
1006 " --xrate-threshold <rate> If the transfer rate drops below given threshold force\n"
1007 " the client to use different source or if no more sources\n"
1008 " are available fail the transfer. You can suffix the value\n"
1009 " with 'k', 'm', or 'g'\n"
1010 "-z | --zip <file> treat the source as a ZIP archive containing given file\n"
1011 " --zip-append append file to existing zip archive\n"
1012 " --zip-mtln-cksum use the checksum available in a metalink file even if\n"
1013 " a file is being extracted from a ZIP archive\n"
1015 "Legacy options: [-adler] [-DI<var> <val>] [-DS<var> <val>] [-np]\n"
1016 " [-md5] [-OD<cgi>] [-OS<cgi>] [-version] [-x]";
1018 std::cerr <<(Opts &
opt1Src ? Syntax1 : Syntax) <<Options;
1019 std::cerr <<(Opts &
optNoStdIn ? Syntay2 : Syntax2) <<Syntax3 <<std::endl;
1020 if (!rc) std::cerr <<Detail <<std::endl;
int inList(const char *var, const char **Vec)
static XrdSysError eDest(0,"crypto_")
int open(const char *path, int oflag,...)
const char * XrdSysE2T(int errcode)
virtual const char * Type(int &csSize)=0
int Set(const char *csName)
static const int NameSize
virtual int Init(const char *ConfigFN, const char *DfltCalc=0)=0
virtual XrdCksCalc * Object(const char *name)
static void SetMsgPfx(const char *pfx)
int Extend(XrdCpFile **pLast, int &nFile, long long &nBytes)
const char * SetPrefix(const char *prefix)
XrdVERSIONINFODEF(myVersion, cmsclient, XrdVNUMBER, XrdVERSION)
static XrdSysLogger Logger
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
static const uint64_t DoCksum
static const uint64_t OpPosc
static const uint64_t DoXrate
static const uint64_t DoCksrc
static const uint64_t OpZipMtlnCksum
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 int OpAllowHttp
static const uint64_t DoRecurse
static const uint64_t OpTlsNoData
static const int optNoLclCp
static const uint64_t DoXrateThreshold
static const uint64_t DoZipAppend
static const uint64_t OpIfile
static const uint64_t DoDynaSrc
static const int DoAllowHttp
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 DoServer
static const uint64_t DoCkprt