// @(#)root/net:$Id$
// Author: Fons Rademakers   14/08/97

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TNetFile                                                             //
//                                                                      //
// A TNetFile is like a normal TFile except that it reads and writes    //
// its data via a rootd server (for more on the rootd daemon see the    //
// source files root/rootd/src/*.cxx). TNetFile file names are in       //
// standard URL format with protocol "root" or "roots". The following   //
// are valid TNetFile URL's:                                            //
//                                                                      //
//    roots://hpsalo/files/aap.root                                     //
//    root://hpbrun.cern.ch/root/hsimple.root                           //
//    root://pcna49a:5151/~na49/data/run821.root                        //
//    root://pcna49d.cern.ch:5050//v1/data/run810.root                  //
//                                                                      //
// The only difference with the well known httpd URL's is that the root //
// of the remote file tree is the user's home directory. Therefore an   //
// absolute pathname requires a // after the host or port specifier     //
// (see last example). Further the expansion of the standard shell      //
// characters, like ~, $, .., are handled as expected.                  //
// TNetFile (actually TUrl) uses 1094 as default port for rootd.        //
//                                                                      //
// Connecting to a rootd requires the remote user id and password.      //
// TNetFile allows three ways for you to provide your login:            //
//   1) Setting it globally via the static functions:                   //
//         TAuthenticate::SetGlobalUser() and                           //
//         TAuthenticate::SetGlobalPasswd()                             //
//   2) Getting it from the ~/.netrc file (same file as used by ftp)    //
//   3) Command line prompt                                             //
// The different methods will be tried in the order given above.        //
// On machines with AFS rootd will authenticate using AFS (if it was    //
// compiled with AFS support).                                          //
//                                                                      //
// If the protocol is specified as "roots" a secure authetication       //
// method will be used. The secure method uses the SRP, Secure Remote   //
// Passwords, package. SRP uses a so called "asymmetric key exchange    //
// protocol" in which no passwords are ever send over the wire. This    //
// protocol is safe against all known security attacks. For more see:   //
// Begin_Html <a href=http://root.cern.ch/root/NetFile.html>NetFile</a> //
// End_Html                                                             //
// If the protocol is specified as "rootk" kerberos5 will be used for   //
// authentication.                                                      //
//                                                                      //
// The rootd daemon lives in the directory $ROOTSYS/bin. It can be      //
// started either via inetd or by hand from the command line (no need   //
// to be super user). For more info about rootd see the web page:       //
// Begin_Html <a href=http://root.cern.ch/root/NetFile.html>NetFile</a> //
// End_Html                                                             //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include <errno.h>

#include "Bytes.h"
#include "NetErrors.h"
#include "TApplication.h"
#include "TEnv.h"
#include "TNetFile.h"
#include "TPSocket.h"
#include "TROOT.h"
#include "TSysEvtHandler.h"
#include "TSystem.h"
#include "TTimeStamp.h"
#include "TVirtualPerfStats.h"

// fgClientProtocol is now in TAuthenticate

ClassImp(TNetFile)
ClassImp(TNetSystem)

//______________________________________________________________________________
TNetFile::TNetFile(const char *url, Option_t *option, const char *ftitle,
                   Int_t compress, Int_t netopt)
   : TFile(url, "NET", ftitle, compress), fEndpointUrl(url)
{
   // Create a TNetFile object. This is actually done inside Create(), so
   // for a description of the options and other arguments see Create().
   // Normally a TNetFile is created via TFile::Open().

   fSocket = 0;
   Create(url, option, netopt);
}

//______________________________________________________________________________
TNetFile::TNetFile(const char *url, const char *ftitle, Int_t compress, Bool_t)
   : TFile(url, "NET", ftitle, compress), fEndpointUrl(url)
{
   // Create a TNetFile object. To be used by derived classes, that need
   // to initialize the TFile base class but not open a connection at this
   // moment.

   fSocket    = 0;
   fProtocol  = 0;
   fErrorCode = 0;
   fNetopt    = 0;
}

//______________________________________________________________________________
TNetFile::~TNetFile()
{
   // TNetFile dtor. Send close message and close socket.

   Close();
}

//______________________________________________________________________________
Int_t TNetFile::SysOpen(const char * /*file*/, Int_t /*flags*/, UInt_t /*mode*/)
{
   // Open a remote file. Requires fOption to be set correctly.

   if (!fSocket) {

      Create(fUrl.GetUrl(), fOption, fNetopt);
      if (!fSocket) return -1;

   } else {

      if (fProtocol > 15) {
         fSocket->Send(Form("%s %s", fUrl.GetFile(), ToLower(fOption).Data()),
                       kROOTD_OPEN);
      } else {
         // Old daemon versions expect an additional slash at beginning
         fSocket->Send(Form("/%s %s", fUrl.GetFile(), ToLower(fOption).Data()),
                       kROOTD_OPEN);
      }

      EMessageTypes kind;
      int stat;
      Recv(stat, kind);

      if (kind == kROOTD_ERR) {
         PrintError("SysOpen", stat);
         return -1;
      }
   }

   // This means ok for net files
   return -2;  // set as fD in ReOpen
}

//______________________________________________________________________________
Int_t TNetFile::SysClose(Int_t /*fd*/)
{
   // Close currently open file.

   if (fSocket)
      fSocket->Send(kROOTD_CLOSE);

   return 0;
}

//______________________________________________________________________________
Int_t TNetFile::SysStat(Int_t, Long_t *id, Long64_t *size, Long_t *flags, Long_t *modtime)
{
   // Return file stat information. The interface and return value is
   // identical to TSystem::GetPathInfo().

   if (fProtocol < 3) return 1;

   if (!fSocket) return 1;

   fSocket->Send(kROOTD_FSTAT);

   char  msg[1024];
   Int_t kind;
   fSocket->Recv(msg, sizeof(msg), kind);

   Int_t  mode, uid, gid, islink;
   Long_t dev, ino;

   if (fProtocol > 12) {
#ifdef R__WIN32
      sscanf(msg, "%ld %ld %d %d %d %I64d %ld %d", &dev, &ino, &mode,
            &uid, &gid, size, modtime, &islink);
#else
      sscanf(msg, "%ld %ld %d %d %d %lld %ld %d", &dev, &ino, &mode,
            &uid, &gid, size, modtime, &islink);
#endif
      if (dev == -1)
         return 1;
      if (id)
         *id = (dev << 24) + ino;
      if (flags) {
         *flags = 0;
         if (mode & (kS_IXUSR|kS_IXGRP|kS_IXOTH))
            *flags |= 1;
         if (R_ISDIR(mode))
            *flags |= 2;
         if (!R_ISREG(mode) && !R_ISDIR(mode))
            *flags |= 4;
      }
   } else {
#ifdef R__WIN32
      sscanf(msg, "%ld %I64d %ld %ld", id, size, flags, modtime);
#else
      sscanf(msg, "%ld %lld %ld %ld", id, size, flags, modtime);
#endif
      if (*id == -1)
         return 1;
   }

   return 0;
}

//______________________________________________________________________________
void TNetFile::Close(Option_t *opt)
{
   // Close remote file.

   if (!fSocket) return;

   TFile::Close(opt);

   if (fProtocol > 6)
      fSocket->Send(kROOTD_BYE);

   SafeDelete(fSocket);

   fD = -1;  // so TFile::IsOpen() returns false when in TFile::~TFile
}

//______________________________________________________________________________
void TNetFile::Flush()
{
   // Flush file to disk.

   FlushWriteCache();

   if (fSocket && fWritable)
      fSocket->Send(kROOTD_FLUSH);
}

//______________________________________________________________________________
void TNetFile::Init(Bool_t create)
{
   // Initialize a TNetFile object.

   Seek(0);

   TFile::Init(create);
   fD = -2;   // so TFile::IsOpen() returns true when in TFile::~TFile
}

//______________________________________________________________________________
Bool_t TNetFile::IsOpen() const
{
   // Retruns kTRUE if file is open, kFALSE otherwise.

   return fSocket == 0 ? kFALSE : kTRUE;
}

//______________________________________________________________________________
void TNetFile::Print(Option_t *) const
{
   // Print some info about the net file.

   const char *fname = fUrl.GetFile();
   Printf("URL:           %s",   ((TUrl*)&fUrl)->GetUrl());
   Printf("Remote file:   %s",   &fname[1]);
   Printf("Remote user:   %s",   fUser.Data());
   Printf("Title:         %s",   fTitle.Data());
   Printf("Option:        %s",   fOption.Data());
   Printf("Bytes written: %lld", fBytesWrite);
   Printf("Bytes read:    %lld", fBytesRead);
}

//______________________________________________________________________________
void TNetFile::PrintError(const char *where, Int_t err)
{
   // Print error string depending on error code.

   fErrorCode = err;
   Error(where, "%s", gRootdErrStr[err]);
}

//______________________________________________________________________________
Int_t TNetFile::ReOpen(Option_t *mode)
{
   // Reopen a file with a different access mode, like from READ to
   // UPDATE or from NEW, CREATE, RECREATE, UPDATE to READ. Thus the
   // mode argument can be either "READ" or "UPDATE". The method returns
   // 0 in case the mode was successfully modified, 1 in case the mode
   // did not change (was already as requested or wrong input arguments)
   // and -1 in case of failure, in which case the file cannot be used
   // anymore.

   if (fProtocol < 7) {
      Error("ReOpen", "operation not supported by remote rootd (protocol = %d)",
            fProtocol);
      return 1;
   }

   return TFile::ReOpen(mode);
}

