TNetFile.cxx

Go to the documentation of this file.
00001 // @(#)root/net:$Id: TNetFile.cxx 34444 2010-07-16 02:17:39Z pcanal $
00002 // Author: Fons Rademakers   14/08/97
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2000, 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 // TNetFile                                                             //
00015 //                                                                      //
00016 // A TNetFile is like a normal TFile except that it reads and writes    //
00017 // its data via a rootd server (for more on the rootd daemon see the    //
00018 // source files root/rootd/src/*.cxx). TNetFile file names are in       //
00019 // standard URL format with protocol "root" or "roots". The following   //
00020 // are valid TNetFile URL's:                                            //
00021 //                                                                      //
00022 //    roots://hpsalo/files/aap.root                                     //
00023 //    root://hpbrun.cern.ch/root/hsimple.root                           //
00024 //    root://pcna49a:5151/~na49/data/run821.root                        //
00025 //    root://pcna49d.cern.ch:5050//v1/data/run810.root                  //
00026 //                                                                      //
00027 // The only difference with the well known httpd URL's is that the root //
00028 // of the remote file tree is the user's home directory. Therefore an   //
00029 // absolute pathname requires a // after the host or port specifier     //
00030 // (see last example). Further the expansion of the standard shell      //
00031 // characters, like ~, $, .., are handled as expected.                  //
00032 // TNetFile (actually TUrl) uses 1094 as default port for rootd.        //
00033 //                                                                      //
00034 // Connecting to a rootd requires the remote user id and password.      //
00035 // TNetFile allows three ways for you to provide your login:            //
00036 //   1) Setting it globally via the static functions:                   //
00037 //         TAuthenticate::SetGlobalUser() and                           //
00038 //         TAuthenticate::SetGlobalPasswd()                             //
00039 //   2) Getting it from the ~/.netrc file (same file as used by ftp)    //
00040 //   3) Command line prompt                                             //
00041 // The different methods will be tried in the order given above.        //
00042 // On machines with AFS rootd will authenticate using AFS (if it was    //
00043 // compiled with AFS support).                                          //
00044 //                                                                      //
00045 // If the protocol is specified as "roots" a secure authetication       //
00046 // method will be used. The secure method uses the SRP, Secure Remote   //
00047 // Passwords, package. SRP uses a so called "asymmetric key exchange    //
00048 // protocol" in which no passwords are ever send over the wire. This    //
00049 // protocol is safe against all known security attacks. For more see:   //
00050 // Begin_Html <a href=http://root.cern.ch/root/NetFile.html>NetFile</a> //
00051 // End_Html                                                             //
00052 // If the protocol is specified as "rootk" kerberos5 will be used for   //
00053 // authentication.                                                      //
00054 //                                                                      //
00055 // The rootd daemon lives in the directory $ROOTSYS/bin. It can be      //
00056 // started either via inetd or by hand from the command line (no need   //
00057 // to be super user). For more info about rootd see the web page:       //
00058 // Begin_Html <a href=http://root.cern.ch/root/NetFile.html>NetFile</a> //
00059 // End_Html                                                             //
00060 //                                                                      //
00061 //////////////////////////////////////////////////////////////////////////
00062 
00063 #include <errno.h>
00064 
00065 #include "Bytes.h"
00066 #include "NetErrors.h"
00067 #include "TApplication.h"
00068 #include "TEnv.h"
00069 #include "TNetFile.h"
00070 #include "TPSocket.h"
00071 #include "TROOT.h"
00072 #include "TSysEvtHandler.h"
00073 #include "TSystem.h"
00074 #include "TTimeStamp.h"
00075 #include "TVirtualPerfStats.h"
00076 
00077 // fgClientProtocol is now in TAuthenticate
00078 
00079 ClassImp(TNetFile)
00080 ClassImp(TNetSystem)
00081 
00082 //______________________________________________________________________________
00083 TNetFile::TNetFile(const char *url, Option_t *option, const char *ftitle,
00084                    Int_t compress, Int_t netopt)
00085    : TFile(url, "NET", ftitle, compress), fEndpointUrl(url)
00086 {
00087    // Create a TNetFile object. This is actually done inside Create(), so
00088    // for a description of the options and other arguments see Create().
00089    // Normally a TNetFile is created via TFile::Open().
00090 
00091    fSocket = 0;
00092    Create(url, option, netopt);
00093 }
00094 
00095 //______________________________________________________________________________
00096 TNetFile::TNetFile(const char *url, const char *ftitle, Int_t compress, Bool_t)
00097    : TFile(url, "NET", ftitle, compress), fEndpointUrl(url)
00098 {
00099    // Create a TNetFile object. To be used by derived classes, that need
00100    // to initialize the TFile base class but not open a connection at this
00101    // moment.
00102 
00103    fSocket    = 0;
00104    fProtocol  = 0;
00105    fErrorCode = 0;
00106    fNetopt    = 0;
00107 }
00108 
00109 //______________________________________________________________________________
00110 TNetFile::~TNetFile()
00111 {
00112    // TNetFile dtor. Send close message and close socket.
00113 
00114    Close();
00115 }
00116 
00117 //______________________________________________________________________________
00118 Int_t TNetFile::SysOpen(const char * /*file*/, Int_t /*flags*/, UInt_t /*mode*/)
00119 {
00120    // Open a remote file. Requires fOption to be set correctly.
00121 
00122    if (!fSocket) {
00123 
00124       Create(fUrl.GetUrl(), fOption, fNetopt);
00125       if (!fSocket) return -1;
00126 
00127    } else {
00128 
00129       if (fProtocol > 15) {
00130          fSocket->Send(Form("%s %s", fUrl.GetFile(), ToLower(fOption).Data()),
00131                        kROOTD_OPEN);
00132       } else {
00133          // Old daemon versions expect an additional slash at beginning
00134          fSocket->Send(Form("/%s %s", fUrl.GetFile(), ToLower(fOption).Data()),
00135                        kROOTD_OPEN);
00136       }
00137 
00138       EMessageTypes kind;
00139       int stat;
00140       Recv(stat, kind);
00141 
00142       if (kind == kROOTD_ERR) {
00143          PrintError("SysOpen", stat);
00144          return -1;
00145       }
00146    }
00147 
00148    // This means ok for net files
00149    return -2;  // set as fD in ReOpen
00150 }
00151 
00152 //______________________________________________________________________________
00153 Int_t TNetFile::SysClose(Int_t /*fd*/)
00154 {
00155    // Close currently open file.
00156 
00157    if (fSocket)
00158       fSocket->Send(kROOTD_CLOSE);
00159 
00160    return 0;
00161 }
00162 
00163 //______________________________________________________________________________
00164 Int_t TNetFile::SysStat(Int_t, Long_t *id, Long64_t *size, Long_t *flags, Long_t *modtime)
00165 {
00166    // Return file stat information. The interface and return value is
00167    // identical to TSystem::GetPathInfo().
00168 
00169    if (fProtocol < 3) return 1;
00170 
00171    if (!fSocket) return 1;
00172 
00173    fSocket->Send(kROOTD_FSTAT);
00174 
00175    char  msg[1024];
00176    Int_t kind;
00177    fSocket->Recv(msg, sizeof(msg), kind);
00178 
00179    Int_t  mode, uid, gid, islink;
00180    Long_t dev, ino;
00181 
00182    if (fProtocol > 12) {
00183 #ifdef R__WIN32
00184       sscanf(msg, "%ld %ld %d %d %d %I64d %ld %d", &dev, &ino, &mode,
00185             &uid, &gid, size, modtime, &islink);
00186 #else
00187       sscanf(msg, "%ld %ld %d %d %d %lld %ld %d", &dev, &ino, &mode,
00188             &uid, &gid, size, modtime, &islink);
00189 #endif
00190       if (dev == -1)
00191          return 1;
00192       if (id)
00193          *id = (dev << 24) + ino;
00194       if (flags) {
00195          *flags = 0;
00196          if (mode & (kS_IXUSR|kS_IXGRP|kS_IXOTH))
00197             *flags |= 1;
00198          if (R_ISDIR(mode))
00199             *flags |= 2;
00200          if (!R_ISREG(mode) && !R_ISDIR(mode))
00201             *flags |= 4;
00202       }
00203    } else {
00204 #ifdef R__WIN32
00205       sscanf(msg, "%ld %I64d %ld %ld", id, size, flags, modtime);
00206 #else
00207       sscanf(msg, "%ld %lld %ld %ld", id, size, flags, modtime);
00208 #endif
00209       if (*id == -1)
00210          return 1;
00211    }
00212 
00213    return 0;
00214 }
00215 
00216 //______________________________________________________________________________
00217 void TNetFile::Close(Option_t *opt)
00218 {
00219    // Close remote file.
00220 
00221    if (!fSocket) return;
00222 
00223    TFile::Close(opt);
00224 
00225    if (fProtocol > 6)
00226       fSocket->Send(kROOTD_BYE);
00227 
00228    SafeDelete(fSocket);
00229 
00230    fD = -1;  // so TFile::IsOpen() returns false when in TFile::~TFile
00231 }
00232 
00233 //______________________________________________________________________________
00234 void TNetFile::Flush()
00235 {
00236    // Flush file to disk.
00237 
00238    FlushWriteCache();
00239 
00240    if (fSocket && fWritable)
00241       fSocket->Send(kROOTD_FLUSH);
00242 }
00243 
00244 //______________________________________________________________________________
00245 void TNetFile::Init(Bool_t create)
00246 {
00247    // Initialize a TNetFile object.
00248 
00249    Seek(0);
00250 
00251    TFile::Init(create);
00252    fD = -2;   // so TFile::IsOpen() returns true when in TFile::~TFile
00253 }
00254 
00255 //______________________________________________________________________________
00256 Bool_t TNetFile::IsOpen() const
00257 {
00258    // Retruns kTRUE if file is open, kFALSE otherwise.
00259 
00260    return fSocket == 0 ? kFALSE : kTRUE;
00261 }
00262 
00263 //______________________________________________________________________________
00264 void TNetFile::Print(Option_t *) const
00265 {
00266    // Print some info about the net file.
00267 
00268    const char *fname = fUrl.GetFile();
00269    Printf("URL:           %s",   ((TUrl*)&fUrl)->GetUrl());
00270    Printf("Remote file:   %s",   &fname[1]);
00271    Printf("Remote user:   %s",   fUser.Data());
00272    Printf("Title:         %s",   fTitle.Data());
00273    Printf("Option:        %s",   fOption.Data());
00274    Printf("Bytes written: %lld", fBytesWrite);
00275    Printf("Bytes read:    %lld", fBytesRead);
00276 }
00277 
00278 //______________________________________________________________________________
00279 void TNetFile::PrintError(const char *where, Int_t err)
00280 {
00281    // Print error string depending on error code.
00282 
00283    fErrorCode = err;
00284    Error(where, "%s", gRootdErrStr[err]);
00285 }
00286 
00287 //______________________________________________________________________________
00288 Int_t TNetFile::ReOpen(Option_t *mode)
00289 {
00290    // Reopen a file with a different access mode, like from READ to
00291    // UPDATE or from NEW, CREATE, RECREATE, UPDATE to READ. Thus the
00292    // mode argument can be either "READ" or "UPDATE". The method returns
00293    // 0 in case the mode was successfully modified, 1 in case the mode
00294    // did not change (was already as requested or wrong input arguments)
00295    // and -1 in case of failure, in which case the file cannot be used
00296    // anymore.
00297 
00298    if (fProtocol < 7) {
00299       Error("ReOpen", "operation not supported by remote rootd (protocol = %d)",
00300             fProtocol);
00301       return 1;
00302    }
00303 
00304    return TFile::ReOpen(mode);
00305 }
00306 
00307 //______________________________________________________________________________
00308 Bool_t TNetFile::ReadBuffer(char *buf, Int_t len)
00309 {
00310    // Read specified byte range from remote file via rootd daemon.
00311    // Returns kTRUE in case of error.
00312 
00313    if (!fSocket) return kTRUE;
00314    if (len == 0)
00315       return kFALSE;
00316 
00317    Bool_t result = kFALSE;
00318 
00319    Int_t st;
00320    if ((st = ReadBufferViaCache(buf, len))) {
00321       if (st == 2)
00322          return kTRUE;
00323       return kFALSE;
00324    }
00325 
00326    if (gApplication && gApplication->GetSignalHandler())
00327       gApplication->GetSignalHandler()->Delay();
00328 
00329    Double_t start = 0;
00330    if (gPerfStats) start = TTimeStamp();
00331 
00332    if (fSocket->Send(Form("%lld %d", fOffset, len), kROOTD_GET) < 0) {
00333       Error("ReadBuffer", "error sending kROOTD_GET command");
00334       result = kTRUE;
00335       goto end;
00336    }
00337 
00338    Int_t         stat, n;
00339    EMessageTypes kind;
00340 
00341    fErrorCode = -1;
00342    if (Recv(stat, kind) < 0 || kind == kROOTD_ERR) {
00343       PrintError("ReadBuffer", stat);
00344       result = kTRUE;
00345       goto end;
00346    }
00347 
00348    while ((n = fSocket->RecvRaw(buf, len)) < 0 && TSystem::GetErrno() == EINTR)
00349       TSystem::ResetErrno();
00350 
00351    if (n != len) {
00352       Error("ReadBuffer", "error receiving buffer of length %d, got %d", len, n);
00353       result = kTRUE;
00354       goto end;
00355    }
00356 
00357    fOffset += len;
00358 
00359    fBytesRead  += len;
00360    fReadCalls++;
00361 #ifdef R__WIN32
00362    SetFileBytesRead(GetFileBytesRead() + len);
00363    SetFileReadCalls(GetFileReadCalls() + 1);
00364 #else
00365    fgBytesRead += len;
00366    fgReadCalls++;
00367 #endif
00368 
00369 end:
00370 
00371    if (gPerfStats)
00372       gPerfStats->FileReadEvent(this, len, start);
00373 
00374    if (gApplication && gApplication->GetSignalHandler())
00375       gApplication->GetSignalHandler()->HandleDelayedSignal();
00376 
00377    return result;
00378 }
00379 
00380 //______________________________________________________________________________
00381 Bool_t TNetFile::ReadBuffer(char *buf, Long64_t pos, Int_t len)
00382 {
00383    // Read specified byte range from remote file via rootd daemon.
00384    // Returns kTRUE in case of error.
00385 
00386    SetOffset(pos);
00387    return ReadBuffer(buf, len);
00388 }   
00389 
00390 //______________________________________________________________________________
00391 Bool_t TNetFile::ReadBuffers(char *buf,  Long64_t *pos, Int_t *len, Int_t nbuf)
00392 {
00393    // Read a list of buffers given in pos[] and len[] and return it in a single
00394    // buffer.
00395    // Returns kTRUE in case of error.
00396 
00397    if (!fSocket) return kTRUE;
00398 
00399    // If it's an old version of the protocol try the default TFile::ReadBuffers
00400    if (fProtocol < 17)
00401       return TFile::ReadBuffers(buf, pos, len, nbuf);
00402 
00403    Int_t   stat;
00404    Int_t   blockSize = 262144;  //Let's say we transfer 256KB at the time
00405    Bool_t  result = kFALSE;
00406    EMessageTypes kind;
00407    TString data_buf;      // buf to put the info
00408 
00409    if (gApplication && gApplication->GetSignalHandler())
00410       gApplication->GetSignalHandler()->Delay();
00411 
00412    Double_t start = 0;
00413    if (gPerfStats) start = TTimeStamp();
00414 
00415    // Make the string with a list of offsets and lenghts
00416    Long64_t total_len = 0;
00417    Long64_t actual_pos;
00418    for(Int_t i = 0; i < nbuf; i++) {
00419       data_buf += pos[i] + fArchiveOffset;
00420       data_buf += "-";
00421       data_buf += len[i];
00422       data_buf += "/";
00423       total_len += len[i];
00424    }
00425 
00426    // Send the command with the lenght of the info and number of buffers
00427    if (fSocket->Send(Form("%d %d %d", nbuf, data_buf.Length(), blockSize),
00428                           kROOTD_GETS) < 0) {
00429       Error("ReadBuffers", "error sending kROOTD_GETS command");
00430       result = kTRUE;
00431       goto end;
00432    }
00433    // Send buffer with the list of offsets and lengths
00434    if (fSocket->SendRaw(data_buf, data_buf.Length()) < 0) {
00435       Error("ReadBuffers", "error sending buffer");
00436       result = kTRUE;
00437       goto end;
00438    }
00439 
00440    fErrorCode = -1;
00441    if (Recv(stat, kind) < 0 || kind == kROOTD_ERR) {
00442       PrintError("ReadBuffers", stat);
00443       result = kTRUE;
00444       goto end;
00445    }
00446 
00447    actual_pos = 0;
00448    while (actual_pos < total_len) {
00449       Long64_t left = total_len - actual_pos;
00450       if (left > blockSize)
00451          left = blockSize;
00452 
00453       Int_t n;
00454       while ((n = fSocket->RecvRaw(buf + actual_pos, Int_t(left))) < 0 &&
00455              TSystem::GetErrno() == EINTR)
00456          TSystem::ResetErrno();
00457 
00458       if (n != Int_t(left)) {
00459          Error("GetBuffers", "error receiving buffer of length %d, got %d",
00460                Int_t(left), n);
00461          result = kTRUE ;
00462          goto end;
00463       }
00464       actual_pos += left;
00465    }
00466 
00467    fBytesRead  += total_len;
00468    fReadCalls++;
00469 #ifdef R__WIN32
00470    SetFileBytesRead(GetFileBytesRead() + total_len);
00471    SetFileReadCalls(GetFileReadCalls() + 1);
00472 #else
00473    fgBytesRead += total_len;
00474    fgReadCalls++;
00475 #endif
00476 
00477 end:
00478 
00479    if (gPerfStats)
00480       gPerfStats->FileReadEvent(this, total_len, start);
00481 
00482    if (gApplication && gApplication->GetSignalHandler())
00483       gApplication->GetSignalHandler()->HandleDelayedSignal();
00484 
00485    // If found problems try the generic implementation
00486    if (result) {
00487       if (gDebug > 0)
00488          Info("ReadBuffers", "Couldnt use the specific implementation, calling TFile::ReadBuffers");
00489       return TFile::ReadBuffers(buf, pos, len, nbuf);
00490    }
00491 
00492    return result;
00493 }
00494 
00495 //______________________________________________________________________________
00496 Bool_t TNetFile::WriteBuffer(const char *buf, Int_t len)
00497 {
00498    // Write specified byte range to remote file via rootd daemon.
00499    // Returns kTRUE in case of error.
00500 
00501    if (!fSocket || !fWritable) return kTRUE;
00502 
00503    Bool_t result = kFALSE;
00504 
00505    Int_t st;
00506    if ((st = WriteBufferViaCache(buf, len))) {
00507       if (st == 2)
00508          return kTRUE;
00509       return kFALSE;
00510    }
00511 
00512    gSystem->IgnoreInterrupt();
00513 
00514    if (fSocket->Send(Form("%lld %d", fOffset, len), kROOTD_PUT) < 0) {
00515       SetBit(kWriteError);
00516       Error("WriteBuffer", "error sending kROOTD_PUT command");
00517       result = kTRUE;
00518       goto end;
00519    }
00520    if (fSocket->SendRaw(buf, len) < 0) {
00521       SetBit(kWriteError);
00522       Error("WriteBuffer", "error sending buffer");
00523       result = kTRUE;
00524       goto end;
00525    }
00526 
00527    Int_t         stat;
00528    EMessageTypes kind;
00529 
00530    fErrorCode = -1;
00531    if (Recv(stat, kind) < 0 || kind == kROOTD_ERR) {
00532       SetBit(kWriteError);
00533       PrintError("WriteBuffer", stat);
00534       result = kTRUE;
00535       goto end;
00536    }
00537 
00538    fOffset += len;
00539 
00540    fBytesWrite  += len;
00541 #ifdef R__WIN32
00542    SetFileBytesWritten(GetFileBytesWritten() + len);
00543 #else
00544    fgBytesWrite += len;
00545 #endif
00546 
00547 end:
00548    gSystem->IgnoreInterrupt(kFALSE);
00549 
00550    return result;
00551 }
00552 
00553 //______________________________________________________________________________
00554 Int_t TNetFile::Recv(Int_t &status, EMessageTypes &kind)
00555 {
00556    // Return status from rootd server and message kind. Returns -1 in
00557    // case of error otherwise 8 (sizeof 2 words, status and kind).
00558 
00559    kind   = kROOTD_ERR;
00560    status = 0;
00561 
00562    if (!fSocket) return -1;
00563 
00564    Int_t what;
00565    Int_t n = fSocket->Recv(status, what);
00566    kind = (EMessageTypes) what;
00567    return n;
00568 }
00569 
00570 //______________________________________________________________________________
00571 void TNetFile::Seek(Long64_t offset, ERelativeTo pos)
00572 {
00573    // Set position from where to start reading.
00574 
00575    SetOffset(offset, pos);
00576 }
00577 
00578 //______________________________________________________________________________
00579 void TNetFile::ConnectServer(Int_t *stat, EMessageTypes *kind, Int_t netopt,
00580                              Int_t tcpwindowsize, Bool_t forceOpen,
00581                              Bool_t forceRead)
00582 {
00583    // Connect to remote rootd server.
00584    TString fn = fUrl.GetFile();
00585 
00586    // Create Authenticated socket
00587    Int_t sSize = netopt < -1 ? -netopt : 1;
00588    TString url(fUrl.GetProtocol());
00589    if (url.Contains("root")) {
00590       url.Insert(4,"dp");
00591    } else {
00592       url = "rootdp";
00593    }
00594    url += TString(Form("://%s@%s:%d",
00595                        fUrl.GetUser(), fUrl.GetHost(), fUrl.GetPort()));
00596    fSocket = TSocket::CreateAuthSocket(url, sSize, tcpwindowsize, fSocket);
00597    if (!fSocket || !fSocket->IsAuthenticated()) {
00598       if (sSize > 1)
00599          Error("TNetFile", "can't open %d-stream connection to rootd on "
00600                "host %s at port %d", sSize, fUrl.GetHost(), fUrl.GetPort());
00601       else
00602          Error("TNetFile", "can't open connection to rootd on "
00603                "host %s at port %d", fUrl.GetHost(), fUrl.GetPort());
00604       *kind = kROOTD_ERR;
00605       *stat = (Int_t)kErrAuthNotOK;
00606       goto zombie;
00607    }
00608 
00609    // Check if rootd supports new options
00610    fProtocol = fSocket->GetRemoteProtocol();
00611    if (forceRead && fProtocol < 5) {
00612       Warning("ConnectServer", "rootd does not support \"+read\" option");
00613       forceRead = kFALSE;
00614    }
00615 
00616    // Open the file
00617    if (fProtocol < 16)
00618       // For backward compatibility we need to add a '/' at the beginning
00619       fn.Insert(0,"/");
00620    if (forceOpen)
00621       fSocket->Send(Form("%s %s", fn.Data(),
00622                               ToLower("f"+fOption).Data()), kROOTD_OPEN);
00623    else if (forceRead)
00624       fSocket->Send(Form("%s %s", fn.Data(), "+read"), kROOTD_OPEN);
00625    else
00626       fSocket->Send(Form("%s %s", fn.Data(),
00627                               ToLower(fOption).Data()), kROOTD_OPEN);
00628 
00629    EMessageTypes tmpkind;
00630    int  tmpstat;
00631    Recv(tmpstat, tmpkind);
00632    *stat = tmpstat;
00633    *kind = tmpkind;
00634 
00635    return;
00636 
00637 zombie:
00638    // error in file opening occured, make this object a zombie
00639    MakeZombie();
00640    SafeDelete(fSocket);
00641    gDirectory = gROOT;
00642 }
00643 
00644 //______________________________________________________________________________
00645 void TNetFile::Create(const char * /*url*/, Option_t *option, Int_t netopt)
00646 {
00647    // Create a NetFile object. A net file is the same as a TFile
00648    // except that it is being accessed via a rootd server. The url
00649    // argument must be of the form: root[s|k]://host.dom.ain/file.root.
00650    // When protocol is "roots" try using SRP authentication.
00651    // When protocol is "rootk" try using kerberos5 authentication.
00652    // If the file specified in the URL does not exist, is not accessable
00653    // or can not be created the kZombie bit will be set in the TNetFile
00654    // object. Use IsZombie() to see if the file is accessable.
00655    // If the remote daemon thinks the file is still connected, while you are
00656    // sure this is not the case you can force open the file by preceding the
00657    // option argument with an "-", e.g.: "-recreate". Do this only
00658    // in cases when you are very sure nobody else is using the file.
00659    // To bypass the writelock on a file, to allow the reading of a file
00660    // that is being written by another process, explicitely specify the
00661    // "+read" option ("read" being the default option).
00662    // The netopt argument can be used to specify the size of the tcp window in
00663    // bytes (for more info see: http://www.psc.edu/networking/perf_tune.html).
00664    // The default and minimum tcp window size is 65535 bytes.
00665    // If netopt < -1 then |netopt| is the number of parallel sockets that will
00666    // be used to connect to rootd. This option should be used on fat pipes
00667    // (i.e. high bandwidth, high latency links). The ideal number of parallel
00668    // sockets depends on the bandwidth*delay product. Generally 5-7 is a good
00669    // number.
00670    // For a description of the option and other arguments see the TFile ctor.
00671    // The preferred interface to this constructor is via TFile::Open().
00672 
00673    Int_t tcpwindowsize = 65535;
00674 
00675    fErrorCode = -1;
00676    fNetopt    = netopt;
00677    fOption    = option;
00678 
00679    Bool_t forceOpen = kFALSE;
00680    if (option[0] == '-') {
00681       fOption   = &option[1];
00682       forceOpen = kTRUE;
00683    }
00684    // accept 'f', like 'frecreate' still for backward compatibility
00685    if (option[0] == 'F' || option[0] == 'f') {
00686       fOption   = &option[1];
00687       forceOpen = kTRUE;
00688    }
00689 
00690    Bool_t forceRead = kFALSE;
00691    if (!strcasecmp(option, "+read")) {
00692       fOption   = &option[1];
00693       forceRead = kTRUE;
00694    }
00695 
00696    fOption.ToUpper();
00697 
00698    if (fOption == "NEW")
00699       fOption = "CREATE";
00700 
00701    Bool_t create   = (fOption == "CREATE") ? kTRUE : kFALSE;
00702    Bool_t recreate = (fOption == "RECREATE") ? kTRUE : kFALSE;
00703    Bool_t update   = (fOption == "UPDATE") ? kTRUE : kFALSE;
00704    Bool_t read     = (fOption == "READ") ? kTRUE : kFALSE;
00705    if (!create && !recreate && !update && !read) {
00706       read    = kTRUE;
00707       fOption = "READ";
00708    }
00709 
00710    if (!fUrl.IsValid()) {
00711       Error("Create", "invalid URL specified: %s", fUrl.GetUrl());
00712       goto zombie;
00713    }
00714 
00715    if (netopt > tcpwindowsize)
00716       tcpwindowsize = netopt;
00717 
00718    // Open connection to remote rootd server
00719    EMessageTypes kind;
00720    Int_t stat;
00721    ConnectServer(&stat, &kind, netopt, tcpwindowsize, forceOpen, forceRead);
00722    if (gDebug > 2) Info("Create", "got from host %d %d", stat, kind);
00723 
00724    if (kind == kROOTD_ERR) {
00725       PrintError("Create", stat);
00726       Error("Create", "failing on file %s", fUrl.GetUrl());
00727       goto zombie;
00728    }
00729 
00730    if (recreate) {
00731       recreate = kFALSE;
00732       create   = kTRUE;
00733       fOption  = "CREATE";
00734    }
00735 
00736    if (update && stat > 1) {
00737       update = kFALSE;
00738       create = kTRUE;
00739       stat   = 1;
00740    }
00741 
00742    if (stat == 1)
00743       fWritable = kTRUE;
00744    else
00745       fWritable = kFALSE;
00746 
00747    Init(create);
00748    return;
00749 
00750 zombie:
00751    // error in file opening occured, make this object a zombie
00752    MakeZombie();
00753    SafeDelete(fSocket);
00754    gDirectory = gROOT;
00755 }
00756 
00757 //______________________________________________________________________________
00758 void TNetFile::Create(TSocket *s, Option_t *option, Int_t netopt)
00759 {
00760    // Create a NetFile object using an existing connection (socket s).
00761    // Provided for use in TXNetFile.
00762    // See:
00763    //    TNetFile::Create(const char *url, Option_t *option, Int_t netopt)
00764    // for details about the arguments.
00765 
00766    // Import socket
00767    fSocket = s;
00768 
00769    // Create the connection
00770    Create(s->GetUrl(), option, netopt);
00771 }
00772 
00773 //______________________________________________________________________________
00774 Bool_t TNetFile::Matches(const char *url)
00775 {
00776    // Return kTRUE if 'url' matches the coordinates of this file.
00777    // Check the full URL, including port and FQDN.
00778 
00779    // Run standard check on fUrl, first
00780    Bool_t rc = TFile::Matches(url);
00781    if (rc)
00782       // Ok, standard check enough
00783       return kTRUE;
00784 
00785    // Check also endpoint URL
00786    TUrl u(url);
00787    if (!strcmp(u.GetFile(),fEndpointUrl.GetFile())) {
00788       // Candidate info
00789       TString fqdn = u.GetHostFQDN();
00790 
00791       // Check ports
00792       if (u.GetPort() == fEndpointUrl.GetPort()) {
00793          TString fqdnref = fEndpointUrl.GetHostFQDN();
00794          if (fqdn == fqdnref)
00795             // Ok, coordinates match
00796             return kTRUE;
00797       }
00798    }
00799 
00800    // Default is not matching
00801    return kFALSE;
00802 }
00803 
00804 //
00805 // TNetSystem: the directory handler for net files
00806 //
00807 
00808 //______________________________________________________________________________
00809 TNetSystem::TNetSystem(Bool_t ftpowner)
00810            : TSystem("-root", "Net file Helper System")
00811 {
00812    // Create helper class that allows directory access via rootd.
00813    // Use ftpowner = TRUE (default) if this instance is responsible
00814    // for cleaning of the underlying TFTP connection; this allows
00815    // to have control on the order of the final cleaning.
00816 
00817    // name must start with '-' to bypass the TSystem singleton check
00818    SetName("root");
00819 
00820    fDir = kFALSE;
00821    fDirp = 0;
00822    fFTP  = 0;
00823    fFTPOwner = ftpowner;
00824    fUser = "";
00825    fHost = "";
00826    fPort = -1;
00827    fIsLocal = kFALSE;
00828 }
00829 
00830 //______________________________________________________________________________
00831 TNetSystem::TNetSystem(const char *url, Bool_t ftpowner)
00832            : TSystem("-root", "Net file Helper System")
00833 {
00834    // Create helper class that allows directory access via rootd.
00835    // Use ftpowner = TRUE (default) if this instance is responsible
00836    // for cleaning of the underlying TFTP connection; this allows
00837    // to have control on the order of the final cleaning.
00838 
00839    // name must start with '-' to bypass the TSystem singleton check
00840    SetName("root");
00841 
00842    fFTPOwner = ftpowner;
00843    fIsLocal = kFALSE;
00844    Create(url);
00845 }
00846 
00847 //______________________________________________________________________________
00848 void TNetSystem::InitRemoteEntity(const char *url)
00849 {
00850    // Parse and save coordinates of the remote entity (user, host, port, ...)
00851 
00852    TUrl turl(url);
00853 
00854    // Remote username: local as default
00855    fUser = turl.GetUser();
00856    if (!fUser.Length()) {
00857       UserGroup_t *u = gSystem->GetUserInfo();
00858       if (u)
00859          fUser = u->fUser;
00860       delete u;
00861    }
00862 
00863    // Check and save the host FQDN ...
00864    fHost = turl.GetHostFQDN();
00865 
00866    // Remote port: the deafult should be 1094 because we are here
00867    // only if the protocol is "root://"
00868    fPort = turl.GetPort();
00869 }
00870 
00871 //______________________________________________________________________________
00872 void TNetSystem::Create(const char *url, TSocket *sock)
00873 {
00874    // Create a TNetSystem object.
00875 
00876    // If we got here protocol must be at least its short form "^root.*:" :
00877    // make sure that it is in the full form to avoid problems in TFTP
00878    TString surl(url);
00879    if (!surl.Contains("://")) {
00880       surl.Insert(surl.Index(":")+1,"//");
00881    }
00882    TUrl turl(surl);
00883 
00884    fDir  = kFALSE;
00885    fDirp = 0;
00886    fFTP  = 0;
00887 
00888    // Check locality, taking into account possible prefixes
00889    fLocalPrefix = "";
00890    fIsLocal = kFALSE;
00891    // We may have been asked explicitely to go through the daemon
00892    Bool_t forceRemote = gEnv->GetValue("Path.ForceRemote", 0);
00893    TString opts = TUrl(url).GetOptions();
00894    if (opts.Contains("remote=1"))
00895       forceRemote = kTRUE;
00896    else if (opts.Contains("remote=0"))
00897       forceRemote = kFALSE;
00898    if (!forceRemote) {
00899       if ((fIsLocal = TSystem::IsPathLocal(url))) {
00900          fLocalPrefix = gEnv->GetValue("Path.Localroot","");
00901          // Nothing more to do
00902          return;
00903       }
00904    }
00905 
00906    // Fill in user, host, port
00907    InitRemoteEntity(surl);
00908 
00909    // Build a TFTP url
00910    if (fHost.Length()) {
00911       TString eurl = "";
00912       // First the protocol
00913       if (strlen(turl.GetProtocol())) {
00914          eurl = turl.GetProtocol();
00915          eurl += "://";
00916       } else
00917          eurl = "root://";
00918       // Add user, if specified
00919       if (strlen(turl.GetUser())) {
00920          eurl += turl.GetUser();
00921          eurl += "@";
00922       }
00923       // Add host
00924       eurl += fHost;
00925       // Add port
00926       eurl += ":";
00927       eurl += turl.GetPort();
00928 
00929       fFTP  = new TFTP(eurl, 1, TFTP::kDfltWindowSize, sock);
00930       if (fFTP && fFTP->IsOpen()) {
00931          if (fFTP->GetSocket()->GetRemoteProtocol() < 12) {
00932             Error("TNetSystem",
00933                   "remote daemon does not support 'system' functionality");
00934             fFTP->Close();
00935             delete fFTP;
00936          } else {
00937             fUser = fFTP->GetSocket()->GetSecContext()->GetUser();
00938             fHost = fFTP->GetSocket()->GetSecContext()->GetHost();
00939             // If responsible for the TFTP connection, remove it from the
00940             // socket global list to avoid problems with double deletion
00941             // at final cleanup
00942             if (fFTPOwner)
00943                gROOT->GetListOfSockets()->Remove(fFTP);
00944          }
00945       }
00946    }
00947 }
00948 
00949 //______________________________________________________________________________
00950 TNetSystem::~TNetSystem()
00951 {
00952    // Destructor
00953 
00954    // Close FTP connection
00955    if (fFTPOwner) {
00956       if (fFTP) {
00957          if (fFTP->IsOpen()) {
00958 
00959             // Close remote directory if still open
00960             if (fDir) {
00961                fFTP->FreeDirectory(kFALSE);
00962                fDir = kFALSE;
00963             }
00964             fFTP->Close();
00965          }
00966          delete fFTP;
00967       }
00968    }
00969    fDirp = 0;
00970    fFTP  = 0;
00971 }
00972 
00973 //______________________________________________________________________________
00974 Int_t TNetSystem::MakeDirectory(const char *dir)
00975 {
00976    // Make a directory via rootd.
00977 
00978    // If local, use the local TSystem
00979    if (fIsLocal) {
00980       TString edir = TUrl(dir).GetFile();
00981       if (!fLocalPrefix.IsNull())
00982          edir.Insert(0, fLocalPrefix);
00983       return gSystem->MakeDirectory(edir);
00984    }
00985 
00986    if (fFTP && fFTP->IsOpen()) {
00987       // Extract the directory name
00988       TString edir = TUrl(dir).GetFile();
00989       return fFTP->MakeDirectory(edir,kFALSE);
00990    }
00991    return -1;
00992 }
00993 
00994 //______________________________________________________________________________
00995 void *TNetSystem::OpenDirectory(const char *dir)
00996 {
00997    // Open a directory via rfiod. Returns an opaque pointer to a dir
00998    // structure. Returns 0 in case of error.
00999 
01000    // If local, use the local TSystem
01001    if (fIsLocal) {
01002       TString edir = TUrl(dir).GetFile();
01003       if (!fLocalPrefix.IsNull())
01004          edir.Insert(0, fLocalPrefix);
01005       return gSystem->OpenDirectory(edir);
01006    }
01007 
01008    if (!fFTP || !fFTP->IsOpen())
01009       return (void *)0;
01010 
01011    if (fDir) {
01012       if (gDebug > 0)
01013          Info("OpenDirectory", "a directory is already open: close it first");
01014       fFTP->FreeDirectory(kFALSE);
01015       fDir = kFALSE;
01016    }
01017 
01018    // Extract the directory name
01019    TString edir = TUrl(dir).GetFile();
01020 
01021    if (fFTP->OpenDirectory(edir,kFALSE)) {
01022       fDir = kTRUE;
01023       fDirp = (void *)&fDir;
01024       return fDirp;
01025    } else
01026       return (void *)0;
01027 }
01028 
01029 //______________________________________________________________________________
01030 void TNetSystem::FreeDirectory(void *dirp)
01031 {
01032    // Free directory via rootd.
01033 
01034    // If local, use the local TSystem
01035    if (fIsLocal) {
01036       gSystem->FreeDirectory(dirp);
01037       return;
01038    }
01039 
01040    if (dirp != fDirp) {
01041       Error("FreeDirectory", "invalid directory pointer (should never happen)");
01042       return;
01043    }
01044 
01045    if (fFTP && fFTP->IsOpen()) {
01046       if (fDir) {
01047          fFTP->FreeDirectory(kFALSE);
01048          fDir = kFALSE;
01049          fDirp = 0;
01050       }
01051    }
01052 }
01053 
01054 //______________________________________________________________________________
01055 const char *TNetSystem::GetDirEntry(void *dirp)
01056 {
01057    // Get directory entry via rootd. Returns 0 in case no more entries.
01058 
01059    // If local, use the local TSystem
01060    if (fIsLocal) {
01061       return gSystem->GetDirEntry(dirp);
01062    }
01063 
01064    if (dirp != fDirp) {
01065       Error("GetDirEntry", "invalid directory pointer (should never happen)");
01066       return 0;
01067    }
01068 
01069    if (fFTP && fFTP->IsOpen() && fDir) {
01070       return fFTP->GetDirEntry(kFALSE);
01071    }
01072    return 0;
01073 }
01074 
01075 //______________________________________________________________________________
01076 Int_t TNetSystem::GetPathInfo(const char *path, FileStat_t &buf)
01077 {
01078    // Get info about a file. Info is returned in the form of a FileStat_t
01079    // structure (see TSystem.h).
01080    // The function returns 0 in case of success and 1 if the file could
01081    // not be stat'ed.
01082 
01083    // If local, use the local TSystem
01084    if (fIsLocal) {
01085       TString epath = TUrl(path).GetFile();
01086       if (!fLocalPrefix.IsNull())
01087          epath.Insert(0, fLocalPrefix);
01088       return gSystem->GetPathInfo(epath, buf);
01089    }
01090 
01091    if (fFTP && fFTP->IsOpen()) {
01092       // Extract the directory name
01093       TString epath = TUrl(path).GetFile();
01094       fFTP->GetPathInfo(epath, buf, kFALSE);
01095       return 0;
01096    }
01097    return 1;
01098 }
01099 
01100 //______________________________________________________________________________
01101 Bool_t TNetSystem::AccessPathName(const char *path, EAccessMode mode)
01102 {
01103    // Returns FALSE if one can access a file using the specified access mode.
01104    // Mode is the same as for the Unix access(2) function.
01105    // Attention, bizarre convention of return value!!
01106 
01107    // If local, use the local TSystem
01108    if (fIsLocal) {
01109       TString epath = TUrl(path).GetFile();
01110       if (!fLocalPrefix.IsNull())
01111          epath.Insert(0, fLocalPrefix);
01112       return gSystem->AccessPathName(epath, mode);
01113    }
01114 
01115    if (fFTP && fFTP->IsOpen()) {
01116       // Extract the directory name
01117       TString epath = TUrl(path).GetFile();
01118       return fFTP->AccessPathName(epath, mode, kFALSE);
01119    }
01120    return kTRUE;
01121 }
01122 
01123 //______________________________________________________________________________
01124 Bool_t TNetSystem::ConsistentWith(const char *path, void *dirptr)
01125 {
01126    // Check consistency of this helper with the one required
01127    // by 'path' or 'dirptr'.
01128 
01129    // Standard check: only the protocol part of 'path' is required to match
01130    Bool_t checkstd = TSystem::ConsistentWith(path, dirptr);
01131    if (!checkstd) return kFALSE;
01132 
01133    // Require match of 'user' and 'host'
01134    Bool_t checknet = path ? kFALSE : kTRUE;
01135    if (path && strlen(path)) {
01136 
01137       // Get user name
01138       TUrl url(path);
01139       TString user = url.GetUser();
01140       if (!user.Length()) {
01141          UserGroup_t *u = gSystem->GetUserInfo();
01142          if (u)
01143             user = u->fUser;
01144          delete u;
01145       }
01146 
01147       // Get host name
01148       TString host = url.GetHostFQDN();
01149 
01150       // Get port
01151       Int_t port = url.GetPort();
01152 
01153       if (user == fUser && host == fHost && port == fPort)
01154          checknet = kTRUE;
01155    }
01156 
01157    return (checkstd && checknet);
01158 }
01159 
01160 //______________________________________________________________________________
01161 Int_t TNetSystem::Unlink(const char *path)
01162 {
01163    // Remove a path
01164 
01165    // If local, use the local TSystem
01166    if (fIsLocal) {
01167       TString epath = TUrl(path).GetFile();
01168       if (!fLocalPrefix.IsNull())
01169          epath.Insert(0, fLocalPrefix);
01170       return gSystem->Unlink(epath);
01171    }
01172 
01173    // Not implemented for rootd
01174    Warning("Unlink", "functionality not implemented - ignored (path: %s)", path);
01175    return -1;
01176 }

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