Logo ROOT  
Reference Guide
TFTP.cxx
Go to the documentation of this file.
1// @(#)root/net:$Id$
2// Author: Fons Rademakers 13/02/2001
3
4/*************************************************************************
5 * Copyright (C) 1995-2001, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11
12//////////////////////////////////////////////////////////////////////////
13// //
14// TFTP //
15// //
16// This class provides all infrastructure for a performant file //
17// transfer protocol. It works in conjuction with the rootd daemon //
18// and can use parallel sockets to improve performance over fat pipes. //
19// //
20//////////////////////////////////////////////////////////////////////////
21
22#include <ROOT/RConfig.hxx>
23
24#include <fcntl.h>
25#include <errno.h>
26#include <sys/stat.h>
27#ifndef R__WIN32
28# include <unistd.h>
29#else
30# define ssize_t int
31# include <io.h>
32# include <sys/types.h>
33#endif
34
35#include "strlcpy.h"
36#include "TFTP.h"
37#include "TPSocket.h"
38#include "TUrl.h"
39#include "TStopwatch.h"
40#include "TSystem.h"
41#include "TROOT.h"
42#include "TError.h"
43#include "NetErrors.h"
44#include "TRegexp.h"
45#include "TVirtualMutex.h"
46
47#if defined(R__UNIX) || defined(R__MACOSX)
48#define HAVE_MMAP
49#endif
50
51#ifdef HAVE_MMAP
52# include <sys/mman.h>
53#ifndef MAP_FILE
54#define MAP_FILE 0 /* compatability flag */
55#endif
56#endif
57
58
61
62
64
65////////////////////////////////////////////////////////////////////////////////
66/// Open connection to host specified by the url using par parallel sockets.
67/// The url has the form: [root[s,k]://]host[:port].
68/// If port is not specified the default rootd port (1094) will be used.
69/// Using wsize one can specify the tcp window size. Normally this is not
70/// needed when using parallel sockets.
71/// An existing connection (TSocket *sock) can also be used to establish
72/// the FTP session.
73
74TFTP::TFTP(const char *url, Int_t par, Int_t wsize, TSocket *sock)
75{
76 fSocket = sock;
77
78 TString s = url;
79 if (s.Contains("://")) {
80 if (!s.BeginsWith("root")) {
81 Error("TFTP",
82 "url must be of the form \"[root[up,s,k,g,h,ug]://]host[:port]\"");
83 MakeZombie();
84 return;
85 }
86 } else
87 s = "root://" + s;
88
89 Init(s, par, wsize);
90}
91
92////////////////////////////////////////////////////////////////////////////////
93/// Set up the actual connection.
94
95void TFTP::Init(const char *surl, Int_t par, Int_t wsize)
96{
97 TUrl url(surl);
98 TString hurl(url.GetProtocol());
99 if (hurl.Contains("root")) {
100 hurl.Insert(4,"dp");
101 } else {
102 hurl = "rootdp";
103 }
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()) {
108 if (par > 1)
109 Error("TFTP", "can't open %d-stream connection to rootd on "
110 "host %s at port %d", par, url.GetHost(), url.GetPort());
111 else
112 Error("TFTP", "can't open connection to rootd on "
113 "host %s at port %d", url.GetHost(), url.GetPort());
114 goto zombie;
115 }
116
119
120 fHost = url.GetHost();
121 fPort = url.GetPort();
122 fParallel = par;
123 fWindowSize = wsize;
124 fLastBlock = 0;
125 fRestartAt = 0;
127 fMode = kBinary;
128 fBytesWrite = 0;
129 fBytesRead = 0;
130
131 // Replace our socket in the list with this
132 // for consistency during the final cleanup
133 // (The socket will be delete by us when everything is ok remotely)
134 {
136 gROOT->GetListOfSockets()->Remove(fSocket);
137 gROOT->GetListOfSockets()->Add(this);
138 }
139 return;
140
141zombie:
142 MakeZombie();
144}
145
146////////////////////////////////////////////////////////////////////////////////
147/// TFTP dtor. Send close message and close socket.
148
150{
151 Close();
152}
153
154////////////////////////////////////////////////////////////////////////////////
155/// Print some info about the FTP connection.
156
158{
159 TString secCont;
160
161 Printf("Local host: %s", gSystem->HostName());
162 Printf("Remote host: %s [%d]", fHost.Data(), fPort);
163 Printf("Remote user: %s", fUser.Data());
165 Printf("Security context: %s",
166 fSocket->GetSecContext()->AsString(secCont));
167 Printf("Rootd protocol vers.: %d", fSocket->GetRemoteProtocol());
168 if (fParallel > 1) {
169 Printf("Parallel sockets: %d", fParallel);
170 }
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);
177}
178
179////////////////////////////////////////////////////////////////////////////////
180/// Print error string depending on error code.
181
182void TFTP::PrintError(const char *where, Int_t err) const
183{
184 Error(where, "%s", gRootdErrStr[err]);
185}
186
187////////////////////////////////////////////////////////////////////////////////
188/// Return status from rootd server and message kind. Returns -1 in
189/// case of error otherwise 8 (sizeof 2 words, status and kind).
190
191Int_t TFTP::Recv(Int_t &status, EMessageTypes &kind) const
192{
193 kind = kROOTD_ERR;
194 status = 0;
195
196 if (!fSocket) return -1;
197
198 Int_t what;
199 Int_t n = fSocket->Recv(status, what);
200 kind = (EMessageTypes) what;
201 return n;
202}
203
204////////////////////////////////////////////////////////////////////////////////
205/// Make sure the block size is a power of two, with a minimum of 32768.
206
208{
209 if (blockSize < 32768) {
210 fBlockSize = 32768;
211 return;
212 }
213
214 int i;
215 for (i = 0; i < int(sizeof(blockSize)*8); i++)
216 if ((blockSize >> i) == 1)
217 break;
218
219 fBlockSize = 1 << i;
220}
221
222////////////////////////////////////////////////////////////////////////////////
223/// Transfer file to remote host. Returns number of bytes
224/// sent or < 0 in case of error. Error -1 connection is still
225/// open, error -2 connection has been closed. In case of failure
226/// fRestartAt is set to the number of bytes correclty transfered.
227/// Calling PutFile() immediately afterwards will restart at fRestartAt.
228/// If this is not desired call SetRestartAt(0) before calling PutFile().
229/// If rootd reports that the file is locked, and you are sure this is not
230/// the case (e.g. due to a crash), you can force unlock it by prepending
231/// the remoteName with a '-'.
232
233Long64_t TFTP::PutFile(const char *file, const char *remoteName)
234{
235 if (!IsOpen() || !file || !*file) return -1;
236
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);
241#else
242 Int_t fd = open(file, O_RDONLY);
243#endif
244 if (fd < 0) {
245 Error("PutFile", "cannot open %s in read mode", file);
246 return -1;
247 }
248
250 Long_t id, flags, modtime;
251 if (gSystem->GetPathInfo(file, &id, &size, &flags, &modtime) == 0) {
252 if (flags > 1) {
253 Error("PutFile", "%s not a regular file (%ld)", file, flags);
254 close(fd);
255 return -1;
256 }
257 } else {
258 Warning("PutFile", "could not stat %s", file);
259 close(fd);
260 return -1;
261 }
262
263 if (!remoteName)
264 remoteName = file;
265
266 Long64_t restartat = fRestartAt;
267
268 // check if restartat value makes sense
269 if (restartat && (restartat >= size))
270 restartat = 0;
271
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");
275 close(fd);
276 return -2;
277 }
278
279 Int_t stat;
280 EMessageTypes kind;
281
282 if (Recv(stat, kind) < 0 || kind == kROOTD_ERR) {
283 PrintError("PutFile", stat);
284 close(fd);
285 return -1;
286 }
287
288 Info("PutFile", "sending file %s (%lld bytes, starting at %lld)",
289 file, size, restartat);
290
291 TStopwatch timer;
292 timer.Start();
293
294 Long64_t pos = restartat & ~(fBlockSize-1);
295 Int_t skip = restartat - pos;
296
297#ifndef HAVE_MMAP
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);
303#else
304 lseek(fd, pos, SEEK_SET);
305#endif
306#endif
307
308 while (pos < size) {
309 Long64_t left = Long64_t(size - pos);
310 if (left > fBlockSize)
311 left = fBlockSize;
312#ifdef HAVE_MMAP
313#if defined(R__SEEK64)
314 char *buf = (char*) mmap64(0, left, PROT_READ, MAP_FILE | MAP_SHARED, fd, pos);
315#else
316 char *buf = (char*) mmap(0, left, PROT_READ, MAP_FILE | MAP_SHARED, fd, pos);
317#endif
318 if (buf == (char *) -1) {
319 Error("PutFile", "mmap of file %s failed", file);
320 close(fd);
321 return -1;
322 }
323#else
324 Int_t siz;
325 while ((siz = read(fd, buf, left)) < 0 && TSystem::GetErrno() == EINTR)
327 if (siz < 0 || siz != left) {
328 Error("PutFile", "error reading from file %s", file);
329 // Send urgent message to rootd to stop tranfer
330 delete [] buf;
331 close(fd);
332 return -1;
333 }
334#endif
335
336 if (fSocket->SendRaw(buf+skip, left-skip) < 0) {
337 Error("PutFile", "error sending buffer");
338 // Send urgent message to rootd to stop transfer
339#ifdef HAVE_MMAP
340 munmap(buf, left);
341#else
342 delete [] buf;
343#endif
344 close(fd);
345 return -2;
346 }
347
348 fBytesWrite += left-skip;
349 fgBytesWrite += left-skip;
350
351 fRestartAt = pos; // bytes correctly sent up till now
352
353 pos += left;
354 skip = 0;
355
356#ifdef HAVE_MMAP
357 munmap(buf, left);
358#endif
359 }
360
361#ifndef HAVE_MMAP
362 delete [] buf;
363#endif
364
365 close(fd);
366
367 fRestartAt = 0;
368
369 // get acknowlegdement from server that file was stored correctly
370 if (Recv(stat, kind) < 0 || kind == kROOTD_ERR) {
371 PrintError("PutFile", stat);
372 close(fd);
373 return -1;
374 }
375
376 // provide timing numbers
377 Double_t speed, t = timer.RealTime();
378 if (t > 0)
379 speed = Double_t(size - restartat) / t;
380 else
381 speed = 0.0;
382 if (speed > 524288)
383 Info("PutFile", "%.3f seconds, %.2f Mbytes per second",
384 t, speed / 1048576);
385 else if (speed > 512)
386 Info("PutFile", "%.3f seconds, %.2f Kbytes per second",
387 t, speed / 1024);
388 else
389 Info("PutFile", "%.3f seconds, %.2f bytes per second",
390 t, speed);
391
392 return Long64_t(size - restartat);
393}
394
395////////////////////////////////////////////////////////////////////////////////
396/// Transfer file from remote host. Returns number of bytes
397/// received or < 0 in case of error. Error -1 connection is still
398/// open, error -2 connection has been closed. In case of failure
399/// fRestartAt is set to the number of bytes correclty transfered.
400/// Calling GetFile() immediately afterwards will restart at fRestartAt.
401/// If this is not desired call SetRestartAt(0) before calling GetFile().
402/// If rootd reports that the file is locked, and you are sure this is not
403/// the case (e.g. due to a crash), you can force unlock it by prepending
404/// the file name with a '-'.
405
406Long64_t TFTP::GetFile(const char *file, const char *localName)
407{
408 if (!IsOpen() || !file || !*file) return -1;
409
410 if (!localName) {
411 if (file[0] == '-')
412 localName = file+1;
413 else
414 localName = file;
415 }
416
417 Long64_t restartat = fRestartAt;
418
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");
422 return -2;
423 }
424
425 Int_t stat;
426 EMessageTypes kind;
427
428 if (Recv(stat, kind) < 0 || kind == kROOTD_ERR) {
429 PrintError("GetFile", stat);
430 return -1;
431 }
432
433 // get size of remote file
435 Int_t what;
436 char mess[128];
437
438 if (fSocket->Recv(mess, sizeof(mess), what) < 0) {
439 Error("GetFile", "error receiving remote file size");
440 return -2;
441 }
442#ifdef R__WIN32
443 sscanf(mess, "%I64d", &size);
444#else
445 sscanf(mess, "%lld", &size);
446#endif
447
448 // check if restartat value makes sense
449 if (restartat && (restartat >= size))
450 restartat = 0;
451
452 // open local file
453 Int_t fd;
454 if (!restartat) {
455#if defined(R__WIN32) || defined(R__WINGCC)
456 if (fMode == kBinary)
457 fd = open(localName, O_CREAT | O_TRUNC | O_WRONLY | O_BINARY,
458 S_IREAD | S_IWRITE);
459 else
460 fd = open(localName, O_CREAT | O_TRUNC | O_WRONLY,
461 S_IREAD | S_IWRITE);
462#elif defined(R__SEEK64)
463 fd = open64(localName, O_CREAT | O_TRUNC | O_WRONLY, 0600);
464#else
465 fd = open(localName, O_CREAT | O_TRUNC | O_WRONLY, 0600);
466#endif
467 } else {
468#if defined(R__WIN32) || defined(R__WINGCC)
469 if (fMode == kBinary)
470 fd = open(localName, O_WRONLY | O_BINARY, S_IREAD | S_IWRITE);
471 else
472 fd = open(localName, O_WRONLY, S_IREAD | S_IWRITE);
473#elif defined(R__SEEK64)
474 fd = open64(localName, O_WRONLY, 0600);
475#else
476 fd = open(localName, O_WRONLY, 0600);
477#endif
478 }
479
480 if (fd < 0) {
481 Error("GetFile", "cannot open %s", localName);
482 // send urgent message to rootd to stop tranfer
483 return -1;
484 }
485
486 // check file system space
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);
493 // send urgent message to rootd to stop tranfer
494 close(fd);
495 return -1;
496 }
497 } else
498 Warning("GetFile", "could not determine if there is enough free space to store file");
499 }
500
501 // seek to restartat position
502 if (restartat) {
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) {
507#else
508 if (lseek(fd, restartat, SEEK_SET) < 0) {
509#endif
510 Error("GetFile", "cannot seek to position %lld in file %s",
511 restartat, localName);
512 // if cannot seek send urgent message to rootd to stop tranfer
513 close(fd);
514 return -1;
515 }
516 }
517
518 Info("GetFile", "getting file %s (%lld bytes, starting at %lld)",
519 localName, size, restartat);
520
521 TStopwatch timer;
522 timer.Start();
523
524 char *buf = new char[fBlockSize];
525 char *buf2 = 0;
526 if (fMode == kAscii)
527 buf2 = new char[fBlockSize];
528
529 Long64_t pos = restartat & ~(fBlockSize-1);
530 Int_t skip = restartat - pos;
531
532 while (pos < size) {
533 Long64_t left = size - pos;
534 if (left > fBlockSize)
535 left = fBlockSize;
536
537 Int_t n;
538 while ((n = fSocket->RecvRaw(buf, Int_t(left-skip))) < 0 &&
539 TSystem::GetErrno() == EINTR)
541
542 if (n != Int_t(left-skip)) {
543 Error("GetFile", "error receiving buffer of length %d, got %d",
544 Int_t(left-skip), n);
545 close(fd);
546 delete [] buf; delete [] buf2;
547 return -2;
548 }
549
550 // in case of ascii file, loop over buffer and remove \r's
551 ssize_t siz;
552 if (fMode == kAscii) {
553 Int_t i = 0, j = 0;
554 while (i < n) {
555 if (buf[i] == '\r')
556 i++;
557 else
558 buf2[j++] = buf[i++];
559 }
560 n = j;
561 while ((siz = write(fd, buf2, n)) < 0 && TSystem::GetErrno() == EINTR)
563 } else {
564 while ((siz = write(fd, buf, n)) < 0 && TSystem::GetErrno() == EINTR)
566 }
567
568 if (siz < 0) {
569 SysError("GetFile", "error writing file %s", localName);
570 // send urgent message to rootd to stop tranfer
571 close(fd);
572 delete [] buf; delete [] buf2;
573 return -1;
574 }
575
576 if (siz != n) {
577 Error("GetFile", "error writing all requested bytes to file %s, wrote %ld of %d",
578 localName, (Long_t)siz, n);
579 // send urgent message to rootd to stop tranfer
580 close(fd);
581 delete [] buf; delete [] buf2;
582 return -1;
583 }
584
585 fBytesRead += left-skip;
586 fgBytesRead += left-skip;
587
588 fRestartAt = pos; // bytes correctly received up till now
589
590 pos += left;
591 skip = 0;
592 }
593
594 delete [] buf; delete [] buf2;
595
596#ifndef R__WIN32
597 fchmod(fd, 0644);
598#endif
599
600 close(fd);
601
602 fRestartAt = 0;
603
604 // provide timing numbers
605 Double_t speed, t = timer.RealTime();
606 if (t > 0)
607 speed = Double_t(size - restartat) / t;
608 else
609 speed = 0.0;
610 if (speed > 524288)
611 Info("GetFile", "%.3f seconds, %.2f Mbytes per second",
612 t, speed / 1048576);
613 else if (speed > 512)
614 Info("GetFile", "%.3f seconds, %.2f Kbytes per second",
615 t, speed / 1024);
616 else
617 Info("GetFile", "%.3f seconds, %.2f bytes per second",
618 t, speed);
619
620 return Long64_t(size - restartat);
621}
622
623////////////////////////////////////////////////////////////////////////////////
624/// Change the remote directory. If the remote directory contains a .message
625/// file and it is < 1024 characters then the contents is echoed back.
626/// Returns 0 in case of success and -1 in case of failure.
627
628Int_t TFTP::ChangeDirectory(const char *dir) const
629{
630 if (!IsOpen()) return -1;
631
632 if (!dir || !*dir) {
633 Error("ChangeDirectory", "illegal directory name specified");
634 return -1;
635 }
636
637 if (fSocket->Send(Form("%s", dir), kROOTD_CHDIR) < 0) {
638 Error("ChangeDirectory", "error sending kROOTD_CHDIR command");
639 return -1;
640 }
641
642 Int_t what;
643 char mess[1024];
644
645 if (fSocket->Recv(mess, sizeof(mess), what) < 0) {
646 Error("ChangeDirectory", "error receiving chdir confirmation");
647 return -1;
648 }
649 if (what == kMESS_STRING) {
650 Printf("%s\n", mess);
651
652 if (fSocket->Recv(mess, sizeof(mess), what) < 0) {
653 Error("ChangeDirectory", "error receiving chdir confirmation");
654 return -1;
655 }
656 }
657
658 Info("ChangeDirectory", "%s", mess);
659
660 return 0;
661}
662
663////////////////////////////////////////////////////////////////////////////////
664/// Make a remote directory. Anonymous users may not create directories.
665/// Returns 0 in case of success and -1 in case of failure.
666
667Int_t TFTP::MakeDirectory(const char *dir, Bool_t print) const
668{
669 if (!IsOpen()) return -1;
670
671 if (!dir || !*dir) {
672 Error("MakeDirectory", "illegal directory name specified");
673 return -1;
674 }
675
676 if (fSocket->Send(Form("%s", dir), kROOTD_MKDIR) < 0) {
677 Error("MakeDirectory", "error sending kROOTD_MKDIR command");
678 return -1;
679 }
680
681 Int_t what;
682 char mess[1024];
683
684 if (fSocket->Recv(mess, sizeof(mess), what) < 0) {
685 Error("MakeDirectory", "error receiving mkdir confirmation");
686 return -1;
687 }
688
689 if (print)
690 Info("MakeDirectory", "%s", mess);
691
692 if (!strncmp(mess,"OK:",3))
693 return 1;
694
695 return 0;
696}
697
698////////////////////////////////////////////////////////////////////////////////
699/// Delete a remote directory. Anonymous users may not delete directories.
700/// Returns 0 in case of success and -1 in case of failure.
701
702Int_t TFTP::DeleteDirectory(const char *dir) const
703{
704 if (!IsOpen()) return -1;
705
706 if (!dir || !*dir) {
707 Error("DeleteDirectory", "illegal directory name specified");
708 return -1;
709 }
710
711 if (fSocket->Send(Form("%s", dir), kROOTD_RMDIR) < 0) {
712 Error("DeleteDirectory", "error sending kROOTD_RMDIR command");
713 return -1;
714 }
715
716 Int_t what;
717 char mess[1024];
718
719 if (fSocket->Recv(mess, sizeof(mess), what) < 0) {
720 Error("DeleteDirectory", "error receiving rmdir confirmation");
721 return -1;
722 }
723
724 Info("DeleteDirectory", "%s", mess);
725
726 return 0;
727}
728
729////////////////////////////////////////////////////////////////////////////////
730/// List remote directory. With cmd you specify the options and directory
731/// to be listed to ls. Returns 0 in case of success and -1 in case of
732/// failure.
733
735{
736 if (!IsOpen()) return -1;
737
738 if (!cmd || !*cmd)
739 cmd = "ls .";
740
741 if (fSocket->Send(Form("%s", cmd), kROOTD_LSDIR) < 0) {
742 Error("ListDirectory", "error sending kROOTD_LSDIR command");
743 return -1;
744 }
745
746 Int_t what;
747 char mess[1024];
748
749 do {
750 if (fSocket->Recv(mess, sizeof(mess), what) < 0) {
751 Error("ListDirectory", "error receiving lsdir confirmation");
752 return -1;
753 }
754 printf("%s", mess);
755 } while (what == kMESS_STRING);
756
757 return 0;
758}
759
760////////////////////////////////////////////////////////////////////////////////
761/// Print path of remote working directory. Returns 0 in case of succes and
762/// -1 in cse of failure.
763
765{
766 if (!IsOpen()) return -1;
767
768 if (fSocket->Send("", kROOTD_PWD) < 0) {
769 Error("DeleteDirectory", "error sending kROOTD_PWD command");
770 return -1;
771 }
772
773 Int_t what;
774 char mess[1024];
775
776 if (fSocket->Recv(mess, sizeof(mess), what) < 0) {
777 Error("PrintDirectory", "error receiving pwd confirmation");
778 return -1;
779 }
780
781 Info("PrintDirectory", "%s", mess);
782
783 return 0;
784}
785
786////////////////////////////////////////////////////////////////////////////////
787/// Rename a remote file. Anonymous users may not rename files.
788/// Returns 0 in case of success and -1 in case of failure.
789
790Int_t TFTP::RenameFile(const char *file1, const char *file2) const
791{
792 if (!IsOpen()) return -1;
793
794 if (!file1 || !file2 || !*file1 || !*file2) {
795 Error("RenameFile", "illegal file names specified");
796 return -1;
797 }
798
799 if (fSocket->Send(Form("%s %s", file1, file2), kROOTD_MV) < 0) {
800 Error("RenameFile", "error sending kROOTD_MV command");
801 return -1;
802 }
803
804 Int_t what;
805 char mess[1024];
806
807 if (fSocket->Recv(mess, sizeof(mess), what) < 0) {
808 Error("RenameFile", "error receiving mv confirmation");
809 return -1;
810 }
811
812 Info("RenameFile", "%s", mess);
813
814 return 0;
815}
816
817////////////////////////////////////////////////////////////////////////////////
818/// Delete a remote file. Anonymous users may not delete files.
819/// Returns 0 in case of success and -1 in case of failure.
820
821Int_t TFTP::DeleteFile(const char *file) const
822{
823 if (!IsOpen()) return -1;
824
825 if (!file || !*file) {
826 Error("DeleteFile", "illegal file name specified");
827 return -1;
828 }
829
830 if (fSocket->Send(Form("%s", file), kROOTD_RM) < 0) {
831 Error("DeleteFile", "error sending kROOTD_RM command");
832 return -1;
833 }
834
835 Int_t what;
836 char mess[1024];
837
838 if (fSocket->Recv(mess, sizeof(mess), what) < 0) {
839 Error("DeleteFile", "error receiving rm confirmation");
840 return -1;
841 }
842
843 Info("DeleteFile", "%s", mess);
844
845 return 0;
846}
847
848////////////////////////////////////////////////////////////////////////////////
849/// Change permissions of a remote file. Anonymous users may not
850/// chnage permissions. Returns 0 in case of success and -1 in case
851/// of failure.
852
854{
855 if (!IsOpen()) return -1;
856
857 if (!file || !*file) {
858 Error("ChangePermission", "illegal file name specified");
859 return -1;
860 }
861
862 if (fSocket->Send(Form("%s %d", file, mode), kROOTD_CHMOD) < 0) {
863 Error("ChangePermission", "error sending kROOTD_CHMOD command");
864 return -1;
865 }
866
867 Int_t what;
868 char mess[1024];
869
870 if (fSocket->Recv(mess, sizeof(mess), what) < 0) {
871 Error("ChangePermission", "error receiving chmod confirmation");
872 return -1;
873 }
874
875 Info("ChangePermission", "%s", mess);
876
877 return 0;
878}
879
880////////////////////////////////////////////////////////////////////////////////
881/// Close ftp connection. Returns 0 in case of success and -1 in case of
882/// failure.
883
885{
886 if (!IsOpen()) return -1;
887
888 if (fSocket->Send(kROOTD_CLOSE) < 0) {
889 Error("Close", "error sending kROOTD_CLOSE command");
890 return -1;
891 }
892
893 // Ask for remote shutdown
894 if (fProtocol > 6)
896
897 // Remove from the list of Sockets
898 {
900 gROOT->GetListOfSockets()->Remove(this);
901 }
902
903 // Delete socket here
905
906 return 0;
907}
908
909////////////////////////////////////////////////////////////////////////////////
910/// Open a directory via rootd.
911/// Returns kTRUE in case of success.
912/// Returns kFALSE in case of error.
913
914Bool_t TFTP::OpenDirectory(const char *dir, Bool_t print)
915{
916 fDir = kFALSE;
917
918 if (!IsOpen()) return fDir;
919
920 if (fProtocol < 12) {
921 Error("OpenDirectory", "call not supported by remote rootd");
922 return fDir;
923 }
924
925 if (!dir || !*dir) {
926 Error("OpenDirectory", "illegal directory name specified");
927 return fDir;
928 }
929
930 if (fSocket->Send(Form("%s", dir), kROOTD_OPENDIR) < 0) {
931 Error("OpenDirectory", "error sending kROOTD_OPENDIR command");
932 return fDir;
933 }
934
935 Int_t what;
936 char mess[1024];;
937
938 if (fSocket->Recv(mess, sizeof(mess), what) < 0) {
939 Error("OpenDirectory", "error receiving opendir confirmation");
940 return fDir;
941 }
942
943 if (print)
944 Info("OpenDirectory", "%s", mess);
945
946 if (!strncmp(mess,"OK:",3)) {
947 fDir = kTRUE;
948 return fDir;
949 }
950 return fDir;
951}
952
953////////////////////////////////////////////////////////////////////////////////
954/// Free a remotely open directory via rootd.
955
957{
958 if (!IsOpen() || !fDir) return;
959
960 if (fProtocol < 12) {
961 Error("FreeDirectory", "call not supported by remote rootd");
962 return;
963 }
964
965 if (fSocket->Send(kROOTD_FREEDIR) < 0) {
966 Error("FreeDirectory", "error sending kROOTD_FREEDIR command");
967 return;
968 }
969
970 Int_t what;
971 char mess[1024];;
972
973 if (fSocket->Recv(mess, sizeof(mess), what) < 0) {
974 Error("FreeDirectory", "error receiving freedir confirmation");
975 return;
976 }
977
978 if (print)
979 Info("FreeDirectory", "%s", mess);
980
981 return;
982}
983
984////////////////////////////////////////////////////////////////////////////////
985/// Get directory entry via rootd.
986/// Returns 0 in case no more entries or in case of error.
987
988const char *TFTP::GetDirEntry(Bool_t print)
989{
990 static char dirent[1024] = {0};
991
992 if (!IsOpen() || !fDir) return 0;
993
994 if (fProtocol < 12) {
995 Error("GetDirEntry", "call not supported by remote rootd");
996 return 0;
997 }
998
999 if (fSocket->Send(kROOTD_DIRENTRY) < 0) {
1000 Error("GetDirEntry", "error sending kROOTD_DIRENTRY command");
1001 return 0;
1002 }
1003
1004 Int_t what;
1005 char mess[1024];;
1006
1007 if (fSocket->Recv(mess, sizeof(mess), what) < 0) {
1008 Error("GetDirEntry", "error receiving dir entry confirmation");
1009 return 0;
1010 }
1011
1012 if (print)
1013 Info("GetDirEntry", "%s", mess);
1014
1015 if (!strncmp(mess,"OK:",3)) {
1016 strlcpy(dirent,mess+3, sizeof(dirent));
1017 return (const char *)dirent;
1018 }
1019
1020 return 0;
1021}
1022
1023////////////////////////////////////////////////////////////////////////////////
1024/// Get info about a file. Info is returned in the form of a FileStat_t
1025/// structure (see TSystem.h).
1026/// The function returns 0 in case of success and 1 if the file could
1027/// not be stat'ed.
1028
1029Int_t TFTP::GetPathInfo(const char *path, FileStat_t &buf, Bool_t print)
1030{
1031 TUrl url(path);
1032
1033 if (!IsOpen()) return 1;
1034
1035 if (fProtocol < 12) {
1036 Error("GetPathInfo", "call not supported by remote rootd");
1037 return 1;
1038 }
1039
1040 if (!path || !*path) {
1041 Error("GetPathInfo", "illegal path name specified");
1042 return 1;
1043 }
1044
1045 if (fSocket->Send(Form("%s", path), kROOTD_FSTAT) < 0) {
1046 Error("GetPathInfo", "error sending kROOTD_FSTAT command");
1047 return 1;
1048 }
1049
1050 Int_t what;
1051 char mess[1024];;
1052
1053 if (fSocket->Recv(mess, sizeof(mess), what) < 0) {
1054 Error("GetPathInfo", "error receiving fstat confirmation");
1055 return 1;
1056 }
1057 if (print)
1058 Info("GetPathInfo", "%s", mess);
1059
1060 Int_t mode, uid, gid, islink;
1061 Long_t id, flags, dev, ino, mtime;
1062 Long64_t size;
1063 if (fProtocol > 12) {
1064#ifdef R__WIN32
1065 sscanf(mess, "%ld %ld %d %d %d %I64d %ld %d", &dev, &ino, &mode,
1066 &uid, &gid, &size, &mtime, &islink);
1067#else
1068 sscanf(mess, "%ld %ld %d %d %d %lld %ld %d", &dev, &ino, &mode,
1069 &uid, &gid, &size, &mtime, &islink);
1070#endif
1071 if (dev == -1)
1072 return 1;
1073 buf.fDev = dev;
1074 buf.fIno = ino;
1075 buf.fMode = mode;
1076 buf.fUid = uid;
1077 buf.fGid = gid;
1078 buf.fSize = size;
1079 buf.fMtime = mtime;
1080 buf.fIsLink = (islink == 1);
1081 } else {
1082#ifdef R__WIN32
1083 sscanf(mess, "%ld %I64d %ld %ld", &id, &size, &flags, &mtime);
1084#else
1085 sscanf(mess, "%ld %lld %ld %ld", &id, &size, &flags, &mtime);
1086#endif
1087 if (id == -1)
1088 return 1;
1089 buf.fDev = (id >> 24);
1090 buf.fIno = (id & 0x00FFFFFF);
1091 if (flags == 0)
1092 buf.fMode = kS_IFREG;
1093 if (flags & 1)
1095 if (flags & 2)
1096 buf.fMode = kS_IFDIR;
1097 if (flags & 4)
1098 buf.fMode = kS_IFSOCK;
1099 buf.fSize = size;
1100 buf.fMtime = mtime;
1101 }
1102
1103 return 0;
1104}
1105
1106////////////////////////////////////////////////////////////////////////////////
1107/// Returns kFALSE if one can access a file using the specified access mode.
1108/// Mode is the same as for the Unix access(2) function.
1109/// Attention, bizarre convention of return value!!
1110
1112{
1113 if (!IsOpen()) return kTRUE;
1114
1115 if (fProtocol < 12) {
1116 Error("AccessPathName", "call not supported by remote rootd");
1117 return kTRUE;
1118 }
1119
1120 if (!path || !*path) {
1121 Error("AccessPathName", "illegal path name specified");
1122 return kTRUE;
1123 }
1124
1125 if (fSocket->Send(Form("%s %d", path, mode), kROOTD_ACCESS) < 0) {
1126 Error("AccessPathName", "error sending kROOTD_ACCESS command");
1127 return kTRUE;
1128 }
1129
1130 Int_t what;
1131 char mess[1024];;
1132
1133 if (fSocket->Recv(mess, sizeof(mess), what) < 0) {
1134 Error("AccessPathName", "error receiving access confirmation");
1135 return kTRUE;
1136 }
1137 if (print)
1138 Info("AccessPathName", "%s", mess);
1139
1140 if (!strncmp(mess,"OK",2))
1141 return kFALSE;
1142 else
1143 return kTRUE;
1144}
EMessageTypes
Definition: MessageTypes.h:27
@ kROOTD_FSTAT
Definition: MessageTypes.h:105
@ kROOTD_MKDIR
Definition: MessageTypes.h:118
@ kMESS_STRING
Definition: MessageTypes.h:34
@ kROOTD_PWD
Definition: MessageTypes.h:121
@ kROOTD_LSDIR
Definition: MessageTypes.h:120
@ kROOTD_CHMOD
Definition: MessageTypes.h:124
@ kROOTD_BYE
Definition: MessageTypes.h:126
@ kROOTD_CHDIR
Definition: MessageTypes.h:117
@ kROOTD_GETFILE
Definition: MessageTypes.h:116
@ kROOTD_OPENDIR
Definition: MessageTypes.h:131
@ kROOTD_DIRENTRY
Definition: MessageTypes.h:133
@ kROOTD_MV
Definition: MessageTypes.h:122
@ kROOTD_FREEDIR
Definition: MessageTypes.h:132
@ kROOTD_ERR
Definition: MessageTypes.h:113
@ kROOTD_CLOSE
Definition: MessageTypes.h:110
@ kROOTD_RM
Definition: MessageTypes.h:123
@ kROOTD_PUTFILE
Definition: MessageTypes.h:115
@ kROOTD_RMDIR
Definition: MessageTypes.h:119
@ kROOTD_ACCESS
Definition: MessageTypes.h:134
R__EXTERN const char * gRootdErrStr[]
Definition: NetErrors.h:72
#define SafeDelete(p)
Definition: RConfig.hxx:534
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
int Int_t
Definition: RtypesCore.h:45
const Bool_t kFALSE
Definition: RtypesCore.h:101
long Long_t
Definition: RtypesCore.h:54
double Double_t
Definition: RtypesCore.h:59
long long Long64_t
Definition: RtypesCore.h:80
const Bool_t kTRUE
Definition: RtypesCore.h:100
const char Option_t
Definition: RtypesCore.h:66
#define ClassImp(name)
Definition: Rtypes.h:375
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize id
Option_t Option_t TPoint TPoint const char mode
R__EXTERN TVirtualMutex * gROOTMutex
Definition: TROOT.h:63
#define gROOT
Definition: TROOT.h:404
char * Form(const char *fmt,...)
Formats a string in a circular formatting buffer.
Definition: TString.cxx:2447
void Printf(const char *fmt,...)
Formats a string in a circular formatting buffer and prints the string.
Definition: TString.cxx:2461
EAccessMode
Definition: TSystem.h:43
R__EXTERN TSystem * gSystem
Definition: TSystem.h:559
@ kS_IFDIR
Definition: TSystem.h:95
@ kS_IXOTH
Definition: TSystem.h:112
@ kS_IXUSR
Definition: TSystem.h:104
@ kS_IFSOCK
Definition: TSystem.h:90
@ kS_IFREG
Definition: TSystem.h:93
@ kS_IXGRP
Definition: TSystem.h:108
#define R__LOCKGUARD(mutex)
#define O_BINARY
Definition: civetweb.c:912
Definition: TFTP.h:34
Int_t fLastBlock
Definition: TFTP.h:43
Int_t MakeDirectory(const char *dir, Bool_t print=kFALSE) const
Make a remote directory.
Definition: TFTP.cxx:667
Int_t fParallel
Definition: TFTP.h:40
Int_t DeleteDirectory(const char *dir) const
Delete a remote directory.
Definition: TFTP.cxx:702
Long64_t PutFile(const char *file, const char *remoteName=nullptr)
Transfer file to remote host.
Definition: TFTP.cxx:233
TString fUser
Definition: TFTP.h:38
Int_t DeleteFile(const char *file) const
Delete a remote file.
Definition: TFTP.cxx:821
void PrintError(const char *where, Int_t err) const
Print error string depending on error code.
Definition: TFTP.cxx:182
Int_t Recv(Int_t &status, EMessageTypes &kind) const
Return status from rootd server and message kind.
Definition: TFTP.cxx:191
void Print(Option_t *opt="") const override
Print some info about the FTP connection.
Definition: TFTP.cxx:157
void Init(const char *url, Int_t parallel, Int_t wsize)
Set up the actual connection.
Definition: TFTP.cxx:95
Long64_t GetFile(const char *file, const char *localName=nullptr)
Transfer file from remote host.
Definition: TFTP.cxx:406
void FreeDirectory(Bool_t print=kFALSE)
Free a remotely open directory via rootd.
Definition: TFTP.cxx:956
Int_t fMode
Definition: TFTP.h:45
Int_t fBlockSize
Definition: TFTP.h:44
@ kDfltBlockSize
Definition: TFTP.h:69
@ kBinary
Definition: TFTP.h:71
@ kAscii
Definition: TFTP.h:72
Int_t GetPathInfo(const char *path, FileStat_t &buf, Bool_t print=kFALSE)
Get info about a file.
Definition: TFTP.cxx:1029
Int_t RenameFile(const char *file1, const char *file2) const
Rename a remote file.
Definition: TFTP.cxx:790
TSocket * fSocket
Definition: TFTP.h:48
Long64_t fBytesRead
Definition: TFTP.h:50
static Long64_t fgBytesRead
Definition: TFTP.h:65
Bool_t OpenDirectory(const char *name, Bool_t print=kFALSE)
Open a directory via rootd.
Definition: TFTP.cxx:914
Int_t PrintDirectory() const
Print path of remote working directory.
Definition: TFTP.cxx:764
Int_t ListDirectory(Option_t *cmd="") const
List remote directory.
Definition: TFTP.cxx:734
void SetBlockSize(Int_t blockSize)
Make sure the block size is a power of two, with a minimum of 32768.
Definition: TFTP.cxx:207
Int_t ChangePermission(const char *file, Int_t mode) const
Change permissions of a remote file.
Definition: TFTP.cxx:853
TString fHost
Definition: TFTP.h:37
const char * GetDirEntry(Bool_t print=kFALSE)
Get directory entry via rootd.
Definition: TFTP.cxx:988
Int_t Close()
Close ftp connection.
Definition: TFTP.cxx:884
Long64_t fRestartAt
Definition: TFTP.h:46
Int_t fProtocol
Definition: TFTP.h:42
Bool_t AccessPathName(const char *path, EAccessMode mode=kFileExists, Bool_t print=kFALSE)
Returns kFALSE if one can access a file using the specified access mode.
Definition: TFTP.cxx:1111
Bool_t IsOpen() const
Definition: TFTP.h:85
Int_t ChangeDirectory(const char *dir) const
Change the remote directory.
Definition: TFTP.cxx:628
virtual ~TFTP()
TFTP dtor. Send close message and close socket.
Definition: TFTP.cxx:149
TFTP()
Definition: TFTP.h:53
Long64_t fBytesWrite
connection to rootd
Definition: TFTP.h:49
Int_t fWindowSize
Definition: TFTP.h:41
Bool_t fDir
Definition: TFTP.h:51
static Long64_t fgBytesWrite
Definition: TFTP.h:64
Int_t fPort
Definition: TFTP.h:39
virtual void SysError(const char *method, const char *msgfmt,...) const
Issue system error message.
Definition: TObject.cxx:907
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition: TObject.cxx:879
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:893
void MakeZombie()
Definition: TObject.h:49
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition: TObject.cxx:867
const char * GetUser() const
Definition: TSecContext.h:82
virtual const char * AsString(TString &out)
Returns short string with relevant information about this security context.
virtual Int_t Recv(TMessage *&mess)
Receive a TMessage object.
Definition: TSocket.cxx:818
Int_t GetRemoteProtocol() const
Definition: TSocket.h:126
virtual Int_t RecvRaw(void *buffer, Int_t length, ESendRecvOptions opt=kDefault)
Receive a raw buffer of specified length bytes.
Definition: TSocket.cxx:898
TSecContext * GetSecContext() const
Definition: TSocket.h:127
virtual Int_t SendRaw(const void *buffer, Int_t length, ESendRecvOptions opt=kDefault)
Send a raw buffer of specified length.
Definition: TSocket.cxx:620
static TSocket * CreateAuthSocket(const char *user, const char *host, Int_t port, Int_t size=0, Int_t tcpwindowsize=-1, TSocket *s=0, Int_t *err=0)
Creates a socket or a parallel socket and authenticates to the remote server specified in 'url' on re...
Definition: TSocket.cxx:1432
virtual Int_t Send(const TMessage &mess)
Send a TMessage object.
Definition: TSocket.cxx:522
virtual Bool_t IsAuthenticated() const
Definition: TSocket.h:131
Stopwatch class.
Definition: TStopwatch.h:28
Double_t RealTime()
Stop the stopwatch (if it is running) and return the realtime (in seconds) passed between the start a...
Definition: TStopwatch.cxx:110
void Start(Bool_t reset=kTRUE)
Start the stopwatch.
Definition: TStopwatch.cxx:58
Basic string class.
Definition: TString.h:136
TString & Insert(Ssiz_t pos, const char *s)
Definition: TString.h:649
const char * Data() const
Definition: TString.h:369
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition: TString.h:624
virtual int GetFsInfo(const char *path, Long_t *id, Long_t *bsize, Long_t *blocks, Long_t *bfree)
Get info about a file system: fs type, block size, number of blocks, number of free blocks.
Definition: TSystem.cxx:1472
static void ResetErrno()
Static function resetting system error number.
Definition: TSystem.cxx:279
static Int_t GetErrno()
Static function returning system error number.
Definition: TSystem.cxx:263
int GetPathInfo(const char *path, Long_t *id, Long_t *size, Long_t *flags, Long_t *modtime)
Get info about a file: id, size, flags, modification time.
Definition: TSystem.cxx:1398
virtual const char * HostName()
Return the system's host name.
Definition: TSystem.cxx:306
This class represents a WWW compatible URL.
Definition: TUrl.h:33
const char * GetUser() const
Definition: TUrl.h:65
const char * GetHost() const
Definition: TUrl.h:67
const char * GetProtocol() const
Definition: TUrl.h:64
Int_t GetPort() const
Definition: TUrl.h:78
const Int_t n
Definition: legend1.C:16
static constexpr double s
Definition: file.py:1
static const char * what
Definition: stlLoader.cc:6
Int_t fMode
Definition: TSystem.h:127
Long64_t fSize
Definition: TSystem.h:130
Long_t fDev
Definition: TSystem.h:125
Int_t fGid
Definition: TSystem.h:129
Long_t fMtime
Definition: TSystem.h:131
Long_t fIno
Definition: TSystem.h:126
Bool_t fIsLink
Definition: TSystem.h:132
Int_t fUid
Definition: TSystem.h:128