//______________________________________________________________________________
Bool_t TNetFile::ReadBuffer(char *buf, Int_t len)
{
   // Read specified byte range from remote file via rootd daemon.
   // Returns kTRUE in case of error.

   if (!fSocket) return kTRUE;
   if (len == 0)
      return kFALSE;

   Bool_t result = kFALSE;

   Int_t st;
   if ((st = ReadBufferViaCache(buf, len))) {
      if (st == 2)
         return kTRUE;
      return kFALSE;
   }

   if (gApplication && gApplication->GetSignalHandler())
      gApplication->GetSignalHandler()->Delay();

   Double_t start = 0;
   if (gPerfStats) start = TTimeStamp();

   if (fSocket->Send(Form("%lld %d", fOffset, len), kROOTD_GET) < 0) {
      Error("ReadBuffer", "error sending kROOTD_GET command");
      result = kTRUE;
      goto end;
   }

   Int_t         stat, n;
   EMessageTypes kind;

   fErrorCode = -1;
   if (Recv(stat, kind) < 0 || kind == kROOTD_ERR) {
      PrintError("ReadBuffer", stat);
      result = kTRUE;
      goto end;
   }

   while ((n = fSocket->RecvRaw(buf, len)) < 0 && TSystem::GetErrno() == EINTR)
      TSystem::ResetErrno();

   if (n != len) {
      Error("ReadBuffer", "error receiving buffer of length %d, got %d", len, n);
      result = kTRUE;
      goto end;
   }

   fOffset += len;

   fBytesRead  += len;
   fReadCalls++;
#ifdef R__WIN32
   SetFileBytesRead(GetFileBytesRead() + len);
   SetFileReadCalls(GetFileReadCalls() + 1);
#else
   fgBytesRead += len;
   fgReadCalls++;
#endif

end:

   if (gPerfStats)
      gPerfStats->FileReadEvent(this, len, start);

   if (gApplication && gApplication->GetSignalHandler())
      gApplication->GetSignalHandler()->HandleDelayedSignal();

   return result;
}

//______________________________________________________________________________
Bool_t TNetFile::ReadBuffer(char *buf, Long64_t pos, Int_t len)
{
   // Read specified byte range from remote file via rootd daemon.
   // Returns kTRUE in case of error.

   SetOffset(pos);
   return ReadBuffer(buf, len);
}

//______________________________________________________________________________
Bool_t TNetFile::ReadBuffers(char *buf,  Long64_t *pos, Int_t *len, Int_t nbuf)
{
   // Read a list of buffers given in pos[] and len[] and return it in a single
   // buffer.
   // Returns kTRUE in case of error.

   if (!fSocket) return kTRUE;

   // If it's an old version of the protocol try the default TFile::ReadBuffers
   if (fProtocol < 17)
      return TFile::ReadBuffers(buf, pos, len, nbuf);

   Int_t   stat;
   Int_t   blockSize = 262144;  //Let's say we transfer 256KB at the time
   Bool_t  result = kFALSE;
   EMessageTypes kind;
   TString data_buf;      // buf to put the info

   if (gApplication && gApplication->GetSignalHandler())
      gApplication->GetSignalHandler()->Delay();

   Double_t start = 0;
   if (gPerfStats) start = TTimeStamp();

   // Make the string with a list of offsets and lengths
   Long64_t total_len = 0;
   Long64_t actual_pos;
   for(Int_t i = 0; i < nbuf; i++) {
      data_buf += pos[i] + fArchiveOffset;
      data_buf += "-";
      data_buf += len[i];
      data_buf += "/";
      total_len += len[i];
   }

   // Send the command with the length of the info and number of buffers
   if (fSocket->Send(Form("%d %d %d", nbuf, data_buf.Length(), blockSize),
                          kROOTD_GETS) < 0) {
      Error("ReadBuffers", "error sending kROOTD_GETS command");
      result = kTRUE;
      goto end;
   }
   // Send buffer with the list of offsets and lengths
   if (fSocket->SendRaw(data_buf, data_buf.Length()) < 0) {
      Error("ReadBuffers", "error sending buffer");
      result = kTRUE;
      goto end;
   }

   fErrorCode = -1;
   if (Recv(stat, kind) < 0 || kind == kROOTD_ERR) {
      PrintError("ReadBuffers", stat);
      result = kTRUE;
      goto end;
   }

   actual_pos = 0;
   while (actual_pos < total_len) {
      Long64_t left = total_len - actual_pos;
      if (left > blockSize)
         left = blockSize;

      Int_t n;
      while ((n = fSocket->RecvRaw(buf + actual_pos, Int_t(left))) < 0 &&
             TSystem::GetErrno() == EINTR)
         TSystem::ResetErrno();

      if (n != Int_t(left)) {
         Error("GetBuffers", "error receiving buffer of length %d, got %d",
               Int_t(left), n);
         result = kTRUE ;
         goto end;
      }
      actual_pos += left;
   }

   fBytesRead  += total_len;
   fReadCalls++;
#ifdef R__WIN32
   SetFileBytesRead(GetFileBytesRead() + total_len);
   SetFileReadCalls(GetFileReadCalls() + 1);
#else
   fgBytesRead += total_len;
   fgReadCalls++;
#endif

end:

   if (gPerfStats)
      gPerfStats->FileReadEvent(this, total_len, start);

   if (gApplication && gApplication->GetSignalHandler())
      gApplication->GetSignalHandler()->HandleDelayedSignal();

   // If found problems try the generic implementation
   if (result) {
      if (gDebug > 0)
         Info("ReadBuffers", "Couldnt use the specific implementation, calling TFile::ReadBuffers");
      return TFile::ReadBuffers(buf, pos, len, nbuf);
   }

   return result;
}

//______________________________________________________________________________
Bool_t TNetFile::WriteBuffer(const char *buf, Int_t len)
{
   // Write specified byte range to remote file via rootd daemon.
   // Returns kTRUE in case of error.

   if (!fSocket || !fWritable) return kTRUE;

   Bool_t result = kFALSE;

   Int_t st;
   if ((st = WriteBufferViaCache(buf, len))) {
      if (st == 2)
         return kTRUE;
      return kFALSE;
   }

   gSystem->IgnoreInterrupt();

   if (fSocket->Send(Form("%lld %d", fOffset, len), kROOTD_PUT) < 0) {
      SetBit(kWriteError);
      Error("WriteBuffer", "error sending kROOTD_PUT command");
      result = kTRUE;
      goto end;
   }
   if (fSocket->SendRaw(buf, len) < 0) {
      SetBit(kWriteError);
      Error("WriteBuffer", "error sending buffer");
      result = kTRUE;
      goto end;
   }

   Int_t         stat;
   EMessageTypes kind;

   fErrorCode = -1;
   if (Recv(stat, kind) < 0 || kind == kROOTD_ERR) {
      SetBit(kWriteError);
      PrintError("WriteBuffer", stat);
      result = kTRUE;
      goto end;
   }

   fOffset += len;

   fBytesWrite  += len;
#ifdef R__WIN32
   SetFileBytesWritten(GetFileBytesWritten() + len);
#else
   fgBytesWrite += len;
#endif

end:
   gSystem->IgnoreInterrupt(kFALSE);

   return result;
}

//______________________________________________________________________________
Int_t TNetFile::Recv(Int_t &status, EMessageTypes &kind)
{
   // Return status from rootd server and message kind. Returns -1 in
   // case of error otherwise 8 (sizeof 2 words, status and kind).

   kind   = kROOTD_ERR;
   status = 0;

   if (!fSocket) return -1;

   Int_t what;
   Int_t n = fSocket->Recv(status, what);
   kind = (EMessageTypes) what;
   return n;
}

//______________________________________________________________________________
void TNetFile::Seek(Long64_t offset, ERelativeTo pos)
{
   // Set position from where to start reading.

   SetOffset(offset, pos);
}

//______________________________________________________________________________
void TNetFile::ConnectServer(Int_t *stat, EMessageTypes *kind, Int_t netopt,
                             Int_t tcpwindowsize, Bool_t forceOpen,
                             Bool_t forceRead)
{
   // Connect to remote rootd server.
   TString fn = fUrl.GetFile();

   // Create Authenticated socket
   Int_t sSize = netopt < -1 ? -netopt : 1;
   TString url(fUrl.GetProtocol());
   if (url.Contains("root")) {
      url.Insert(4,"dp");
   } else {
      url = "rootdp";
   }
   url += TString(Form("://%s@%s:%d",
                       fUrl.GetUser(), fUrl.GetHost(), fUrl.GetPort()));
   fSocket = TSocket::CreateAuthSocket(url, sSize, tcpwindowsize, fSocket, stat);
   if (!fSocket || (fSocket && !fSocket->IsAuthenticated())) {
      if (sSize > 1)
         Error("TNetFile", "can't open %d-stream connection to rootd on "
               "host %s at port %d", sSize, fUrl.GetHost(), fUrl.GetPort());
      else
         Error("TNetFile", "can't open connection to rootd on "
               "host %s at port %d", fUrl.GetHost(), fUrl.GetPort());
      *kind = kROOTD_ERR;
      goto zombie;
   }

   // Check if rootd supports new options
   fProtocol = fSocket->GetRemoteProtocol();
   if (forceRead && fProtocol < 5) {
      Warning("ConnectServer", "rootd does not support \"+read\" option");
      forceRead = kFALSE;
   }

   // Open the file
   if (fProtocol < 16)
      // For backward compatibility we need to add a '/' at the beginning
      fn.Insert(0,"/");
   if (forceOpen)
      fSocket->Send(Form("%s %s", fn.Data(),
                              ToLower("f"+fOption).Data()), kROOTD_OPEN);
   else if (forceRead)
      fSocket->Send(Form("%s %s", fn.Data(), "+read"), kROOTD_OPEN);
   else
      fSocket->Send(Form("%s %s", fn.Data(),
                              ToLower(fOption).Data()), kROOTD_OPEN);

   EMessageTypes tmpkind;
   int  tmpstat;
   Recv(tmpstat, tmpkind);
   *stat = tmpstat;
   *kind = tmpkind;

   return;

zombie:
   // error in file opening occured, make this object a zombie
   MakeZombie();
   SafeDelete(fSocket);
   gDirectory = gROOT;
}

