32 # include <sys/types.h>
47 #if defined(R__UNIX) || defined(R__MACOSX)
52 # include <sys/mman.h>
59 Long64_t TFTP::fgBytesWrite = 0;
60 Long64_t TFTP::fgBytesRead = 0;
74 TFTP::TFTP(
const char *url, Int_t par, Int_t wsize, TSocket *sock)
79 if (s.Contains(
"://")) {
80 if (!s.BeginsWith(
"root")) {
82 "url must be of the form \"[root[up,s,k,g,h,ug]://]host[:port]\"");
95 void TFTP::Init(
const char *surl, Int_t par, Int_t wsize)
98 TString hurl(url.GetProtocol());
99 if (hurl.Contains(
"root")) {
104 hurl += TString(Form(
"://%s@%s:%d",
105 url.GetUser(), url.GetHost(), url.GetPort()));
106 fSocket = TSocket::CreateAuthSocket(hurl, par, wsize, fSocket);
107 if (!fSocket || !fSocket->IsAuthenticated()) {
109 Error(
"TFTP",
"can't open %d-stream connection to rootd on "
110 "host %s at port %d", par, url.GetHost(), url.GetPort());
112 Error(
"TFTP",
"can't open connection to rootd on "
113 "host %s at port %d", url.GetHost(), url.GetPort());
117 fProtocol = fSocket->GetRemoteProtocol();
118 fUser = fSocket->GetSecContext()->GetUser();
120 fHost = url.GetHost();
121 fPort = url.GetPort();
126 fBlockSize = kDfltBlockSize;
135 R__LOCKGUARD(gROOTMutex);
136 gROOT->GetListOfSockets()->Remove(fSocket);
137 gROOT->GetListOfSockets()->Add(
this);
157 void TFTP::Print(Option_t *)
const
161 Printf(
"Local host: %s", gSystem->HostName());
162 Printf(
"Remote host: %s [%d]", fHost.Data(), fPort);
163 Printf(
"Remote user: %s", fUser.Data());
164 if (fSocket->IsAuthenticated())
165 Printf(
"Security context: %s",
166 fSocket->GetSecContext()->AsString(secCont));
167 Printf(
"Rootd protocol vers.: %d", fSocket->GetRemoteProtocol());
169 Printf(
"Parallel sockets: %d", fParallel);
171 Printf(
"TCP window size: %d", fWindowSize);
172 Printf(
"Rootd protocol: %d", fProtocol);
173 Printf(
"Transfer block size: %d", fBlockSize);
174 Printf(
"Transfer mode: %s", fMode ?
"ascii" :
"binary");
175 Printf(
"Bytes sent: %lld", fBytesWrite);
176 Printf(
"Bytes received: %lld", fBytesRead);
182 void TFTP::PrintError(
const char *where, Int_t err)
const
184 Error(where,
"%s", gRootdErrStr[err]);
191 Int_t TFTP::Recv(Int_t &status, EMessageTypes &kind)
const
196 if (!fSocket)
return -1;
199 Int_t n = fSocket->Recv(status, what);
200 kind = (EMessageTypes) what;
207 void TFTP::SetBlockSize(Int_t blockSize)
209 if (blockSize < 32768) {
215 for (i = 0; i < int(
sizeof(blockSize)*8); i++)
216 if ((blockSize >> i) == 1)
233 Long64_t TFTP::PutFile(
const char *file,
const char *remoteName)
235 if (!IsOpen() || !file || !*file)
return -1;
237 #if defined(R__WIN32) || defined(R__WINGCC)
238 Int_t fd = open(file, O_RDONLY | O_BINARY);
239 #elif defined(R__SEEK64)
240 Int_t fd = open64(file, O_RDONLY);
242 Int_t fd = open(file, O_RDONLY);
245 Error(
"PutFile",
"cannot open %s in read mode", file);
250 Long_t id, flags, modtime;
251 if (gSystem->GetPathInfo(file, &
id, &size, &flags, &modtime) == 0) {
253 Error(
"PutFile",
"%s not a regular file (%ld)", file, flags);
258 Warning(
"PutFile",
"could not stat %s", file);
266 Long64_t restartat = fRestartAt;
269 if (restartat && (restartat >= size))
272 if (fSocket->Send(Form(
"%s %d %d %lld %lld", remoteName, fBlockSize, fMode,
273 size, restartat), kROOTD_PUTFILE) < 0) {
274 Error(
"PutFile",
"error sending kROOTD_PUTFILE command");
282 if (Recv(stat, kind) < 0 || kind == kROOTD_ERR) {
283 PrintError(
"PutFile", stat);
288 Info(
"PutFile",
"sending file %s (%lld bytes, starting at %lld)",
289 file, size, restartat);
294 Long64_t pos = restartat & ~(fBlockSize-1);
295 Int_t skip = restartat - pos;
298 char *buf =
new char[fBlockSize];
299 #if defined(R__SEEK64)
300 lseek64(fd, pos, SEEK_SET);
301 #elif defined(R__WIN32)
302 _lseeki64(fd, pos, SEEK_SET);
304 lseek(fd, pos, SEEK_SET);
309 Long64_t left = Long64_t(size - pos);
310 if (left > fBlockSize)
313 #if defined(R__SEEK64)
314 char *buf = (
char*) mmap64(0, left, PROT_READ, MAP_FILE | MAP_SHARED, fd, pos);
316 char *buf = (
char*) mmap(0, left, PROT_READ, MAP_FILE | MAP_SHARED, fd, pos);
318 if (buf == (
char *) -1) {
319 Error(
"PutFile",
"mmap of file %s failed", file);
325 while ((siz = read(fd, buf, left)) < 0 && TSystem::GetErrno() == EINTR)
326 TSystem::ResetErrno();
327 if (siz < 0 || siz != left) {
328 Error(
"PutFile",
"error reading from file %s", file);
336 if (fSocket->SendRaw(buf+skip, left-skip) < 0) {
337 Error(
"PutFile",
"error sending buffer");
348 fBytesWrite += left-skip;
349 fgBytesWrite += left-skip;
370 if (Recv(stat, kind) < 0 || kind == kROOTD_ERR) {
371 PrintError(
"PutFile", stat);
377 Double_t speed, t = timer.RealTime();
379 speed = Double_t(size - restartat) / t;
383 Info(
"PutFile",
"%.3f seconds, %.2f Mbytes per second",
385 else if (speed > 512)
386 Info(
"PutFile",
"%.3f seconds, %.2f Kbytes per second",
389 Info(
"PutFile",
"%.3f seconds, %.2f bytes per second",
392 return Long64_t(size - restartat);
406 Long64_t TFTP::GetFile(
const char *file,
const char *localName)
408 if (!IsOpen() || !file || !*file)
return -1;
417 Long64_t restartat = fRestartAt;
419 if (fSocket->Send(Form(
"%s %d %d %lld", file, fBlockSize, fMode,
420 restartat), kROOTD_GETFILE) < 0) {
421 Error(
"GetFile",
"error sending kROOTD_GETFILE command");
428 if (Recv(stat, kind) < 0 || kind == kROOTD_ERR) {
429 PrintError(
"GetFile", stat);
438 if (fSocket->Recv(mess,
sizeof(mess), what) < 0) {
439 Error(
"GetFile",
"error receiving remote file size");
443 sscanf(mess,
"%I64d", &size);
445 sscanf(mess,
"%lld", &size);
449 if (restartat && (restartat >= size))
455 #if defined(R__WIN32) || defined(R__WINGCC)
456 if (fMode == kBinary)
457 fd = open(localName, O_CREAT | O_TRUNC | O_WRONLY | O_BINARY,
460 fd = open(localName, O_CREAT | O_TRUNC | O_WRONLY,
462 #elif defined(R__SEEK64)
463 fd = open64(localName, O_CREAT | O_TRUNC | O_WRONLY, 0600);
465 fd = open(localName, O_CREAT | O_TRUNC | O_WRONLY, 0600);
468 #if defined(R__WIN32) || defined(R__WINGCC)
469 if (fMode == kBinary)
470 fd = open(localName, O_WRONLY | O_BINARY, S_IREAD | S_IWRITE);
472 fd = open(localName, O_WRONLY, S_IREAD | S_IWRITE);
473 #elif defined(R__SEEK64)
474 fd = open64(localName, O_WRONLY, 0600);
476 fd = open(localName, O_WRONLY, 0600);
481 Error(
"GetFile",
"cannot open %s", localName);
487 if (strcmp(localName,
"/dev/null")) {
488 Long_t id, bsize, blocks, bfree;
489 if (gSystem->GetFsInfo(localName, &
id, &bsize, &blocks, &bfree) == 0) {
490 Long64_t space = (Long64_t)bsize * (Long64_t)bfree;
491 if (space < size - restartat) {
492 Error(
"GetFile",
"not enough space to store file %s", localName);
498 Warning(
"GetFile",
"could not determine if there is enough free space to store file");
503 #if defined(R__SEEK64)
504 if (lseek64(fd, restartat, SEEK_SET) < 0) {
505 #elif defined(R__WIN32)
506 if (_lseeki64(fd, restartat, SEEK_SET) < 0) {
508 if (lseek(fd, restartat, SEEK_SET) < 0) {
510 Error(
"GetFile",
"cannot seek to position %lld in file %s",
511 restartat, localName);
518 Info(
"GetFile",
"getting file %s (%lld bytes, starting at %lld)",
519 localName, size, restartat);
524 char *buf =
new char[fBlockSize];
527 buf2 =
new char[fBlockSize];
529 Long64_t pos = restartat & ~(fBlockSize-1);
530 Int_t skip = restartat - pos;
533 Long64_t left = size - pos;
534 if (left > fBlockSize)
538 while ((n = fSocket->RecvRaw(buf, Int_t(left-skip))) < 0 &&
539 TSystem::GetErrno() == EINTR)
540 TSystem::ResetErrno();
542 if (n != Int_t(left-skip)) {
543 Error(
"GetFile",
"error receiving buffer of length %d, got %d",
544 Int_t(left-skip), n);
546 delete [] buf;
delete [] buf2;
552 if (fMode == kAscii) {
558 buf2[j++] = buf[i++];
561 while ((siz = write(fd, buf2, n)) < 0 && TSystem::GetErrno() == EINTR)
562 TSystem::ResetErrno();
564 while ((siz = write(fd, buf, n)) < 0 && TSystem::GetErrno() == EINTR)
565 TSystem::ResetErrno();
569 SysError(
"GetFile",
"error writing file %s", localName);
572 delete [] buf;
delete [] buf2;
577 Error(
"GetFile",
"error writing all requested bytes to file %s, wrote %ld of %d",
578 localName, (Long_t)siz, n);
581 delete [] buf;
delete [] buf2;
585 fBytesRead += left-skip;
586 fgBytesRead += left-skip;
594 delete [] buf;
delete [] buf2;
605 Double_t speed, t = timer.RealTime();
607 speed = Double_t(size - restartat) / t;
611 Info(
"GetFile",
"%.3f seconds, %.2f Mbytes per second",
613 else if (speed > 512)
614 Info(
"GetFile",
"%.3f seconds, %.2f Kbytes per second",
617 Info(
"GetFile",
"%.3f seconds, %.2f bytes per second",
620 return Long64_t(size - restartat);
628 Int_t TFTP::ChangeDirectory(
const char *dir)
const
630 if (!IsOpen())
return -1;
633 Error(
"ChangeDirectory",
"illegal directory name specified");
637 if (fSocket->Send(Form(
"%s", dir), kROOTD_CHDIR) < 0) {
638 Error(
"ChangeDirectory",
"error sending kROOTD_CHDIR command");
645 if (fSocket->Recv(mess,
sizeof(mess), what) < 0) {
646 Error(
"ChangeDirectory",
"error receiving chdir confirmation");
649 if (what == kMESS_STRING) {
650 Printf(
"%s\n", mess);
652 if (fSocket->Recv(mess,
sizeof(mess), what) < 0) {
653 Error(
"ChangeDirectory",
"error receiving chdir confirmation");
658 Info(
"ChangeDirectory",
"%s", mess);
667 Int_t TFTP::MakeDirectory(
const char *dir, Bool_t print)
const
669 if (!IsOpen())
return -1;
672 Error(
"MakeDirectory",
"illegal directory name specified");
676 if (fSocket->Send(Form(
"%s", dir), kROOTD_MKDIR) < 0) {
677 Error(
"MakeDirectory",
"error sending kROOTD_MKDIR command");
684 if (fSocket->Recv(mess,
sizeof(mess), what) < 0) {
685 Error(
"MakeDirectory",
"error receiving mkdir confirmation");
690 Info(
"MakeDirectory",
"%s", mess);
692 if (!strncmp(mess,
"OK:",3))
702 Int_t TFTP::DeleteDirectory(
const char *dir)
const
704 if (!IsOpen())
return -1;
707 Error(
"DeleteDirectory",
"illegal directory name specified");
711 if (fSocket->Send(Form(
"%s", dir), kROOTD_RMDIR) < 0) {
712 Error(
"DeleteDirectory",
"error sending kROOTD_RMDIR command");
719 if (fSocket->Recv(mess,
sizeof(mess), what) < 0) {
720 Error(
"DeleteDirectory",
"error receiving rmdir confirmation");
724 Info(
"DeleteDirectory",
"%s", mess);
734 Int_t TFTP::ListDirectory(Option_t *cmd)
const
736 if (!IsOpen())
return -1;
741 if (fSocket->Send(Form(
"%s", cmd), kROOTD_LSDIR) < 0) {
742 Error(
"ListDirectory",
"error sending kROOTD_LSDIR command");
750 if (fSocket->Recv(mess,
sizeof(mess), what) < 0) {
751 Error(
"ListDirectory",
"error receiving lsdir confirmation");
755 }
while (what == kMESS_STRING);
764 Int_t TFTP::PrintDirectory()
const
766 if (!IsOpen())
return -1;
768 if (fSocket->Send(
"", kROOTD_PWD) < 0) {
769 Error(
"DeleteDirectory",
"error sending kROOTD_PWD command");
776 if (fSocket->Recv(mess,
sizeof(mess), what) < 0) {
777 Error(
"PrintDirectory",
"error receiving pwd confirmation");
781 Info(
"PrintDirectory",
"%s", mess);
790 Int_t TFTP::RenameFile(
const char *file1,
const char *file2)
const
792 if (!IsOpen())
return -1;
794 if (!file1 || !file2 || !*file1 || !*file2) {
795 Error(
"RenameFile",
"illegal file names specified");
799 if (fSocket->Send(Form(
"%s %s", file1, file2), kROOTD_MV) < 0) {
800 Error(
"RenameFile",
"error sending kROOTD_MV command");
807 if (fSocket->Recv(mess,
sizeof(mess), what) < 0) {
808 Error(
"RenameFile",
"error receiving mv confirmation");
812 Info(
"RenameFile",
"%s", mess);
821 Int_t TFTP::DeleteFile(
const char *file)
const
823 if (!IsOpen())
return -1;
825 if (!file || !*file) {
826 Error(
"DeleteFile",
"illegal file name specified");
830 if (fSocket->Send(Form(
"%s", file), kROOTD_RM) < 0) {
831 Error(
"DeleteFile",
"error sending kROOTD_RM command");
838 if (fSocket->Recv(mess,
sizeof(mess), what) < 0) {
839 Error(
"DeleteFile",
"error receiving rm confirmation");
843 Info(
"DeleteFile",
"%s", mess);
853 Int_t TFTP::ChangePermission(
const char *file, Int_t mode)
const
855 if (!IsOpen())
return -1;
857 if (!file || !*file) {
858 Error(
"ChangePermission",
"illegal file name specified");
862 if (fSocket->Send(Form(
"%s %d", file, mode), kROOTD_CHMOD) < 0) {
863 Error(
"ChangePermission",
"error sending kROOTD_CHMOD command");
870 if (fSocket->Recv(mess,
sizeof(mess), what) < 0) {
871 Error(
"ChangePermission",
"error receiving chmod confirmation");
875 Info(
"ChangePermission",
"%s", mess);
886 if (!IsOpen())
return -1;
888 if (fSocket->Send(kROOTD_CLOSE) < 0) {
889 Error(
"Close",
"error sending kROOTD_CLOSE command");
895 fSocket->Send(kROOTD_BYE);
899 R__LOCKGUARD(gROOTMutex);
900 gROOT->GetListOfSockets()->Remove(
this);
914 Bool_t TFTP::OpenDirectory(
const char *dir, Bool_t print)
918 if (!IsOpen())
return fDir;
920 if (fProtocol < 12) {
921 Error(
"OpenDirectory",
"call not supported by remote rootd");
926 Error(
"OpenDirectory",
"illegal directory name specified");
930 if (fSocket->Send(Form(
"%s", dir), kROOTD_OPENDIR) < 0) {
931 Error(
"OpenDirectory",
"error sending kROOTD_OPENDIR command");
938 if (fSocket->Recv(mess,
sizeof(mess), what) < 0) {
939 Error(
"OpenDirectory",
"error receiving opendir confirmation");
944 Info(
"OpenDirectory",
"%s", mess);
946 if (!strncmp(mess,
"OK:",3)) {
956 void TFTP::FreeDirectory(Bool_t print)
958 if (!IsOpen() || !fDir)
return;
960 if (fProtocol < 12) {
961 Error(
"FreeDirectory",
"call not supported by remote rootd");
965 if (fSocket->Send(kROOTD_FREEDIR) < 0) {
966 Error(
"FreeDirectory",
"error sending kROOTD_FREEDIR command");
973 if (fSocket->Recv(mess,
sizeof(mess), what) < 0) {
974 Error(
"FreeDirectory",
"error receiving freedir confirmation");
979 Info(
"FreeDirectory",
"%s", mess);
988 const char *TFTP::GetDirEntry(Bool_t print)
990 static char dirent[1024] = {0};
992 if (!IsOpen() || !fDir)
return 0;
994 if (fProtocol < 12) {
995 Error(
"GetDirEntry",
"call not supported by remote rootd");
999 if (fSocket->Send(kROOTD_DIRENTRY) < 0) {
1000 Error(
"GetDirEntry",
"error sending kROOTD_DIRENTRY command");
1007 if (fSocket->Recv(mess,
sizeof(mess), what) < 0) {
1008 Error(
"GetDirEntry",
"error receiving dir entry confirmation");
1013 Info(
"GetDirEntry",
"%s", mess);
1015 if (!strncmp(mess,
"OK:",3)) {
1016 strlcpy(dirent,mess+3,
sizeof(dirent));
1017 return (
const char *)dirent;
1029 Int_t TFTP::GetPathInfo(
const char *path, FileStat_t &buf, Bool_t print)
1033 if (!IsOpen())
return 1;
1035 if (fProtocol < 12) {
1036 Error(
"GetPathInfo",
"call not supported by remote rootd");
1040 if (!path || !*path) {
1041 Error(
"GetPathInfo",
"illegal path name specified");
1045 if (fSocket->Send(Form(
"%s", path), kROOTD_FSTAT) < 0) {
1046 Error(
"GetPathInfo",
"error sending kROOTD_FSTAT command");
1053 if (fSocket->Recv(mess,
sizeof(mess), what) < 0) {
1054 Error(
"GetPathInfo",
"error receiving fstat confirmation");
1058 Info(
"GetPathInfo",
"%s", mess);
1060 Int_t mode, uid, gid, islink;
1061 Long_t id, flags, dev, ino, mtime;
1063 if (fProtocol > 12) {
1065 sscanf(mess,
"%ld %ld %d %d %d %I64d %ld %d", &dev, &ino, &mode,
1066 &uid, &gid, &size, &mtime, &islink);
1068 sscanf(mess,
"%ld %ld %d %d %d %lld %ld %d", &dev, &ino, &mode,
1069 &uid, &gid, &size, &mtime, &islink);
1080 buf.fIsLink = (islink == 1);
1083 sscanf(mess,
"%ld %I64d %ld %ld", &
id, &size, &flags, &mtime);
1085 sscanf(mess,
"%ld %lld %ld %ld", &
id, &size, &flags, &mtime);
1089 buf.fDev = (
id >> 24);
1090 buf.fIno = (
id & 0x00FFFFFF);
1092 buf.fMode = kS_IFREG;
1094 buf.fMode = (kS_IFREG|kS_IXUSR|kS_IXGRP|kS_IXOTH);
1096 buf.fMode = kS_IFDIR;
1098 buf.fMode = kS_IFSOCK;
1111 Bool_t TFTP::AccessPathName(
const char *path, EAccessMode mode, Bool_t print)
1113 if (!IsOpen())
return kTRUE;
1115 if (fProtocol < 12) {
1116 Error(
"AccessPathName",
"call not supported by remote rootd");
1120 if (!path || !*path) {
1121 Error(
"AccessPathName",
"illegal path name specified");
1125 if (fSocket->Send(Form(
"%s %d", path, mode), kROOTD_ACCESS) < 0) {
1126 Error(
"AccessPathName",
"error sending kROOTD_ACCESS command");
1133 if (fSocket->Recv(mess,
sizeof(mess), what) < 0) {
1134 Error(
"AccessPathName",
"error receiving access confirmation");
1138 Info(
"AccessPathName",
"%s", mess);
1140 if (!strncmp(mess,
"OK",2))