TFTP.cxx

Go to the documentation of this file.
00001 // @(#)root/net:$Id: TFTP.cxx 36149 2010-10-07 13:30:24Z rdm $
00002 // Author: Fons Rademakers   13/02/2001
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2001, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 //////////////////////////////////////////////////////////////////////////
00013 //                                                                      //
00014 // TFTP                                                                 //
00015 //                                                                      //
00016 // This class provides all infrastructure for a performant file         //
00017 // transfer protocol. It works in conjuction with the rootd daemon      //
00018 // and can use parallel sockets to improve performance over fat pipes.  //
00019 //                                                                      //
00020 //////////////////////////////////////////////////////////////////////////
00021 
00022 #include "RConfig.h"
00023 
00024 #include <fcntl.h>
00025 #include <errno.h>
00026 #include <sys/stat.h>
00027 #ifndef R__WIN32
00028 #   include <unistd.h>
00029 #else
00030 #   define ssize_t int
00031 #   include <io.h>
00032 #   include <sys/types.h>
00033 #endif
00034 
00035 #include "TFTP.h"
00036 #include "TPSocket.h"
00037 #include "TUrl.h"
00038 #include "TStopwatch.h"
00039 #include "TSystem.h"
00040 #include "TEnv.h"
00041 #include "TROOT.h"
00042 #include "TError.h"
00043 #include "NetErrors.h"
00044 #include "TRegexp.h"
00045 #include "TVirtualMutex.h"
00046 
00047 #if defined(R__UNIX) || defined(R__MACOSX)
00048 #define HAVE_MMAP
00049 #endif
00050 
00051 #ifdef HAVE_MMAP
00052 #   include <sys/mman.h>
00053 #ifndef MAP_FILE
00054 #define MAP_FILE 0           /* compatability flag */
00055 #endif
00056 #endif
00057 
00058 
00059 Long64_t TFTP::fgBytesWrite = 0;
00060 Long64_t TFTP::fgBytesRead  = 0;
00061 
00062 
00063 ClassImp(TFTP)
00064 
00065 //______________________________________________________________________________
00066 TFTP::TFTP(const char *url, Int_t par, Int_t wsize, TSocket *sock)
00067 {
00068    // Open connection to host specified by the url using par parallel sockets.
00069    // The url has the form: [root[s,k]://]host[:port].
00070    // If port is not specified the default rootd port (1094) will be used.
00071    // Using wsize one can specify the tcp window size. Normally this is not
00072    // needed when using parallel sockets.
00073    // An existing connection (TSocket *sock) can also be used to establish
00074    // the FTP session.
00075 
00076    fSocket = sock;
00077 
00078    TString s = url;
00079    if (s.Contains("://")) {
00080       if (!s.BeginsWith("root")) {
00081          Error("TFTP",
00082                "url must be of the form \"[root[up,s,k,g,h,ug]://]host[:port]\"");
00083          MakeZombie();
00084          return;
00085       }
00086    } else
00087       s = "root://" + s;
00088 
00089    Init(s, par, wsize);
00090 }
00091 
00092 //______________________________________________________________________________
00093 void TFTP::Init(const char *surl, Int_t par, Int_t wsize)
00094 {
00095    // Set up the actual connection.
00096 
00097    TUrl url(surl);
00098    TString hurl(url.GetProtocol());
00099    if (hurl.Contains("root")) {
00100       hurl.Insert(4,"dp");
00101    } else {
00102       hurl = "rootdp";
00103    }
00104    hurl += TString(Form("://%s@%s:%d",
00105                         url.GetUser(), url.GetHost(), url.GetPort()));
00106    fSocket = TSocket::CreateAuthSocket(hurl, par, wsize, fSocket);
00107    if (!fSocket || !fSocket->IsAuthenticated()) {
00108       if (par > 1)
00109          Error("TFTP", "can't open %d-stream connection to rootd on "
00110                "host %s at port %d", par, url.GetHost(), url.GetPort());
00111       else
00112          Error("TFTP", "can't open connection to rootd on "
00113                "host %s at port %d", url.GetHost(), url.GetPort());
00114       goto zombie;
00115    }
00116 
00117    fProtocol = fSocket->GetRemoteProtocol();
00118    fUser = fSocket->GetSecContext()->GetUser();
00119 
00120    fHost       = url.GetHost();
00121    fPort       = url.GetPort();
00122    fParallel   = par;
00123    fWindowSize = wsize;
00124    fLastBlock  = 0;
00125    fRestartAt  = 0;
00126    fBlockSize  = kDfltBlockSize;
00127    fMode       = kBinary;
00128    fBytesWrite = 0;
00129    fBytesRead  = 0;
00130 
00131    // Replace our socket in the list with this
00132    // for consistency during the final cleanup
00133    // (The socket will be delete by us when everything is ok remotely)
00134    {
00135       R__LOCKGUARD2(gROOTMutex);
00136       gROOT->GetListOfSockets()->Remove(fSocket);
00137       gROOT->GetListOfSockets()->Add(this);
00138    }
00139    return;
00140 
00141 zombie:
00142    MakeZombie();
00143    SafeDelete(fSocket);
00144 }
00145 
00146 //______________________________________________________________________________
00147 TFTP::~TFTP()
00148 {
00149    // TFTP dtor. Send close message and close socket.
00150 
00151    Close();
00152 }
00153 
00154 //______________________________________________________________________________
00155 void TFTP::Print(Option_t *) const
00156 {
00157    // Print some info about the FTP connection.
00158 
00159    TString secCont;
00160 
00161    Printf("Local host:           %s", gSystem->HostName());
00162    Printf("Remote host:          %s [%d]", fHost.Data(), fPort);
00163    Printf("Remote user:          %s", fUser.Data());
00164    if (fSocket->IsAuthenticated())
00165       Printf("Security context:     %s",
00166                                       fSocket->GetSecContext()->AsString(secCont));
00167    Printf("Rootd protocol vers.: %d", fSocket->GetRemoteProtocol());
00168    if (fParallel > 1) {
00169       Printf("Parallel sockets:     %d", fParallel);
00170    }
00171    Printf("TCP window size:      %d",   fWindowSize);
00172    Printf("Rootd protocol:       %d",   fProtocol);
00173    Printf("Transfer block size:  %d",   fBlockSize);
00174    Printf("Transfer mode:        %s",   fMode ? "ascii" : "binary");
00175    Printf("Bytes sent:           %lld", fBytesWrite);
00176    Printf("Bytes received:       %lld", fBytesRead);
00177 }
00178 
00179 //______________________________________________________________________________
00180 void TFTP::PrintError(const char *where, Int_t err) const
00181 {
00182    // Print error string depending on error code.
00183 
00184    Error(where, "%s", gRootdErrStr[err]);
00185 }
00186 
00187 //______________________________________________________________________________
00188 Int_t TFTP::Recv(Int_t &status, EMessageTypes &kind) const
00189 {
00190    // Return status from rootd server and message kind. Returns -1 in
00191    // case of error otherwise 8 (sizeof 2 words, status and kind).
00192 
00193    kind   = kROOTD_ERR;
00194    status = 0;
00195 
00196    if (!fSocket) return -1;
00197 
00198    Int_t what;
00199    Int_t n = fSocket->Recv(status, what);
00200    kind = (EMessageTypes) what;
00201    return n;
00202 }
00203 
00204 //______________________________________________________________________________
00205 void TFTP::SetBlockSize(Int_t blockSize)
00206 {
00207    // Make sure the block size is a power of two, with a minimum of 32768.
00208 
00209    if (blockSize < 32768) {
00210       fBlockSize = 32768;
00211       return;
00212    }
00213 
00214    int i;
00215    for (i = 0; i < int(sizeof(blockSize)*8); i++)
00216       if ((blockSize >> i) == 1)
00217          break;
00218 
00219    fBlockSize = 1 << i;
00220 }
00221 
00222 //______________________________________________________________________________
00223 Long64_t TFTP::PutFile(const char *file, const char *remoteName)
00224 {
00225    // Transfer file to remote host. Returns number of bytes
00226    // sent or < 0 in case of error. Error -1 connection is still
00227    // open, error -2 connection has been closed. In case of failure
00228    // fRestartAt is set to the number of bytes correclty transfered.
00229    // Calling PutFile() immediately afterwards will restart at fRestartAt.
00230    // If this is not desired call SetRestartAt(0) before calling PutFile().
00231    // If rootd reports that the file is locked, and you are sure this is not
00232    // the case (e.g. due to a crash), you can force unlock it by prepending
00233    // the remoteName with a '-'.
00234 
00235    if (!IsOpen() || !file || !*file) return -1;
00236 
00237 #if defined(R__WIN32) || defined(R__WINGCC)
00238    Int_t fd = open(file, O_RDONLY | O_BINARY);
00239 #elif defined(R__SEEK64)
00240    Int_t fd = open64(file, O_RDONLY);
00241 #else
00242    Int_t fd = open(file, O_RDONLY);
00243 #endif
00244    if (fd < 0) {
00245       Error("PutFile", "cannot open %s in read mode", file);
00246       return -1;
00247    }
00248 
00249    Long64_t size;
00250    Long_t id, flags, modtime;
00251    if (gSystem->GetPathInfo(file, &id, &size, &flags, &modtime) == 0) {
00252       if (flags > 1) {
00253          Error("PutFile", "%s not a regular file (%ld)", file, flags);
00254          close(fd);
00255          return -1;
00256       }
00257    } else {
00258       Warning("PutFile", "could not stat %s", file);
00259       close(fd);
00260       return -1;
00261    }
00262 
00263    if (!remoteName)
00264       remoteName = file;
00265 
00266    Long64_t restartat = fRestartAt;
00267 
00268    // check if restartat value makes sense
00269    if (restartat && (restartat >= size))
00270       restartat = 0;
00271 
00272    if (fSocket->Send(Form("%s %d %d %lld %lld", remoteName, fBlockSize, fMode,
00273                      size, restartat), kROOTD_PUTFILE) < 0) {
00274       Error("PutFile", "error sending kROOTD_PUTFILE command");
00275       close(fd);
00276       return -2;
00277    }
00278 
00279    Int_t         stat;
00280    EMessageTypes kind;
00281 
00282    if (Recv(stat, kind) < 0 || kind == kROOTD_ERR) {
00283       PrintError("PutFile", stat);
00284       close(fd);
00285       return -1;
00286    }
00287 
00288    Info("PutFile", "sending file %s (%lld bytes, starting at %lld)",
00289         file, size, restartat);
00290 
00291    TStopwatch timer;
00292    timer.Start();
00293 
00294    Long64_t pos = restartat & ~(fBlockSize-1);
00295    Int_t skip = restartat - pos;
00296 
00297 #ifndef HAVE_MMAP
00298    char *buf = new char[fBlockSize];
00299 #if defined(R__SEEK64)
00300    lseek64(fd, pos, SEEK_SET);
00301 #elif defined(R__WIN32)
00302    _lseeki64(fd, pos, SEEK_SET);
00303 #else
00304    lseek(fd, pos, SEEK_SET);
00305 #endif
00306 #endif
00307 
00308    while (pos < size) {
00309       Long64_t left = Long64_t(size - pos);
00310       if (left > fBlockSize)
00311          left = fBlockSize;
00312 #ifdef HAVE_MMAP
00313 #if defined(R__SEEK64)
00314       char *buf = (char*) mmap64(0, left, PROT_READ, MAP_FILE | MAP_SHARED, fd, pos);
00315 #else
00316       char *buf = (char*) mmap(0, left, PROT_READ, MAP_FILE | MAP_SHARED, fd, pos);
00317 #endif
00318       if (buf == (char *) -1) {
00319          Error("PutFile", "mmap of file %s failed", file);
00320          close(fd);
00321          return -1;
00322       }
00323 #else
00324       Int_t siz;
00325       while ((siz = read(fd, buf, left)) < 0 && TSystem::GetErrno() == EINTR)
00326          TSystem::ResetErrno();
00327       if (siz < 0 || siz != left) {
00328          Error("PutFile", "error reading from file %s", file);
00329          // Send urgent message to rootd to stop tranfer
00330          delete [] buf;
00331          close(fd);
00332          return -1;
00333       }
00334 #endif
00335 
00336       if (fSocket->SendRaw(buf+skip, left-skip) < 0) {
00337          Error("PutFile", "error sending buffer");
00338          // Send urgent message to rootd to stop transfer
00339 #ifdef HAVE_MMAP
00340          munmap(buf, left);
00341 #else
00342          delete [] buf;
00343 #endif
00344          close(fd);
00345          return -2;
00346       }
00347 
00348       fBytesWrite  += left-skip;
00349       fgBytesWrite += left-skip;
00350 
00351       fRestartAt = pos;   // bytes correctly sent up till now
00352 
00353       pos += left;
00354       skip = 0;
00355 
00356 #ifdef HAVE_MMAP
00357       munmap(buf, left);
00358 #endif
00359    }
00360 
00361 #ifndef HAVE_MMAP
00362    delete [] buf;
00363 #endif
00364 
00365    close(fd);
00366 
00367    fRestartAt = 0;
00368 
00369    // get acknowlegdement from server that file was stored correctly
00370    if (Recv(stat, kind) < 0 || kind == kROOTD_ERR) {
00371       PrintError("PutFile", stat);
00372       close(fd);
00373       return -1;
00374    }
00375 
00376    // provide timing numbers
00377    Double_t speed, t = timer.RealTime();
00378    if (t > 0)
00379       speed = Double_t(size - restartat) / t;
00380    else
00381       speed = 0.0;
00382    if (speed > 524288)
00383       Info("PutFile", "%.3f seconds, %.2f Mbytes per second",
00384            t, speed / 1048576);
00385    else if (speed > 512)
00386       Info("PutFile", "%.3f seconds, %.2f Kbytes per second",
00387            t, speed / 1024);
00388    else
00389       Info("PutFile", "%.3f seconds, %.2f bytes per second",
00390            t, speed);
00391 
00392    return Long64_t(size - restartat);
00393 }
00394 
00395 //______________________________________________________________________________
00396 Long64_t TFTP::GetFile(const char *file, const char *localName)
00397 {
00398    // Transfer file from remote host. Returns number of bytes
00399    // received or < 0 in case of error. Error -1 connection is still
00400    // open, error -2 connection has been closed. In case of failure
00401    // fRestartAt is set to the number of bytes correclty transfered.
00402    // Calling GetFile() immediately afterwards will restart at fRestartAt.
00403    // If this is not desired call SetRestartAt(0) before calling GetFile().
00404    // If rootd reports that the file is locked, and you are sure this is not
00405    // the case (e.g. due to a crash), you can force unlock it by prepending
00406    // the file name with a '-'.
00407 
00408    if (!IsOpen() || !file || !*file) return -1;
00409 
00410    if (!localName) {
00411       if (file[0] == '-')
00412          localName = file+1;
00413       else
00414          localName = file;
00415    }
00416 
00417    Long64_t restartat = fRestartAt;
00418 
00419    if (fSocket->Send(Form("%s %d %d %lld", file, fBlockSize, fMode,
00420                      restartat), kROOTD_GETFILE) < 0) {
00421       Error("GetFile", "error sending kROOTD_GETFILE command");
00422       return -2;
00423    }
00424 
00425    Int_t         stat;
00426    EMessageTypes kind;
00427 
00428    if (Recv(stat, kind) < 0 || kind == kROOTD_ERR) {
00429       PrintError("GetFile", stat);
00430       return -1;
00431    }
00432 
00433    // get size of remote file
00434    Long64_t size;
00435    Int_t    what;
00436    char     mess[128];
00437 
00438    if (fSocket->Recv(mess, sizeof(mess), what) < 0) {
00439       Error("GetFile", "error receiving remote file size");
00440       return -2;
00441    }
00442 #ifdef R__WIN32
00443    sscanf(mess, "%I64d", &size);
00444 #else
00445    sscanf(mess, "%lld", &size);
00446 #endif
00447 
00448    // check if restartat value makes sense
00449    if (restartat && (restartat >= size))
00450       restartat = 0;
00451 
00452    // open local file
00453    Int_t fd;
00454    if (!restartat) {
00455 #if defined(R__WIN32) || defined(R__WINGCC)
00456       if (fMode == kBinary)
00457          fd = open(localName, O_CREAT | O_TRUNC | O_WRONLY | O_BINARY,
00458                    S_IREAD | S_IWRITE);
00459       else
00460          fd = open(localName, O_CREAT | O_TRUNC | O_WRONLY,
00461                    S_IREAD | S_IWRITE);
00462 #elif defined(R__SEEK64)
00463       fd = open64(localName, O_CREAT | O_TRUNC | O_WRONLY, 0600);
00464 #else
00465       fd = open(localName, O_CREAT | O_TRUNC | O_WRONLY, 0600);
00466 #endif
00467    } else {
00468 #if defined(R__WIN32) || defined(R__WINGCC)
00469       if (fMode == kBinary)
00470          fd = open(localName, O_WRONLY | O_BINARY, S_IREAD | S_IWRITE);
00471       else
00472          fd = open(localName, O_WRONLY, S_IREAD | S_IWRITE);
00473 #elif defined(R__SEEK64)
00474       fd = open64(localName, O_WRONLY, 0600);
00475 #else
00476       fd = open(localName, O_WRONLY, 0600);
00477 #endif
00478    }
00479 
00480    if (fd < 0) {
00481       Error("GetFile", "cannot open %s", localName);
00482       // send urgent message to rootd to stop tranfer
00483       return -1;
00484    }
00485 
00486    // check file system space
00487    if (strcmp(localName, "/dev/null")) {
00488       Long_t id, bsize, blocks, bfree;
00489       if (gSystem->GetFsInfo(localName, &id, &bsize, &blocks, &bfree) == 0) {
00490          Long64_t space = (Long64_t)bsize * (Long64_t)bfree;
00491          if (space < size - restartat) {
00492             Error("GetFile", "not enough space to store file %s", localName);
00493             // send urgent message to rootd to stop tranfer
00494             close(fd);
00495             return -1;
00496          }
00497       } else
00498          Warning("GetFile", "could not determine if there is enough free space to store file");
00499    }
00500 
00501    // seek to restartat position
00502    if (restartat) {
00503 #if defined(R__SEEK64)
00504       if (lseek64(fd, restartat, SEEK_SET) < 0) {
00505 #elif defined(R__WIN32)
00506       if (_lseeki64(fd, restartat, SEEK_SET) < 0) {
00507 #else
00508       if (lseek(fd, restartat, SEEK_SET) < 0) {
00509 #endif
00510          Error("GetFile", "cannot seek to position %lld in file %s",
00511                restartat, localName);
00512          // if cannot seek send urgent message to rootd to stop tranfer
00513          close(fd);
00514          return -1;
00515       }
00516    }
00517 
00518    Info("GetFile", "getting file %s (%lld bytes, starting at %lld)",
00519         localName, size, restartat);
00520 
00521    TStopwatch timer;
00522    timer.Start();
00523 
00524    char *buf = new char[fBlockSize];
00525    char *buf2 = 0;
00526    if (fMode == kAscii)
00527       buf2 = new char[fBlockSize];
00528 
00529    Long64_t pos = restartat & ~(fBlockSize-1);
00530    Int_t skip = restartat - pos;
00531 
00532    while (pos < size) {
00533       Long64_t left = size - pos;
00534       if (left > fBlockSize)
00535          left = fBlockSize;
00536 
00537       Int_t n;
00538       while ((n = fSocket->RecvRaw(buf, Int_t(left-skip))) < 0 &&
00539              TSystem::GetErrno() == EINTR)
00540          TSystem::ResetErrno();
00541 
00542       if (n != Int_t(left-skip)) {
00543          Error("GetFile", "error receiving buffer of length %d, got %d",
00544                Int_t(left-skip), n);
00545          close(fd);
00546          delete [] buf; delete [] buf2;
00547          return -2;
00548       }
00549 
00550       // in case of ascii file, loop over buffer and remove \r's
00551       ssize_t siz;
00552       if (fMode == kAscii) {
00553          Int_t i = 0, j = 0;
00554          while (i < n) {
00555             if (buf[i] == '\r')
00556                i++;
00557             else
00558                buf2[j++] = buf[i++];
00559          }
00560          n = j;
00561          while ((siz = write(fd, buf2, n)) < 0 && TSystem::GetErrno() == EINTR)
00562             TSystem::ResetErrno();
00563       } else {
00564          while ((siz = write(fd, buf, n)) < 0 && TSystem::GetErrno() == EINTR)
00565             TSystem::ResetErrno();
00566       }
00567 
00568       if (siz < 0) {
00569          SysError("GetFile", "error writing file %s", localName);
00570          // send urgent message to rootd to stop tranfer
00571          close(fd);
00572          delete [] buf; delete [] buf2;
00573          return -1;
00574       }
00575 
00576       if (siz != n) {
00577          Error("GetFile", "error writing all requested bytes to file %s, wrote %ld of %d",
00578                localName, (Long_t)siz, n);
00579          // send urgent message to rootd to stop tranfer
00580          close(fd);
00581          delete [] buf; delete [] buf2;
00582          return -1;
00583       }
00584 
00585       fBytesRead  += left-skip;
00586       fgBytesRead += left-skip;
00587 
00588       fRestartAt = pos;   // bytes correctly received up till now
00589 
00590       pos += left;
00591       skip = 0;
00592    }
00593 
00594    delete [] buf; delete [] buf2;
00595 
00596 #ifndef R__WIN32
00597    fchmod(fd, 0644);
00598 #endif
00599 
00600    close(fd);
00601 
00602    fRestartAt = 0;
00603 
00604    // provide timing numbers
00605    Double_t speed, t = timer.RealTime();
00606    if (t > 0)
00607       speed = Double_t(size - restartat) / t;
00608    else
00609       speed = 0.0;
00610    if (speed > 524288)
00611       Info("GetFile", "%.3f seconds, %.2f Mbytes per second",
00612            t, speed / 1048576);
00613    else if (speed > 512)
00614       Info("GetFile", "%.3f seconds, %.2f Kbytes per second",
00615            t, speed / 1024);
00616    else
00617       Info("GetFile", "%.3f seconds, %.2f bytes per second",
00618            t, speed);
00619 
00620    return Long64_t(size - restartat);
00621 }
00622 
00623 //______________________________________________________________________________
00624 Int_t TFTP::ChangeDirectory(const char *dir) const
00625 {
00626    // Change the remote directory. If the remote directory contains a .message
00627    // file and it is < 1024 characters then the contents is echoed back.
00628    // Returns 0 in case of success and -1 in case of failure.
00629 
00630    if (!IsOpen()) return -1;
00631 
00632    if (!dir || !*dir) {
00633       Error("ChangeDirectory", "illegal directory name specified");
00634       return -1;
00635    }
00636 
00637    if (fSocket->Send(Form("%s", dir), kROOTD_CHDIR) < 0) {
00638       Error("ChangeDirectory", "error sending kROOTD_CHDIR command");
00639       return -1;
00640    }
00641 
00642    Int_t what;
00643    char  mess[1024];
00644 
00645    if (fSocket->Recv(mess, sizeof(mess), what) < 0) {
00646       Error("ChangeDirectory", "error receiving chdir confirmation");
00647       return -1;
00648    }
00649    if (what == kMESS_STRING) {
00650       Printf("%s\n", mess);
00651 
00652       if (fSocket->Recv(mess, sizeof(mess), what) < 0) {
00653          Error("ChangeDirectory", "error receiving chdir confirmation");
00654          return -1;
00655       }
00656    }
00657 
00658    Info("ChangeDirectory", "%s", mess);
00659 
00660    return 0;
00661 }
00662 
00663 //______________________________________________________________________________
00664 Int_t TFTP::MakeDirectory(const char *dir, Bool_t print) const
00665 {
00666    // Make a remote directory. Anonymous users may not create directories.
00667    // Returns 0 in case of success and -1 in case of failure.
00668 
00669    if (!IsOpen()) return -1;
00670 
00671    if (!dir || !*dir) {
00672       Error("MakeDirectory", "illegal directory name specified");
00673       return -1;
00674    }
00675 
00676    if (fSocket->Send(Form("%s", dir), kROOTD_MKDIR) < 0) {
00677       Error("MakeDirectory", "error sending kROOTD_MKDIR command");
00678       return -1;
00679    }
00680 
00681    Int_t what;
00682    char  mess[1024];
00683 
00684    if (fSocket->Recv(mess, sizeof(mess), what) < 0) {
00685       Error("MakeDirectory", "error receiving mkdir confirmation");
00686       return -1;
00687    }
00688 
00689    if (print)
00690       Info("MakeDirectory", "%s", mess);
00691 
00692    if (!strncmp(mess,"OK:",3))
00693       return 1;
00694 
00695    return 0;
00696 }
00697 
00698 //______________________________________________________________________________
00699 Int_t TFTP::DeleteDirectory(const char *dir) const
00700 {
00701    // Delete a remote directory. Anonymous users may not delete directories.
00702    // Returns 0 in case of success and -1 in case of failure.
00703 
00704    if (!IsOpen()) return -1;
00705 
00706    if (!dir || !*dir) {
00707       Error("DeleteDirectory", "illegal directory name specified");
00708       return -1;
00709    }
00710 
00711    if (fSocket->Send(Form("%s", dir), kROOTD_RMDIR) < 0) {
00712       Error("DeleteDirectory", "error sending kROOTD_RMDIR command");
00713       return -1;
00714    }
00715 
00716    Int_t what;
00717    char  mess[1024];
00718 
00719    if (fSocket->Recv(mess, sizeof(mess), what) < 0) {
00720       Error("DeleteDirectory", "error receiving rmdir confirmation");
00721       return -1;
00722    }
00723 
00724    Info("DeleteDirectory", "%s", mess);
00725 
00726    return 0;
00727 }
00728 
00729 //______________________________________________________________________________
00730 Int_t TFTP::ListDirectory(Option_t *cmd) const
00731 {
00732    // List remote directory. With cmd you specify the options and directory
00733    // to be listed to ls. Returns 0 in case of success and -1 in case of
00734    // failure.
00735 
00736    if (!IsOpen()) return -1;
00737 
00738    if (!cmd || !*cmd)
00739       cmd = "ls .";
00740 
00741    if (fSocket->Send(Form("%s", cmd), kROOTD_LSDIR) < 0) {
00742       Error("ListDirectory", "error sending kROOTD_LSDIR command");
00743       return -1;
00744    }
00745 
00746    Int_t what;
00747    char  mess[1024];
00748 
00749    do {
00750       if (fSocket->Recv(mess, sizeof(mess), what) < 0) {
00751          Error("ListDirectory", "error receiving lsdir confirmation");
00752          return -1;
00753       }
00754       printf("%s", mess);
00755    } while (what == kMESS_STRING);
00756 
00757    return 0;
00758 }
00759 
00760 //______________________________________________________________________________
00761 Int_t TFTP::PrintDirectory() const
00762 {
00763    // Print path of remote working directory. Returns 0 in case of succes and
00764    // -1 in cse of failure.
00765 
00766    if (!IsOpen()) return -1;
00767 
00768    if (fSocket->Send("", kROOTD_PWD) < 0) {
00769       Error("DeleteDirectory", "error sending kROOTD_PWD command");
00770       return -1;
00771    }
00772 
00773    Int_t what;
00774    char  mess[1024];
00775 
00776    if (fSocket->Recv(mess, sizeof(mess), what) < 0) {
00777       Error("PrintDirectory", "error receiving pwd confirmation");
00778       return -1;
00779    }
00780 
00781    Info("PrintDirectory", "%s", mess);
00782 
00783    return 0;
00784 }
00785 
00786 //______________________________________________________________________________
00787 Int_t TFTP::RenameFile(const char *file1, const char *file2) const
00788 {
00789    // Rename a remote file. Anonymous users may not rename files.
00790    // Returns 0 in case of success and -1 in case of failure.
00791 
00792    if (!IsOpen()) return -1;
00793 
00794    if (!file1 || !file2 || !*file1 || !*file2) {
00795       Error("RenameFile", "illegal file names specified");
00796       return -1;
00797    }
00798 
00799    if (fSocket->Send(Form("%s %s", file1, file2), kROOTD_MV) < 0) {
00800       Error("RenameFile", "error sending kROOTD_MV command");
00801       return -1;
00802    }
00803 
00804    Int_t what;
00805    char  mess[1024];
00806 
00807    if (fSocket->Recv(mess, sizeof(mess), what) < 0) {
00808       Error("RenameFile", "error receiving mv confirmation");
00809       return -1;
00810    }
00811 
00812    Info("RenameFile", "%s", mess);
00813 
00814    return 0;
00815 }
00816 
00817 //______________________________________________________________________________
00818 Int_t TFTP::DeleteFile(const char *file) const
00819 {
00820    // Delete a remote file. Anonymous users may not delete files.
00821    // Returns 0 in case of success and -1 in case of failure.
00822 
00823    if (!IsOpen()) return -1;
00824 
00825    if (!file || !*file) {
00826       Error("DeleteFile", "illegal file name specified");
00827       return -1;
00828    }
00829 
00830    if (fSocket->Send(Form("%s", file), kROOTD_RM) < 0) {
00831       Error("DeleteFile", "error sending kROOTD_RM command");
00832       return -1;
00833    }
00834 
00835    Int_t what;
00836    char  mess[1024];
00837 
00838    if (fSocket->Recv(mess, sizeof(mess), what) < 0) {
00839       Error("DeleteFile", "error receiving rm confirmation");
00840       return -1;
00841    }
00842 
00843    Info("DeleteFile", "%s", mess);
00844 
00845    return 0;
00846 }
00847 
00848 //______________________________________________________________________________
00849 Int_t TFTP::ChangePermission(const char *file, Int_t mode) const
00850 {
00851    // Change permissions of a remote file. Anonymous users may not
00852    // chnage permissions. Returns 0 in case of success and -1 in case
00853    // of failure.
00854 
00855    if (!IsOpen()) return -1;
00856 
00857    if (!file || !*file) {
00858       Error("ChangePermission", "illegal file name specified");
00859       return -1;
00860    }
00861 
00862    if (fSocket->Send(Form("%s %d", file, mode), kROOTD_CHMOD) < 0) {
00863       Error("ChangePermission", "error sending kROOTD_CHMOD command");
00864       return -1;
00865    }
00866 
00867    Int_t what;
00868    char  mess[1024];
00869 
00870    if (fSocket->Recv(mess, sizeof(mess), what) < 0) {
00871       Error("ChangePermission", "error receiving chmod confirmation");
00872       return -1;
00873    }
00874 
00875    Info("ChangePermission", "%s", mess);
00876 
00877    return 0;
00878 }
00879 
00880 //______________________________________________________________________________
00881 Int_t TFTP::Close()
00882 {
00883    // Close ftp connection. Returns 0 in case of success and -1 in case of
00884    // failure.
00885 
00886    if (!IsOpen()) return -1;
00887 
00888    if (fSocket->Send(kROOTD_CLOSE) < 0) {
00889       Error("Close", "error sending kROOTD_CLOSE command");
00890       return -1;
00891    }
00892 
00893    // Ask for remote shutdown
00894    if (fProtocol > 6)
00895       fSocket->Send(kROOTD_BYE);
00896 
00897    // Remove from the list of Sockets
00898    {
00899       R__LOCKGUARD2(gROOTMutex);
00900       gROOT->GetListOfSockets()->Remove(this);
00901    }
00902 
00903    // Delete socket here
00904    SafeDelete(fSocket);
00905 
00906    return 0;
00907 }
00908 
00909 //______________________________________________________________________________
00910 Bool_t TFTP::OpenDirectory(const char *dir, Bool_t print)
00911 {
00912    // Open a directory via rootd.
00913    // Returns kTRUE in case of success.
00914    // Returns kFALSE in case of error.
00915 
00916    fDir = kFALSE;
00917 
00918    if (!IsOpen()) return fDir;
00919 
00920    if (fProtocol < 12) {
00921       Error("OpenDirectory", "call not supported by remote rootd");
00922       return fDir;
00923    }
00924 
00925    if (!dir || !*dir) {
00926       Error("OpenDirectory", "illegal directory name specified");
00927       return fDir;
00928    }
00929 
00930    if (fSocket->Send(Form("%s", dir), kROOTD_OPENDIR) < 0) {
00931       Error("OpenDirectory", "error sending kROOTD_OPENDIR command");
00932       return fDir;
00933    }
00934 
00935    Int_t what;
00936    char  mess[1024];;
00937 
00938    if (fSocket->Recv(mess, sizeof(mess), what) < 0) {
00939       Error("OpenDirectory", "error receiving opendir confirmation");
00940       return fDir;
00941    }
00942 
00943    if (print)
00944       Info("OpenDirectory", "%s", mess);
00945 
00946    if (!strncmp(mess,"OK:",3)) {
00947       fDir = kTRUE;
00948       return fDir;
00949    }
00950    return fDir;
00951 }
00952 
00953 //______________________________________________________________________________
00954 void TFTP::FreeDirectory(Bool_t print)
00955 {
00956    // Free a remotely open directory via rootd.
00957 
00958    if (!IsOpen() || !fDir) return;
00959 
00960    if (fProtocol < 12) {
00961       Error("FreeDirectory", "call not supported by remote rootd");
00962       return;
00963    }
00964 
00965    if (fSocket->Send(kROOTD_FREEDIR) < 0) {
00966       Error("FreeDirectory", "error sending kROOTD_FREEDIR command");
00967       return;
00968    }
00969 
00970    Int_t what;
00971    char  mess[1024];;
00972 
00973    if (fSocket->Recv(mess, sizeof(mess), what) < 0) {
00974       Error("FreeDirectory", "error receiving freedir confirmation");
00975       return;
00976    }
00977 
00978    if (print)
00979       Info("FreeDirectory", "%s", mess);
00980 
00981    return;
00982 }
00983 
00984 //______________________________________________________________________________
00985 const char *TFTP::GetDirEntry(Bool_t print)
00986 {
00987    // Get directory entry via rootd.
00988    // Returns 0 in case no more entries or in case of error.
00989 
00990    static char dirent[1024] = {0};
00991 
00992    if (!IsOpen() || !fDir) return 0;
00993 
00994    if (fProtocol < 12) {
00995       Error("GetDirEntry", "call not supported by remote rootd");
00996       return 0;
00997    }
00998 
00999    if (fSocket->Send(kROOTD_DIRENTRY) < 0) {
01000       Error("GetDirEntry", "error sending kROOTD_DIRENTRY command");
01001       return 0;
01002    }
01003 
01004    Int_t what;
01005    char  mess[1024];;
01006 
01007    if (fSocket->Recv(mess, sizeof(mess), what) < 0) {
01008       Error("GetDirEntry", "error receiving dir entry confirmation");
01009       return 0;
01010    }
01011 
01012    if (print)
01013       Info("GetDirEntry", "%s", mess);
01014 
01015    if (!strncmp(mess,"OK:",3)) {
01016       strlcpy(dirent,mess+3, sizeof(dirent));
01017       return (const char *)dirent;
01018    }
01019 
01020    return 0;
01021 }
01022 
01023 //______________________________________________________________________________
01024 Int_t TFTP::GetPathInfo(const char *path, FileStat_t &buf, Bool_t print)
01025 {
01026    // Get info about a file. Info is returned in the form of a FileStat_t
01027    // structure (see TSystem.h).
01028    // The function returns 0 in case of success and 1 if the file could
01029    // not be stat'ed.
01030 
01031    TUrl url(path);
01032 
01033    if (!IsOpen()) return 1;
01034 
01035    if (fProtocol < 12) {
01036       Error("GetPathInfo", "call not supported by remote rootd");
01037       return 1;
01038    }
01039 
01040    if (!path || !*path) {
01041       Error("GetPathInfo", "illegal path name specified");
01042       return 1;
01043    }
01044 
01045    if (fSocket->Send(Form("%s", path), kROOTD_FSTAT) < 0) {
01046       Error("GetPathInfo", "error sending kROOTD_FSTAT command");
01047       return 1;
01048    }
01049 
01050    Int_t what;
01051    char  mess[1024];;
01052 
01053    if (fSocket->Recv(mess, sizeof(mess), what) < 0) {
01054       Error("GetPathInfo", "error receiving fstat confirmation");
01055       return 1;
01056    }
01057    if (print)
01058       Info("GetPathInfo", "%s", mess);
01059 
01060    Int_t    mode, uid, gid, islink;
01061    Long_t   id, flags, dev, ino, mtime;
01062    Long64_t size;
01063    if (fProtocol > 12) {
01064 #ifdef R__WIN32
01065       sscanf(mess, "%ld %ld %d %d %d %I64d %ld %d", &dev, &ino, &mode,
01066              &uid, &gid, &size, &mtime, &islink);
01067 #else
01068       sscanf(mess, "%ld %ld %d %d %d %lld %ld %d", &dev, &ino, &mode,
01069              &uid, &gid, &size, &mtime, &islink);
01070 #endif
01071       if (dev == -1)
01072          return 1;
01073       buf.fDev    = dev;
01074       buf.fIno    = ino;
01075       buf.fMode   = mode;
01076       buf.fUid    = uid;
01077       buf.fGid    = gid;
01078       buf.fSize   = size;
01079       buf.fMtime  = mtime;
01080       buf.fIsLink = (islink == 1);
01081    } else {
01082 #ifdef R__WIN32
01083       sscanf(mess, "%ld %I64d %ld %ld", &id, &size, &flags, &mtime);
01084 #else
01085       sscanf(mess, "%ld %lld %ld %ld", &id, &size, &flags, &mtime);
01086 #endif
01087       if (id == -1)
01088          return 1;
01089       buf.fDev    = (id >> 24);
01090       buf.fIno    = (id & 0x00FFFFFF);
01091       if (flags == 0)
01092          buf.fMode = kS_IFREG;
01093       if (flags & 1)
01094          buf.fMode = (kS_IFREG|kS_IXUSR|kS_IXGRP|kS_IXOTH);
01095       if (flags & 2)
01096          buf.fMode = kS_IFDIR;
01097       if (flags & 4)
01098          buf.fMode = kS_IFSOCK;
01099       buf.fSize   = size;
01100       buf.fMtime  = mtime;
01101    }
01102 
01103    return 0;
01104 }
01105 
01106 //______________________________________________________________________________
01107 Bool_t TFTP::AccessPathName(const char *path, EAccessMode mode, Bool_t print)
01108 {
01109    // Returns kFALSE if one can access a file using the specified access mode.
01110    // Mode is the same as for the Unix access(2) function.
01111    // Attention, bizarre convention of return value!!
01112 
01113    if (!IsOpen()) return kTRUE;
01114 
01115    if (fProtocol < 12) {
01116       Error("AccessPathName", "call not supported by remote rootd");
01117       return kTRUE;
01118    }
01119 
01120    if (!path || !*path) {
01121       Error("AccessPathName", "illegal path name specified");
01122       return kTRUE;
01123    }
01124 
01125    if (fSocket->Send(Form("%s %d", path, mode), kROOTD_ACCESS) < 0) {
01126       Error("AccessPathName", "error sending kROOTD_ACCESS command");
01127       return kTRUE;
01128    }
01129 
01130    Int_t what;
01131    char  mess[1024];;
01132 
01133    if (fSocket->Recv(mess, sizeof(mess), what) < 0) {
01134       Error("AccessPathName", "error receiving access confirmation");
01135       return kTRUE;
01136    }
01137    if (print)
01138       Info("AccessPathName", "%s", mess);
01139 
01140    if (!strncmp(mess,"OK",2))
01141       return kFALSE;
01142    else
01143       return kTRUE;
01144 }

Generated on Tue Jul 5 14:46:10 2011 for ROOT_528-00b_version by  doxygen 1.5.1