//______________________________________________________________________________
void TNetFile::Create(const char * /*url*/, Option_t *option, Int_t netopt)
{
   // Create a NetFile object. A net file is the same as a TFile
   // except that it is being accessed via a rootd server. The url
   // argument must be of the form: root[s|k]://host.dom.ain/file.root.
   // When protocol is "roots" try using SRP authentication.
   // When protocol is "rootk" try using kerberos5 authentication.
   // If the file specified in the URL does not exist, is not accessable
   // or can not be created the kZombie bit will be set in the TNetFile
   // object. Use IsZombie() to see if the file is accessable.
   // If the remote daemon thinks the file is still connected, while you are
   // sure this is not the case you can force open the file by preceding the
   // option argument with an "-", e.g.: "-recreate". Do this only
   // in cases when you are very sure nobody else is using the file.
   // To bypass the writelock on a file, to allow the reading of a file
   // that is being written by another process, explicitly specify the
   // "+read" option ("read" being the default option).
   // The netopt argument can be used to specify the size of the tcp window in
   // bytes (for more info see: http://www.psc.edu/networking/perf_tune.html).
   // The default and minimum tcp window size is 65535 bytes.
   // If netopt < -1 then |netopt| is the number of parallel sockets that will
   // be used to connect to rootd. This option should be used on fat pipes
   // (i.e. high bandwidth, high latency links). The ideal number of parallel
   // sockets depends on the bandwidth*delay product. Generally 5-7 is a good
   // number.
   // For a description of the option and other arguments see the TFile ctor.
   // The preferred interface to this constructor is via TFile::Open().

   Int_t tcpwindowsize = 65535;

   fErrorCode = -1;
   fNetopt    = netopt;
   fOption    = option;

   Bool_t forceOpen = kFALSE;
   if (option[0] == '-') {
      fOption   = &option[1];
      forceOpen = kTRUE;
   }
   // accept 'f', like 'frecreate' still for backward compatibility
   if (option[0] == 'F' || option[0] == 'f') {
      fOption   = &option[1];
      forceOpen = kTRUE;
   }

   Bool_t forceRead = kFALSE;
   if (!strcasecmp(option, "+read")) {
      fOption   = &option[1];
      forceRead = kTRUE;
   }

   fOption.ToUpper();

   if (fOption == "NEW")
      fOption = "CREATE";

   Bool_t create   = (fOption == "CREATE") ? kTRUE : kFALSE;
   Bool_t recreate = (fOption == "RECREATE") ? kTRUE : kFALSE;
   Bool_t update   = (fOption == "UPDATE") ? kTRUE : kFALSE;
   Bool_t read     = (fOption == "READ") ? kTRUE : kFALSE;
   if (!create && !recreate && !update && !read) {
      read    = kTRUE;
      fOption = "READ";
   }

   if (!fUrl.IsValid()) {
      Error("Create", "invalid URL specified: %s", fUrl.GetUrl());
      goto zombie;
   }

   if (netopt > tcpwindowsize)
      tcpwindowsize = netopt;

   // Open connection to remote rootd server
   EMessageTypes kind;
   Int_t stat;
   ConnectServer(&stat, &kind, netopt, tcpwindowsize, forceOpen, forceRead);
   if (gDebug > 2) Info("Create", "got from host %d %d", stat, kind);

   if (kind == kROOTD_ERR) {
      PrintError("Create", stat);
      Error("Create", "failing on file %s", fUrl.GetUrl());
      goto zombie;
   }

   if (recreate) {
      recreate = kFALSE;
      create   = kTRUE;
      fOption  = "CREATE";
   }

   if (update && stat > 1) {
      update = kFALSE;
      create = kTRUE;
      stat   = 1;
   }

   if (stat == 1)
      fWritable = kTRUE;
   else
      fWritable = kFALSE;

   Init(create);
   return;

zombie:
   // error in file opening occured, make this object a zombie
   MakeZombie();
   SafeDelete(fSocket);
   gDirectory = gROOT;
}

//______________________________________________________________________________
void TNetFile::Create(TSocket *s, Option_t *option, Int_t netopt)
{
   // Create a NetFile object using an existing connection (socket s).
   // Provided for use in TXNetFile.
   // See:
   //    TNetFile::Create(const char *url, Option_t *option, Int_t netopt)
   // for details about the arguments.

   // Import socket
   fSocket = s;

   // Create the connection
   Create(s->GetUrl(), option, netopt);
}

//______________________________________________________________________________
Bool_t TNetFile::Matches(const char *url)
{
   // Return kTRUE if 'url' matches the coordinates of this file.
   // Check the full URL, including port and FQDN.

   // Run standard check on fUrl, first
   Bool_t rc = TFile::Matches(url);
   if (rc)
      // Ok, standard check enough
      return kTRUE;

   // Check also endpoint URL
   TUrl u(url);
   if (!strcmp(u.GetFile(),fEndpointUrl.GetFile())) {
      // Candidate info
      TString fqdn = u.GetHostFQDN();

      // Check ports
      if (u.GetPort() == fEndpointUrl.GetPort()) {
         TString fqdnref = fEndpointUrl.GetHostFQDN();
         if (fqdn == fqdnref)
            // Ok, coordinates match
            return kTRUE;
      }
   }

   // Default is not matching
   return kFALSE;
}

//
// TNetSystem: the directory handler for net files
//

//______________________________________________________________________________
TNetSystem::TNetSystem(Bool_t ftpowner)
           : TSystem("-root", "Net file Helper System")
{
   // Create helper class that allows directory access via rootd.
   // Use ftpowner = TRUE (default) if this instance is responsible
   // for cleaning of the underlying TFTP connection; this allows
   // to have control on the order of the final cleaning.

   // name must start with '-' to bypass the TSystem singleton check
   SetName("root");

   fDir = kFALSE;
   fDirp = 0;
   fFTP  = 0;
   fFTPOwner = ftpowner;
   fUser = "";
   fHost = "";
   fPort = -1;
   fIsLocal = kFALSE;
}

//______________________________________________________________________________
TNetSystem::TNetSystem(const char *url, Bool_t ftpowner)
           : TSystem("-root", "Net file Helper System")
{
   // Create helper class that allows directory access via rootd.
   // Use ftpowner = TRUE (default) if this instance is responsible
   // for cleaning of the underlying TFTP connection; this allows
   // to have control on the order of the final cleaning.

   // name must start with '-' to bypass the TSystem singleton check
   SetName("root");

   fFTPOwner = ftpowner;
   fIsLocal = kFALSE;
   Create(url);
}

//______________________________________________________________________________
void TNetSystem::InitRemoteEntity(const char *url)
{
   // Parse and save coordinates of the remote entity (user, host, port, ...)

   TUrl turl(url);

   // Remote username: local as default
   fUser = turl.GetUser();
   if (!fUser.Length()) {
      UserGroup_t *u = gSystem->GetUserInfo();
      if (u)
         fUser = u->fUser;
      delete u;
   }

   // Check and save the host FQDN ...
   fHost = turl.GetHostFQDN();

   // Remote port: the default should be 1094 because we are here
   // only if the protocol is "root://"
   fPort = turl.GetPort();
}

