Logo ROOT   6.12/07
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 "RConfig.h"
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 "TEnv.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 
63 ClassImp(TFTP);
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 
74 TFTP::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 
95 void 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 
141 zombie:
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 
157 void TFTP::Print(Option_t *) const
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());
164  if (fSocket->IsAuthenticated())
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 
182 void 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 
191 Int_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 
207 void TFTP::SetBlockSize(Int_t blockSize)
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 
233 Long64_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 
249  Long64_t size;
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 
406 Long64_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
434  Long64_t size;
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 
628 Int_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 
667 Int_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 
702 Int_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 
790 Int_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 
821 Int_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 
853 Int_t TFTP::ChangePermission(const char *file, Int_t mode) const
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 
914 Bool_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 
988 const 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 
1029 Int_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 
1111 Bool_t TFTP::AccessPathName(const char *path, EAccessMode mode, Bool_t print)
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 }
void PrintError(const char *where, Int_t err) const
Print error string depending on error code.
Definition: TFTP.cxx:182
virtual void SysError(const char *method, const char *msgfmt,...) const
Issue system error message.
Definition: TObject.cxx:894
Int_t GetPathInfo(const char *path, FileStat_t &buf, Bool_t print=kFALSE)
Get info about a file.
Definition: TFTP.cxx:1029
TString fUser
Definition: TFTP.h:38
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition: TObject.cxx:854
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
TSocket * fSocket
Definition: TFTP.h:48
long long Long64_t
Definition: RtypesCore.h:69
void Start(Bool_t reset=kTRUE)
Start the stopwatch.
Definition: TStopwatch.cxx:58
R__EXTERN const char * gRootdErrStr[]
Definition: NetErrors.h:72
Int_t fBlockSize
Definition: TFTP.h:44
const char Option_t
Definition: RtypesCore.h:62
virtual Int_t Send(const TMessage &mess)
Send a TMessage object.
Definition: TSocket.cxx:527
This class represents a WWW compatible URL.
Definition: TUrl.h:35
Int_t fUid
Definition: TSystem.h:129
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:1374
virtual Int_t Recv(TMessage *&mess)
Receive a TMessage object.
Definition: TSocket.cxx:822
const char * GetProtocol() const
Definition: TUrl.h:67
Long64_t fBytesRead
Definition: TFTP.h:50
#define gROOT
Definition: TROOT.h:402
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:1448
#define O_BINARY
Definition: civetweb.c:451
Basic string class.
Definition: TString.h:125
Int_t DeleteFile(const char *file) const
Delete a remote file.
Definition: TFTP.cxx:821
int Int_t
Definition: RtypesCore.h:41
bool Bool_t
Definition: RtypesCore.h:59
R__EXTERN TVirtualMutex * gROOTMutex
Definition: TROOT.h:57
Bool_t OpenDirectory(const char *name, Bool_t print=kFALSE)
Open a directory via rootd.
Definition: TFTP.cxx:914
Long_t fMtime
Definition: TSystem.h:132
Definition: TFTP.h:34
Long64_t fSize
Definition: TSystem.h:131
TString & Insert(Ssiz_t pos, const char *s)
Definition: TString.h:595
Int_t fLastBlock
Definition: TFTP.h:43
static Int_t GetErrno()
Static function returning system error number.
Definition: TSystem.cxx:268
Int_t fMode
Definition: TSystem.h:128
virtual Int_t SendRaw(const void *buffer, Int_t length, ESendRecvOptions opt=kDefault)
Send a raw buffer of specified length.
Definition: TSocket.cxx:625
const char * GetHost() const
Definition: TUrl.h:70
#define SafeDelete(p)
Definition: RConfig.h:509
Long64_t GetFile(const char *file, const char *localName=0)
Transfer file from remote host.
Definition: TFTP.cxx:406
Int_t fPort
Definition: TFTP.h:39
Int_t ChangeDirectory(const char *dir) const
Change the remote directory.
Definition: TFTP.cxx:628
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 &#39;url&#39; on re...
Definition: TSocket.cxx:1457
static Long64_t fgBytesWrite
Definition: TFTP.h:64
XFontStruct * id
Definition: TGX11.cxx:108
Int_t GetRemoteProtocol() const
Definition: TSocket.h:145
Long64_t fBytesWrite
connection to rootd
Definition: TFTP.h:49
virtual ~TFTP()
TFTP dtor. Send close message and close socket.
Definition: TFTP.cxx:149
Int_t fWindowSize
Definition: TFTP.h:41
Int_t fGid
Definition: TSystem.h:130
const char * GetUser() const
Definition: TSecContext.h:82
const char * GetUser() const
Definition: TUrl.h:68
Int_t ListDirectory(Option_t *cmd="") const
List remote directory.
Definition: TFTP.cxx:734
Int_t ChangePermission(const char *file, Int_t mode) const
Change permissions of a remote file.
Definition: TFTP.cxx:853
static Long64_t fgBytesRead
Definition: TFTP.h:65
Bool_t fIsLink
Definition: TSystem.h:133
R__EXTERN TSystem * gSystem
Definition: TSystem.h:540
Int_t Recv(Int_t &status, EMessageTypes &kind) const
Return status from rootd server and message kind.
Definition: TFTP.cxx:191
Bool_t BeginsWith(const char *s, ECaseCompare cmp=kExact) const
Definition: TString.h:561
TString fHost
Definition: TFTP.h:37
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:880
char * Form(const char *fmt,...)
Int_t fParallel
Definition: TFTP.h:40
EMessageTypes
Definition: MessageTypes.h:27
const char * GetDirEntry(Bool_t print=kFALSE)
Get directory entry via rootd.
Definition: TFTP.cxx:988
virtual const char * AsString(TString &out)
Returns short string with relevant information about this security context.
Int_t fMode
Definition: TFTP.h:45
Int_t RenameFile(const char *file1, const char *file2) const
Rename a remote file.
Definition: TFTP.cxx:790
Long64_t PutFile(const char *file, const char *remoteName=0)
Transfer file to remote host.
Definition: TFTP.cxx:233
Int_t MakeDirectory(const char *dir, Bool_t print=kFALSE) const
Make a remote directory.
Definition: TFTP.cxx:667
#define Printf
Definition: TGeoToOCC.h:18
const Bool_t kFALSE
Definition: RtypesCore.h:88
void Print(Option_t *opt="") const
Print some info about the FTP connection.
Definition: TFTP.cxx:157
long Long_t
Definition: RtypesCore.h:50
#define ClassImp(name)
Definition: Rtypes.h:359
double Double_t
Definition: RtypesCore.h:55
virtual const char * HostName()
Return the system&#39;s host name.
Definition: TSystem.cxx:311
Long64_t fRestartAt
Definition: TFTP.h:46
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition: TString.h:570
static constexpr double s
#define R__LOCKGUARD(mutex)
virtual Bool_t IsAuthenticated() const
Definition: TSocket.h:150
Int_t Close()
Close ftp connection.
Definition: TFTP.cxx:884
EAccessMode
Definition: TSystem.h:44
Int_t GetPort() const
Definition: TUrl.h:81
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 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
TSecContext * GetSecContext() const
Definition: TSocket.h:146
Bool_t fDir
Definition: TFTP.h:51
Definition: file.py:1
void MakeZombie()
Definition: TObject.h:49
Int_t PrintDirectory() const
Print path of remote working directory.
Definition: TFTP.cxx:764
Long_t fIno
Definition: TSystem.h:127
void Init(const char *url, Int_t parallel, Int_t wsize)
Set up the actual connection.
Definition: TFTP.cxx:95
void FreeDirectory(Bool_t print=kFALSE)
Free a remotely open directory via rootd.
Definition: TFTP.cxx:956
static void ResetErrno()
Static function resetting system error number.
Definition: TSystem.cxx:284
Long_t fDev
Definition: TSystem.h:126
Int_t DeleteDirectory(const char *dir) const
Delete a remote directory.
Definition: TFTP.cxx:702
virtual Int_t RecvRaw(void *buffer, Int_t length, ESendRecvOptions opt=kDefault)
Receive a raw buffer of specified length bytes.
Definition: TSocket.cxx:902
const Bool_t kTRUE
Definition: RtypesCore.h:87
TFTP()
Definition: TFTP.h:53
static char * skip(char **buf, const char *delimiters)
Definition: civetweb.c:2039
Bool_t IsOpen() const
Definition: TFTP.h:85
const Int_t n
Definition: legend1.C:16
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition: TObject.cxx:866
const char * Data() const
Definition: TString.h:345
Stopwatch class.
Definition: TStopwatch.h:28