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