//______________________________________________________________________________
void TNetSystem::Create(const char *url, TSocket *sock)
{
   // Create a TNetSystem object.

   // If we got here protocol must be at least its short form "^root.*:" :
   // make sure that it is in the full form to avoid problems in TFTP
   TString surl(url);
   if (!surl.Contains("://")) {
      surl.Insert(surl.Index(":")+1,"//");
   }
   TUrl turl(surl);

   fDir  = kFALSE;
   fDirp = 0;
   fFTP  = 0;

   // Check locality, taking into account possible prefixes
   fLocalPrefix = "";
   fIsLocal = kFALSE;
   // We may have been asked explicitly to go through the daemon
   Bool_t forceRemote = gEnv->GetValue("Path.ForceRemote", 0);
   TString opts = TUrl(url).GetOptions();
   if (opts.Contains("remote=1"))
      forceRemote = kTRUE;
   else if (opts.Contains("remote=0"))
      forceRemote = kFALSE;
   if (!forceRemote) {
      if ((fIsLocal = TSystem::IsPathLocal(url))) {
         fLocalPrefix = gEnv->GetValue("Path.Localroot","");
         // Nothing more to do
         return;
      }
   }

   // Fill in user, host, port
   InitRemoteEntity(surl);

   // Build a TFTP url
   if (fHost.Length()) {
      TString eurl = "";
      // First the protocol
      if (strlen(turl.GetProtocol())) {
         eurl = turl.GetProtocol();
         eurl += "://";
      } else
         eurl = "root://";
      // Add user, if specified
      if (strlen(turl.GetUser())) {
         eurl += turl.GetUser();
         eurl += "@";
      }
      // Add host
      eurl += fHost;
      // Add port
      eurl += ":";
      eurl += turl.GetPort();

      fFTP  = new TFTP(eurl, 1, TFTP::kDfltWindowSize, sock);
      if (fFTP && fFTP->IsOpen()) {
         if (fFTP->GetSocket()->GetRemoteProtocol() < 12) {
            Error("Create",
                  "remote daemon does not support 'system' functionality");
            fFTP->Close();
            delete fFTP;
         } else {
            fUser = fFTP->GetSocket()->GetSecContext()->GetUser();
            fHost = fFTP->GetSocket()->GetSecContext()->GetHost();
            // If responsible for the TFTP connection, remove it from the
            // socket global list to avoid problems with double deletion
            // at final cleanup
            if (fFTPOwner)
               gROOT->GetListOfSockets()->Remove(fFTP);
         }
      }
   }
}

//______________________________________________________________________________
TNetSystem::~TNetSystem()
{
   // Destructor

   // Close FTP connection
   if (fFTPOwner) {
      if (fFTP) {
         if (fFTP->IsOpen()) {

            // Close remote directory if still open
            if (fDir) {
               fFTP->FreeDirectory(kFALSE);
               fDir = kFALSE;
            }
            fFTP->Close();
         }
         delete fFTP;
      }
   }
   fDirp = 0;
   fFTP  = 0;
}

//______________________________________________________________________________
Int_t TNetSystem::MakeDirectory(const char *dir)
{
   // Make a directory via rootd.

   // If local, use the local TSystem
   if (fIsLocal) {
      TString edir = TUrl(dir).GetFile();
      if (!fLocalPrefix.IsNull())
         edir.Insert(0, fLocalPrefix);
      return gSystem->MakeDirectory(edir);
   }

   if (fFTP && fFTP->IsOpen()) {
      // Extract the directory name
      TString edir = TUrl(dir).GetFile();
      return fFTP->MakeDirectory(edir,kFALSE);
   }
   return -1;
}

//______________________________________________________________________________
void *TNetSystem::OpenDirectory(const char *dir)
{
   // Open a directory via rfiod. Returns an opaque pointer to a dir
   // structure. Returns 0 in case of error.

   // If local, use the local TSystem
   if (fIsLocal) {
      TString edir = TUrl(dir).GetFile();
      if (!fLocalPrefix.IsNull())
         edir.Insert(0, fLocalPrefix);
      return gSystem->OpenDirectory(edir);
   }

   if (!fFTP || !fFTP->IsOpen())
      return (void *)0;

   if (fDir) {
      if (gDebug > 0)
         Info("OpenDirectory", "a directory is already open: close it first");
      fFTP->FreeDirectory(kFALSE);
      fDir = kFALSE;
   }

   // Extract the directory name
   TString edir = TUrl(dir).GetFile();

   if (fFTP->OpenDirectory(edir,kFALSE)) {
      fDir = kTRUE;
      fDirp = (void *)&fDir;
      return fDirp;
   } else
      return (void *)0;
}

//______________________________________________________________________________
void TNetSystem::FreeDirectory(void *dirp)
{
   // Free directory via rootd.

   // If local, use the local TSystem
   if (fIsLocal) {
      gSystem->FreeDirectory(dirp);
      return;
   }

   if (dirp != fDirp) {
      Error("FreeDirectory", "invalid directory pointer (should never happen)");
      return;
   }

   if (fFTP && fFTP->IsOpen()) {
      if (fDir) {
         fFTP->FreeDirectory(kFALSE);
         fDir = kFALSE;
         fDirp = 0;
      }
   }
}

//______________________________________________________________________________
const char *TNetSystem::GetDirEntry(void *dirp)
{
   // Get directory entry via rootd. Returns 0 in case no more entries.

   // If local, use the local TSystem
   if (fIsLocal) {
      return gSystem->GetDirEntry(dirp);
   }

   if (dirp != fDirp) {
      Error("GetDirEntry", "invalid directory pointer (should never happen)");
      return 0;
   }

   if (fFTP && fFTP->IsOpen() && fDir) {
      return fFTP->GetDirEntry(kFALSE);
   }
   return 0;
}

//______________________________________________________________________________
Int_t TNetSystem::GetPathInfo(const char *path, FileStat_t &buf)
{
   // Get info about a file. Info is returned in the form of a FileStat_t
   // structure (see TSystem.h).
   // The function returns 0 in case of success and 1 if the file could
   // not be stat'ed.

   // If local, use the local TSystem
   if (fIsLocal) {
      TString epath = TUrl(path).GetFile();
      if (!fLocalPrefix.IsNull())
         epath.Insert(0, fLocalPrefix);
      return gSystem->GetPathInfo(epath, buf);
   }

   if (fFTP && fFTP->IsOpen()) {
      // Extract the directory name
      TString epath = TUrl(path).GetFile();
      fFTP->GetPathInfo(epath, buf, kFALSE);
      return 0;
   }
   return 1;
}

//______________________________________________________________________________
Bool_t TNetSystem::AccessPathName(const char *path, EAccessMode mode)
{
   // Returns FALSE if one can access a file using the specified access mode.
   // Mode is the same as for the Unix access(2) function.
   // Attention, bizarre convention of return value!!

   // If local, use the local TSystem
   if (fIsLocal) {
      TString epath = TUrl(path).GetFile();
      if (!fLocalPrefix.IsNull())
         epath.Insert(0, fLocalPrefix);
      return gSystem->AccessPathName(epath, mode);
   }

   if (fFTP && fFTP->IsOpen()) {
      // Extract the directory name
      TString epath = TUrl(path).GetFile();
      return fFTP->AccessPathName(epath, mode, kFALSE);
   }
   return kTRUE;
}

//______________________________________________________________________________
Bool_t TNetSystem::ConsistentWith(const char *path, void *dirptr)
{
   // Check consistency of this helper with the one required
   // by 'path' or 'dirptr'.

   // Standard check: only the protocol part of 'path' is required to match
   Bool_t checkstd = TSystem::ConsistentWith(path, dirptr);
   if (!checkstd) return kFALSE;

   // Require match of 'user' and 'host'
   Bool_t checknet = path ? kFALSE : kTRUE;
   if (path && strlen(path)) {

      // Get user name
      TUrl url(path);
      TString user = url.GetUser();
      if (user.IsNull() && !fUser.IsNull()) {
         UserGroup_t *u = gSystem->GetUserInfo();
         if (u)
            user = u->fUser;
         delete u;
      }

      // Get host name
      TString host = url.GetHostFQDN();

      // Get port
      Int_t port = url.GetPort();
      if (gDebug > 1)
         Info("ConsistentWith", "fUser:'%s' (%s), fHost:'%s' (%s), fPort:%d (%d)",
                                fUser.Data(), user.Data(), fHost.Data(), host.Data(),
                                fPort, port);

      if (user == fUser && host == fHost && port == fPort)
         checknet = kTRUE;
   }

   return (checkstd && checknet);
}

//______________________________________________________________________________
Int_t TNetSystem::Unlink(const char *path)
{
   // Remove a path

   // If local, use the local TSystem
   if (fIsLocal) {
      TString epath = TUrl(path).GetFile();
      if (!fLocalPrefix.IsNull())
         epath.Insert(0, fLocalPrefix);
      return gSystem->Unlink(epath);
   }

   // Not implemented for rootd
   Warning("Unlink", "functionality not implemented - ignored (path: %s)", path);
   return -1;
}
 TNetFile.cxx:1
 TNetFile.cxx:2
 TNetFile.cxx:3
 TNetFile.cxx:4
 TNetFile.cxx:5
 TNetFile.cxx:6
 TNetFile.cxx:7
 TNetFile.cxx:8
 TNetFile.cxx:9
 TNetFile.cxx:10
 TNetFile.cxx:11
 TNetFile.cxx:12
 TNetFile.cxx:13
 TNetFile.cxx:14
 TNetFile.cxx:15
 TNetFile.cxx:16
 TNetFile.cxx:17
 TNetFile.cxx:18
 TNetFile.cxx:19
 TNetFile.cxx:20
 TNetFile.cxx:21
 TNetFile.cxx:22
 TNetFile.cxx:23
 TNetFile.cxx:24
 TNetFile.cxx:25
 TNetFile.cxx:26
 TNetFile.cxx:27
 TNetFile.cxx:28
 TNetFile.cxx:29
 TNetFile.cxx:30
 TNetFile.cxx:31
 TNetFile.cxx:32
 TNetFile.cxx:33
 TNetFile.cxx:34
 TNetFile.cxx:35
 TNetFile.cxx:36
 TNetFile.cxx:37
 TNetFile.cxx:38
 TNetFile.cxx:39
 TNetFile.cxx:40
 TNetFile.cxx:41
 TNetFile.cxx:42
 TNetFile.cxx:43
 TNetFile.cxx:44
 TNetFile.cxx:45
 TNetFile.cxx:46
 TNetFile.cxx:47
 TNetFile.cxx:48
 TNetFile.cxx:49
 TNetFile.cxx:50
 TNetFile.cxx:51
 TNetFile.cxx:52
 TNetFile.cxx:53
 TNetFile.cxx:54
 TNetFile.cxx:55
 TNetFile.cxx:56
 TNetFile.cxx:57
 TNetFile.cxx:58
 TNetFile.cxx:59
 TNetFile.cxx:60
 TNetFile.cxx:61
 TNetFile.cxx:62
 TNetFile.cxx:63
 TNetFile.cxx:64
 TNetFile.cxx:65
 TNetFile.cxx:66
 TNetFile.cxx:67
 TNetFile.cxx:68
 TNetFile.cxx:69
 TNetFile.cxx:70
 TNetFile.cxx:71
 TNetFile.cxx:72
 TNetFile.cxx:73
 TNetFile.cxx:74
 TNetFile.cxx:75
 TNetFile.cxx:76
 TNetFile.cxx:77
 TNetFile.cxx:78
 TNetFile.cxx:79
 TNetFile.cxx:80
 TNetFile.cxx:81
 TNetFile.cxx:82
 TNetFile.cxx:83
 TNetFile.cxx:84
 TNetFile.cxx:85
 TNetFile.cxx:86
 TNetFile.cxx:87
 TNetFile.cxx:88
 TNetFile.cxx:89
 TNetFile.cxx:90
 TNetFile.cxx:91
 TNetFile.cxx:92
 TNetFile.cxx:93
 TNetFile.cxx:94
 TNetFile.cxx:95
 TNetFile.cxx:96
 TNetFile.cxx:97
 TNetFile.cxx:98
 TNetFile.cxx:99
 TNetFile.cxx:100
 TNetFile.cxx:101
 TNetFile.cxx:102
 TNetFile.cxx:103
 TNetFile.cxx:104
 TNetFile.cxx:105
 TNetFile.cxx:106
 TNetFile.cxx:107
 TNetFile.cxx:108
 TNetFile.cxx:109
 TNetFile.cxx:110
 TNetFile.cxx:111
 TNetFile.cxx:112
 TNetFile.cxx:113
 TNetFile.cxx:114
 TNetFile.cxx:115
 TNetFile.cxx:116
 TNetFile.cxx:117
 TNetFile.cxx:118
 TNetFile.cxx:119
 TNetFile.cxx:120
 TNetFile.cxx:121
 TNetFile.cxx:122
 TNetFile.cxx:123
 TNetFile.cxx:124
 TNetFile.cxx:125
 TNetFile.cxx:126
 TNetFile.cxx:127
 TNetFile.cxx:128
 TNetFile.cxx:129
 TNetFile.cxx:130
 TNetFile.cxx:131
 TNetFile.cxx:132
 TNetFile.cxx:133
 TNetFile.cxx:134
 TNetFile.cxx:135
 TNetFile.cxx:136
 TNetFile.cxx:137
 TNetFile.cxx:138
 TNetFile.cxx:139
 TNetFile.cxx:140
 TNetFile.cxx:141
 TNetFile.cxx:142
 TNetFile.cxx:143
 TNetFile.cxx:144
 TNetFile.cxx:145
 TNetFile.cxx:146
 TNetFile.cxx:147
 TNetFile.cxx:148
 TNetFile.cxx:149
 TNetFile.cxx:150
 TNetFile.cxx:151
 TNetFile.cxx:152
 TNetFile.cxx:153
 TNetFile.cxx:154
 TNetFile.cxx:155
 TNetFile.cxx:156
 TNetFile.cxx:157
 TNetFile.cxx:158
 TNetFile.cxx:159
 TNetFile.cxx:160
 TNetFile.cxx:161
 TNetFile.cxx:162
 TNetFile.cxx:163
 TNetFile.cxx:164
 TNetFile.cxx:165
 TNetFile.cxx:166
 TNetFile.cxx:167
 TNetFile.cxx:168
 TNetFile.cxx:169
 TNetFile.cxx:170
 TNetFile.cxx:171
 TNetFile.cxx:172
 TNetFile.cxx:173
 TNetFile.cxx:174
 TNetFile.cxx:175
 TNetFile.cxx:176
 TNetFile.cxx:177
 TNetFile.cxx:178
 TNetFile.cxx:179
 TNetFile.cxx:180
 TNetFile.cxx:181
 TNetFile.cxx:182
 TNetFile.cxx:183
 TNetFile.cxx:184
 TNetFile.cxx:185
 TNetFile.cxx:186
 TNetFile.cxx:187
 TNetFile.cxx:188
 TNetFile.cxx:189
 TNetFile.cxx:190
 TNetFile.cxx:191
 TNetFile.cxx:192
 TNetFile.cxx:193
 TNetFile.cxx:194
 TNetFile.cxx:195
 TNetFile.cxx:196
 TNetFile.cxx:197
 TNetFile.cxx:198
 TNetFile.cxx:199
 TNetFile.cxx:200
 TNetFile.cxx:201
 TNetFile.cxx:202
 TNetFile.cxx:203
 TNetFile.cxx:204
 TNetFile.cxx:205
 TNetFile.cxx:206
 TNetFile.cxx:207
 TNetFile.cxx:208
 TNetFile.cxx:209
 TNetFile.cxx:210
 TNetFile.cxx:211
 TNetFile.cxx:212
 TNetFile.cxx:213
 TNetFile.cxx:214
 TNetFile.cxx:215
 TNetFile.cxx:216
 TNetFile.cxx:217
 TNetFile.cxx:218
 TNetFile.cxx:219
 TNetFile.cxx:220
 TNetFile.cxx:221
 TNetFile.cxx:222
 TNetFile.cxx:223
 TNetFile.cxx:224
 TNetFile.cxx:225
 TNetFile.cxx:226
 TNetFile.cxx:227
 TNetFile.cxx:228
 TNetFile.cxx:229
 TNetFile.cxx:230
 TNetFile.cxx:231
 TNetFile.cxx:232
 TNetFile.cxx:233
 TNetFile.cxx:234
 TNetFile.cxx:235
 TNetFile.cxx:236
 TNetFile.cxx:237
 TNetFile.cxx:238
 TNetFile.cxx:239
 TNetFile.cxx:240
 TNetFile.cxx:241
 TNetFile.cxx:242
 TNetFile.cxx:243
 TNetFile.cxx:244
 TNetFile.cxx:245
 TNetFile.cxx:246
 TNetFile.cxx:247
 TNetFile.cxx:248
 TNetFile.cxx:249
 TNetFile.cxx:250
 TNetFile.cxx:251
 TNetFile.cxx:252
 TNetFile.cxx:253
 TNetFile.cxx:254
 TNetFile.cxx:255
 TNetFile.cxx:256
 TNetFile.cxx:257
 TNetFile.cxx:258
 TNetFile.cxx:259
 TNetFile.cxx:260
 TNetFile.cxx:261
 TNetFile.cxx:262
 TNetFile.cxx:263
 TNetFile.cxx:264
 TNetFile.cxx:265
 TNetFile.cxx:266
 TNetFile.cxx:267
 TNetFile.cxx:268
 TNetFile.cxx:269
 TNetFile.cxx:270
 TNetFile.cxx:271
 TNetFile.cxx:272
 TNetFile.cxx:273
 TNetFile.cxx:274
 TNetFile.cxx:275
 TNetFile.cxx:276
 TNetFile.cxx:277
 TNetFile.cxx:278
 TNetFile.cxx:279
 TNetFile.cxx:280
 TNetFile.cxx:281
 TNetFile.cxx:282
 TNetFile.cxx:283
 TNetFile.cxx:284
 TNetFile.cxx:285
 TNetFile.cxx:286
 TNetFile.cxx:287
 TNetFile.cxx:288
 TNetFile.cxx:289
 TNetFile.cxx:290
 TNetFile.cxx:291
 TNetFile.cxx:292
 TNetFile.cxx:293
 TNetFile.cxx:294
 TNetFile.cxx:295
 TNetFile.cxx:296
 TNetFile.cxx:297
 TNetFile.cxx:298
 TNetFile.cxx:299
 TNetFile.cxx:300
 TNetFile.cxx:301
 TNetFile.cxx:302
 TNetFile.cxx:303
 TNetFile.cxx:304
 TNetFile.cxx:305
 TNetFile.cxx:306
 TNetFile.cxx:307
 TNetFile.cxx:308
 TNetFile.cxx:309
 TNetFile.cxx:310
 TNetFile.cxx:311
 TNetFile.cxx:312
 TNetFile.cxx:313
 TNetFile.cxx:314
 TNetFile.cxx:315
 TNetFile.cxx:316
 TNetFile.cxx:317
 TNetFile.cxx:318
 TNetFile.cxx:319
 TNetFile.cxx:320
 TNetFile.cxx:321
 TNetFile.cxx:322
 TNetFile.cxx:323
 TNetFile.cxx:324
 TNetFile.cxx:325
 TNetFile.cxx:326
 TNetFile.cxx:327
 TNetFile.cxx:328
 TNetFile.cxx:329
 TNetFile.cxx:330
 TNetFile.cxx:331
 TNetFile.cxx:332
 TNetFile.cxx:333
 TNetFile.cxx:334
 TNetFile.cxx:335
 TNetFile.cxx:336
 TNetFile.cxx:337
 TNetFile.cxx:338
 TNetFile.cxx:339
 TNetFile.cxx:340
 TNetFile.cxx:341
 TNetFile.cxx:342
 TNetFile.cxx:343
 TNetFile.cxx:344
 TNetFile.cxx:345
 TNetFile.cxx:346
 TNetFile.cxx:347
 TNetFile.cxx:348
 TNetFile.cxx:349
 TNetFile.cxx:350
 TNetFile.cxx:351
 TNetFile.cxx:352
 TNetFile.cxx:353
 TNetFile.cxx:354
 TNetFile.cxx:355
 TNetFile.cxx:356
 TNetFile.cxx:357
 TNetFile.cxx:358
 TNetFile.cxx:359
 TNetFile.cxx:360
 TNetFile.cxx:361
 TNetFile.cxx:362
 TNetFile.cxx:363
 TNetFile.cxx:364
 TNetFile.cxx:365
 TNetFile.cxx:366
 TNetFile.cxx:367
 TNetFile.cxx:368
 TNetFile.cxx:369
 TNetFile.cxx:370
 TNetFile.cxx:371
 TNetFile.cxx:372
 TNetFile.cxx:373
 TNetFile.cxx:374
 TNetFile.cxx:375
 TNetFile.cxx:376
 TNetFile.cxx:377
 TNetFile.cxx:378
 TNetFile.cxx:379
 TNetFile.cxx:380
 TNetFile.cxx:381
 TNetFile.cxx:382
 TNetFile.cxx:383
 TNetFile.cxx:384
 TNetFile.cxx:385
 TNetFile.cxx:386
 TNetFile.cxx:387
 TNetFile.cxx:388
 TNetFile.cxx:389
 TNetFile.cxx:390
 TNetFile.cxx:391
 TNetFile.cxx:392
 TNetFile.cxx:393
 TNetFile.cxx:394
 TNetFile.cxx:395
 TNetFile.cxx:396
 TNetFile.cxx:397
 TNetFile.cxx:398
 TNetFile.cxx:399
 TNetFile.cxx:400
 TNetFile.cxx:401
 TNetFile.cxx:402
 TNetFile.cxx:403
 TNetFile.cxx:404
 TNetFile.cxx:405
 TNetFile.cxx:406
 TNetFile.cxx:407
 TNetFile.cxx:408
 TNetFile.cxx:409
 TNetFile.cxx:410
 TNetFile.cxx:411
 TNetFile.cxx:412
 TNetFile.cxx:413
 TNetFile.cxx:414
 TNetFile.cxx:415
 TNetFile.cxx:416
 TNetFile.cxx:417
 TNetFile.cxx:418
 TNetFile.cxx:419
 TNetFile.cxx:420
 TNetFile.cxx:421
 TNetFile.cxx:422
 TNetFile.cxx:423
 TNetFile.cxx:424
 TNetFile.cxx:425
 TNetFile.cxx:426
 TNetFile.cxx:427
 TNetFile.cxx:428
 TNetFile.cxx:429
 TNetFile.cxx:430
 TNetFile.cxx:431
 TNetFile.cxx:432
 TNetFile.cxx:433
 TNetFile.cxx:434
 TNetFile.cxx:435
 TNetFile.cxx:436
 TNetFile.cxx:437
 TNetFile.cxx:438
 TNetFile.cxx:439
 TNetFile.cxx:440
 TNetFile.cxx:441
 TNetFile.cxx:442
 TNetFile.cxx:443
 TNetFile.cxx:444
 TNetFile.cxx:445
 TNetFile.cxx:446
 TNetFile.cxx:447
 TNetFile.cxx:448
 TNetFile.cxx:449
 TNetFile.cxx:450
 TNetFile.cxx:451
 TNetFile.cxx:452
 TNetFile.cxx:453
 TNetFile.cxx:454
 TNetFile.cxx:455
 TNetFile.cxx:456
 TNetFile.cxx:457
 TNetFile.cxx:458
 TNetFile.cxx:459
 TNetFile.cxx:460
 TNetFile.cxx:461
 TNetFile.cxx:462
 TNetFile.cxx:463
 TNetFile.cxx:464
 TNetFile.cxx:465
 TNetFile.cxx:466
 TNetFile.cxx:467
 TNetFile.cxx:468
 TNetFile.cxx:469
 TNetFile.cxx:470
 TNetFile.cxx:471
 TNetFile.cxx:472
 TNetFile.cxx:473
 TNetFile.cxx:474
 TNetFile.cxx:475
 TNetFile.cxx:476
 TNetFile.cxx:477
 TNetFile.cxx:478
 TNetFile.cxx:479
 TNetFile.cxx:480
 TNetFile.cxx:481
 TNetFile.cxx:482
 TNetFile.cxx:483
 TNetFile.cxx:484
 TNetFile.cxx:485
 TNetFile.cxx:486
 TNetFile.cxx:487
 TNetFile.cxx:488
 TNetFile.cxx:489
 TNetFile.cxx:490
 TNetFile.cxx:491
 TNetFile.cxx:492
 TNetFile.cxx:493
 TNetFile.cxx:494
 TNetFile.cxx:495
 TNetFile.cxx:496
 TNetFile.cxx:497
 TNetFile.cxx:498
 TNetFile.cxx:499
 TNetFile.cxx:500
 TNetFile.cxx:501
 TNetFile.cxx:502
 TNetFile.cxx:503
 TNetFile.cxx:504
 TNetFile.cxx:505
 TNetFile.cxx:506
 TNetFile.cxx:507
 TNetFile.cxx:508
 TNetFile.cxx:509
 TNetFile.cxx:510
 TNetFile.cxx:511
 TNetFile.cxx:512
 TNetFile.cxx:513
 TNetFile.cxx:514
 TNetFile.cxx:515
 TNetFile.cxx:516
 TNetFile.cxx:517
 TNetFile.cxx:518
 TNetFile.cxx:519
 TNetFile.cxx:520
 TNetFile.cxx:521
 TNetFile.cxx:522
 TNetFile.cxx:523
 TNetFile.cxx:524
 TNetFile.cxx:525
 TNetFile.cxx:526
 TNetFile.cxx:527
 TNetFile.cxx:528
 TNetFile.cxx:529
 TNetFile.cxx:530
 TNetFile.cxx:531
 TNetFile.cxx:532
 TNetFile.cxx:533
 TNetFile.cxx:534
 TNetFile.cxx:535
 TNetFile.cxx:536
 TNetFile.cxx:537
 TNetFile.cxx:538
 TNetFile.cxx:539
 TNetFile.cxx:540
 TNetFile.cxx:541
 TNetFile.cxx:542
 TNetFile.cxx:543
 TNetFile.cxx:544
 TNetFile.cxx:545
 TNetFile.cxx:546
 TNetFile.cxx:547
 TNetFile.cxx:548
 TNetFile.cxx:549
 TNetFile.cxx:550
 TNetFile.cxx:551
 TNetFile.cxx:552
 TNetFile.cxx:553
 TNetFile.cxx:554
 TNetFile.cxx:555
 TNetFile.cxx:556
 TNetFile.cxx:557
 TNetFile.cxx:558
 TNetFile.cxx:559
 TNetFile.cxx:560
 TNetFile.cxx:561
 TNetFile.cxx:562
 TNetFile.cxx:563
 TNetFile.cxx:564
 TNetFile.cxx:565
 TNetFile.cxx:566
 TNetFile.cxx:567
 TNetFile.cxx:568
 TNetFile.cxx:569
 TNetFile.cxx:570
 TNetFile.cxx:571
 TNetFile.cxx:572
 TNetFile.cxx:573
 TNetFile.cxx:574
 TNetFile.cxx:575
 TNetFile.cxx:576
 TNetFile.cxx:577
 TNetFile.cxx:578
 TNetFile.cxx:579
 TNetFile.cxx:580
 TNetFile.cxx:581
 TNetFile.cxx:582
 TNetFile.cxx:583
 TNetFile.cxx:584
 TNetFile.cxx:585
 TNetFile.cxx:586
 TNetFile.cxx:587
 TNetFile.cxx:588
 TNetFile.cxx:589
 TNetFile.cxx:590
 TNetFile.cxx:591
 TNetFile.cxx:592
 TNetFile.cxx:593
 TNetFile.cxx:594
 TNetFile.cxx:595
 TNetFile.cxx:596
 TNetFile.cxx:597
 TNetFile.cxx:598
 TNetFile.cxx:599
 TNetFile.cxx:600
 TNetFile.cxx:601
 TNetFile.cxx:602
 TNetFile.cxx:603
 TNetFile.cxx:604
 TNetFile.cxx:605
 TNetFile.cxx:606
 TNetFile.cxx:607
 TNetFile.cxx:608
 TNetFile.cxx:609
 TNetFile.cxx:610
 TNetFile.cxx:611
 TNetFile.cxx:612
 TNetFile.cxx:613
 TNetFile.cxx:614
 TNetFile.cxx:615
 TNetFile.cxx:616
 TNetFile.cxx:617
 TNetFile.cxx:618
 TNetFile.cxx:619
 TNetFile.cxx:620
 TNetFile.cxx:621
 TNetFile.cxx:622
 TNetFile.cxx:623
 TNetFile.cxx:624
 TNetFile.cxx:625
 TNetFile.cxx:626
 TNetFile.cxx:627
 TNetFile.cxx:628
 TNetFile.cxx:629
 TNetFile.cxx:630
 TNetFile.cxx:631
 TNetFile.cxx:632
 TNetFile.cxx:633
 TNetFile.cxx:634
 TNetFile.cxx:635
 TNetFile.cxx:636
 TNetFile.cxx:637
 TNetFile.cxx:638
 TNetFile.cxx:639
 TNetFile.cxx:640
 TNetFile.cxx:641
 TNetFile.cxx:642
 TNetFile.cxx:643
 TNetFile.cxx:644
 TNetFile.cxx:645
 TNetFile.cxx:646
 TNetFile.cxx:647
 TNetFile.cxx:648
 TNetFile.cxx:649
 TNetFile.cxx:650
 TNetFile.cxx:651
 TNetFile.cxx:652
 TNetFile.cxx:653
 TNetFile.cxx:654
 TNetFile.cxx:655
 TNetFile.cxx:656
 TNetFile.cxx:657
 TNetFile.cxx:658
 TNetFile.cxx:659
 TNetFile.cxx:660
 TNetFile.cxx:661
 TNetFile.cxx:662
 TNetFile.cxx:663
 TNetFile.cxx:664
 TNetFile.cxx:665
 TNetFile.cxx:666
 TNetFile.cxx:667
 TNetFile.cxx:668
 TNetFile.cxx:669
 TNetFile.cxx:670
 TNetFile.cxx:671
 TNetFile.cxx:672
 TNetFile.cxx:673
 TNetFile.cxx:674
 TNetFile.cxx:675
 TNetFile.cxx:676
 TNetFile.cxx:677
 TNetFile.cxx:678
 TNetFile.cxx:679
 TNetFile.cxx:680
 TNetFile.cxx:681
 TNetFile.cxx:682
 TNetFile.cxx:683
 TNetFile.cxx:684
 TNetFile.cxx:685
 TNetFile.cxx:686
 TNetFile.cxx:687
 TNetFile.cxx:688
 TNetFile.cxx:689
 TNetFile.cxx:690
 TNetFile.cxx:691
 TNetFile.cxx:692
 TNetFile.cxx:693
 TNetFile.cxx:694
 TNetFile.cxx:695
 TNetFile.cxx:696
 TNetFile.cxx:697
 TNetFile.cxx:698
 TNetFile.cxx:699
 TNetFile.cxx:700
 TNetFile.cxx:701
 TNetFile.cxx:702
 TNetFile.cxx:703
 TNetFile.cxx:704
 TNetFile.cxx:705
 TNetFile.cxx:706
 TNetFile.cxx:707
 TNetFile.cxx:708
 TNetFile.cxx:709
 TNetFile.cxx:710
 TNetFile.cxx:711
 TNetFile.cxx:712
 TNetFile.cxx:713
 TNetFile.cxx:714
 TNetFile.cxx:715
 TNetFile.cxx:716
 TNetFile.cxx:717
 TNetFile.cxx:718
 TNetFile.cxx:719
 TNetFile.cxx:720
 TNetFile.cxx:721
 TNetFile.cxx:722
 TNetFile.cxx:723
 TNetFile.cxx:724
 TNetFile.cxx:725
 TNetFile.cxx:726
 TNetFile.cxx:727
 TNetFile.cxx:728
 TNetFile.cxx:729
 TNetFile.cxx:730
 TNetFile.cxx:731
 TNetFile.cxx:732
 TNetFile.cxx:733
 TNetFile.cxx:734
 TNetFile.cxx:735
 TNetFile.cxx:736
 TNetFile.cxx:737
 TNetFile.cxx:738
 TNetFile.cxx:739
 TNetFile.cxx:740
 TNetFile.cxx:741
 TNetFile.cxx:742
 TNetFile.cxx:743
 TNetFile.cxx:744
 TNetFile.cxx:745
 TNetFile.cxx:746
 TNetFile.cxx:747
 TNetFile.cxx:748
 TNetFile.cxx:749
 TNetFile.cxx:750
 TNetFile.cxx:751
 TNetFile.cxx:752
 TNetFile.cxx:753
 TNetFile.cxx:754
 TNetFile.cxx:755
 TNetFile.cxx:756
 TNetFile.cxx:757
 TNetFile.cxx:758
 TNetFile.cxx:759
 TNetFile.cxx:760
 TNetFile.cxx:761
 TNetFile.cxx:762
 TNetFile.cxx:763
 TNetFile.cxx:764
 TNetFile.cxx:765
 TNetFile.cxx:766
 TNetFile.cxx:767
 TNetFile.cxx:768
 TNetFile.cxx:769
 TNetFile.cxx:770
 TNetFile.cxx:771
 TNetFile.cxx:772
 TNetFile.cxx:773
 TNetFile.cxx:774
 TNetFile.cxx:775
 TNetFile.cxx:776
 TNetFile.cxx:777
 TNetFile.cxx:778
 TNetFile.cxx:779
 TNetFile.cxx:780
 TNetFile.cxx:781
 TNetFile.cxx:782
 TNetFile.cxx:783
 TNetFile.cxx:784
 TNetFile.cxx:785
 TNetFile.cxx:786
 TNetFile.cxx:787
 TNetFile.cxx:788
 TNetFile.cxx:789
 TNetFile.cxx:790
 TNetFile.cxx:791
 TNetFile.cxx:792
 TNetFile.cxx:793
 TNetFile.cxx:794
 TNetFile.cxx:795
 TNetFile.cxx:796
 TNetFile.cxx:797
 TNetFile.cxx:798
 TNetFile.cxx:799
 TNetFile.cxx:800
 TNetFile.cxx:801
 TNetFile.cxx:802
 TNetFile.cxx:803
 TNetFile.cxx:804
 TNetFile.cxx:805
 TNetFile.cxx:806
 TNetFile.cxx:807
 TNetFile.cxx:808
 TNetFile.cxx:809
 TNetFile.cxx:810
 TNetFile.cxx:811
 TNetFile.cxx:812
 TNetFile.cxx:813
 TNetFile.cxx:814
 TNetFile.cxx:815
 TNetFile.cxx:816
 TNetFile.cxx:817
 TNetFile.cxx:818
 TNetFile.cxx:819
 TNetFile.cxx:820
 TNetFile.cxx:821
 TNetFile.cxx:822
 TNetFile.cxx:823
 TNetFile.cxx:824
 TNetFile.cxx:825
 TNetFile.cxx:826
 TNetFile.cxx:827
 TNetFile.cxx:828
 TNetFile.cxx:829
 TNetFile.cxx:830
 TNetFile.cxx:831
 TNetFile.cxx:832
 TNetFile.cxx:833
 TNetFile.cxx:834
 TNetFile.cxx:835
 TNetFile.cxx:836
 TNetFile.cxx:837
 TNetFile.cxx:838
 TNetFile.cxx:839
 TNetFile.cxx:840
 TNetFile.cxx:841
 TNetFile.cxx:842
 TNetFile.cxx:843
 TNetFile.cxx:844
 TNetFile.cxx:845
 TNetFile.cxx:846
 TNetFile.cxx:847
 TNetFile.cxx:848
 TNetFile.cxx:849
 TNetFile.cxx:850
 TNetFile.cxx:851
 TNetFile.cxx:852
 TNetFile.cxx:853
 TNetFile.cxx:854
 TNetFile.cxx:855
 TNetFile.cxx:856
 TNetFile.cxx:857
 TNetFile.cxx:858
 TNetFile.cxx:859
 TNetFile.cxx:860
 TNetFile.cxx:861
 TNetFile.cxx:862
 TNetFile.cxx:863
 TNetFile.cxx:864
 TNetFile.cxx:865
 TNetFile.cxx:866
 TNetFile.cxx:867
 TNetFile.cxx:868
 TNetFile.cxx:869
 TNetFile.cxx:870
 TNetFile.cxx:871
 TNetFile.cxx:872
 TNetFile.cxx:873
 TNetFile.cxx:874
 TNetFile.cxx:875
 TNetFile.cxx:876
 TNetFile.cxx:877
 TNetFile.cxx:878
 TNetFile.cxx:879
 TNetFile.cxx:880
 TNetFile.cxx:881
 TNetFile.cxx:882
 TNetFile.cxx:883
 TNetFile.cxx:884
 TNetFile.cxx:885
 TNetFile.cxx:886
 TNetFile.cxx:887
 TNetFile.cxx:888
 TNetFile.cxx:889
 TNetFile.cxx:890
 TNetFile.cxx:891
 TNetFile.cxx:892
 TNetFile.cxx:893
 TNetFile.cxx:894
 TNetFile.cxx:895
 TNetFile.cxx:896
 TNetFile.cxx:897
 TNetFile.cxx:898
 TNetFile.cxx:899
 TNetFile.cxx:900
 TNetFile.cxx:901
 TNetFile.cxx:902
 TNetFile.cxx:903
 TNetFile.cxx:904
 TNetFile.cxx:905
 TNetFile.cxx:906
 TNetFile.cxx:907
 TNetFile.cxx:908
 TNetFile.cxx:909
 TNetFile.cxx:910
 TNetFile.cxx:911
 TNetFile.cxx:912
 TNetFile.cxx:913
 TNetFile.cxx:914
 TNetFile.cxx:915
 TNetFile.cxx:916
 TNetFile.cxx:917
 TNetFile.cxx:918
 TNetFile.cxx:919
 TNetFile.cxx:920
 TNetFile.cxx:921
 TNetFile.cxx:922
 TNetFile.cxx:923
 TNetFile.cxx:924
 TNetFile.cxx:925
 TNetFile.cxx:926
 TNetFile.cxx:927
 TNetFile.cxx:928
 TNetFile.cxx:929
 TNetFile.cxx:930
 TNetFile.cxx:931
 TNetFile.cxx:932
 TNetFile.cxx:933
 TNetFile.cxx:934
 TNetFile.cxx:935
 TNetFile.cxx:936
 TNetFile.cxx:937
 TNetFile.cxx:938
 TNetFile.cxx:939
 TNetFile.cxx:940
 TNetFile.cxx:941
 TNetFile.cxx:942
 TNetFile.cxx:943
 TNetFile.cxx:944
 TNetFile.cxx:945
 TNetFile.cxx:946
 TNetFile.cxx:947
 TNetFile.cxx:948
 TNetFile.cxx:949
 TNetFile.cxx:950
 TNetFile.cxx:951
 TNetFile.cxx:952
 TNetFile.cxx:953
 TNetFile.cxx:954
 TNetFile.cxx:955
 TNetFile.cxx:956
 TNetFile.cxx:957
 TNetFile.cxx:958
 TNetFile.cxx:959
 TNetFile.cxx:960
 TNetFile.cxx:961
 TNetFile.cxx:962
 TNetFile.cxx:963
 TNetFile.cxx:964
 TNetFile.cxx:965
 TNetFile.cxx:966
 TNetFile.cxx:967
 TNetFile.cxx:968
 TNetFile.cxx:969
 TNetFile.cxx:970
 TNetFile.cxx:971
 TNetFile.cxx:972
 TNetFile.cxx:973
 TNetFile.cxx:974
 TNetFile.cxx:975
 TNetFile.cxx:976
 TNetFile.cxx:977
 TNetFile.cxx:978
 TNetFile.cxx:979
 TNetFile.cxx:980
 TNetFile.cxx:981
 TNetFile.cxx:982
 TNetFile.cxx:983
 TNetFile.cxx:984
 TNetFile.cxx:985
 TNetFile.cxx:986
 TNetFile.cxx:987
 TNetFile.cxx:988
 TNetFile.cxx:989
 TNetFile.cxx:990
 TNetFile.cxx:991
 TNetFile.cxx:992
 TNetFile.cxx:993
 TNetFile.cxx:994
 TNetFile.cxx:995
 TNetFile.cxx:996
 TNetFile.cxx:997
 TNetFile.cxx:998
 TNetFile.cxx:999
 TNetFile.cxx:1000
 TNetFile.cxx:1001
 TNetFile.cxx:1002
 TNetFile.cxx:1003
 TNetFile.cxx:1004
 TNetFile.cxx:1005
 TNetFile.cxx:1006
 TNetFile.cxx:1007
 TNetFile.cxx:1008
 TNetFile.cxx:1009
 TNetFile.cxx:1010
 TNetFile.cxx:1011
 TNetFile.cxx:1012
 TNetFile.cxx:1013
 TNetFile.cxx:1014
 TNetFile.cxx:1015
 TNetFile.cxx:1016
 TNetFile.cxx:1017
 TNetFile.cxx:1018
 TNetFile.cxx:1019
 TNetFile.cxx:1020
 TNetFile.cxx:1021
 TNetFile.cxx:1022
 TNetFile.cxx:1023
 TNetFile.cxx:1024
 TNetFile.cxx:1025
 TNetFile.cxx:1026
 TNetFile.cxx:1027
 TNetFile.cxx:1028
 TNetFile.cxx:1029
 TNetFile.cxx:1030
 TNetFile.cxx:1031
 TNetFile.cxx:1032
 TNetFile.cxx:1033
 TNetFile.cxx:1034
 TNetFile.cxx:1035
 TNetFile.cxx:1036
 TNetFile.cxx:1037
 TNetFile.cxx:1038
 TNetFile.cxx:1039
 TNetFile.cxx:1040
 TNetFile.cxx:1041
 TNetFile.cxx:1042
 TNetFile.cxx:1043
 TNetFile.cxx:1044
 TNetFile.cxx:1045
 TNetFile.cxx:1046
 TNetFile.cxx:1047
 TNetFile.cxx:1048
 TNetFile.cxx:1049
 TNetFile.cxx:1050
 TNetFile.cxx:1051
 TNetFile.cxx:1052
 TNetFile.cxx:1053
 TNetFile.cxx:1054
 TNetFile.cxx:1055
 TNetFile.cxx:1056
 TNetFile.cxx:1057
 TNetFile.cxx:1058
 TNetFile.cxx:1059
 TNetFile.cxx:1060
 TNetFile.cxx:1061
 TNetFile.cxx:1062
 TNetFile.cxx:1063
 TNetFile.cxx:1064
 TNetFile.cxx:1065
 TNetFile.cxx:1066
 TNetFile.cxx:1067
 TNetFile.cxx:1068
 TNetFile.cxx:1069
 TNetFile.cxx:1070
 TNetFile.cxx:1071
 TNetFile.cxx:1072
 TNetFile.cxx:1073
 TNetFile.cxx:1074
 TNetFile.cxx:1075
 TNetFile.cxx:1076
 TNetFile.cxx:1077
 TNetFile.cxx:1078
 TNetFile.cxx:1079
 TNetFile.cxx:1080
 TNetFile.cxx:1081
 TNetFile.cxx:1082
 TNetFile.cxx:1083
 TNetFile.cxx:1084
 TNetFile.cxx:1085
 TNetFile.cxx:1086
 TNetFile.cxx:1087
 TNetFile.cxx:1088
 TNetFile.cxx:1089
 TNetFile.cxx:1090
 TNetFile.cxx:1091
 TNetFile.cxx:1092
 TNetFile.cxx:1093
 TNetFile.cxx:1094
 TNetFile.cxx:1095
 TNetFile.cxx:1096
 TNetFile.cxx:1097
 TNetFile.cxx:1098
 TNetFile.cxx:1099
 TNetFile.cxx:1100
 TNetFile.cxx:1101
 TNetFile.cxx:1102
 TNetFile.cxx:1103
 TNetFile.cxx:1104
 TNetFile.cxx:1105
 TNetFile.cxx:1106
 TNetFile.cxx:1107
 TNetFile.cxx:1108
 TNetFile.cxx:1109
 TNetFile.cxx:1110
 TNetFile.cxx:1111
 TNetFile.cxx:1112
 TNetFile.cxx:1113
 TNetFile.cxx:1114
 TNetFile.cxx:1115
 TNetFile.cxx:1116
 TNetFile.cxx:1117
 TNetFile.cxx:1118
 TNetFile.cxx:1119
 TNetFile.cxx:1120
 TNetFile.cxx:1121
 TNetFile.cxx:1122
 TNetFile.cxx:1123
 TNetFile.cxx:1124
 TNetFile.cxx:1125
 TNetFile.cxx:1126
 TNetFile.cxx:1127
 TNetFile.cxx:1128
 TNetFile.cxx:1129
 TNetFile.cxx:1130
 TNetFile.cxx:1131
 TNetFile.cxx:1132
 TNetFile.cxx:1133
 TNetFile.cxx:1134
 TNetFile.cxx:1135
 TNetFile.cxx:1136
 TNetFile.cxx:1137
 TNetFile.cxx:1138
 TNetFile.cxx:1139
 TNetFile.cxx:1140
 TNetFile.cxx:1141
 TNetFile.cxx:1142
 TNetFile.cxx:1143
 TNetFile.cxx:1144
 TNetFile.cxx:1145
 TNetFile.cxx:1146
 TNetFile.cxx:1147
 TNetFile.cxx:1148
 TNetFile.cxx:1149
 TNetFile.cxx:1150
 TNetFile.cxx:1151
 TNetFile.cxx:1152
 TNetFile.cxx:1153
 TNetFile.cxx:1154
 TNetFile.cxx:1155
 TNetFile.cxx:1156
 TNetFile.cxx:1157
 TNetFile.cxx:1158
 TNetFile.cxx:1159
 TNetFile.cxx:1160
 TNetFile.cxx:1161
 TNetFile.cxx:1162
 TNetFile.cxx:1163
 TNetFile.cxx:1164
 TNetFile.cxx:1165
 TNetFile.cxx:1166
 TNetFile.cxx:1167
 TNetFile.cxx:1168
 TNetFile.cxx:1169
 TNetFile.cxx:1170
 TNetFile.cxx:1171
 TNetFile.cxx:1172
 TNetFile.cxx:1173
 TNetFile.cxx:1174
 TNetFile.cxx:1175
 TNetFile.cxx:1176
 TNetFile.cxx:1177
 TNetFile.cxx:1178
 TNetFile.cxx:1179