TFile.cxx

Go to the documentation of this file.
00001 // @(#)root/io:$Id: TFile.cxx 37531 2010-12-10 20:38:06Z pcanal $
00002 // Author: Rene Brun   28/11/94
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 // A ROOT file is a suite of consecutive data records (TKey's) with
00014 // the following format (see also the TKey class). If the key is
00015 // located past the 32 bit file limit (> 2 GB) then some fields will
00016 // be 8 instead of 4 bytes:
00017 //    1->4            Nbytes    = Length of compressed object (in bytes)
00018 //    5->6            Version   = TKey version identifier
00019 //    7->10           ObjLen    = Length of uncompressed object
00020 //    11->14          Datime    = Date and time when object was written to file
00021 //    15->16          KeyLen    = Length of the key structure (in bytes)
00022 //    17->18          Cycle     = Cycle of key
00023 //    19->22 [19->26] SeekKey   = Pointer to record itself (consistency check)
00024 //    23->26 [27->34] SeekPdir  = Pointer to directory header
00025 //    27->27 [35->35] lname     = Number of bytes in the class name
00026 //    28->.. [36->..] ClassName = Object Class Name
00027 //    ..->..          lname     = Number of bytes in the object name
00028 //    ..->..          Name      = lName bytes with the name of the object
00029 //    ..->..          lTitle    = Number of bytes in the object title
00030 //    ..->..          Title     = Title of the object
00031 //    ----->          DATA      = Data bytes associated to the object
00032 //
00033 // The first data record starts at byte fBEGIN (currently set to kBEGIN).
00034 // Bytes 1->kBEGIN contain the file description, when fVersion >= 1000000
00035 // it is a large file (> 2 GB) and the offsets will be 8 bytes long and
00036 // fUnits will be set to 8:
00037 //    1->4            "root"      = Root file identifier
00038 //    5->8            fVersion    = File format version
00039 //    9->12           fBEGIN      = Pointer to first data record
00040 //    13->16 [13->20] fEND        = Pointer to first free word at the EOF
00041 //    17->20 [21->28] fSeekFree   = Pointer to FREE data record
00042 //    21->24 [29->32] fNbytesFree = Number of bytes in FREE data record
00043 //    25->28 [33->36] nfree       = Number of free data records
00044 //    29->32 [37->40] fNbytesName = Number of bytes in TNamed at creation time
00045 //    33->33 [41->41] fUnits      = Number of bytes for file pointers
00046 //    34->37 [42->45] fCompress   = Zip compression level
00047 //    38->41 [46->53] fSeekInfo   = Pointer to TStreamerInfo record
00048 //    42->45 [54->57] fNbytesInfo = Number of bytes in TStreamerInfo record
00049 //    46->63 [58->75] fUUID       = Universal Unique ID
00050 //Begin_Html
00051 /*
00052 <img src="gif/file_layout.gif">
00053 */
00054 //End_Html
00055 //
00056 // The structure of a directory is shown in TDirectoryFile::TDirectoryFile
00057 //
00058 ////////////////////////////////////////////////////////////////////////////////
00059 
00060 #include "RConfig.h"
00061 
00062 #ifdef R__LINUX
00063 // for posix_fadvise
00064 #ifndef _XOPEN_SOURCE
00065 #define _XOPEN_SOURCE 600
00066 #endif
00067 #endif
00068 #include <fcntl.h>
00069 #include <errno.h>
00070 #include <sys/stat.h>
00071 #ifndef WIN32
00072 #   include <unistd.h>
00073 #else
00074 #   define ssize_t int
00075 #   include <io.h>
00076 #   include <sys/types.h>
00077 #endif
00078 
00079 #include "Bytes.h"
00080 #include "Riostream.h"
00081 #include "Strlen.h"
00082 #include "TArrayC.h"
00083 #include "TClass.h"
00084 #include "TClassEdit.h"
00085 #include "TClassTable.h"
00086 #include "TDatime.h"
00087 #include "TError.h"
00088 #include "TFile.h"
00089 #include "TFileCacheRead.h"
00090 #include "TFileCacheWrite.h"
00091 #include "TFree.h"
00092 #include "TInterpreter.h"
00093 #include "TKey.h"
00094 #include "TMakeProject.h"
00095 #include "TPluginManager.h"
00096 #include "TProcessUUID.h"
00097 #include "TRegexp.h"
00098 #include "TROOT.h"
00099 #include "TStreamerInfo.h"
00100 #include "TStreamerElement.h"
00101 #include "TSystem.h"
00102 #include "TTimeStamp.h"
00103 #include "TVirtualPerfStats.h"
00104 #include "TArchiveFile.h"
00105 #include "TEnv.h"
00106 #include "TVirtualMonitoring.h"
00107 #include "TVirtualMutex.h"
00108 #include "TMathBase.h"
00109 #include "TObjString.h"
00110 #include "TStopwatch.h"
00111 #include "compiledata.h"
00112 #include <cmath>
00113 #include <set>
00114 #include "TSchemaRule.h"
00115 #include "TSchemaRuleSet.h"
00116 
00117 TFile *gFile;                 //Pointer to current file
00118 
00119 
00120 Long64_t TFile::fgBytesRead  = 0;
00121 Long64_t TFile::fgBytesWrite = 0;
00122 Long64_t TFile::fgFileCounter = 0;
00123 Int_t    TFile::fgReadaheadSize = 256000;
00124 Int_t    TFile::fgReadCalls = 0;
00125 Bool_t   TFile::fgReadInfo = kTRUE;
00126 TList   *TFile::fgAsyncOpenRequests = 0;
00127 TString  TFile::fgCacheFileDir;
00128 Bool_t   TFile::fgCacheFileForce = kFALSE;
00129 Bool_t   TFile::fgCacheFileDisconnected = kTRUE;
00130 UInt_t   TFile::fgOpenTimeout = TFile::kEternalTimeout;
00131 Bool_t   TFile::fgOnlyStaged = 0;
00132 
00133 const Int_t kBEGIN = 100;
00134 
00135 ClassImp(TFile)
00136 
00137 //*-*x17 macros/layout_file
00138 
00139 //______________________________________________________________________________
00140 TFile::TFile() : TDirectoryFile(), fInfoCache(0)
00141 {
00142    // File default Constructor.
00143 
00144    fD               = -1;
00145    fFree            = 0;
00146    fWritten         = 0;
00147    fSumBuffer       = 0;
00148    fSum2Buffer      = 0;
00149    fClassIndex      = 0;
00150    fProcessIDs      = 0;
00151    fNProcessIDs     = 0;
00152    fOffset          = 0;
00153    fArchive         = 0;
00154    fCacheRead       = 0;
00155    fCacheWrite      = 0;
00156    fArchiveOffset   = 0;
00157    fReadCalls       = 0;
00158    fInfoCache       = 0;
00159    fOpenPhases      = 0;
00160    fNoAnchorInName  = kFALSE;
00161    fIsRootFile      = kTRUE;
00162    fIsArchive       = kFALSE;
00163    fInitDone        = kFALSE;
00164    fMustFlush       = kTRUE;
00165    fAsyncHandle     = 0;
00166    fAsyncOpenStatus = kAOSNotAsync;
00167    SetBit(kBinaryFile, kTRUE);
00168 
00169    if (gDebug)
00170       Info("TFile", "default ctor");
00171 }
00172 
00173 //_____________________________________________________________________________
00174 TFile::TFile(const char *fname1, Option_t *option, const char *ftitle, Int_t compress)
00175            : TDirectoryFile(), fUrl(fname1,kTRUE), fInfoCache(0), fOpenPhases(0)
00176 {
00177    // Opens or creates a local ROOT file whose name is fname1. It is
00178    // recommended to specify fname1 as "<file>.root". The suffix ".root"
00179    // will be used by object browsers to automatically identify the file as
00180    // a ROOT file. If the constructor fails in any way IsZombie() will
00181    // return true. Use IsOpen() to check if the file is (still) open.
00182    //
00183    // To open non-local files use the static TFile::Open() method, that
00184    // will take care of opening the files using the correct remote file
00185    // access plugin.
00186    //
00187    // If option = NEW or CREATE   create a new file and open it for writing,
00188    //                             if the file already exists the file is
00189    //                             not opened.
00190    //           = RECREATE        create a new file, if the file already
00191    //                             exists it will be overwritten.
00192    //           = UPDATE          open an existing file for writing.
00193    //                             if no file exists, it is created.
00194    //           = READ            open an existing file for reading (default).
00195    //           = NET             used by derived remote file access
00196    //                             classes, not a user callable option
00197    //           = WEB             used by derived remote http access
00198    //                             class, not a user callable option
00199    // If option = "" (default), READ is assumed.
00200    //
00201    // The file can be specified as a URL of the form:
00202    //    file:///user/rdm/bla.root or file:/user/rdm/bla.root
00203    //
00204    // The file can also be a member of an archive, in which case it is
00205    // specified as:
00206    //    multi.zip#file.root or multi.zip#0
00207    // which will open file.root which is a member of the file multi.zip
00208    // archive or member 1 from the archive. For more on archive file
00209    // support see the TArchiveFile class.
00210    //
00211    // TFile and its remote access plugins can also be used to open any
00212    // file, i.e. also non ROOT files, using:
00213    //    file.tar?filetype=raw
00214    // This is convenient because the many remote file access plugins allow
00215    // easy access to/from the many different mass storage systems.
00216    //
00217    // The title of the file (ftitle) will be shown by the ROOT browsers.
00218    //
00219    // A ROOT file (like a Unix file system) may contain objects and
00220    // directories. There are no restrictions for the number of levels
00221    // of directories.
00222    //
00223    // A ROOT file is designed such that one can write in the file in pure
00224    // sequential mode (case of BATCH jobs). In this case, the file may be
00225    // read sequentially again without using the file index written
00226    // at the end of the file. In case of a job crash, all the information
00227    // on the file is therefore protected.
00228    //
00229    // A ROOT file can be used interactively. In this case, one has the
00230    // possibility to delete existing objects and add new ones.
00231    // When an object is deleted from the file, the freed space is added
00232    // into the FREE linked list (fFree). The FREE list consists of a chain
00233    // of consecutive free segments on the file. At the same time, the first
00234    // 4 bytes of the freed record on the file are overwritten by GAPSIZE
00235    // where GAPSIZE = -(Number of bytes occupied by the record).
00236    //
00237    // Option compress is used to specify the compression level:
00238    //  compress = 0 objects written to this file will not be compressed.
00239    //  compress = 1 minimal compression level but fast.
00240    //  ....
00241    //  compress = 9 maximal compression level but slow.
00242    //
00243    // Note that the compression level may be changed at any time.
00244    // The new compression level will only apply to newly written objects.
00245    // The function TFile::Map() shows the compression factor
00246    // for each object written to this file.
00247    // The function TFile::GetCompressionFactor returns the global
00248    // compression factor for this file.
00249    //
00250    // In case the file does not exist or is not a valid ROOT file,
00251    // it is made a Zombie. One can detect this situation with a code like:
00252    //    TFile f("file.root");
00253    //    if (f.IsZombie()) {
00254    //       cout << "Error opening file" << endl;
00255    //       exit(-1);
00256    //    }
00257    //
00258    //  When opening the file, the system checks the validity of this directory.
00259    //  If something wrong is detected, an automatic Recovery is performed. In
00260    //  this case, the file is scanned sequentially reading all logical blocks
00261    //  and attempting to rebuild a correct directory (see TFile::Recover).
00262    //  One can disable the automatic recovery procedure when reading one
00263    //  or more files by setting the environment variable "TFile::Recover 0"
00264    //  in the system.rootrc file.
00265    //
00266 
00267    if (!gROOT)
00268       ::Fatal("TFile::TFile", "ROOT system not initialized");
00269 
00270    // store name without the options as name and title
00271    TString sfname1 = fname1;
00272    fNoAnchorInName = kFALSE;
00273    if (sfname1.Index("?") != kNPOS) {
00274       TString s = sfname1(0, sfname1.Index("?"));
00275       SetName(s);
00276       fNoAnchorInName = kTRUE;
00277    } else
00278       SetName(fname1);
00279 
00280    SetTitle(ftitle);
00281 
00282    // accept also URL like "file:..." syntax
00283    fname1 = fUrl.GetFile();
00284 
00285    // if option contains filetype=raw then go into raw file mode
00286    fIsRootFile = kTRUE;
00287    if (strstr(fUrl.GetOptions(), "filetype=raw"))
00288       fIsRootFile = kFALSE;
00289 
00290    // Init initialization control flag
00291    fInitDone   = kFALSE;
00292    fMustFlush  = kTRUE;
00293 
00294    // We are opening synchronously
00295    fAsyncHandle = 0;
00296    fAsyncOpenStatus = kAOSNotAsync;
00297 
00298    TDirectoryFile::Build(this, 0);
00299 
00300    fD            = -1;
00301    fFree         = 0;
00302    fVersion      = gROOT->GetVersionInt();  //ROOT version in integer format
00303    fUnits        = 4;
00304    fOption       = option;
00305    fCompress     = compress;
00306    fWritten      = 0;
00307    fSumBuffer    = 0;
00308    fSum2Buffer   = 0;
00309    fBytesRead    = 0;
00310    fBytesReadExtra = 0;
00311    fBytesWrite   = 0;
00312    fClassIndex   = 0;
00313    fSeekInfo     = 0;
00314    fNbytesInfo   = 0;
00315    fProcessIDs   = 0;
00316    fNProcessIDs  = 0;
00317    fOffset       = 0;
00318    fCacheRead    = 0;
00319    fCacheWrite   = 0;
00320    fReadCalls    = 0;
00321    SetBit(kBinaryFile, kTRUE);
00322 
00323    fOption.ToUpper();
00324 
00325    fArchiveOffset = 0;
00326    fIsArchive     = kFALSE;
00327    fArchive       = 0;
00328    if (fIsRootFile) {
00329       fArchive = TArchiveFile::Open(fUrl.GetUrl(), this);
00330       if (fArchive) {
00331         fname1 = fArchive->GetArchiveName();
00332          // if no archive member is specified then this TFile is just used
00333          // to read the archive contents
00334          if (!strlen(fArchive->GetMemberName()))
00335             fIsArchive = kTRUE;
00336       }
00337    }
00338 
00339    if (fOption == "NET")
00340       return;
00341 
00342    if (fOption == "WEB") {
00343       fOption   = "READ";
00344       fWritable = kFALSE;
00345       return;
00346    }
00347 
00348    if (fOption == "NEW")
00349       fOption = "CREATE";
00350 
00351    Bool_t create   = (fOption == "CREATE") ? kTRUE : kFALSE;
00352    Bool_t recreate = (fOption == "RECREATE") ? kTRUE : kFALSE;
00353    Bool_t update   = (fOption == "UPDATE") ? kTRUE : kFALSE;
00354    Bool_t read     = (fOption == "READ") ? kTRUE : kFALSE;
00355    if (!create && !recreate && !update && !read) {
00356       read    = kTRUE;
00357       fOption = "READ";
00358    }
00359 
00360    Bool_t devnull = kFALSE;
00361 
00362    if (!fname1 || !strlen(fname1)) {
00363       Error("TFile", "file name is not specified");
00364       goto zombie;
00365    }
00366 
00367    // support dumping to /dev/null on UNIX
00368    if (!strcmp(fname1, "/dev/null") &&
00369        !gSystem->AccessPathName(fname1, kWritePermission)) {
00370       devnull  = kTRUE;
00371       create   = kTRUE;
00372       recreate = kFALSE;
00373       update   = kFALSE;
00374       read     = kFALSE;
00375       fOption  = "CREATE";
00376       SetBit(kDevNull);
00377    }
00378 
00379    const char *fname;
00380    if ((fname = gSystem->ExpandPathName(fname1))) {
00381       SetName(fname);
00382       delete [] fname;
00383       fRealName = GetName();
00384       fname = fRealName.Data();
00385    } else {
00386       Error("TFile", "error expanding path %s", fname1);
00387       goto zombie;
00388    }
00389 
00390    if (recreate) {
00391       if (!gSystem->AccessPathName(fname, kFileExists))
00392          gSystem->Unlink(fname);
00393       recreate = kFALSE;
00394       create   = kTRUE;
00395       fOption  = "CREATE";
00396    }
00397    if (create && !devnull && !gSystem->AccessPathName(fname, kFileExists)) {
00398       Error("TFile", "file %s already exists", fname);
00399       goto zombie;
00400    }
00401    if (update) {
00402       if (gSystem->AccessPathName(fname, kFileExists)) {
00403          update = kFALSE;
00404          create = kTRUE;
00405       }
00406       if (update && gSystem->AccessPathName(fname, kWritePermission)) {
00407          Error("TFile", "no write permission, could not open file %s", fname);
00408          goto zombie;
00409       }
00410    }
00411    if (read) {
00412       if (gSystem->AccessPathName(fname, kFileExists)) {
00413          Error("TFile", "file %s does not exist", fname);
00414          goto zombie;
00415       }
00416       if (gSystem->AccessPathName(fname, kReadPermission)) {
00417          Error("TFile", "no read permission, could not open file %s", fname);
00418          goto zombie;
00419       }
00420    }
00421 
00422    // Connect to file system stream
00423    if (create || update) {
00424 #ifndef WIN32
00425       fD = SysOpen(fname, O_RDWR | O_CREAT, 0644);
00426 #else
00427       fD = SysOpen(fname, O_RDWR | O_CREAT | O_BINARY, S_IREAD | S_IWRITE);
00428 #endif
00429       if (fD == -1) {
00430          SysError("TFile", "file %s can not be opened", fname);
00431          goto zombie;
00432       }
00433       fWritable = kTRUE;
00434    } else {
00435 #ifndef WIN32
00436       fD = SysOpen(fname, O_RDONLY, 0644);
00437 #else
00438       fD = SysOpen(fname, O_RDONLY | O_BINARY, S_IREAD | S_IWRITE);
00439 #endif
00440       if (fD == -1) {
00441          SysError("TFile", "file %s can not be opened for reading", fname);
00442          goto zombie;
00443       }
00444       fWritable = kFALSE;
00445    }
00446 
00447    Init(create);
00448 
00449    return;
00450 
00451 zombie:
00452    // error in file opening occured, make this object a zombie
00453    MakeZombie();
00454    gDirectory = gROOT;
00455 }
00456 
00457 //______________________________________________________________________________
00458 TFile::TFile(const TFile &) : TDirectoryFile(), fInfoCache(0)
00459 {
00460    // TFile objects can not be copied.
00461 
00462    MayNotUse("TFile::TFile(const TFile &)");
00463 }
00464 
00465 //______________________________________________________________________________
00466 TFile::~TFile()
00467 {
00468    // File destructor.
00469 
00470    Close();
00471 
00472    SafeDelete(fProcessIDs);
00473    SafeDelete(fFree);
00474    SafeDelete(fArchive);
00475    SafeDelete(fInfoCache);
00476    SafeDelete(fOpenPhases);
00477    SafeDelete(fAsyncHandle);
00478    SafeDelete(fCacheRead);
00479    SafeDelete(fCacheWrite);
00480 
00481    R__LOCKGUARD2(gROOTMutex);
00482    gROOT->GetListOfFiles()->Remove(this);
00483    gROOT->GetUUIDs()->RemoveUUID(GetUniqueID());
00484 
00485    if (gDebug)
00486       Info("~TFile", "dtor called for %s [%lx]", GetName(),(Long_t)this);
00487 }
00488 
00489 //______________________________________________________________________________
00490 void TFile::Init(Bool_t create)
00491 {
00492    // Initialize a TFile object.
00493    // TFile implementations providing asynchronous open functionality need to
00494    // override this method to run the appropriate checks before calling this
00495    // standard initialization part. See TXNetFile::Init for an example.
00496 
00497    if (fInitDone)
00498       // Already called once
00499       return;
00500    fInitDone = kTRUE;
00501 
00502    if (!fIsRootFile) {
00503       gDirectory = gROOT;
00504       return;
00505    }
00506 
00507    if (fArchive) {
00508       if (fOption != "READ") {
00509          Error("Init", "archive %s can only be opened in read mode", GetName());
00510          delete fArchive;
00511          fArchive = 0;
00512          fIsArchive = kFALSE;
00513          goto zombie;
00514       }
00515 
00516       fArchive->OpenArchive();
00517 
00518       if (fIsArchive) return;
00519 
00520       // Make sure the anchor is in the name
00521       if (!fNoAnchorInName)
00522          if (!strchr(GetName(),'#'))
00523             SetName(Form("%s#%s", GetName(), fArchive->GetMemberName()));
00524 
00525       if (fArchive->SetCurrentMember() != -1)
00526          fArchiveOffset = fArchive->GetMemberFilePosition();
00527       else {
00528          Error("Init", "member %s not found in archive %s",
00529                fArchive->GetMemberName(), fArchive->GetArchiveName());
00530          delete fArchive;
00531          fArchive = 0;
00532          fIsArchive = kFALSE;
00533          goto zombie;
00534       }
00535    }
00536 
00537    Int_t nfree;
00538    fBEGIN = (Long64_t)kBEGIN;    //First used word in file following the file header
00539 
00540    // make newly opened file the current file and directory
00541    cd();
00542 
00543    if (create) {
00544       //*-*---------------NEW file
00545       fFree        = new TList;
00546       fEND         = fBEGIN;    //Pointer to end of file
00547       new TFree(fFree, fBEGIN, Long64_t(kStartBigFile));  //Create new free list
00548 
00549       //*-* Write Directory info
00550       Int_t namelen= TNamed::Sizeof();
00551       Int_t nbytes = namelen + TDirectoryFile::Sizeof();
00552       TKey *key    = new TKey(fName, fTitle, IsA(), nbytes, this);
00553       fNbytesName  = key->GetKeylen() + namelen;
00554       fSeekDir     = key->GetSeekKey();
00555       fSeekFree    = 0;
00556       fNbytesFree  = 0;
00557       WriteHeader();
00558       char *buffer = key->GetBuffer();
00559       TNamed::FillBuffer(buffer);
00560       TDirectoryFile::FillBuffer(buffer);
00561       key->WriteFile();
00562       delete key;
00563    } else {
00564       //*-*----------------UPDATE
00565       //char *header = new char[kBEGIN];
00566       char *header = new char[kBEGIN+200];
00567       Seek(0);
00568       //ReadBuffer(header, kBEGIN);
00569       ReadBuffer(header, kBEGIN+200);
00570 
00571       // make sure this is a ROOT file
00572       if (strncmp(header, "root", 4)) {
00573          Error("Init", "%s not a ROOT file", GetName());
00574          delete [] header;
00575          goto zombie;
00576       }
00577 
00578       char *buffer = header + 4;    // skip the "root" file identifier
00579       frombuf(buffer, &fVersion);
00580       Int_t headerLength;
00581       frombuf(buffer, &headerLength);
00582       fBEGIN = (Long64_t)headerLength;
00583       if (fVersion < 1000000) { //small file
00584          Int_t send,sfree,sinfo;
00585          frombuf(buffer, &send);         fEND     = (Long64_t)send;
00586          frombuf(buffer, &sfree);        fSeekFree= (Long64_t)sfree;
00587          frombuf(buffer, &fNbytesFree);
00588          frombuf(buffer, &nfree);
00589          frombuf(buffer, &fNbytesName);
00590          frombuf(buffer, &fUnits );
00591          frombuf(buffer, &fCompress);
00592          frombuf(buffer, &sinfo);        fSeekInfo = (Long64_t)sinfo;
00593          frombuf(buffer, &fNbytesInfo);
00594       } else { // new format to support large files
00595          frombuf(buffer, &fEND);
00596          frombuf(buffer, &fSeekFree);
00597          frombuf(buffer, &fNbytesFree);
00598          frombuf(buffer, &nfree);
00599          frombuf(buffer, &fNbytesName);
00600          frombuf(buffer, &fUnits );
00601          frombuf(buffer, &fCompress);
00602          frombuf(buffer, &fSeekInfo);
00603          frombuf(buffer, &fNbytesInfo);
00604       }
00605       fSeekDir = fBEGIN;
00606       //*-*-------------Read Free segments structure if file is writable
00607       if (fWritable) {
00608          fFree = new TList;
00609          if (fSeekFree > fBEGIN) {
00610             ReadFree();
00611          } else {
00612             Warning("Init","file %s probably not closed, cannot read free segments",GetName());
00613          }
00614       }
00615       //*-*-------------Read directory info
00616       // buffer_keyloc is the start of the key record.
00617       char *buffer_keyloc = 0;
00618 
00619       Int_t nbytes = fNbytesName + TDirectoryFile::Sizeof();
00620       if (nbytes+fBEGIN > kBEGIN+200) {
00621          delete [] header;
00622          header       = new char[nbytes];
00623          buffer       = header;
00624          Seek(fBEGIN);
00625          ReadBuffer(buffer,nbytes);
00626          buffer = header+fNbytesName;
00627          buffer_keyloc = header;
00628       } else {
00629          buffer = header+fBEGIN+fNbytesName;
00630          buffer_keyloc = header+fBEGIN;
00631       }
00632       Version_t version,versiondir;
00633       frombuf(buffer,&version); versiondir = version%1000;
00634       fDatimeC.ReadBuffer(buffer);
00635       fDatimeM.ReadBuffer(buffer);
00636       frombuf(buffer, &fNbytesKeys);
00637       frombuf(buffer, &fNbytesName);
00638       if (version > 1000) {
00639          frombuf(buffer, &fSeekDir);
00640          frombuf(buffer, &fSeekParent);
00641          frombuf(buffer, &fSeekKeys);
00642       } else {
00643          Int_t sdir,sparent,skeys;
00644          frombuf(buffer, &sdir);    fSeekDir    = (Long64_t)sdir;
00645          frombuf(buffer, &sparent); fSeekParent = (Long64_t)sparent;
00646          frombuf(buffer, &skeys);   fSeekKeys   = (Long64_t)skeys;
00647       }
00648       if (versiondir > 1) fUUID.ReadBuffer(buffer);
00649 
00650       //*-*---------read TKey::FillBuffer info
00651       buffer_keyloc += sizeof(Int_t); // Skip NBytes;
00652       Version_t keyversion;
00653       frombuf(buffer_keyloc, &keyversion);
00654       // Skip ObjLen, DateTime, KeyLen, Cycle, SeekKey, SeekPdir
00655       if (keyversion > 1000) {
00656          // Large files
00657          buffer_keyloc += 2*sizeof(Int_t)+2*sizeof(Short_t)+2*sizeof(Long64_t);
00658       } else {
00659          buffer_keyloc += 2*sizeof(Int_t)+2*sizeof(Short_t)+2*sizeof(Int_t);
00660       }
00661       TString cname;
00662       cname.ReadBuffer(buffer_keyloc);
00663       cname.ReadBuffer(buffer_keyloc); // fName.ReadBuffer(buffer); file may have been renamed
00664       fTitle.ReadBuffer(buffer_keyloc);
00665       delete [] header;
00666       if (fNbytesName < 10 || fNbytesName > 10000) {
00667          Error("Init","cannot read directory info of file %s", GetName());
00668          goto zombie;
00669       }
00670 
00671       //*-* -------------Check if file is truncated
00672       Long64_t size;
00673       if ((size = GetSize()) == -1) {
00674          Error("Init", "cannot stat the file %s", GetName());
00675          goto zombie;
00676       }
00677 
00678       //*-* -------------Check if, in case of inconsistencies, we are requested to
00679       //*-* -------------attempt recovering the file
00680       Bool_t tryrecover = (gEnv->GetValue("TFile.Recover", 1) == 1) ? kTRUE : kFALSE;
00681 
00682       //*-* -------------Read keys of the top directory
00683       if (fSeekKeys > fBEGIN && fEND <= size) {
00684          //normal case. Recover only if file has no keys
00685          TDirectoryFile::ReadKeys(kFALSE);
00686          gDirectory = this;
00687          if (!GetNkeys()) {
00688             if (tryrecover) {
00689                Recover();
00690             } else {
00691                Error("Init", "file %s has no keys", GetName());
00692                goto zombie;
00693             }
00694          }
00695       } else if ((fBEGIN+nbytes == fEND) && (fEND == size)) {
00696          //the file might be open by another process and nothing written to the file yet
00697          Warning("Init","file %s has no keys", GetName());
00698          gDirectory = this;
00699       } else {
00700          //something had been written to the file. Trailer is missing, must recover
00701          if (fEND > size) {
00702             if (tryrecover) {
00703                Error("Init","file %s is truncated at %lld bytes: should be %lld, "
00704                      "trying to recover", GetName(), size, fEND);
00705             } else {
00706                Error("Init","file %s is truncated at %lld bytes: should be %lld",
00707                      GetName(), size, fEND);
00708                goto zombie;
00709             }
00710          } else {
00711             if (tryrecover) {
00712                Warning("Init","file %s probably not closed, "
00713                        "trying to recover", GetName());
00714             } else {
00715                Warning("Init","file %s probably not closed", GetName());
00716                goto zombie;
00717             }
00718          }
00719          Int_t nrecov = Recover();
00720          if (nrecov) {
00721             Warning("Init", "successfully recovered %d keys", nrecov);
00722          } else {
00723             Warning("Init", "no keys recovered, file has been made a Zombie");
00724             goto zombie;
00725          }
00726       }
00727    }
00728 
00729    {
00730       R__LOCKGUARD2(gROOTMutex);
00731       gROOT->GetListOfFiles()->Add(this);
00732       gROOT->GetUUIDs()->AddUUID(fUUID,this);
00733    }
00734 
00735    // Create StreamerInfo index
00736    {
00737       Int_t lenIndex = gROOT->GetListOfStreamerInfo()->GetSize()+1;
00738       if (lenIndex < 5000) lenIndex = 5000;
00739       fClassIndex = new TArrayC(lenIndex);
00740       if (fgReadInfo) {
00741          if (fSeekInfo > fBEGIN) {
00742             ReadStreamerInfo();
00743          } else if (fVersion != gROOT->GetVersionInt() && fVersion > 30000) {
00744             Warning("Init","no StreamerInfo found in %s therefore preventing schema evolution when reading this file.",GetName());
00745          }
00746       }
00747    }
00748 
00749    // Count number of TProcessIDs in this file
00750    {
00751       TIter next(fKeys);
00752       TKey *key;
00753       while ((key = (TKey*)next())) {
00754          if (!strcmp(key->GetClassName(),"TProcessID")) fNProcessIDs++;
00755       }
00756       fProcessIDs = new TObjArray(fNProcessIDs+1);
00757       return;
00758    }
00759 
00760 zombie:
00761    // error in file opening occured, make this object a zombie
00762    MakeZombie();
00763    gDirectory = gROOT;
00764 }
00765 
00766 //______________________________________________________________________________
00767 void TFile::Close(Option_t *option)
00768 {
00769    // Close a file.
00770    // If option == "R", all TProcessIDs referenced by this file are deleted.
00771    // Calling TFile::Close("R") might be necessary in case one reads a long list
00772    // of files having TRef, writing some of the referenced objects or TRef
00773    // to a new file. If the TRef or referenced objects of the file being closed
00774    // will not be referenced again, it is possible to minimize the size
00775    // of the TProcessID data structures in memory by forcing a delete of
00776    // the unused TProcessID.
00777 
00778    TString opt = option;
00779 
00780    opt.ToLower();
00781 
00782    if (!IsOpen()) return;
00783 
00784    if (fIsArchive || !fIsRootFile) {
00785       FlushWriteCache();
00786       SysClose(fD);
00787       fD = -1;
00788 
00789       if (gMonitoringWriter)
00790          gMonitoringWriter->SendFileCloseEvent(this);
00791 
00792       return;
00793    }
00794 
00795    if (IsWritable()) {
00796       WriteStreamerInfo();
00797    }
00798 
00799    delete fClassIndex;
00800    fClassIndex = 0;
00801 
00802    // Delete all supported directories structures from memory
00803    // If gDirectory points to this object or any of the nested
00804    // TDirectoryFile, TDirectoryFile::Close will induce the proper cd.
00805    TDirectoryFile::Close();
00806 
00807    if (IsWritable()) {
00808       TFree *f1 = (TFree*)fFree->First();
00809       if (f1) {
00810          WriteFree();       //*-*- Write free segments linked list
00811          WriteHeader();     //*-*- Now write file header
00812       }
00813    }
00814 
00815    FlushWriteCache();
00816 
00817    if (gMonitoringWriter)
00818       gMonitoringWriter->SendFileCloseEvent(this);
00819 
00820    // Delete free segments from free list (but don't delete list header)
00821    if (fFree) {
00822       fFree->Delete();
00823    }
00824 
00825    if (IsOpen()) {
00826       SysClose(fD);
00827       fD = -1;
00828    }
00829 
00830    fWritable = kFALSE;
00831 
00832    // delete the TProcessIDs
00833    TList pidDeleted;
00834    TIter next(fProcessIDs);
00835    TProcessID *pid;
00836    while ((pid = (TProcessID*)next())) {
00837       if (!pid->DecrementCount()) {
00838          if (pid != TProcessID::GetSessionProcessID()) pidDeleted.Add(pid);
00839       } else if(opt.Contains("r")) {
00840          pid->Clear();
00841       }
00842    }
00843    pidDeleted.Delete();
00844 
00845    R__LOCKGUARD2(gROOTMutex);
00846    gROOT->GetListOfFiles()->Remove(this);
00847    gROOT->GetListOfBrowsers()->RecursiveRemove(this);
00848 }
00849 
00850 //____________________________________________________________________________________
00851 TKey* TFile::CreateKey(TDirectory* mother, const TObject* obj, const char* name, Int_t bufsize)
00852 {
00853    // Creates key for object and converts data to buffer.
00854 
00855    return new TKey(obj, name, bufsize, mother);
00856 }
00857 
00858 //____________________________________________________________________________________
00859 TKey* TFile::CreateKey(TDirectory* mother, const void* obj, const TClass* cl, const char* name, Int_t bufsize)
00860 {
00861    // Creates key for object and converts data to buffer.
00862 
00863    return new TKey(obj, cl, name, bufsize, mother);
00864 }
00865 
00866 //______________________________________________________________________________
00867 void TFile::Delete(const char *namecycle)
00868 {
00869    // Delete object namecycle.
00870    // Namecycle identifies an object in the top directory of the file
00871    //   namecycle has the format name;cycle
00872    //   name  = * means all
00873    //   cycle = * means all cycles (memory and keys)
00874    //   cycle = "" or cycle = 9999 ==> apply to a memory object
00875    //   When name=* use T* to delete subdirectories also
00876    //
00877    // Examples:
00878    //     foo   : delete object named foo in memory
00879    //     foo;1 : delete cycle 1 of foo on file
00880    //     foo;* : delete all cycles of foo on disk and also from memory
00881    //     *;2   : delete all objects on file having the cycle 2
00882    //     *;*   : delete all objects from memory and file
00883    //    T*;*   : delete all objects from memory and file and all subdirectories
00884 
00885    if (gDebug)
00886       Info("Delete", "deleting name = %s", namecycle);
00887 
00888    TDirectoryFile::Delete(namecycle);
00889 }
00890 
00891 //______________________________________________________________________________
00892 void TFile::Draw(Option_t *option)
00893 {
00894    // Fill Graphics Structure and Paint.
00895    // Loop on all objects (memory or file) and all subdirectories.
00896 
00897    GetList()->R__FOR_EACH(TObject,Draw)(option);
00898 }
00899 
00900 //______________________________________________________________________________
00901 void TFile::DrawMap(const char *keys, Option_t *option)
00902 {
00903    // Draw map of objects in this file.
00904 
00905    TPluginHandler *h;
00906    if ((h = gROOT->GetPluginManager()->FindHandler("TFileDrawMap"))) {
00907       if (h->LoadPlugin() == -1)
00908          return;
00909       h->ExecPlugin(3, this, keys, option);
00910    }
00911 }
00912 
00913 //______________________________________________________________________________
00914 void TFile::Flush()
00915 {
00916    // Synchronize a file's in-core and on-disk states.
00917    if (IsOpen() && fWritable) {
00918       FlushWriteCache();
00919       if (SysSync(fD) < 0) {
00920          // Write the system error only once for this file
00921          SetBit(kWriteError); SetWritable(kFALSE);
00922          SysError("Flush", "error flushing file %s", GetName());
00923       }
00924    }
00925 }
00926 
00927 //______________________________________________________________________________
00928 Bool_t TFile::FlushWriteCache()
00929 {
00930    // Flush the write cache if active.
00931    // Return kTRUE in case of error
00932 
00933    if (fCacheWrite && IsOpen() && fWritable)
00934       return fCacheWrite->Flush();
00935    return kFALSE;
00936 }
00937 
00938 //______________________________________________________________________________
00939 void TFile::FillBuffer(char *&buffer)
00940 {
00941    // Encode file output buffer.
00942    // The file output buffer contains only the FREE data record.
00943 
00944    Version_t version = TFile::Class_Version();
00945    tobuf(buffer, version);
00946 }
00947 
00948 //______________________________________________________________________________
00949 Int_t TFile::GetBestBuffer() const
00950 {
00951    // Return the best buffer size of objects on this file.
00952    // The best buffer size is estimated based on the current mean value
00953    // and standard deviation of all objects written so far to this file.
00954    // Returns mean value + one standard deviation.
00955 
00956    if (!fWritten) return TBuffer::kInitialSize;
00957    Double_t mean = fSumBuffer/fWritten;
00958    Double_t rms2 = TMath::Abs(fSum2Buffer/fSumBuffer -mean*mean);
00959    return (Int_t)(mean + sqrt(rms2));
00960 }
00961 
00962 //______________________________________________________________________________
00963 Float_t TFile::GetCompressionFactor()
00964 {
00965    // Return the file compression factor.
00966    // Add total number of compressed/uncompressed bytes for each key.
00967    // return ratio of the two.
00968 
00969    Short_t  keylen;
00970    UInt_t   datime;
00971    Int_t    nbytes, objlen, nwh = 64;
00972    char    *header = new char[fBEGIN];
00973    char    *buffer;
00974    Long64_t   idcur = fBEGIN;
00975    Float_t comp,uncomp;
00976    comp = uncomp = fBEGIN;
00977 
00978    while (idcur < fEND-100) {
00979       Seek(idcur);
00980       ReadBuffer(header, nwh);
00981       buffer=header;
00982       frombuf(buffer, &nbytes);
00983       if (nbytes < 0) {
00984          idcur -= nbytes;
00985          Seek(idcur);
00986          continue;
00987       }
00988       if (nbytes == 0) break; //this may happen when the file is corrupted
00989       Version_t versionkey;
00990       frombuf(buffer, &versionkey);
00991       frombuf(buffer, &objlen);
00992       frombuf(buffer, &datime);
00993       frombuf(buffer, &keylen);
00994       if (!objlen) objlen = nbytes-keylen;
00995       comp   += nbytes;
00996       uncomp += keylen + objlen;
00997       idcur  += nbytes;
00998    }
00999    delete [] header;
01000    return uncomp/comp;
01001 }
01002 
01003 //______________________________________________________________________________
01004 Int_t TFile::GetErrno() const
01005 {
01006    // Method returning errno. Is overriden in TRFIOFile.
01007 
01008    return TSystem::GetErrno();
01009 }
01010 
01011 //______________________________________________________________________________
01012 void TFile::ResetErrno() const
01013 {
01014    // Method resetting the errno. Is overridden in TRFIOFile.
01015 
01016    TSystem::ResetErrno();
01017 }
01018 
01019 //______________________________________________________________________________
01020 TFileCacheRead *TFile::GetCacheRead() const
01021 {
01022    // Return a pointer to the current read cache.
01023 
01024    return fCacheRead;
01025 }
01026 
01027 //______________________________________________________________________________
01028 TFileCacheWrite *TFile::GetCacheWrite() const
01029 {
01030    // Return a pointer to the current write cache.
01031 
01032    return fCacheWrite;
01033 }
01034 
01035 //______________________________________________________________________________
01036 Int_t TFile::GetRecordHeader(char *buf, Long64_t first, Int_t maxbytes, Int_t &nbytes, Int_t &objlen, Int_t &keylen)
01037 {
01038    // Read the logical record header starting at position first.
01039    // Maxbytes bytes are read into buf the function reads nread bytes
01040    // where nread is the minimum of maxbytes and the number of bytes
01041    // before the end of file. The function returns nread.
01042    // In output arguments:
01043    //    nbytes : number of bytes in record
01044    //             if negative, this is a deleted record
01045    //             if 0, cannot read record, wrong value of argument first
01046    //    objlen : uncompressed object size
01047    //    keylen : length of logical record header
01048    // Note that the arguments objlen and keylen are returned only
01049    // if maxbytes >=16
01050 
01051    if (first < fBEGIN) return 0;
01052    if (first > fEND)   return 0;
01053    Seek(first);
01054    Int_t nread = maxbytes;
01055    if (first+maxbytes > fEND) nread = fEND-maxbytes;
01056    if (nread < 4) {
01057       Warning("GetRecordHeader","%s: parameter maxbytes = %d must be >= 4",
01058               GetName(), nread);
01059       return nread;
01060    }
01061    ReadBuffer(buf,nread);
01062    Version_t versionkey;
01063    Short_t  klen;
01064    UInt_t   datime;
01065    Int_t    nb,olen;
01066    char *buffer = buf;
01067    frombuf(buffer,&nb);
01068    nbytes = nb;
01069    if (nb < 0) return nread;
01070    //   const Int_t headerSize = Int_t(sizeof(nb) +sizeof(versionkey) +sizeof(olen) +sizeof(datime) +sizeof(klen));
01071    const Int_t headerSize = 16;
01072    if (nread < headerSize) return nread;
01073    frombuf(buffer, &versionkey);
01074    frombuf(buffer, &olen);
01075    frombuf(buffer, &datime);
01076    frombuf(buffer, &klen);
01077    if (!olen) olen = nbytes-klen;
01078    objlen = olen;
01079    keylen = klen;
01080    return nread;
01081 }
01082 
01083 //______________________________________________________________________________
01084 Long64_t TFile::GetSize() const
01085 {
01086    // Returns the current file size. Returns -1 in case the file could not
01087    // be stat'ed.
01088 
01089    Long64_t size;
01090 
01091    if (fArchive && fArchive->GetMember()) {
01092       size = fArchive->GetMember()->GetDecompressedSize();
01093    } else {
01094       Long_t id, flags, modtime;
01095       if (const_cast<TFile*>(this)->SysStat(fD, &id, &size, &flags, &modtime)) {
01096          Error("GetSize", "cannot stat the file %s", GetName());
01097          return -1;
01098       }
01099    }
01100    return size;
01101 }
01102 
01103 //______________________________________________________________________________
01104 const TList *TFile::GetStreamerInfoCache()
01105 {
01106    // Returns the cached list of StreamerInfos used in this file.
01107 
01108    return fInfoCache ?  fInfoCache : (fInfoCache=GetStreamerInfoList());
01109 }
01110 
01111 //______________________________________________________________________________
01112 TList *TFile::GetStreamerInfoList()
01113 {
01114    // Read the list of TStreamerInfo objects written to this file.
01115    // The function returns a TList. It is the user'responsability
01116    // to delete the list created by this function.
01117    //
01118    // Using the list, one can access additional information,eg:
01119    //   TFile f("myfile.root");
01120    //   TList *list = f.GetStreamerInfoList();
01121    //   TStreamerInfo *info = (TStreamerInfo*)list->FindObject("MyClass");
01122    //   Int_t classversionid = info->GetClassVersion();
01123    //   delete list;
01124 
01125    TList *list = 0;
01126    if (fSeekInfo) {
01127       TDirectory::TContext ctx(gDirectory,this); // gFile and gDirectory used in ReadObj
01128       TKey *key = new TKey(this);
01129       char *buffer = new char[fNbytesInfo+1];
01130       char *buf    = buffer;
01131       Seek(fSeekInfo);
01132       ReadBuffer(buf,fNbytesInfo);
01133       key->ReadKeyBuffer(buf);
01134       list = (TList*)key->ReadObjWithBuffer(buffer);
01135       if (list) list->SetOwner();
01136       delete [] buffer;
01137       delete key;
01138    } else {
01139       list = (TList*)Get("StreamerInfo"); //for versions 2.26 (never released)
01140    }
01141 
01142    if (list == 0) {
01143       Info("GetStreamerInfoList", "cannot find the StreamerInfo record in file %s",
01144            GetName());
01145       return 0;
01146    }
01147 
01148    return list;
01149 }
01150 
01151 //______________________________________________________________________________
01152 void TFile::ls(Option_t *option) const
01153 {
01154    // List File contents.
01155    // Indentation is used to identify the file tree.
01156    // Subdirectories are listed first, then objects in memory,
01157    // then objects on the file.
01158 
01159    TROOT::IndentLevel();
01160    cout <<ClassName()<<"**\t\t"<<GetName()<<"\t"<<GetTitle()<<endl;
01161    TROOT::IncreaseDirLevel();
01162    TDirectoryFile::ls(option);
01163    TROOT::DecreaseDirLevel();
01164 }
01165 
01166 //______________________________________________________________________________
01167 Bool_t TFile::IsOpen() const
01168 {
01169    // Returns kTRUE in case file is open and kFALSE if file is not open.
01170 
01171    return fD == -1 ? kFALSE : kTRUE;
01172 }
01173 
01174 //______________________________________________________________________________
01175 void TFile::MakeFree(Long64_t first, Long64_t last)
01176 {
01177    // Mark unused bytes on the file.
01178    // The list of free segments is in the fFree linked list.
01179    // When an object is deleted from the file, the freed space is added
01180    // into the FREE linked list (fFree). The FREE list consists of a chain
01181    // of consecutive free segments on the file. At the same time, the first
01182    // 4 bytes of the freed record on the file are overwritten by GAPSIZE
01183    // where GAPSIZE = -(Number of bytes occupied by the record).
01184 
01185    TFree *f1      = (TFree*)fFree->First();
01186    if (!f1) return;
01187    TFree *newfree = f1->AddFree(fFree,first,last);
01188    if(!newfree) return;
01189    Long64_t nfirst = newfree->GetFirst();
01190    Long64_t nlast  = newfree->GetLast();
01191    Long64_t nbytesl= nlast-nfirst+1;
01192    if (nbytesl > 2000000000) nbytesl = 2000000000;
01193    Int_t nbytes    = -Int_t (nbytesl);
01194    Int_t nb        = sizeof(Int_t);
01195    char * buffer   = new char[nb];
01196    char * psave    = buffer;
01197    tobuf(buffer, nbytes);
01198    if (last == fEND-1) fEND = nfirst;
01199    Seek(nfirst);
01200    WriteBuffer(psave, nb);
01201    Flush();
01202    delete [] psave;
01203 }
01204 
01205 //______________________________________________________________________________
01206 void TFile::Map()
01207 {
01208    // List the contents of a file sequentially.
01209    // For each logical record found, it prints:
01210    //  Date/Time  Record_Adress Logical_Record_Length  ClassName  CompressionFactor
01211    //
01212    //  Example of output
01213    //  20010404/150437  At:64        N=150       TFile
01214    //  20010404/150440  At:214       N=28326     TBasket        CX =  1.13
01215    //  20010404/150440  At:28540     N=29616     TBasket        CX =  1.08
01216    //  20010404/150440  At:58156     N=29640     TBasket        CX =  1.08
01217    //  20010404/150440  At:87796     N=29076     TBasket        CX =  1.10
01218    //  20010404/150440  At:116872    N=10151     TBasket        CX =  3.15
01219    //  20010404/150441  At:127023    N=28341     TBasket        CX =  1.13
01220    //  20010404/150441  At:155364    N=29594     TBasket        CX =  1.08
01221    //  20010404/150441  At:184958    N=29616     TBasket        CX =  1.08
01222    //  20010404/150441  At:214574    N=29075     TBasket        CX =  1.10
01223    //  20010404/150441  At:243649    N=9583      TBasket        CX =  3.34
01224    //  20010404/150442  At:253232    N=28324     TBasket        CX =  1.13
01225    //  20010404/150442  At:281556    N=29641     TBasket        CX =  1.08
01226    //  20010404/150442  At:311197    N=29633     TBasket        CX =  1.08
01227    //  20010404/150442  At:340830    N=29091     TBasket        CX =  1.10
01228    //  20010404/150442  At:369921    N=10341     TBasket        CX =  3.09
01229    //  20010404/150442  At:380262    N=509       TH1F           CX =  1.93
01230    //  20010404/150442  At:380771    N=1769      TH2F           CX =  4.32
01231    //  20010404/150442  At:382540    N=1849      TProfile       CX =  1.65
01232    //  20010404/150442  At:384389    N=18434     TNtuple        CX =  4.51
01233    //  20010404/150442  At:402823    N=307       KeysList
01234    //  20010404/150443  At:403130    N=4548      StreamerInfo   CX =  3.65
01235    //  20010404/150443  At:407678    N=86        FreeSegments
01236    //  20010404/150443  At:407764    N=1         END
01237 
01238    Short_t  keylen,cycle;
01239    UInt_t   datime;
01240    Int_t    nbytes,date,time,objlen,nwheader;
01241    Long64_t seekkey,seekpdir;
01242    char    *buffer;
01243    char     nwhc;
01244    Long64_t idcur = fBEGIN;
01245 
01246    nwheader = 64;
01247    Int_t nread = nwheader;
01248 
01249    char header[kBEGIN];
01250    char classname[512];
01251 
01252    while (idcur < fEND) {
01253       Seek(idcur);
01254       if (idcur+nread >= fEND) nread = fEND-idcur-1;
01255       ReadBuffer(header, nread);
01256       buffer=header;
01257       frombuf(buffer, &nbytes);
01258       if (!nbytes) {
01259          Printf("Address = %lld\tNbytes = %d\t=====E R R O R=======", idcur, nbytes);
01260          date = 0; time = 0;
01261          break;
01262       }
01263       if (nbytes < 0) {
01264          Printf("Address = %lld\tNbytes = %d\t=====G A P===========", idcur, nbytes);
01265          idcur -= nbytes;
01266          Seek(idcur);
01267          continue;
01268       }
01269       Version_t versionkey;
01270       frombuf(buffer, &versionkey);
01271       frombuf(buffer, &objlen);
01272       frombuf(buffer, &datime);
01273       frombuf(buffer, &keylen);
01274       frombuf(buffer, &cycle);
01275       if (versionkey > 1000) {
01276          frombuf(buffer, &seekkey);
01277          frombuf(buffer, &seekpdir);
01278       } else {
01279          Int_t skey,sdir;
01280          frombuf(buffer, &skey);  seekkey  = (Long64_t)skey;
01281          frombuf(buffer, &sdir);  seekpdir = (Long64_t)sdir;
01282       }
01283       frombuf(buffer, &nwhc);
01284       for (int i = 0;i < nwhc; i++) frombuf(buffer, &classname[i]);
01285       classname[(int)nwhc] = '\0'; //cast to avoid warning with gcc3.4
01286       if (idcur == fSeekFree) strlcpy(classname,"FreeSegments",512);
01287       if (idcur == fSeekInfo) strlcpy(classname,"StreamerInfo",512);
01288       if (idcur == fSeekKeys) strlcpy(classname,"KeysList",512);
01289       TDatime::GetDateTime(datime, date, time);
01290       if (objlen != nbytes-keylen) {
01291          Float_t cx = Float_t(objlen+keylen)/Float_t(nbytes);
01292          Printf("%d/%06d  At:%lld  N=%-8d  %-14s CX = %5.2f",date,time,idcur,nbytes,classname,cx);
01293       } else {
01294          Printf("%d/%06d  At:%lld  N=%-8d  %-14s",date,time,idcur,nbytes,classname);
01295       }
01296       idcur += nbytes;
01297    }
01298    Printf("%d/%06d  At:%lld  N=%-8d  %-14s",date,time,idcur,1,"END");
01299 }
01300 
01301 //______________________________________________________________________________
01302 void TFile::Paint(Option_t *option)
01303 {
01304    // Paint all objects in the file.
01305 
01306    GetList()->R__FOR_EACH(TObject,Paint)(option);
01307 }
01308 
01309 //______________________________________________________________________________
01310 void TFile::Print(Option_t *option) const
01311 {
01312    // Print all objects in the file.
01313 
01314    Printf("TFile: name=%s, title=%s, option=%s", GetName(), GetTitle(), GetOption());
01315    GetList()->R__FOR_EACH(TObject,Print)(option);
01316 }
01317 
01318 //______________________________________________________________________________
01319 Bool_t TFile::ReadBuffer(char *buf, Long64_t pos, Int_t len)
01320 {
01321    // Read a buffer from the file at the offset 'pos' in the file.
01322    // Returns kTRUE in case of failure.
01323    // Compared to ReadBuffer(char*, Int_t), this routine does _not_
01324    // change the cursor on the physical file representation (fD)
01325    // if the data is in this TFile's cache.
01326 
01327    if (IsOpen()) {
01328 
01329       SetOffset(pos);
01330 
01331       Int_t st;
01332       if ((st = ReadBufferViaCache(buf, len))) {
01333          if (st == 2)
01334             return kTRUE;
01335          return kFALSE;
01336       }
01337 
01338       Seek(pos);
01339 
01340       ssize_t siz;
01341       Double_t start = 0;
01342       if (gPerfStats != 0) start = TTimeStamp();
01343 
01344       while ((siz = SysRead(fD, buf, len)) < 0 && GetErrno() == EINTR)
01345          ResetErrno();
01346 
01347       if (siz < 0) {
01348          SysError("ReadBuffer", "error reading from file %s", GetName());
01349          return kTRUE;
01350       }
01351       if (siz != len) {
01352          Error("ReadBuffer", "error reading all requested bytes from file %s, got %ld of %d",
01353                GetName(), (Long_t)siz, len);
01354          return kTRUE;
01355       }
01356       fBytesRead  += siz;
01357       fgBytesRead += siz;
01358       fReadCalls++;
01359       fgReadCalls++;
01360 
01361       if (gMonitoringWriter)
01362          gMonitoringWriter->SendFileReadProgress(this);
01363       if (gPerfStats != 0) {
01364          gPerfStats->FileReadEvent(this, len, start);
01365       }
01366       return kFALSE;
01367    }
01368    return kTRUE;
01369 }
01370 
01371 //______________________________________________________________________________
01372 Bool_t TFile::ReadBuffer(char *buf, Int_t len)
01373 {
01374    // Read a buffer from the file. This is the basic low level read operation.
01375    // Returns kTRUE in case of failure.
01376 
01377    if (IsOpen()) {
01378 
01379       Int_t st;
01380       if ((st = ReadBufferViaCache(buf, len))) {
01381          if (st == 2)
01382             return kTRUE;
01383          return kFALSE;
01384       }
01385 
01386       ssize_t siz;
01387 
01388       Double_t start = 0;
01389       if (gPerfStats != 0) start = TTimeStamp();
01390 
01391       while ((siz = SysRead(fD, buf, len)) < 0 && GetErrno() == EINTR)
01392          ResetErrno();
01393 
01394       if (siz < 0) {
01395          SysError("ReadBuffer", "error reading from file %s", GetName());
01396          return kTRUE;
01397       }
01398       if (siz != len) {
01399          Error("ReadBuffer", "error reading all requested bytes from file %s, got %ld of %d",
01400                GetName(), (Long_t)siz, len);
01401          return kTRUE;
01402       }
01403       fBytesRead  += siz;
01404       fgBytesRead += siz;
01405       fReadCalls++;
01406       fgReadCalls++;
01407 
01408       if (gMonitoringWriter)
01409          gMonitoringWriter->SendFileReadProgress(this);
01410       if (gPerfStats != 0) {
01411          gPerfStats->FileReadEvent(this, len, start);
01412       }
01413       return kFALSE;
01414    }
01415    return kTRUE;
01416 }
01417 
01418 //______________________________________________________________________________
01419 Bool_t TFile::ReadBuffers(char *buf, Long64_t *pos, Int_t *len, Int_t nbuf)
01420 {
01421    // Read the nbuf blocks described in arrays pos and len,
01422    // where pos[i] is the seek position of block i of length len[i].
01423    // Note that for nbuf=1, this call is equivalent to TFile::ReafBuffer.
01424    // This function is overloaded by TNetFile, TWebFile, etc.
01425    // Returns kTRUE in case of failure.
01426 
01427    // called with buf=0, from TFileCacheRead to pass list of readahead buffers
01428    if (!buf) {
01429       for (Int_t j = 0; j < nbuf; j++) {
01430          if (ReadBufferAsync(pos[j], len[j])) {
01431              return kTRUE;
01432          }
01433       }
01434       return kFALSE;
01435    }
01436 
01437    Int_t k = 0;
01438    Bool_t result = kTRUE;
01439    TFileCacheRead *old = fCacheRead;
01440    fCacheRead = 0;
01441    Long64_t curbegin = pos[0];
01442    Long64_t cur;
01443    char *buf2 = 0;
01444    Int_t i = 0, n = 0;
01445    while (i < nbuf) {
01446       cur = pos[i]+len[i];
01447       Bool_t bigRead = kTRUE;
01448       if (cur -curbegin < fgReadaheadSize) {n++; i++; bigRead = kFALSE;}
01449       if (bigRead || (i>=nbuf)) {
01450          if (n == 0) {
01451             //if the block to read is about the same size as the read-ahead buffer
01452             //we read the block directly
01453             Seek(pos[i]);
01454             result = ReadBuffer(&buf[k], len[i]);
01455             if (result) break;
01456             k += len[i];
01457             i++;
01458          } else {
01459             //otherwise we read all blocks that fit in the read-ahead buffer
01460             Seek(curbegin);
01461             if (buf2 == 0) buf2 = new char[fgReadaheadSize];
01462             //we read ahead
01463             Long64_t nahead = pos[i-1]+len[i-1]-curbegin;
01464             result = ReadBuffer(buf2, nahead);
01465             if (result) break;
01466             //now copy from the read-ahead buffer to the cache
01467             Int_t kold = k;
01468             for (Int_t j=0;j<n;j++) {
01469                memcpy(&buf[k],&buf2[pos[i-n+j]-curbegin],len[i-n+j]);
01470                k += len[i-n+j];
01471             }
01472             Int_t nok = k-kold;
01473             Long64_t extra = nahead-nok;
01474             fBytesReadExtra += extra;
01475             fBytesRead      -= extra;
01476             fgBytesRead     -= extra;
01477             n = 0;
01478          }
01479          curbegin = pos[i];
01480       }
01481    }
01482    if (buf2) delete [] buf2;
01483    fCacheRead = old;
01484    return result;
01485 }
01486 
01487 //______________________________________________________________________________
01488 Int_t TFile::ReadBufferViaCache(char *buf, Int_t len)
01489 {
01490    // Read buffer via cache. Returns 0 if the requested block is
01491    // not in the cache, 1 in case read via cache was successful,
01492    // 2 in case read via cache failed.
01493 
01494    Long64_t off = GetRelOffset();
01495    if (fCacheRead) {
01496       Int_t st = fCacheRead->ReadBuffer(buf, off, len);
01497       if (st < 0)
01498          return 2;  // failure reading
01499       else if (st == 1) {
01500          // fOffset might have been changed via TFileCacheRead::ReadBuffer(), reset it
01501          SetOffset(off + len);
01502          return 1;
01503       }
01504       // fOffset might have been changed via TFileCacheRead::ReadBuffer(), reset it
01505       Seek(off);
01506    } else {
01507       // if write cache is active check if data still in write cache
01508       if (fWritable && fCacheWrite) {
01509          if (fCacheWrite->ReadBuffer(buf, off, len) == 0) {
01510             SetOffset(off + len);
01511             return 1;
01512          }
01513          // fOffset might have been changed via TFileCacheWrite::ReadBuffer(), reset it
01514          SetOffset(off);
01515       }
01516    }
01517 
01518    return 0;
01519 }
01520 
01521 //______________________________________________________________________________
01522 void TFile::ReadFree()
01523 {
01524    // Read the FREE linked list.
01525    // Every file has a linked list (fFree) of free segments.
01526    // This linked list has been written on the file via WriteFree
01527    // as a single data record.
01528 
01529    TKey *headerfree = new TKey(fSeekFree, fNbytesFree, this);
01530    headerfree->ReadFile();
01531    char *buffer = headerfree->GetBuffer();
01532    headerfree->ReadKeyBuffer(buffer);
01533    buffer = headerfree->GetBuffer();
01534    while (1) {
01535       TFree *afree = new TFree();
01536       afree->ReadBuffer(buffer);
01537       fFree->Add(afree);
01538       if (afree->GetLast() > fEND) break;
01539    }
01540    delete headerfree;
01541 }
01542 
01543 //______________________________________________________________________________
01544 TProcessID  *TFile::ReadProcessID(UShort_t pidf)
01545 {
01546    //The TProcessID with number pidf is read from this file.
01547    //If the object is not already entered in the gROOT list, it is added.
01548 
01549    TProcessID *pid = 0;
01550    TObjArray *pids = GetListOfProcessIDs();
01551    if (pidf < pids->GetSize()) pid = (TProcessID *)pids->UncheckedAt(pidf);
01552    if (pid) {
01553       pid->CheckInit();
01554       return pid;
01555    }
01556 
01557    //check if fProcessIDs[uid] is set in file
01558    //if not set, read the process uid from file
01559    char pidname[32];
01560    snprintf(pidname,32,"ProcessID%d",pidf);
01561    pid = (TProcessID *)Get(pidname);
01562    if (gDebug > 0) {
01563       printf("ReadProcessID, name=%s, file=%s, pid=%lx\n",pidname,GetName(),(Long_t)pid);
01564    }
01565    if (!pid) {
01566       //file->Error("ReadProcessID","Cannot find %s in file %s",pidname,file->GetName());
01567       return pid;
01568    }
01569       //check that a similar pid is not already registered in fgPIDs
01570    TObjArray *pidslist = TProcessID::GetPIDs();
01571    TIter next(pidslist);
01572    TProcessID *p;
01573    while ((p = (TProcessID*)next())) {
01574       if (!strcmp(p->GetTitle(),pid->GetTitle())) {
01575          delete pid;
01576          pids->AddAtAndExpand(p,pidf);
01577          p->IncrementCount();
01578          return p;
01579       }
01580    }
01581    pids->AddAtAndExpand(pid,pidf);
01582    pid->IncrementCount();
01583    pidslist->Add(pid);
01584    Int_t ind = pidslist->IndexOf(pid);
01585    pid->SetUniqueID((UInt_t)ind);
01586    return pid;
01587 }
01588 
01589 
01590 //______________________________________________________________________________
01591 Int_t TFile::Recover()
01592 {
01593    // Attempt to recover file if not correctly closed.
01594    // The function returns the number of keys that have been recovered.
01595    // If no keys can be recovered, the file will be declared Zombie by
01596    // the calling function. This function is automatically called when
01597    // opening a file.
01598    //
01599    // If the file is open in read only mode, the file is not modified.
01600    // If open in update mode and the function finds something to recover,
01601    //  a new directory header is written to the file. When opening the file gain
01602    //  no message from Recover will be reported.
01603    // If keys have been recovered, the file is usable and you can safely
01604    // read the corresponding objects.
01605    // If the file is not usable (a zombie), you can test for this case
01606    // with code like:
01607    //   TFile f("myfile.root");
01608    //   if (f.IsZombie()) {file is unusable)
01609    // If the file has been recovered, the bit kRecovered is set in the TFile object in memory.
01610    // You can test if the file has been recovered with
01611    //   if (f.TestBit(TFile::kRecovered)) {.. the file has been recovered}
01612    //
01613    // When writing TTrees to a file, it is important to save the Tree header
01614    // at regular intervals (see TTree::AutoSave). If a file containing a Tree
01615    // is recovered, the last Tree header written to the file will be used.
01616    // In this case all the entries in all the branches written before writing
01617    // the header are valid entries.
01618    //
01619    // One can disable the automatic recovery procedure by setting
01620    // TFile.Recover 0
01621    // in the system.rootrc file.
01622 
01623    Short_t  keylen,cycle;
01624    UInt_t   datime;
01625    Int_t    nbytes,date,time,objlen,nwheader;
01626    Long64_t seekkey,seekpdir;
01627    char     header[1024];
01628    char    *buffer, *bufread;
01629    char     nwhc;
01630    Long64_t idcur = fBEGIN;
01631 
01632    Long64_t size;
01633    if ((size = GetSize()) == -1) {
01634       Error("Recover", "cannot stat the file %s", GetName());
01635       return 0;
01636    }
01637 
01638    fEND = Long64_t(size);
01639 
01640    if (fWritable && !fFree) fFree  = new TList;
01641 
01642    TKey *key;
01643    Int_t nrecov = 0;
01644    nwheader = 1024;
01645    Int_t nread = nwheader;
01646 
01647    while (idcur < fEND) {
01648       Seek(idcur);
01649       if (idcur+nread >= fEND) nread = fEND-idcur-1;
01650       ReadBuffer(header, nread);
01651       buffer  = header;
01652       bufread = header;
01653       frombuf(buffer, &nbytes);
01654       if (!nbytes) {
01655          Printf("Address = %lld\tNbytes = %d\t=====E R R O R=======", idcur, nbytes);
01656          break;
01657       }
01658       if (nbytes < 0) {
01659          idcur -= nbytes;
01660          if (fWritable) new TFree(fFree,idcur,idcur-nbytes-1);
01661          Seek(idcur);
01662          continue;
01663       }
01664       Version_t versionkey;
01665       frombuf(buffer, &versionkey);
01666       frombuf(buffer, &objlen);
01667       frombuf(buffer, &datime);
01668       frombuf(buffer, &keylen);
01669       frombuf(buffer, &cycle);
01670       if (versionkey > 1000) {
01671          frombuf(buffer, &seekkey);
01672          frombuf(buffer, &seekpdir);
01673       } else {
01674          Int_t skey,sdir;
01675          frombuf(buffer, &skey);  seekkey  = (Long64_t)skey;
01676          frombuf(buffer, &sdir);  seekpdir = (Long64_t)sdir;
01677       }
01678       frombuf(buffer, &nwhc);
01679       char *classname = 0;
01680       if (nwhc <= 0 || nwhc > 100) break;
01681       classname = new char[nwhc+1];
01682       int i, nwhci = nwhc;
01683       for (i = 0;i < nwhc; i++) frombuf(buffer, &classname[i]);
01684       classname[nwhci] = '\0';
01685       TDatime::GetDateTime(datime, date, time);
01686       TClass *tclass = TClass::GetClass(classname);
01687       if (seekpdir == fSeekDir && tclass && !tclass->InheritsFrom(TFile::Class())
01688                                && strcmp(classname,"TBasket")) {
01689          key = new TKey(this);
01690          key->ReadKeyBuffer(bufread);
01691          if (!strcmp(key->GetName(),"StreamerInfo")) {
01692             fSeekInfo = seekkey;
01693             SafeDelete(fInfoCache);
01694             fNbytesInfo = nbytes;
01695          } else {
01696             AppendKey(key);
01697             nrecov++;
01698             SetBit(kRecovered);
01699             Info("Recover", "%s, recovered key %s:%s at address %lld",GetName(),key->GetClassName(),key->GetName(),idcur);
01700          }
01701       }
01702       delete [] classname;
01703       idcur += nbytes;
01704    }
01705    if (fWritable) {
01706       Long64_t max_file_size = Long64_t(kStartBigFile);
01707       if (max_file_size < fEND) max_file_size = fEND+1000000000;
01708       TFree *last = (TFree*)fFree->Last();
01709       if (last) {
01710          last->AddFree(fFree,fEND,max_file_size);
01711       } else {
01712          new TFree(fFree,fEND,max_file_size);
01713       }
01714       if (nrecov) Write();
01715    }
01716    return nrecov;
01717 }
01718 
01719 //______________________________________________________________________________
01720 Int_t TFile::ReOpen(Option_t *mode)
01721 {
01722    // Reopen a file with a different access mode, like from READ to
01723    // UPDATE or from NEW, CREATE, RECREATE, UPDATE to READ. Thus the
01724    // mode argument can be either "READ" or "UPDATE". The method returns
01725    // 0 in case the mode was successfully modified, 1 in case the mode
01726    // did not change (was already as requested or wrong input arguments)
01727    // and -1 in case of failure, in which case the file cannot be used
01728    // anymore. The current directory (gFile) is changed to this file.
01729 
01730    cd();
01731 
01732    TString opt = mode;
01733    opt.ToUpper();
01734 
01735    if (opt != "READ" && opt != "UPDATE") {
01736       Error("ReOpen", "mode must be either READ or UPDATE, not %s", opt.Data());
01737       return 1;
01738    }
01739 
01740    if (opt == fOption || (opt == "UPDATE" && fOption == "CREATE"))
01741       return 1;
01742 
01743    if (opt == "READ") {
01744       // switch to READ mode
01745 
01746       // flush data still in the pipeline and close the file
01747       if (IsOpen() && IsWritable()) {
01748          WriteStreamerInfo();
01749 
01750          // save directory key list and header
01751          Save();
01752 
01753          TFree *f1 = (TFree*)fFree->First();
01754          if (f1) {
01755             WriteFree();       // write free segments linked list
01756             WriteHeader();     // now write file header
01757          }
01758 
01759          FlushWriteCache();
01760 
01761          // delete free segments from free list
01762          if (fFree) {
01763             fFree->Delete();
01764             SafeDelete(fFree);
01765          }
01766 
01767          SysClose(fD);
01768          fD = -1;
01769 
01770          SetWritable(kFALSE);
01771       }
01772 
01773       // open in READ mode
01774       fOption = opt;    // set fOption before SysOpen() for TNetFile
01775 #ifndef WIN32
01776       fD = SysOpen(fRealName, O_RDONLY, 0644);
01777 #else
01778       fD = SysOpen(fRealName, O_RDONLY | O_BINARY, S_IREAD | S_IWRITE);
01779 #endif
01780       if (fD == -1) {
01781          SysError("ReOpen", "file %s can not be opened in read mode", GetName());
01782          return -1;
01783       }
01784       SetWritable(kFALSE);
01785 
01786    } else {
01787       // switch to UPDATE mode
01788 
01789       // close readonly file
01790       if (IsOpen()) {
01791          SysClose(fD);
01792          fD = -1;
01793       }
01794 
01795       // open in UPDATE mode
01796       fOption = opt;    // set fOption before SysOpen() for TNetFile
01797 #ifndef WIN32
01798       fD = SysOpen(fRealName, O_RDWR | O_CREAT, 0644);
01799 #else
01800       fD = SysOpen(fRealName, O_RDWR | O_CREAT | O_BINARY, S_IREAD | S_IWRITE);
01801 #endif
01802       if (fD == -1) {
01803          SysError("ReOpen", "file %s can not be opened in update mode", GetName());
01804          return -1;
01805       }
01806       SetWritable(kTRUE);
01807 
01808       fFree = new TList;
01809       if (fSeekFree > fBEGIN)
01810          ReadFree();
01811       else
01812          Warning("ReOpen","file %s probably not closed, cannot read free segments", GetName());
01813    }
01814 
01815    return 0;
01816 }
01817 
01818 //______________________________________________________________________________
01819 void TFile::SetOffset(Long64_t offset, ERelativeTo pos)
01820 {
01821    // Set position from where to start reading.
01822 
01823    switch (pos) {
01824       case kBeg:
01825          fOffset = offset + fArchiveOffset;
01826          break;
01827       case kCur:
01828          fOffset += offset;
01829          break;
01830       case kEnd:
01831          // this option is not used currently in the ROOT code
01832          if (fArchiveOffset)
01833             Error("SetOffset", "seeking from end in archive is not (yet) supported");
01834          fOffset = fEND + offset;  // is fEND really EOF or logical EOF?
01835          break;
01836    }
01837 }
01838 
01839 //______________________________________________________________________________
01840 void TFile::Seek(Long64_t offset, ERelativeTo pos)
01841 {
01842    // Seek to a specific position in the file. Pos it either kBeg, kCur or kEnd.
01843 
01844    int whence = 0;
01845    switch (pos) {
01846       case kBeg:
01847          whence = SEEK_SET;
01848          offset += fArchiveOffset;
01849          break;
01850       case kCur:
01851          whence = SEEK_CUR;
01852          break;
01853       case kEnd:
01854          whence = SEEK_END;
01855          // this option is not used currently in the ROOT code
01856          if (fArchiveOffset)
01857             Error("Seek", "seeking from end in archive is not (yet) supported");
01858          break;
01859    }
01860    Long64_t retpos;
01861    if ((retpos = SysSeek(fD, offset, whence)) < 0)
01862       SysError("Seek", "cannot seek to position %lld in file %s, retpos=%lld",
01863                offset, GetName(), retpos);
01864 
01865    // used by TFileCacheRead::ReadBuffer()
01866    fOffset = retpos;
01867 }
01868 
01869 //______________________________________________________________________________
01870 void TFile::SetCompressionLevel(Int_t level)
01871 {
01872    // Set level of compression for this file:
01873    //  level = 0 objects written to this file will not be compressed.
01874    //  level = 1 minimal compression level but fast.
01875    //  ....
01876    //  level = 9 maximal compression level but slow.
01877    //
01878    // Note that the compression level may be changed at any time.
01879    // The new compression level will only apply to newly written objects.
01880    // The function TFile::Map shows the compression factor
01881    // for each object written to this file.
01882    // The function TFile::GetCompressionFactor returns the global
01883    // compression factor for this file.
01884 
01885    if (level < 0) level = 0;
01886    if (level > 9) level = 9;
01887    fCompress = level;
01888 }
01889 
01890 //______________________________________________________________________________
01891 void TFile::SetCacheRead(TFileCacheRead *cache)
01892 {
01893    // Set a pointer to the read cache.
01894    // NOTE:  This relinquish ownership of the previous cache, so if you do not
01895    // already have a pointer to the previous cache (and there was a previous
01896    // cache), you ought to retrieve (and delete it if needed) using:
01897    //    TFileCacheRead *older = myfile->GetCacheRead();
01898 
01899    fCacheRead = cache;
01900 }
01901 
01902 //______________________________________________________________________________
01903 void TFile::SetCacheWrite(TFileCacheWrite *cache)
01904 {
01905    // Set a pointer to the write cache.
01906    // If file is null the existing write cache is deleted.
01907 
01908    if (!cache && fCacheWrite) delete fCacheWrite;
01909    fCacheWrite = cache;
01910 }
01911 
01912 //______________________________________________________________________________
01913 Int_t TFile::Sizeof() const
01914 {
01915    // Return the size in bytes of the file header.
01916 
01917    return 0;
01918 }
01919 
01920 //_______________________________________________________________________
01921 void TFile::Streamer(TBuffer &b)
01922 {
01923    // Stream a TFile object.
01924 
01925    if (b.IsReading()) {
01926       b.ReadVersion();  //Version_t v = b.ReadVersion();
01927    } else {
01928       b.WriteVersion(TFile::IsA());
01929    }
01930 }
01931 
01932 //_______________________________________________________________________
01933 void TFile::SumBuffer(Int_t bufsize)
01934 {
01935    // Increment statistics for buffer sizes of objects in this file.
01936 
01937    fWritten++;
01938    fSumBuffer  += bufsize;
01939    fSum2Buffer += bufsize*bufsize;
01940 }
01941 
01942 //_______________________________________________________________________
01943 void TFile::UseCache(Int_t /*maxCacheSize*/, Int_t /*pageSize*/)
01944 {
01945    // Dummy function kept for backward compatibility.
01946    // The read  cache is now managed by TFileCacheRead
01947    // The write cache is now managed by TFileCacheWrite
01948    // Both caches are created automatically by the system.
01949 
01950 }
01951 
01952 //______________________________________________________________________________
01953 Int_t TFile::Write(const char *, Int_t opt, Int_t bufsiz)
01954 {
01955    // Write memory objects to this file.
01956    // Loop on all objects in memory (including subdirectories).
01957    // A new key is created in the KEYS linked list for each object.
01958    // The list of keys is then saved on the file (via WriteKeys)
01959    // as a single data record.
01960    // For values of opt see TObject::Write().
01961    // The directory header info is rewritten on the directory header record.
01962    // The linked list of FREE segments is written.
01963    // The file header is written (bytes 1->fBEGIN).
01964 
01965    if (!IsWritable()) {
01966       if (!TestBit(kWriteError)) {
01967          // Do not print the warning if we already had a SysError.
01968          Warning("Write", "file %s not opened in write mode", GetName());
01969       }
01970       return 0;
01971    }
01972 
01973    TDirectory *cursav = gDirectory;
01974    cd();
01975 
01976    if (gDebug) {
01977       if (!GetTitle() || strlen(GetTitle()) == 0)
01978          Info("Write", "writing name = %s", GetName());
01979       else
01980          Info("Write", "writing name = %s title = %s", GetName(), GetTitle());
01981    }
01982 
01983    fMustFlush = kFALSE;
01984    Int_t nbytes = TDirectoryFile::Write(0, opt, bufsiz); // Write directory tree
01985    WriteStreamerInfo();
01986    WriteFree();                       // Write free segments linked list
01987    WriteHeader();                     // Now write file header
01988    fMustFlush = kTRUE;
01989 
01990    if (cursav) {
01991       cursav->cd();
01992    } else {
01993       gDirectory = 0;
01994    }
01995    return nbytes;
01996 }
01997 
01998 //______________________________________________________________________________
01999 Int_t TFile::Write(const char *n, Int_t opt, Int_t bufsize) const
02000 {
02001    // One can not save a const TDirectory object.
02002 
02003    Error("Write const","A const TFile object should not be saved. We try to proceed anyway.");
02004    return const_cast<TFile*>(this)->Write(n, opt, bufsize);
02005 }
02006 
02007 //______________________________________________________________________________
02008 Bool_t TFile::WriteBuffer(const char *buf, Int_t len)
02009 {
02010    // Write a buffer to the file. This is the basic low level write operation.
02011    // Returns kTRUE in case of failure.
02012 
02013    if (IsOpen() && fWritable) {
02014 
02015       Int_t st;
02016       if ((st = WriteBufferViaCache(buf, len))) {
02017          if (st == 2)
02018             return kTRUE;
02019          return kFALSE;
02020       }
02021 
02022       ssize_t siz;
02023       gSystem->IgnoreInterrupt();
02024       while ((siz = SysWrite(fD, buf, len)) < 0 && GetErrno() == EINTR)
02025          ResetErrno();
02026       gSystem->IgnoreInterrupt(kFALSE);
02027       if (siz < 0) {
02028          // Write the system error only once for this file
02029          SetBit(kWriteError); SetWritable(kFALSE);
02030          SysError("WriteBuffer", "error writing to file %s (%ld)", GetName(), (Long_t)siz);
02031          return kTRUE;
02032       }
02033       if (siz != len) {
02034          SetBit(kWriteError);
02035          Error("WriteBuffer", "error writing all requested bytes to file %s, wrote %ld of %d",
02036                GetName(), (Long_t)siz, len);
02037          return kTRUE;
02038       }
02039       fBytesWrite  += siz;
02040       fgBytesWrite += siz;
02041 
02042       if (gMonitoringWriter)
02043          gMonitoringWriter->SendFileWriteProgress(this);
02044 
02045       return kFALSE;
02046    }
02047    return kTRUE;
02048 }
02049 
02050 //______________________________________________________________________________
02051 Int_t TFile::WriteBufferViaCache(const char *buf, Int_t len)
02052 {
02053    // Write buffer via cache. Returns 0 if cache is not active, 1 in case
02054    // write via cache was successful, 2 in case write via cache failed.
02055 
02056    if (!fCacheWrite) return 0;
02057 
02058    Int_t st;
02059    Long64_t off = GetRelOffset();
02060    if ((st = fCacheWrite->WriteBuffer(buf, off, len)) < 0) {
02061       SetBit(kWriteError);
02062       Error("WriteBuffer", "error writing to cache");
02063       return 2;
02064    }
02065    if (st > 0) {
02066       // fOffset might have been changed via TFileCacheWrite::WriteBuffer(), reset it
02067       Seek(off + len);
02068       return 1;
02069    }
02070    return 0;
02071 }
02072 
02073 //______________________________________________________________________________
02074 void TFile::WriteFree()
02075 {
02076    // Write FREE linked list on the file.
02077    // The linked list of FREE segments (fFree) is written as a single data
02078    // record.
02079 
02080    //*-* Delete old record if it exists
02081    if (fSeekFree != 0){
02082       MakeFree(fSeekFree, fSeekFree + fNbytesFree -1);
02083    }
02084 
02085    Int_t nbytes = 0;
02086    TFree *afree;
02087    TIter next (fFree);
02088    while ((afree = (TFree*) next())) {
02089       nbytes += afree->Sizeof();
02090    }
02091    if (!nbytes) return;
02092 
02093    TKey *key    = new TKey(fName,fTitle,IsA(),nbytes,this);
02094    if (key->GetSeekKey() == 0) {
02095       delete key;
02096       return;
02097    }
02098    char *buffer = key->GetBuffer();
02099    char *start = buffer;
02100 
02101    next.Reset();
02102    while ((afree = (TFree*) next())) {
02103       afree->FillBuffer(buffer);
02104    }
02105    if ( (buffer-start)!=nbytes ) {
02106       // Most likely one of the 'free' segment was used to store this
02107       // TKey, so we had one less TFree to store than we planned.
02108       memset(buffer,0,nbytes-(buffer-start));
02109    }
02110    fNbytesFree = key->GetNbytes();
02111    fSeekFree   = key->GetSeekKey();
02112    key->WriteFile();
02113    delete key;
02114 }
02115 
02116 //______________________________________________________________________________
02117 void TFile::WriteHeader()
02118 {
02119    // Write File Header.
02120 
02121    SafeDelete(fInfoCache);
02122    TFree *lastfree = (TFree*)fFree->Last();
02123    if (lastfree) fEND  = lastfree->GetFirst();
02124    const char *root = "root";
02125    char *psave  = new char[fBEGIN];
02126    char *buffer = psave;
02127    Int_t nfree  = fFree->GetSize();
02128    memcpy(buffer, root, 4); buffer += 4;
02129    Int_t version = fVersion;
02130    if (version <1000000 && fEND > kStartBigFile) {version += 1000000; fUnits = 8;}
02131    tobuf(buffer, version);
02132    tobuf(buffer, (Int_t)fBEGIN);
02133    if (version < 1000000) {
02134       tobuf(buffer, (Int_t)fEND);
02135       tobuf(buffer, (Int_t)fSeekFree);
02136       tobuf(buffer, fNbytesFree);
02137       tobuf(buffer, nfree);
02138       tobuf(buffer, fNbytesName);
02139       tobuf(buffer, fUnits);
02140       tobuf(buffer, fCompress);
02141       tobuf(buffer, (Int_t)fSeekInfo);
02142       tobuf(buffer, fNbytesInfo);
02143    } else {
02144       tobuf(buffer, fEND);
02145       tobuf(buffer, fSeekFree);
02146       tobuf(buffer, fNbytesFree);
02147       tobuf(buffer, nfree);
02148       tobuf(buffer, fNbytesName);
02149       tobuf(buffer, fUnits);
02150       tobuf(buffer, fCompress);
02151       tobuf(buffer, fSeekInfo);
02152       tobuf(buffer, fNbytesInfo);
02153    }
02154    fUUID.FillBuffer(buffer);
02155    Int_t nbytes  = buffer - psave;
02156    Seek(0);
02157    WriteBuffer(psave, nbytes);
02158    Flush();
02159    delete [] psave;
02160 }
02161 
02162 //______________________________________________________________________________
02163 void TFile::MakeProject(const char *dirname, const char * /*classes*/,
02164                         Option_t *option)
02165 {
02166    // Generate code in directory dirname for all classes specified in
02167    // argument classes If classes = "*" (default and currently the
02168    // only supported value), the function generates an include file
02169    // for each class in the StreamerInfo list for which a TClass
02170    // object does not exist.
02171    //
02172    // The code generated includes:
02173    //    dirnameProjectHeaders.h  // contains one #include statement per generated header file
02174    //    dirnameProjectSource.cxx // contains all the constructors and destructors implementation.
02175    // and one header per class that is not nested inside another class.
02176    // The header file name is the fully qualified name of the class after all the special characters
02177    // "<>,:" are replaced by underscored.  For example for pair<edm::Vertex,int> the file name is
02178    // pair_edm__Vertex_int_.h
02179    //
02180    // In the generated classes, map, multimap when the first template parameter is a class
02181    // are replaced by a vector of pair. set and multiset when the tempalte parameter
02182    // is a class are replaced by a vector. This is required since we do not have the
02183    // code needed to order and/or compare the object of the classes.
02184    //
02185    // If option = "new" (default) a new directory dirname is created.
02186    //                   If dirname already exist, an error message is printed
02187    //                   and the function returns.
02188    // If option = "recreate", then;
02189    //                   if dirname does not exist, it is created (like in "new")
02190    //                   if dirname already exist, all existing files in dirname
02191    //                   are deleted before creating the new files.
02192    // If option = "update", then new classes are added to the existing directory.
02193    //                   Existing classes with the same name are replaced by the
02194    //                   new definition. If the directory dirname doest not exist,
02195    //                   same effect as "new".
02196    // If option = "genreflex", then use genreflex rather than rootcint to generate
02197    //                   the dictionary.
02198    // If, in addition to one of the 3 above options, the option "+" is specified,
02199    // the function will generate:
02200    //   - a script called MAKEP to build the shared lib
02201    //   - a dirnameLinkDef.h file
02202    //   - rootcint will be run to generate a dirnameProjectDict.cxx file
02203    //   - dirnameProjectDict.cxx will be compiled with the current options in compiledata.h
02204    //   - a shared lib dirname.so will be created.
02205    // If the option "++" is specified, the generated shared lib is dynamically
02206    // linked with the current executable module.
02207    // If the option "+" and "nocompile" are specified, the utility files are generated
02208    // as in the option "+" but they are not executed.
02209    // Example:
02210    //  file.MakeProject("demo","*","recreate++");
02211    //  - creates a new directory demo unless it already exist
02212    //  - clear the previous directory content
02213    //  - generate the xxx.h files for all classes xxx found in this file
02214    //    and not yet known to the CINT dictionary.
02215    //  - creates the build script MAKEP
02216    //  - creates a LinkDef.h file
02217    //  - runs rootcint generating demoProjectDict.cxx
02218    //  - compiles demoProjectDict.cxx into demoProjectDict.o
02219    //  - generates a shared lib demo.so
02220    //  - dynamically links the shared lib demo.so to the executable
02221    //  If only the option "+" had been specified, one can still link the
02222    //  shared lib to the current executable module with:
02223    //     gSystem->load("demo/demo.so");
02224    //
02225    // The following feature is not yet enabled:
02226    // One can restrict the list of classes to be generated by using expressions like:
02227    //   classes = "Ali*" generate code only for classes starting with Ali
02228    //   classes = "myClass" generate code for class MyClass only.
02229    //
02230 
02231    TString opt = option;
02232    opt.ToLower();
02233    {
02234       void *dir = gSystem->OpenDirectory(dirname);
02235       TString dirpath;
02236 
02237       if (opt.Contains("update")) {
02238          // check that directory exist, if not create it
02239          if (dir == 0) {
02240             gSystem->mkdir(dirname);
02241          }
02242          
02243       } else if (opt.Contains("recreate")) {
02244          // check that directory exist, if not create it
02245          if (dir == 0) {
02246             gSystem->mkdir(dirname);
02247          }
02248          // clear directory
02249          while (dir) {
02250             const char *afile = gSystem->GetDirEntry(dir);
02251             if (afile == 0) break;
02252             if (strcmp(afile,".") == 0) continue;
02253             if (strcmp(afile,"..") == 0) continue;
02254             dirpath.Form("%s/%s",dirname,afile);
02255             gSystem->Unlink(dirpath);
02256          }
02257          
02258       } else {
02259          // new is assumed
02260          // if directory already exist, print error message and return
02261          if (dir) {
02262             Error("MakeProject","cannot create directory %s, already existing",dirname);
02263             gSystem->FreeDirectory(dir);
02264             return;
02265          }
02266          gSystem->mkdir(dirname);
02267       }
02268       if (dir) {
02269          gSystem->FreeDirectory(dir);
02270       }
02271    }
02272    Bool_t genreflex = opt.Contains("genreflex");
02273 
02274    // we are now ready to generate the classes
02275    // loop on all TStreamerInfo
02276    TList *filelist = (TList*)GetStreamerInfoCache()->Clone();
02277    if (filelist == 0) {
02278       Error("MakeProject","file %s has no StreamerInfo", GetName());
02279       return;
02280    }
02281 
02282    // Start the source file
02283    TString spath; spath.Form("%s/%sProjectSource.cxx",dirname,dirname);
02284    FILE *sfp = fopen(spath.Data(),"w");
02285    fprintf(sfp, "#include \"%sProjectHeaders.h\"\n\n",dirname );
02286    if (!genreflex) fprintf(sfp, "#include \"%sLinkDef.h\"\n\n",dirname );
02287    fprintf(sfp, "#include \"%sProjectDict.cxx\"\n\n",dirname );
02288    fprintf(sfp, "struct DeleteObjectFunctor {\n");
02289    fprintf(sfp, "   template <typename T>\n");
02290    fprintf(sfp, "   void operator()(const T *ptr) const {\n");
02291    fprintf(sfp, "      delete ptr;\n");
02292    fprintf(sfp, "   }\n");
02293    fprintf(sfp, "   template <typename T, typename Q>\n");
02294    fprintf(sfp, "   void operator()(const std::pair<T,Q> &) const {\n");
02295    fprintf(sfp, "      // Do nothing\n");
02296    fprintf(sfp, "   }\n");
02297    fprintf(sfp, "   template <typename T, typename Q>\n");
02298    fprintf(sfp, "   void operator()(const std::pair<T,Q*> &ptr) const {\n");
02299    fprintf(sfp, "      delete ptr.second;\n");
02300    fprintf(sfp, "   }\n");
02301    fprintf(sfp, "   template <typename T, typename Q>\n");
02302    fprintf(sfp, "   void operator()(const std::pair<T*,Q> &ptr) const {\n");
02303    fprintf(sfp, "      delete ptr.first;\n");
02304    fprintf(sfp, "   }\n");
02305    fprintf(sfp, "   template <typename T, typename Q>\n");
02306    fprintf(sfp, "   void operator()(const std::pair<T*,Q*> &ptr) const {\n");
02307    fprintf(sfp, "      delete ptr.first;\n");
02308    fprintf(sfp, "      delete ptr.second;\n");
02309    fprintf(sfp, "   }\n");
02310    fprintf(sfp, "};\n\n");
02311    fclose( sfp );
02312 
02313    // loop on all TStreamerInfo classes to check for empty classes
02314    // and enums listed either as data member or template parameters,
02315    // and filter out 'duplicates' classes/streamerInfos.
02316    TStreamerInfo *info;
02317    TIter flnext(filelist);
02318    TList extrainfos;
02319    TList *list = new TList();
02320    while ((info = (TStreamerInfo*)flnext())) {
02321       if (info->IsA() != TStreamerInfo::Class()) {
02322          continue;
02323       }
02324       TClass *cl = TClass::GetClass(info->GetName());
02325       if (cl) {
02326          if (cl->GetClassInfo()) continue; // skip known classes
02327       }
02328       // Find and use the proper rules for the TStreamerInfos.
02329       TMakeProject::GenerateMissingStreamerInfos( &extrainfos, info->GetName() );
02330       TIter enext( info->GetElements() );
02331       TStreamerElement *el;
02332       const ROOT::TSchemaMatch* rules = 0;
02333       if (cl && cl->GetSchemaRules()) {
02334          rules = cl->GetSchemaRules()->FindRules(cl->GetName(), info->GetClassVersion());
02335       }
02336       while( (el=(TStreamerElement*)enext()) ) {
02337          if (rules) {
02338             for(Int_t art = 0; art < rules->GetEntries(); ++art) {
02339                ROOT::TSchemaRule *rule = (ROOT::TSchemaRule*)rules->At(art);
02340                if( rule->IsRenameRule() || rule->IsAliasRule() )
02341                   continue;
02342                // Check whether this is an 'attribute' rule.
02343                if ( rule->HasTarget( el->GetName()) && rule->GetAttributes()[0] != 0 ) {
02344                   TString attr( rule->GetAttributes() );
02345                   attr.ToLower();
02346                   if (attr.Contains("owner")) {
02347                      if (attr.Contains("notowner")) {
02348                         el->SetBit(TStreamerElement::kDoNotDelete);
02349                      } else {
02350                         el->ResetBit(TStreamerElement::kDoNotDelete);
02351                      }
02352                   }
02353                }
02354             }
02355          }
02356          TMakeProject::GenerateMissingStreamerInfos(&extrainfos, el);
02357       }
02358       delete rules;
02359       TVirtualStreamerInfo *alternate = (TVirtualStreamerInfo*)list->FindObject(info->GetName());
02360       if (alternate) {
02361          if ((info->GetClass() && info->GetClassVersion() == info->GetClass()->GetClassVersion())
02362              || (info->GetClassVersion() > alternate->GetClassVersion()) ) {
02363             list->AddAfter(alternate, info);
02364             list->Remove(alternate);
02365          } // otherwise ingnore this info as not being the official one.
02366       } else {
02367          list->Add(info);
02368       }
02369    }
02370    // Now transfer the new StreamerInfo onto the main list and
02371    // to the owning list.
02372    TIter nextextra(&extrainfos);
02373    while ((info = (TStreamerInfo*)nextextra())) {
02374       list->Add(info);
02375       filelist->Add(info);
02376    }
02377 
02378    // loop on all TStreamerInfo classes
02379    TIter next(list);
02380    Int_t ngener = 0;
02381    while ((info = (TStreamerInfo*)next())) {
02382       if (info->IsA() != TStreamerInfo::Class()) {
02383          continue;
02384       }
02385       if (info->GetClassVersion()==-4) continue; // Skip outer level namespace
02386       TIter subnext(list);
02387       TStreamerInfo *subinfo;
02388       TList subClasses;
02389       Int_t len = strlen(info->GetName());
02390       while ((subinfo = (TStreamerInfo*)subnext())) {
02391          if (subinfo->IsA() != TStreamerInfo::Class()) {
02392             continue;
02393          }
02394          if (strncmp(info->GetName(),subinfo->GetName(),len)==0) {
02395             // The 'sub' StreamerInfo start with the main StreamerInfo name,
02396             // it subinfo is likely to be a nested class.
02397             const Int_t sublen = strlen(subinfo->GetName());
02398             if ( (sublen > len) && subinfo->GetName()[len+1]==':'
02399                && !subClasses.FindObject(subinfo->GetName()) /* We need to insure uniqueness */)
02400             {
02401                subClasses.Add(subinfo);
02402             }
02403          }
02404       }
02405       ngener += info->GenerateHeaderFile(dirname,&subClasses,&extrainfos);
02406       subClasses.Clear("nodelete");
02407    }
02408    TString path;
02409    path.Form("%s/%sProjectHeaders.h",dirname,dirname);
02410    FILE *allfp = fopen(path,"a");
02411    if (!allfp) {
02412       Error("MakeProject","Cannot open output file:%s\n",path.Data());
02413    } else {
02414       fprintf(allfp,"#include \"%sProjectInstances.h\"\n", dirname);
02415       fclose(allfp);
02416    }
02417 
02418    printf("MakeProject has generated %d classes in %s\n",ngener,dirname);
02419 
02420    // generate the shared lib
02421    if (!opt.Contains("+")) {
02422       delete list;
02423       filelist->Delete();
02424       delete filelist;
02425       return;
02426    }
02427 
02428    // create the MAKEP file by looping on all *.h files
02429    // delete MAKEP if it already exists
02430 #ifdef WIN32
02431    path.Form("%s/makep.cmd",dirname);
02432 #else
02433    path.Form("%s/MAKEP",dirname);
02434 #endif
02435 #ifdef R__WINGCC
02436    FILE *fpMAKE = fopen(path,"wb");
02437 #else
02438    FILE *fpMAKE = fopen(path,"w");
02439 #endif
02440    if (!fpMAKE) {
02441       Error("MakeProject", "cannot open file %s", path.Data());
02442       delete list;
02443       filelist->Delete();
02444       delete filelist;
02445       return;
02446    }
02447 
02448    // Add rootcint/genreflex statement generating ProjectDict.cxx
02449    FILE *ifp = 0;
02450    path.Form("%s/%sProjectInstances.h",dirname,dirname);
02451 #ifdef R__WINGCC
02452    ifp = fopen(path,"wb");
02453 #else
02454    ifp = fopen(path,"w");
02455 #endif
02456    if (!ifp) {
02457       Error("MakeProject", "cannot open path file %s", path.Data());
02458       delete list;
02459       filelist->Delete();
02460       delete filelist;
02461       fclose(fpMAKE);
02462       return;
02463    }
02464 
02465    if (genreflex) {
02466       fprintf(fpMAKE,"genreflex %sProjectHeaders.h -o %sProjectDict.cxx --comments --iocomments %s ",dirname,dirname,gSystem->GetIncludePath());
02467       path.Form("%s/%sSelection.xml",dirname,dirname);
02468    } else {
02469       fprintf(fpMAKE,"rootcint -f %sProjectDict.cxx -c %s ",dirname,gSystem->GetIncludePath());
02470       path.Form("%s/%sLinkDef.h",dirname,dirname);
02471    }
02472    // Create the LinkDef.h or xml selection file by looping on all *.h files
02473    // replace any existing file.
02474 #ifdef R__WINGCC
02475    FILE *fp = fopen(path,"wb");
02476 #else
02477    FILE *fp = fopen(path,"w");
02478 #endif
02479    if (!fp) {
02480       Error("MakeProject", "cannot open path file %s", path.Data());
02481       delete list;
02482       filelist->Delete();
02483       delete filelist;
02484       fclose(fpMAKE);
02485       fclose(ifp);
02486       return;
02487    }
02488    if (genreflex) {
02489       fprintf(fp,"<lcgdict>\n");
02490       fprintf(fp,"\n");
02491    } else {
02492       fprintf(fp,"#ifdef __CINT__\n");
02493       fprintf(fp,"\n");
02494    }
02495 
02496    TString tmp;
02497    TString instances;
02498    TString selections;
02499    next.Reset();
02500    while ((info = (TStreamerInfo*)next())) {
02501       if (info->IsA() != TStreamerInfo::Class()) {
02502          continue;
02503       }
02504       TClass *cl = TClass::GetClass(info->GetName());
02505       if (cl) {
02506          if (cl->GetClassInfo()) continue; // skip known classes
02507          const ROOT::TSchemaMatch* rules = 0;
02508          if (cl->GetSchemaRules()) {
02509             rules = cl->GetSchemaRules()->FindRules(cl->GetName(), info->GetClassVersion());
02510             TString strrule;
02511             if (rules) {
02512                for(Int_t art = 0; art < rules->GetEntries(); ++art) {
02513                   ROOT::TSchemaRule *rule = (ROOT::TSchemaRule*)rules->At(art);
02514                   strrule.Clear();
02515                   if (genreflex) {
02516                      rule->AsString(strrule,"x");
02517                      strrule.Append("\n");
02518                      if ( selections.Index(strrule) == kNPOS ) {
02519                         selections.Append(strrule);
02520                      }
02521                   } else {
02522                      rule->AsString(strrule);
02523                      if (strncmp(strrule.Data(),"type=",5)==0) {
02524                         strrule.Remove(0,5);
02525                      }
02526                      fprintf(fp,"#pragma %s;\n",strrule.Data());
02527                   }
02528                }
02529             }
02530             delete rules;
02531          }
02532 
02533       }
02534       if (TClassEdit::IsSTLCont(info->GetName())) {
02535          std::vector<std::string> inside;
02536          int nestedLoc;
02537          TClassEdit::GetSplit( info->GetName(), inside, nestedLoc, TClassEdit::kLong64 );
02538          Int_t stlkind =  TClassEdit::STLKind(inside[0].c_str());
02539          TClass *key = TClass::GetClass(inside[1].c_str());
02540          if (key) {
02541             TString what;
02542             switch ( stlkind )  {
02543             case TClassEdit::kMap:
02544             case TClassEdit::kMultiMap:
02545                if (TClass::GetClass(inside[1].c_str())) {
02546                   what = "std::pair<";
02547                   what += TMakeProject::UpdateAssociativeToVector( inside[1].c_str() );
02548                   what += ",";
02549                   what += TMakeProject::UpdateAssociativeToVector( inside[2].c_str() );
02550                   if (what[what.Length()-1]=='>') {
02551                      what += " >";
02552                   } else {
02553                      what += ">";
02554                   }
02555                   if (genreflex) {
02556                      tmp.Form("<class name=\"%s\" />\n",what.Data());
02557                      if ( selections.Index(tmp) == kNPOS ) {
02558                         selections.Append(tmp);
02559                      }
02560                      tmp.Form("template class %s;\n",what.Data());
02561                      if ( instances.Index(tmp) == kNPOS ) {
02562                         instances.Append(tmp);
02563                      }
02564                   } else {
02565                      what.ReplaceAll("std::","");
02566                      fprintf(fp,"#pragma link C++ class %s+;\n",what.Data());
02567                   }
02568                   break;
02569                }
02570             default:
02571                if (strncmp(key->GetName(),"pair<",strlen("pair<"))==0) {
02572                   if (genreflex) {
02573                      tmp.Form("<class name=\"%s\" />\n",key->GetName());
02574                      if ( selections.Index(tmp) == kNPOS ) {
02575                         selections.Append(tmp);
02576                      }
02577                      tmp.Form("template class %s;\n",key->GetName());
02578                      if ( instances.Index(tmp) == kNPOS ) {
02579                         instances.Append(tmp);
02580                      }
02581                   } else {
02582                      what.ReplaceAll("std::","");
02583                      fprintf(fp,"#pragma link C++ class %s+;\n",key->GetName());
02584                   }
02585                }
02586                break;
02587             }
02588          }
02589          continue;
02590       }
02591       {
02592          TString what(TMakeProject::UpdateAssociativeToVector(info->GetName()).Data());
02593          if (genreflex) {
02594             tmp.Form("<class name=\"%s\" />\n",what.Data());
02595             if ( selections.Index(tmp) == kNPOS ) {
02596                selections.Append(tmp);
02597             }
02598             if (what[what.Length()-1] == '>') {
02599                tmp.Form("template class %s;\n",what.Data());
02600                if ( instances.Index(tmp) == kNPOS ) {
02601                   instances.Append(tmp);
02602                }
02603             }
02604          } else {
02605             what.ReplaceAll("std::","");
02606             fprintf(fp,"#pragma link C++ class %s+;\n",what.Data());
02607          }
02608       }
02609       if (genreflex) {
02610          // Also request the dictionary for the STL container used as members ...
02611          TIter eliter( info->GetElements() );
02612          TStreamerElement *element;
02613          while( (element = (TStreamerElement*)eliter() ) ) {
02614             if (element->GetClass() && !element->GetClass()->IsLoaded() && element->GetClass()->GetCollectionProxy()) {
02615                TString what( TMakeProject::UpdateAssociativeToVector(element->GetClass()->GetName()) );
02616                tmp.Form("<class name=\"%s\" />\n",what.Data());
02617                if ( selections.Index(tmp) == kNPOS ) {
02618                   selections.Append(tmp);
02619                }
02620                tmp.Form("template class %s;\n",what.Data());
02621                if ( instances.Index(tmp) == kNPOS ) {
02622                   instances.Append(tmp);
02623                }
02624             }
02625          }
02626       }
02627    }
02628    if (genreflex) {
02629       fprintf(ifp,"#ifndef PROJECT_INSTANCES_H\n");
02630       fprintf(ifp,"#define PROJECT_INSTANCES_H\n");
02631       fprintf(ifp,"%s",instances.Data());
02632       fprintf(ifp,"#endif\n");
02633       fprintf(fp,"%s",selections.Data());
02634       fprintf(fp,"</lcgdict>\n");
02635    } else {
02636       fprintf(fp,"#endif\n");
02637    }
02638    fclose(fp);
02639    fclose(ifp);
02640    if (genreflex) {
02641       fprintf(fpMAKE,"-s %sSelection.xml \n",dirname);
02642    } else {
02643       fprintf(fpMAKE,"%sProjectHeaders.h ",dirname);
02644       fprintf(fpMAKE,"%sLinkDef.h \n",dirname);
02645    }
02646 
02647    // add compilation line
02648    TString sdirname(dirname);
02649 
02650    TString cmd = gSystem->GetMakeSharedLib();
02651    TString sources( sdirname+"ProjectSource.cxx ");
02652    cmd.ReplaceAll("$SourceFiles",sources.Data());
02653    TString object( sdirname + "ProjectSource." );
02654    object.Append( gSystem->GetObjExt() );
02655    cmd.ReplaceAll("$ObjectFiles", object.Data());
02656    cmd.ReplaceAll("$IncludePath",TString(gSystem->GetIncludePath()) + " -I" + dirname);
02657    cmd.ReplaceAll("$SharedLib",sdirname+"."+gSystem->GetSoExt());
02658    cmd.ReplaceAll("$LinkedLibs",gSystem->GetLibraries("","SDL"));
02659    cmd.ReplaceAll("$LibName",sdirname);
02660    cmd.ReplaceAll("$BuildDir",".");
02661    TString sOpt;
02662    TString rootbuild = ROOTBUILD;
02663    if (rootbuild.Index("debug",0,TString::kIgnoreCase)==kNPOS) {
02664       sOpt = gSystem->GetFlagsOpt();
02665    } else {
02666       sOpt = gSystem->GetFlagsDebug();
02667    }
02668    cmd.ReplaceAll("$Opt", sOpt);
02669 
02670    fprintf(fpMAKE,"%s\n",cmd.Data());
02671 
02672    fclose(fpMAKE);
02673    printf("%s/MAKEP file has been generated\n",dirname);
02674 
02675    if (!opt.Contains("nocompilation")) {
02676       // now execute the generated script compiling and generating the shared lib
02677       path = gSystem->WorkingDirectory();
02678       gSystem->ChangeDirectory(dirname);
02679 #ifndef WIN32
02680       gSystem->Exec("chmod +x MAKEP");
02681       int res = !gSystem->Exec("./MAKEP");
02682 #else
02683       // not really needed for Windows but it would work both both Unix and NT
02684       chmod("makep.cmd",00700);
02685       int res = !gSystem->Exec("MAKEP");
02686 #endif
02687       gSystem->ChangeDirectory(path);
02688       path.Form("%s/%s.%s",dirname,dirname,gSystem->GetSoExt());
02689       if (res) printf("Shared lib %s has been generated\n",path.Data());
02690 
02691       //dynamically link the generated shared lib
02692       if (opt.Contains("++")) {
02693          res = !gSystem->Load(path);
02694          if (res) printf("Shared lib %s has been dynamically linked\n",path.Data());
02695       }
02696    }
02697 
02698    extrainfos.Clear("nodelete");
02699    // filelist->Clear("nodetele");
02700    delete list;
02701    filelist->Delete();
02702    delete filelist;
02703 }
02704 
02705 //______________________________________________________________________________
02706 void TFile::ReadStreamerInfo()
02707 {
02708    // Read the list of StreamerInfo from this file.
02709    // The key with name holding the list of TStreamerInfo objects is read.
02710    // The corresponding TClass objects are updated.
02711    // Note that this function is not called if the static member fgReadInfo is falsse.
02712    //  (see TFile::SetReadStreamerInfo)
02713 
02714    TList *list = GetStreamerInfoList();
02715    if (!list) {
02716       MakeZombie();
02717       return;
02718    }
02719 
02720    list->SetOwner(kFALSE);
02721 
02722    if (gDebug > 0) Info("ReadStreamerInfo", "called for file %s",GetName());
02723 
02724    // loop on all TStreamerInfo classes
02725    TStreamerInfo *info;
02726    for (int mode=0;mode<2; ++mode) {
02727       // In order for the collection proxy to be initialized properly, we need
02728       // to setup the TStreamerInfo for non-stl class before the stl classes.
02729       TObjLink *lnk = list->FirstLink();
02730       while (lnk) {
02731          info = (TStreamerInfo*)lnk->GetObject();
02732 
02733          if (info->IsA() != TStreamerInfo::Class()) {
02734             if (mode==1) {
02735                TObject *obj = (TObject*)info;
02736                if (strcmp(obj->GetName(),"listOfRules")==0) {
02737                   TList *listOfRules = (TList*)obj;
02738                   TObjLink *rulelnk = listOfRules->FirstLink();
02739                   while (rulelnk) {
02740                      TObjString *rule = (TObjString*)rulelnk->GetObject();
02741                      TClass::AddRule( rule->String().Data() );
02742                      rulelnk = rulelnk->Next();
02743                   }
02744                } else {
02745                   Warning("ReadStreamerInfo","%s has a %s in the list of TStreamerInfo.", GetName(), info->IsA()->GetName());
02746                }
02747                info->SetBit(kCanDelete);
02748             }
02749             lnk = lnk->Next();
02750             continue;
02751          }
02752          // This is a quick way (instead of parsing the name) to see if this is
02753          // the description of an STL container.
02754          TObject *element = info->GetElements()->UncheckedAt(0);
02755          Bool_t isstl = element && strcmp("This",element->GetName())==0;
02756 
02757          if ( (!isstl && mode ==0) || (isstl && mode ==1) ) {
02758                // Skip the STL container the first time around
02759                // Skip the regular classes the second time around;
02760             info->BuildCheck();
02761             Int_t uid = info->GetNumber();
02762             Int_t asize = fClassIndex->GetSize();
02763             if (uid >= asize && uid <100000) fClassIndex->Set(2*asize);
02764             if (uid >= 0 && uid < fClassIndex->GetSize()) fClassIndex->fArray[uid] = 1;
02765             else {
02766                printf("ReadStreamerInfo, class:%s, illegal uid=%d\n",info->GetName(),uid);
02767             }
02768             if (gDebug > 0) printf(" -class: %s version: %d info read at slot %d\n",info->GetName(), info->GetClassVersion(),uid);
02769          }
02770          lnk = lnk->Next();
02771       }
02772    }
02773    fClassIndex->fArray[0] = 0;
02774    list->Clear();  //this will delete all TStreamerInfo objects with kCanDelete bit set
02775    delete list;
02776 }
02777 
02778 //______________________________________________________________________________
02779 void TFile::SetReadStreamerInfo(Bool_t readinfo)
02780 {
02781    // static function to set fgReadInfo.
02782    // If fgReadInfo is true (default) TFile::ReadStreamerInfo is called
02783    //  when opening the file.
02784    // It may be interesting to set fgReadInfo to false to speedup the file
02785    // opening time or in case libraries containing classes referenced
02786    // by the file have not yet been loaded.
02787    // if fgReadInfo is false, one can still read the StreamerInfo with
02788    //    myfile.ReadStreamerInfo();
02789 
02790    fgReadInfo = readinfo;
02791 }
02792 
02793 //______________________________________________________________________________
02794 void TFile::ShowStreamerInfo()
02795 {
02796    // Show the StreamerInfo of all classes written to this file.
02797 
02798    TList *list = GetStreamerInfoList();
02799 
02800    if (!list) return;
02801 
02802    list->ls();
02803    delete list;
02804 }
02805 
02806 //______________________________________________________________________________
02807 UShort_t TFile::WriteProcessID(TProcessID *pidd)
02808 {
02809    // Check if the ProcessID pidd is already in the file,
02810    // if not, add it and return the index  number in the local file list.
02811 
02812    TProcessID *pid = pidd;
02813    if (!pid) pid = TProcessID::GetPID();
02814    TObjArray *pids = GetListOfProcessIDs();
02815    Int_t npids = GetNProcessIDs();
02816    for (Int_t i=0;i<npids;i++) {
02817       if (pids->At(i) == pid) return (UShort_t)i;
02818    }
02819 
02820    this->SetBit(TFile::kHasReferences);
02821    pids->AddAtAndExpand(pid,npids);
02822    pid->IncrementCount();
02823    char name[32];
02824    snprintf(name,32,"ProcessID%d",npids);
02825    this->WriteTObject(pid,name);
02826    this->IncrementProcessIDs();
02827    if (gDebug > 0) {
02828       Info("WriteProcessID", "name=%s, file=%s", name, GetName());
02829    }
02830    return (UShort_t)npids;
02831 }
02832 
02833 
02834 //______________________________________________________________________________
02835 void TFile::WriteStreamerInfo()
02836 {
02837    // Write the list of TStreamerInfo as a single object in this file
02838    // The class Streamer description for all classes written to this file
02839    // is saved. See class TStreamerInfo.
02840 
02841    //if (!gFile) return;
02842    if (!fWritable) return;
02843    if (!fClassIndex) return;
02844    //no need to update the index if no new classes added to the file
02845    if (fClassIndex->fArray[0] == 0) return;
02846    if (gDebug > 0) Info("WriteStreamerInfo", "called for file %s",GetName());
02847 
02848    SafeDelete(fInfoCache);
02849 
02850    // build a temporary list with the marked files
02851    TIter next(gROOT->GetListOfStreamerInfo());
02852    TStreamerInfo *info;
02853    TList list;
02854    TList listOfRules;
02855    listOfRules.SetOwner(kTRUE);
02856    listOfRules.SetName("listOfRules");
02857    std::set<TClass*> classSet;
02858 
02859 
02860    while ((info = (TStreamerInfo*)next())) {
02861       Int_t uid = info->GetNumber();
02862       if (fClassIndex->fArray[uid]) {
02863          list.Add(info);
02864          if (gDebug > 0) printf(" -class: %s info number %d saved\n",info->GetName(),uid);
02865 
02866          // Add the IO customization rules to the list to be saved for the underlying
02867          // class but make sure to add them only once.
02868          TClass *clinfo = info->GetClass();
02869          if (clinfo && clinfo->GetSchemaRules()) {
02870             if ( classSet.find( clinfo ) == classSet.end() ) {
02871                if (gDebug > 0) printf(" -class: %s stored the I/O customization rules\n",info->GetName());
02872 
02873                TObjArrayIter it( clinfo->GetSchemaRules()->GetRules() );
02874                ROOT::TSchemaRule *rule;
02875                while( (rule = (ROOT::TSchemaRule*)it.Next()) ) {
02876                   TObjString *obj = new TObjString();
02877                   rule->AsString(obj->String());
02878                   listOfRules.Add(obj);
02879                }
02880                classSet.insert(clinfo);
02881             }
02882          }
02883       }
02884    }
02885    if (list.GetSize() == 0) return;
02886    fClassIndex->fArray[0] = 2; //to prevent adding classes in TStreamerInfo::TagFile
02887 
02888    if (listOfRules.GetEntries()) {
02889       // Only the list of rules if we have something to say.
02890       list.Add(&listOfRules);
02891    }
02892 
02893    // always write with compression on
02894    Int_t compress = fCompress;
02895    fCompress = 1;
02896 
02897    //free previous StreamerInfo record
02898    if (fSeekInfo) MakeFree(fSeekInfo,fSeekInfo+fNbytesInfo-1);
02899    //Create new key
02900    TKey key(&list,"StreamerInfo",GetBestBuffer(), this);
02901    fKeys->Remove(&key);
02902    fSeekInfo   = key.GetSeekKey();
02903    fNbytesInfo = key.GetNbytes();
02904    SumBuffer(key.GetObjlen());
02905    key.WriteFile(0);
02906 
02907    fClassIndex->fArray[0] = 0;
02908    fCompress = compress;
02909 
02910    list.RemoveLast(); // remove the listOfRules.
02911 }
02912 
02913 //______________________________________________________________________________
02914 TFile *TFile::OpenFromCache(const char *name, Option_t *, const char *ftitle,
02915                    Int_t compress, Int_t netopt)
02916 {
02917    // Static member function allowing to open a file for reading through the file
02918    // cache. The file will be downloaded to the cache and opened from there.
02919    // If the download fails, it will be opened remotely.
02920    // The file will be downloaded to the directory specified by SetCacheFileDir().
02921 
02922    TFile *f = 0;
02923 
02924    if (fgCacheFileDir == "") {
02925       ::Warning("TFile::OpenFromCache",
02926                 "you want to read through a cache, but you have no valid cache "
02927                 "directory set - reading remotely");
02928       ::Info("TFile::OpenFromCache", "set cache directory using TFile::SetCacheFileDir()");
02929    } else {
02930       TUrl fileurl(name);
02931       TUrl tagurl;
02932 
02933       if ((!strcmp(fileurl.GetProtocol(), "file"))) {
02934          // it makes no sense to read local files through a file cache
02935          if (!fgCacheFileForce)
02936             ::Warning("TFile::OpenFromCache",
02937                       "you want to read through a cache, but you are reading "
02938                       "local files - CACHEREAD disabled");
02939       } else {
02940          // this is a remote file and worthwhile to be put into the local cache
02941          // now create cachepath to put it
02942          TString cachefilepath;
02943          TString cachefilepathbasedir;
02944          cachefilepath = fgCacheFileDir;
02945          cachefilepath += fileurl.GetFile();
02946          cachefilepathbasedir = gSystem->DirName(cachefilepath);
02947          if ((gSystem->mkdir(cachefilepathbasedir, kTRUE) < 0) &&
02948                (gSystem->AccessPathName(cachefilepathbasedir, kFileExists))) {
02949             ::Warning("TFile::OpenFromCache","you want to read through a cache, but I "
02950                       "cannot create the directory %s - CACHEREAD disabled",
02951                       cachefilepathbasedir.Data());
02952          } else {
02953             // check if this should be a zip file
02954             if (strlen(fileurl.GetAnchor())) {
02955                // remove the anchor and change the target name
02956                cachefilepath += "__";
02957                cachefilepath += fileurl.GetAnchor();
02958                fileurl.SetAnchor("");
02959             }
02960             if (strstr(name,"zip=")) {
02961                // filter out this option and change the target cache name
02962                TString urloptions = fileurl.GetOptions();
02963                TString newoptions;
02964                TObjArray *objOptions = urloptions.Tokenize("&");
02965                Int_t optioncount = 0;
02966                TString zipname;
02967                for (Int_t n = 0; n < objOptions->GetEntries(); n++) {
02968                   TString loption = ((TObjString*)objOptions->At(n))->GetName();
02969                   TObjArray *objTags = loption.Tokenize("=");
02970                   if (objTags->GetEntries() == 2) {
02971                      TString key   = ((TObjString*)objTags->At(0))->GetName();
02972                      TString value = ((TObjString*)objTags->At(1))->GetName();
02973                      if (key.CompareTo("zip", TString::kIgnoreCase)) {
02974                         if (optioncount!=0) {
02975                            newoptions += "&";
02976                         }
02977                         newoptions += key;
02978                         newoptions += "=";
02979                         newoptions += value;
02980                         ++optioncount;
02981                      } else {
02982                         zipname = value;
02983                      }
02984                   }
02985                   delete objTags;
02986                }
02987                delete objOptions;
02988                fileurl.SetOptions(newoptions.Data());
02989                cachefilepath += "__";
02990                cachefilepath += zipname;
02991                fileurl.SetAnchor("");
02992             }
02993 
02994             Bool_t need2copy = kFALSE;
02995 
02996             // check if file is in the cache
02997             Long_t id;
02998             Long64_t size;
02999             Long_t flags;
03000             Long_t modtime;
03001             if (!gSystem->GetPathInfo(cachefilepath, &id, &size, &flags, &modtime)) {
03002                // file is in the cache
03003                if (!fgCacheFileDisconnected) {
03004                   char cacheblock[256];
03005                   char remotblock[256];
03006                   // check the remote file for it's size and compare some magic bytes
03007                   TString cfurl;
03008                   cfurl = cachefilepath;
03009                   cfurl += "?filetype=raw";
03010                   TUrl rurl(name);
03011                   TString ropt = rurl.GetOptions();
03012                   ropt += "&filetype=raw";
03013                   rurl.SetOptions(ropt);
03014 
03015                   Bool_t forcedcache = fgCacheFileForce;
03016                   fgCacheFileForce = kFALSE;
03017 
03018                   TFile *cachefile = TFile::Open(cfurl, "READ");
03019                   TFile *remotfile = TFile::Open(rurl.GetUrl(), "READ");
03020 
03021                   fgCacheFileForce = forcedcache;
03022 
03023                   if (!cachefile) {
03024                      need2copy = kTRUE;
03025                      ::Error("TFile::OpenFromCache",
03026                              "cannot open the cache file to check cache consistency");
03027                      return 0;
03028                   }
03029 
03030                   if (!remotfile) {
03031                      ::Error("TFile::OpenFromCache",
03032                              "cannot open the remote file to check cache consistency");
03033                      return 0;
03034                   }
03035 
03036                   cachefile->Seek(0);
03037                   remotfile->Seek(0);
03038 
03039                   if ((!cachefile->ReadBuffer(cacheblock,256)) &&
03040                       (!remotfile->ReadBuffer(remotblock,256))) {
03041                      if (memcmp(cacheblock, remotblock, 256)) {
03042                         ::Warning("TFile::OpenFromCache", "the header of the cache file "
03043                                   "differs from the remote file - forcing an update");
03044                         need2copy = kTRUE;
03045                      }
03046                   } else {
03047                      ::Warning("TFile::OpenFromCache", "the header of the cache and/or "
03048                                "remote file are not readable - forcing an update");
03049                      need2copy = kTRUE;
03050                   }
03051 
03052                   delete remotfile;
03053                   delete cachefile;
03054                }
03055             } else {
03056                need2copy = kTRUE;
03057             }
03058 
03059             // try to fetch the file (disable now the forced caching)
03060             Bool_t forcedcache = fgCacheFileForce;
03061             fgCacheFileForce = kFALSE;
03062             if (need2copy && !TFile::Cp(name, cachefilepath)) {
03063                ::Warning("TFile::OpenFromCache", "you want to read through a cache, but I "
03064                          "cannot make a cache copy of %s - CACHEREAD disabled",
03065                          cachefilepathbasedir.Data());
03066                fgCacheFileForce = forcedcache;
03067                if (fgOpenTimeout != 0)
03068                   return 0;
03069             } else {
03070                fgCacheFileForce = forcedcache;
03071                ::Info("TFile::OpenFromCache", "using local cache copy of %s [%s]",
03072                        name, cachefilepath.Data());
03073                // finally we have the file and can open it locally
03074                fileurl.SetProtocol("file");
03075                fileurl.SetFile(cachefilepath);
03076 
03077                tagurl = fileurl;
03078                TString tagfile;
03079                tagfile = cachefilepath;
03080                tagfile += ".ROOT.cachefile";
03081                tagurl.SetFile(tagfile);
03082                // we symlink this file as a ROOT cached file
03083                gSystem->Symlink(cachefilepath, tagfile);
03084                return TFile::Open(fileurl.GetUrl(), "READ", ftitle, compress, netopt);
03085             }
03086          }
03087       }
03088    }
03089 
03090    // Failed
03091    return f;
03092 }
03093 
03094 //______________________________________________________________________________
03095 TFile *TFile::Open(const char *url, Option_t *options, const char *ftitle,
03096                    Int_t compress, Int_t netopt)
03097 {
03098    // Static member function allowing the creation/opening of either a
03099    // TFile, TNetFile, TWebFile or any TFile derived class for which an
03100    // plugin library handler has been registered with the plugin manager
03101    // (for the plugin manager see the TPluginManager class). The returned
03102    // type of TFile depends on the file name specified by 'url'.
03103    // If 'url' is a '|'-separated list of file URLs, the 'URLs' are tried
03104    // sequentially in the specified order until a successful open.
03105    // If the file starts with "root:", "roots:" or "rootk:" a TNetFile object
03106    // will be returned, with "http:" a TWebFile, with "file:" a local TFile,
03107    // etc. (see the list of TFile plugin handlers in $ROOTSYS/etc/system.rootrc
03108    // for regular expressions that will be checked) and as last a local file will
03109    // be tried.
03110    // Before opening a file via TNetFile a check is made to see if the URL
03111    // specifies a local file. If that is the case the file will be opened
03112    // via a normal TFile. To force the opening of a local file via a
03113    // TNetFile use either TNetFile directly or specify as host "localhost".
03114    // The netopt argument is only used by TNetFile. For the meaning of the
03115    // options and other arguments see the constructors of the individual
03116    // file classes. In case of error returns 0.
03117    //
03118    // For TFile implementations supporting asynchronous file open, see
03119    // TFile::AsyncOpen(...), it is possible to request a timeout with the
03120    // option:
03121    //  TIMEOUT=<secs>   the timeout must be specified in seconds and
03122    //                   it will be internally checked with granularity of
03123    //                   one millisec.
03124    //
03125    // For remote files there is the option:
03126    //  CACHEREAD     opens an existing file for reading through the file cache.
03127    //                The file will be downloaded to the cache and opened from there.
03128    //                If the download fails, it will be opened remotely.
03129    //                The file will be downloaded to the directory specified by
03130    //                SetCacheFileDir().
03131 
03132    TPluginHandler *h;
03133    TFile *f = 0;
03134    EFileType type = kFile;
03135 
03136    // Check input
03137    if (!url || strlen(url) <= 0) {
03138       ::Error("TFile::Open", "no url specified");
03139       return f;
03140    }
03141 
03142    TString expandedUrl(url);
03143    gSystem->ExpandPathName(expandedUrl);
03144 
03145    // If a timeout has been specified extract the value and try to apply it (it requires
03146    // support for asynchronous open, though; the following is completely transparent if
03147    // such support if not available for the required protocol)
03148    TString opts(options);
03149    Int_t ito = opts.Index("TIMEOUT=");
03150    if (ito != kNPOS) {
03151       TString sto = opts(ito + strlen("TIMEOUT="), opts.Length());
03152       while (!(sto.IsDigit()) && !(sto.IsNull())) { sto.Remove(sto.Length()-1,1); }
03153       if (!(sto.IsNull())) {
03154          // Timeout in millisecs
03155          Int_t toms = sto.Atoi() * 1000;
03156          if (gDebug > 0) ::Info("TFile::Open", "timeout of %d millisec requested", toms);
03157          // Remove from the options field
03158          sto.Insert(0, "TIMEOUT=");
03159          opts.ReplaceAll(sto, "");
03160          // Asynchrounous open
03161          TFileOpenHandle *fh = TFile::AsyncOpen(expandedUrl, opts, ftitle, compress, netopt);
03162          // Check the result in steps of 1 millisec
03163          TFile::EAsyncOpenStatus aos = TFile::kAOSNotAsync;
03164          aos = TFile::GetAsyncOpenStatus(fh);
03165          Int_t xtms = toms;
03166          while (aos != TFile::kAOSNotAsync && aos == TFile::kAOSInProgress && xtms > 0) {
03167             gSystem->Sleep(1);
03168             xtms -= 1;
03169             aos = TFile::GetAsyncOpenStatus(fh);
03170          }
03171          if (aos == TFile::kAOSNotAsync || aos == TFile::kAOSSuccess) {
03172             // Do open the file now
03173             f = TFile::Open(fh);
03174             if (gDebug > 0) {
03175                if (aos == TFile::kAOSSuccess)
03176                   ::Info("TFile::Open", "waited %d millisec for asynchronous open", toms - xtms);
03177                else
03178                   ::Info("TFile::Open", "timeout option not supported (requires asynchronous"
03179                                         " open support)");
03180             }
03181          } else {
03182             if (xtms <= 0)
03183                ::Error("TFile::Open", "timeout expired while opening '%s'", expandedUrl.Data());
03184             // Cleanup the request
03185             SafeDelete(fh);
03186          }
03187          // Done
03188          return f;
03189       } else {
03190          ::Warning("TFile::Open", "incomplete 'TIMEOUT=' option specification - ignored");
03191          opts.ReplaceAll("TIMEOUT=", "");
03192       }
03193    }
03194 
03195    // We will use this from now on
03196    const char *option = opts;
03197 
03198    // Many URLs? Redirect output and print errors in case of global failure
03199    TString namelist(expandedUrl);
03200    Ssiz_t ip = namelist.Index("|");
03201    Bool_t rediroutput = (ip != kNPOS &&
03202                          ip != namelist.Length()-1 && gDebug <= 0) ? kTRUE : kFALSE;
03203    RedirectHandle_t rh;
03204    if (rediroutput) {
03205       TString outf = ".TFileOpen_";
03206       FILE *fout = gSystem->TempFileName(outf);
03207       if (fout) {
03208          fclose(fout);
03209          gSystem->RedirectOutput(outf, "w", &rh);
03210       }
03211    }
03212 
03213    // Try sequentially all names in 'names'
03214    TString name, n;
03215    Ssiz_t from = 0;
03216    while (namelist.Tokenize(n, from, "|") && !f) {
03217 
03218       // check if we read through a file cache
03219       if (!strcasecmp(option, "CACHEREAD") ||
03220          ((!strcasecmp(option,"READ") || !strlen(option)) && fgCacheFileForce)) {
03221          // Try opening the file from the cache
03222          if ((f = TFile::OpenFromCache(n, option, ftitle, compress, netopt)))
03223             return f;
03224       }
03225 
03226       IncrementFileCounter();
03227 
03228       // change names from e.g. /castor/cern.ch/alice/file.root to
03229       // castor:/castor/cern.ch/alice/file.root as recognized by the plugin manager
03230       TUrl urlname(n, kTRUE);
03231       name = urlname.GetUrl();
03232       // Check first if a pending async open request matches this one
03233       if (fgAsyncOpenRequests && (fgAsyncOpenRequests->GetSize() > 0)) {
03234          TIter nxr(fgAsyncOpenRequests);
03235          TFileOpenHandle *fh = 0;
03236          while ((fh = (TFileOpenHandle *)nxr()))
03237             if (fh->Matches(name))
03238                return TFile::Open(fh);
03239       }
03240 
03241       // Resolve the file type; this also adjusts names
03242       TString lfname = gEnv->GetValue("Path.Localroot", "");
03243       type = GetType(name, option, &lfname);
03244 
03245       if (type == kLocal) {
03246 
03247          // Local files
03248          if (lfname.IsNull()) {
03249             urlname.SetHost("");
03250             urlname.SetProtocol("file");
03251             lfname = urlname.GetUrl();
03252          }
03253          f = new TFile(lfname.Data(), option, ftitle, compress);
03254 
03255       } else if (type == kNet) {
03256 
03257          // Network files
03258          if ((h = gROOT->GetPluginManager()->FindHandler("TFile", name))) {
03259             if (h->LoadPlugin() == -1)
03260                return 0;
03261             f = (TFile*) h->ExecPlugin(5, name.Data(), option, ftitle, compress, netopt);
03262          }
03263 
03264       } else if (type == kWeb) {
03265 
03266          // Web files
03267          if ((h = gROOT->GetPluginManager()->FindHandler("TFile", name))) {
03268             if (h->LoadPlugin() == -1)
03269                return 0;
03270             f = (TFile*) h->ExecPlugin(2, name.Data(), option);
03271          }
03272 
03273       } else if (type == kFile) {
03274 
03275          // 'file:' protocol
03276          if ((h = gROOT->GetPluginManager()->FindHandler("TFile", name)) &&
03277             h->LoadPlugin() == 0) {
03278             name.ReplaceAll("file:", "");
03279             f = (TFile*) h->ExecPlugin(4, name.Data(), option, ftitle, compress);
03280          } else
03281             f = new TFile(name.Data(), option, ftitle, compress);
03282 
03283       } else {
03284 
03285          // no recognized specification: try the plugin manager
03286          if ((h = gROOT->GetPluginManager()->FindHandler("TFile", name.Data()))) {
03287             if (h->LoadPlugin() == -1)
03288                return 0;
03289             TClass *cl = TClass::GetClass(h->GetClass());
03290             if (cl && cl->InheritsFrom("TNetFile"))
03291                f = (TFile*) h->ExecPlugin(5, name.Data(), option, ftitle, compress, netopt);
03292             else
03293                f = (TFile*) h->ExecPlugin(4, name.Data(), option, ftitle, compress);
03294          } else {
03295             // Just try to open it locally but via TFile::Open, so that we pick-up the correct
03296             // plug-in in the case file name contains information about a special backend (e.g.
03297             // "srm://srm.cern.ch//castor/cern.ch/grid/..." should be considered a castor file
03298             // /castor/cern.ch/grid/...").
03299             f = TFile::Open(urlname.GetFileAndOptions(), option, ftitle, compress);
03300          }
03301       }
03302 
03303       if (f && f->IsZombie()) {
03304          delete f;
03305          f = 0;
03306       }
03307    }
03308 
03309    if (rediroutput) {
03310       // Restore output to stdout
03311       gSystem->RedirectOutput(0, "", &rh);
03312       // If we failed print error messages
03313       if (!f)
03314          gSystem->ShowOutput(&rh);
03315       // Remove the file
03316       gSystem->Unlink(rh.fFile);
03317    }
03318 
03319    // if the file is writable, non local, and not opened in raw mode
03320    // we create a default write cache of 512 KBytes
03321    if (type != kLocal && type != kFile &&
03322        f && f->IsWritable() && !f->IsRaw()) {
03323       new TFileCacheWrite(f, 1);
03324    }
03325 
03326    return f;
03327 }
03328 
03329 //______________________________________________________________________________
03330 TFileOpenHandle *TFile::AsyncOpen(const char *url, Option_t *option,
03331                                   const char *ftitle, Int_t compress,
03332                                   Int_t netopt)
03333 {
03334    // Static member function to submit an open request. The request will be
03335    // processed asynchronously. See TFile::Open(const char *, ...) for an
03336    // explanation of the arguments. A handler is returned which is to be passed
03337    // to TFile::Open(TFileOpenHandle *) to get the real TFile instance once
03338    // the file is open.
03339    // This call never blocks and it is provided to allow parallel submission
03340    // of file opening operations expected to take a long time.
03341    // TFile::Open(TFileOpenHandle *) may block if the file is not yet ready.
03342    // The sequence
03343    //    TFile::Open(TFile::AsyncOpen(const char *, ...))
03344    // is equivalent to
03345    //    TFile::Open(const char *, ...) .
03346    // To be effective, the underlying TFile implementation must be able to
03347    // support asynchronous open functionality. Currently, only TXNetFile
03348    // supports it. If the functionality is not implemented, this call acts
03349    // transparently by returning an handle with the arguments for the
03350    // standard synchronous open run by TFile::Open(TFileOpenHandle *).
03351    // The retuned handle will be adopted by TFile after opening completion
03352    // in TFile::Open(TFileOpenHandle *); if opening is not finalized the
03353    // handle must be deleted by the caller.
03354 
03355    TFileOpenHandle *fh = 0;
03356    TPluginHandler *h;
03357    TFile *f = 0;
03358    Bool_t notfound = kTRUE;
03359 
03360    // Check input
03361    if (!url || strlen(url) <= 0) {
03362       ::Error("TFile::AsyncOpen", "no url specified");
03363       return fh;
03364    }
03365 
03366    // Many URLs? Redirect output and print errors in case of global failure
03367    TString namelist(url);
03368    gSystem->ExpandPathName(namelist);
03369    Ssiz_t ip = namelist.Index("|");
03370    Bool_t rediroutput = (ip != kNPOS &&
03371                          ip != namelist.Length()-1 && gDebug <= 0) ? kTRUE : kFALSE;
03372    RedirectHandle_t rh;
03373    if (rediroutput) {
03374       TString outf = ".TFileAsyncOpen_";
03375       FILE *fout = gSystem->TempFileName(outf);
03376       if (fout) {
03377          fclose(fout);
03378          gSystem->RedirectOutput(outf, "w", &rh);
03379       }
03380    }
03381 
03382    // Try sequentially all names in 'names'
03383    TString name, n;
03384    Ssiz_t from = 0;
03385    while (namelist.Tokenize(n, from, "|") && !f) {
03386 
03387       // change names from e.g. /castor/cern.ch/alice/file.root to
03388       // castor:/castor/cern.ch/alice/file.root as recognized by the plugin manager
03389       TUrl urlname(n, kTRUE);
03390       name = urlname.GetUrl();
03391 
03392       // Resolve the file type; this also adjusts names
03393       EFileType type = GetType(name, option);
03394 
03395       // Here we send the asynchronous request if the functionality is implemented
03396       if (type == kNet) {
03397          // Network files
03398          if ((h = gROOT->GetPluginManager()->FindHandler("TFile", name)) &&
03399             !strcmp(h->GetClass(),"TXNetFile") && h->LoadPlugin() == 0) {
03400             f = (TFile*) h->ExecPlugin(6, name.Data(), option, ftitle, compress, netopt, kTRUE);
03401             notfound = kFALSE;
03402          }
03403       }
03404       if ((h = gROOT->GetPluginManager()->FindHandler("TFile", name)) &&
03405          !strcmp(h->GetClass(),"TAlienFile") && h->LoadPlugin() == 0) {
03406          f = (TFile*) h->ExecPlugin(5, name.Data(), option, ftitle, compress, kTRUE);
03407          notfound = kFALSE;
03408       }
03409 
03410    }
03411 
03412    if (rediroutput) {
03413       // Restore output to stdout
03414       gSystem->RedirectOutput(0, "", &rh);
03415       // If we failed print error messages
03416       if (!notfound && !f)
03417          gSystem->ShowOutput(&rh);
03418       // Remove the file
03419       gSystem->Unlink(rh.fFile);
03420    }
03421 
03422    // Make sure that no error occured
03423    if (notfound) {
03424       SafeDelete(f);
03425       // Save the arguments in the handler, so that a standard open can be
03426       // attempted later on
03427       fh = new TFileOpenHandle(name, option, ftitle, compress, netopt);
03428    } else if (f) {
03429       // Fill the opaque handler to be use to attach the file later on
03430       fh = new TFileOpenHandle(f);
03431    }
03432 
03433    // Record this request
03434    if (fh) {
03435       // Create the lst, if not done already
03436       if (!fgAsyncOpenRequests)
03437          fgAsyncOpenRequests = new TList;
03438       fgAsyncOpenRequests->Add(fh);
03439    }
03440 
03441    // We are done
03442    return fh;
03443 }
03444 
03445 //______________________________________________________________________________
03446 TFile *TFile::Open(TFileOpenHandle *fh)
03447 {
03448    // Waits for the completion of an asynchronous open request.
03449    // Returns the associated TFile, transferring ownership of the
03450    // handle to the TFile instance.
03451 
03452    TFile *f = 0;
03453 
03454    // Note that the request may have failed
03455    if (fh && fgAsyncOpenRequests) {
03456       // Remove it from the pending list: we need to do it at this level to avoid
03457       // recursive calls in the standard TFile::Open
03458       fgAsyncOpenRequests->Remove(fh);
03459       // Was asynchronous open functionality implemented?
03460       if ((f = fh->GetFile()) && !(f->IsZombie())) {
03461          // Yes: wait for the completion of the open phase, if needed
03462          Bool_t cr = (!strcmp(f->GetOption(),"CREATE") ||
03463                       !strcmp(f->GetOption(),"RECREATE") ||
03464                       !strcmp(f->GetOption(),"NEW")) ? kTRUE : kFALSE;
03465          f->Init(cr);
03466       } else {
03467          // No: process a standard open
03468          f = TFile::Open(fh->GetName(), fh->GetOpt(), fh->GetTitle(),
03469                          fh->GetCompress(), fh->GetNetOpt());
03470       }
03471 
03472       // Adopt the handle instance in the TFile instance so that it gets
03473       // automatically cleaned up
03474       f->fAsyncHandle = fh;
03475    }
03476 
03477    // We are done
03478    return f;
03479 }
03480 
03481 //______________________________________________________________________________
03482 Int_t TFile::SysOpen(const char *pathname, Int_t flags, UInt_t mode)
03483 {
03484    // Interface to system open. All arguments like in POSIX open().
03485 
03486 #if defined(R__WINGCC)
03487    // ALWAYS use binary mode - even cygwin text should be in unix format
03488    // although this is posix default it has to be set explicitly
03489    return ::open(pathname, flags | O_BINARY, mode);
03490 #elif defined(R__SEEK64)
03491    return ::open64(pathname, flags, mode);
03492 #else
03493    return ::open(pathname, flags, mode);
03494 #endif
03495 }
03496 
03497 //______________________________________________________________________________
03498 Int_t TFile::SysClose(Int_t fd)
03499 {
03500    // Interface to system close. All arguments like in POSIX close().
03501 
03502    if (fd < 0) return 0;
03503    return ::close(fd);
03504 }
03505 
03506 //______________________________________________________________________________
03507 Int_t TFile::SysRead(Int_t fd, void *buf, Int_t len)
03508 {
03509    // Interface to system read. All arguments like in POSIX read().
03510 
03511    return ::read(fd, buf, len);
03512 }
03513 
03514 //______________________________________________________________________________
03515 Int_t TFile::SysWrite(Int_t fd, const void *buf, Int_t len)
03516 {
03517    // Interface to system write. All arguments like in POSIX write().
03518 
03519    return ::write(fd, buf, len);
03520 }
03521 //______________________________________________________________________________
03522 Long64_t TFile::SysSeek(Int_t fd, Long64_t offset, Int_t whence)
03523 {
03524    // Interface to system lseek. All arguments like in POSIX lseek()
03525    // except that the offset and return value are of a type which are
03526    // able to handle 64 bit file systems.
03527 
03528 #if defined (R__SEEK64)
03529    return ::lseek64(fd, offset, whence);
03530 #elif defined(WIN32)
03531    return ::_lseeki64(fd, offset, whence);
03532 #else
03533    return ::lseek(fd, offset, whence);
03534 #endif
03535 }
03536 
03537 //______________________________________________________________________________
03538 Int_t TFile::SysStat(Int_t, Long_t *id, Long64_t *size, Long_t *flags,
03539                      Long_t *modtime)
03540 {
03541    // Return file stat information. The interface and return value is
03542    // identical to TSystem::GetPathInfo(). The function returns 0 in
03543    // case of success and 1 if the file could not be stat'ed.
03544 
03545    return gSystem->GetPathInfo(fRealName, id, size, flags, modtime);
03546 }
03547 
03548 //______________________________________________________________________________
03549 Int_t TFile::SysSync(Int_t fd)
03550 {
03551    // Interface to system fsync. All arguments like in POSIX fsync().
03552 
03553    if (TestBit(kDevNull)) return 0;
03554 
03555 #ifndef WIN32
03556    return ::fsync(fd);
03557 #else
03558    return ::_commit(fd);
03559 #endif
03560 }
03561 
03562 //______________________________________________________________________________
03563 Long64_t TFile::GetBytesWritten() const
03564 {
03565    // Return the total number of bytes written so far to the file.
03566 
03567    return fCacheWrite ? fCacheWrite->GetBytesInCache() + fBytesWrite : fBytesWrite;
03568 }
03569 
03570 //______________________________________________________________________________
03571 Long64_t TFile::GetFileBytesRead()
03572 {
03573    // Static function returning the total number of bytes read from all files.
03574 
03575    return fgBytesRead;
03576 }
03577 
03578 //______________________________________________________________________________
03579 Long64_t TFile::GetFileBytesWritten()
03580 {
03581    // Static function returning the total number of bytes written to all files.
03582    // Does not take into account what might still be in the write caches.
03583 
03584    return fgBytesWrite;
03585 }
03586 
03587 //______________________________________________________________________________
03588 Int_t TFile::GetFileReadCalls()
03589 {
03590    // Static function returning the total number of read calls from all files.
03591 
03592    return fgReadCalls;
03593 }
03594 
03595 //______________________________________________________________________________
03596 Int_t TFile::GetReadaheadSize()
03597 {
03598    // Static function returning the readahead buffer size.
03599 
03600    return fgReadaheadSize;
03601 }
03602 
03603 //______________________________________________________________________________
03604 void TFile::SetReadaheadSize(Int_t bytes) { fgReadaheadSize = bytes; }
03605 
03606 //______________________________________________________________________________
03607 void TFile::SetFileBytesRead(Long64_t bytes) { fgBytesRead = bytes; }
03608 
03609 //______________________________________________________________________________
03610 void TFile::SetFileBytesWritten(Long64_t bytes) { fgBytesWrite = bytes; }
03611 
03612 //______________________________________________________________________________
03613 void TFile::SetFileReadCalls(Int_t readcalls) { fgReadCalls = readcalls; }
03614 
03615 //______________________________________________________________________________
03616 Long64_t TFile::GetFileCounter() { return fgFileCounter; }
03617 
03618 //______________________________________________________________________________
03619 void TFile::IncrementFileCounter() { fgFileCounter++; }
03620 
03621 //______________________________________________________________________________
03622 Bool_t TFile::SetCacheFileDir(const char *cachedir, Bool_t operatedisconnected,
03623                               Bool_t forcecacheread )
03624 {
03625    // Sets the directory where to locally stage/cache remote files.
03626    // If the directory is not writable by us return kFALSE.
03627 
03628    TString cached = cachedir;
03629    if (!cached.EndsWith("/"))
03630       cached += "/";
03631 
03632    if (gSystem->AccessPathName(cached, kFileExists)) {
03633       // try to create it
03634       gSystem->mkdir(cached, kTRUE);
03635       if (gSystem->AccessPathName(cached, kFileExists)) {
03636          ::Error("TFile::SetCacheFileDir", "no suffcient permissions on cache directory %s or cannot create it", cachedir);
03637          fgCacheFileDir = "";
03638          return kFALSE;
03639       }
03640       gSystem->Chmod(cached, 0700);
03641    }
03642    if (gSystem->AccessPathName(cached, kWritePermission))
03643       gSystem->Chmod(cached, 0700);
03644    fgCacheFileDir          = cached;
03645    fgCacheFileDisconnected = operatedisconnected;
03646    fgCacheFileForce        = forcecacheread;
03647    return kTRUE;
03648 }
03649 
03650 //______________________________________________________________________________
03651 const char *TFile::GetCacheFileDir()
03652 {
03653    // Get the directory where to locally stage/cache remote files.
03654 
03655    return fgCacheFileDir;
03656 }
03657 
03658 //______________________________________________________________________________
03659 Bool_t TFile::ShrinkCacheFileDir(Long64_t shrinksize, Long_t cleanupinterval)
03660 {
03661    // We try to shrink the cache to the desired size.
03662    // With the clenupinterval you can specify the minimum amount of time after
03663    // the previous cleanup before the cleanup operation is repeated in
03664    // the cache directory
03665 
03666    if (fgCacheFileDir == "") {
03667       return kFALSE;
03668    }
03669 
03670    // check the last clean-up in the cache
03671    Long_t id;
03672    Long64_t size;
03673    Long_t flags;
03674    Long_t modtime;
03675 
03676    TString cachetagfile = fgCacheFileDir;
03677    cachetagfile += ".tag.ROOT.cache";
03678    if (!gSystem->GetPathInfo(cachetagfile, &id, &size, &flags, &modtime)) {
03679       // check the time passed since last cache cleanup
03680       Long_t lastcleanuptime = ((Long_t)time(0) - modtime);
03681       if (lastcleanuptime < cleanupinterval) {
03682          ::Info("TFile::ShrinkCacheFileDir", "clean-up is skipped - last cleanup %lu seconds ago - you requested %lu", lastcleanuptime, cleanupinterval);
03683          return kTRUE;
03684       }
03685    }
03686 
03687    // (re-)create the cache tag file
03688    cachetagfile += "?filetype=raw";
03689    TFile *tagfile = 0;
03690 
03691    if (!(tagfile = TFile::Open(cachetagfile, "RECREATE"))) {
03692       ::Error("TFile::ShrinkCacheFileDir", "cannot create the cache tag file %s", cachetagfile.Data());
03693       return kFALSE;
03694    }
03695 
03696    // the shortest garbage collector in the world - one long line of PERL - unlinks files only,
03697    // if there is a symbolic link with '.ROOT.cachefile' for safety ;-)
03698 
03699    TString cmd;
03700 #if defined(R__WIN32)
03701    cmd = "echo <TFile::ShrinkCacheFileDir>: cleanup to be implemented";
03702 #elif defined(R__MACOSX)
03703    cmd.Format("perl -e 'my $cachepath = \"%s\"; my $cachesize = %lld;my $findcommand=\"find $cachepath -type f -exec stat -f \\\"\\%%a::\\%%N::\\%%z\\\" \\{\\} \\\\\\;\";my $totalsize=0;open FIND, \"$findcommand | sort -k 1 |\";while (<FIND>) { my ($accesstime, $filename, $filesize) = split \"::\",$_; $totalsize += $filesize;if ($totalsize > $cachesize) {if ( ( -e \"${filename}.ROOT.cachefile\" ) && ( -e \"${filename}\" ) ) {unlink \"$filename.ROOT.cachefile\";unlink \"$filename\";}}}close FIND;' ", fgCacheFileDir.Data(),shrinksize);
03704 #else
03705    cmd.Format("perl -e 'my $cachepath = \"%s\"; my $cachesize = %lld;my $findcommand=\"find $cachepath -type f -exec stat -c \\\"\\%%x::\\%%n::\\%%s\\\" \\{\\} \\\\\\;\";my $totalsize=0;open FIND, \"$findcommand | sort -k 1 |\";while (<FIND>) { my ($accesstime, $filename, $filesize) = split \"::\",$_; $totalsize += $filesize;if ($totalsize > $cachesize) {if ( ( -e \"${filename}.ROOT.cachefile\" ) && ( -e \"${filename}\" ) ) {unlink \"$filename.ROOT.cachefile\";unlink \"$filename\";}}}close FIND;' ", fgCacheFileDir.Data(),shrinksize);
03706 #endif
03707 
03708    tagfile->WriteBuffer(cmd, 4096);
03709    delete tagfile;
03710 
03711    if ((gSystem->Exec(cmd)) != 0) {
03712       ::Error("TFile::ShrinkCacheFileDir", "error executing clean-up script");
03713       return kFALSE;
03714    }
03715 
03716    return kTRUE;
03717 }
03718 
03719 //______________________________________________________________________________
03720 UInt_t TFile::SetOpenTimeout(UInt_t timeout)
03721 {
03722    // Sets open timeout time (in ms). Returns previous timeout value.
03723 
03724    UInt_t to = fgOpenTimeout;
03725    fgOpenTimeout = timeout;
03726    return to;
03727 }
03728 
03729 //______________________________________________________________________________
03730 UInt_t TFile::GetOpenTimeout()
03731 {
03732    // Returns open timeout (in ms).
03733 
03734    return fgOpenTimeout;
03735 }
03736 
03737 //______________________________________________________________________________
03738 Bool_t TFile::SetOnlyStaged(Bool_t onlystaged)
03739 {
03740    // Sets only staged flag. Returns previous value of flag.
03741    // When true we check before opening the file if it is staged, if not,
03742    // the open fails.
03743 
03744    Bool_t f = fgOnlyStaged;
03745    fgOnlyStaged = onlystaged;
03746    return f;
03747 }
03748 
03749 //______________________________________________________________________________
03750 Bool_t TFile::GetOnlyStaged()
03751 {
03752    // Returns staged only flag.
03753 
03754    return fgOnlyStaged;
03755 }
03756 
03757 //______________________________________________________________________________
03758 Bool_t TFile::Matches(const char *url)
03759 {
03760    // Return kTRUE if 'url' matches the coordinates of this file.
03761    // The check is implementation dependent and may need to be overload
03762    // by each TFile implememtation relying on this check.
03763    // The default implementation checks the file name only.
03764 
03765    // Check the full URL, including port and FQDN.
03766    TUrl u(url);
03767 
03768    // Check
03769    if (!strcmp(u.GetFile(), fUrl.GetFile())) {
03770       // Check ports
03771       if (u.GetPort() == fUrl.GetPort()) {
03772          if (!strcmp(u.GetHostFQDN(), fUrl.GetHostFQDN())) {
03773             // Ok, coordinates match
03774             return kTRUE;
03775          }
03776       }
03777    }
03778 
03779    // Default is not matching
03780    return kFALSE;
03781 }
03782 
03783 //______________________________________________________________________________
03784 Bool_t TFileOpenHandle::Matches(const char *url)
03785 {
03786    // Return kTRUE if this async request matches the open request
03787    // specified by 'url'
03788 
03789    if (fFile) {
03790       return fFile->Matches(url);
03791    } else if (fName.Length() > 0){
03792       // Deep check of URLs
03793       TUrl u(url);
03794       TUrl uref(fName);
03795       if (!strcmp(u.GetFile(), uref.GetFile())) {
03796          // Check ports
03797          if (u.GetPort() == uref.GetPort()) {
03798             // Check also the host name
03799             if (!strcmp(u.GetHostFQDN(), uref.GetHostFQDN())) {
03800                // Ok, coordinates match
03801                return kTRUE;
03802             }
03803          }
03804       }
03805    }
03806 
03807    // Default is not matching
03808    return kFALSE;
03809 }
03810 
03811 //______________________________________________________________________________
03812 TFile::EFileType TFile::GetType(const char *name, Option_t *option, TString *prefix)
03813 {
03814    // Resolve the file type as a function of the protocol field in 'name'
03815    // If defined, the string 'prefix' is added when testing the locality of
03816    // a 'name' with network-like structure (i.e. root://host//path); if the file
03817    // is local, on return 'prefix' will contain the actual local path of the file.
03818 
03819    EFileType type = kDefault;
03820 
03821    TRegexp re("^root.*:");
03822    TString sname = name;
03823    if (sname.Index(re) != kNPOS) {
03824       //
03825       // Should be a network file ...
03826       type = kNet;
03827       // ... but make sure that is not local or that a remote-like connection
03828       // is forced. Treat it as local if:
03829       //    i)  the url points to the localhost, the file will be opened in
03830       //        readonly mode and the current user has read access;
03831       //    ii) the specified user is equal to the current user then open local
03832       //        TFile.
03833       Bool_t localFile = kFALSE;
03834       TUrl url(name);
03835       //
03836       // Check whether we should try to optimize for local files
03837       Bool_t forceRemote = gEnv->GetValue("Path.ForceRemote", 0);
03838       forceRemote = (forceRemote) ? kTRUE : gEnv->GetValue("TFile.ForceRemote", 0);
03839       TString opts = url.GetOptions();
03840       if (opts.Contains("remote=1"))
03841          forceRemote = kTRUE;
03842       else if (opts.Contains("remote=0"))
03843          forceRemote = kFALSE;
03844       if (!forceRemote) {
03845          // Generic locality test
03846          localFile = gSystem->IsPathLocal(name);
03847          if (localFile) {
03848             // Local path including the prefix
03849             const char *fname = url.GetFileAndOptions();
03850             TString lfname;
03851             if (fname[0] == '/') {
03852                if (prefix)
03853                   lfname = Form("%s%s", prefix->Data(), fname);
03854                else
03855                   lfname = fname;
03856             } else if (fname[0] == '~' || fname[0] == '$') {
03857                lfname = fname;
03858             } else {
03859                lfname = Form("%s/%s", gSystem->HomeDirectory(), fname);
03860             }
03861             // If option "READ" test existence and access
03862             TString opt = option;
03863             Bool_t read = (opt.IsNull() ||
03864                           !opt.CompareTo("READ", TString::kIgnoreCase)) ? kTRUE : kFALSE;
03865             if (read) {
03866                char *fn;
03867                if ((fn = gSystem->ExpandPathName(TUrl(lfname).GetFile()))) {
03868                   if (gSystem->AccessPathName(fn, kReadPermission))
03869                      localFile = kFALSE;
03870                   delete [] fn;
03871                }
03872             }
03873             // Return full local path if requested (and if the case)
03874             if (localFile && prefix)
03875                *prefix = lfname;
03876          }
03877       }
03878       //
03879       // Adjust the type according to findings
03880       type = (localFile) ? kLocal : type;
03881    } else if (!strncmp(name, "http:", 5)) {
03882       //
03883       // Web file
03884       type = kWeb;
03885    } else if (!strncmp(name, "file:", 5)) {
03886       //
03887       // 'file' protocol
03888       type = kFile;
03889    }
03890 
03891    // We are done
03892    return type;
03893 }
03894 
03895 //______________________________________________________________________________
03896 TFile::EAsyncOpenStatus TFile::GetAsyncOpenStatus(const char* name)
03897 {
03898    // Get status of the async open request related to 'name'.
03899 
03900    // Check the list of pending async opem requests
03901    if (fgAsyncOpenRequests && (fgAsyncOpenRequests->GetSize() > 0)) {
03902       TIter nxr(fgAsyncOpenRequests);
03903       TFileOpenHandle *fh = 0;
03904       while ((fh = (TFileOpenHandle *)nxr()))
03905          if (fh->Matches(name))
03906             return TFile::GetAsyncOpenStatus(fh);
03907    }
03908 
03909    // Check also the list of files open
03910    TSeqCollection *of = gROOT->GetListOfFiles();
03911    if (of && (of->GetSize() > 0)) {
03912       TIter nxf(of);
03913       TFile *f = 0;
03914       while ((f = (TFile *)nxf()))
03915          if (f->Matches(name))
03916             return f->GetAsyncOpenStatus();
03917    }
03918 
03919    // Default is synchronous mode
03920    return kAOSNotAsync;
03921 }
03922 
03923 //______________________________________________________________________________
03924 TFile::EAsyncOpenStatus TFile::GetAsyncOpenStatus(TFileOpenHandle *handle)
03925 {
03926    // Get status of the async open request related to 'handle'.
03927 
03928    if (handle && handle->fFile) {
03929       if (!handle->fFile->IsZombie())
03930          return handle->fFile->GetAsyncOpenStatus();
03931       else
03932          return TFile::kAOSFailure;
03933    }
03934 
03935    // Default is synchronous mode
03936    return TFile::kAOSNotAsync;
03937 }
03938 
03939 //______________________________________________________________________________
03940 const TUrl *TFile::GetEndpointUrl(const char* name)
03941 {
03942    // Get final URL for file being opened asynchronously.
03943    // Returns 0 is the information is not yet available.
03944 
03945    // Check the list of pending async opem requests
03946    if (fgAsyncOpenRequests && (fgAsyncOpenRequests->GetSize() > 0)) {
03947       TIter nxr(fgAsyncOpenRequests);
03948       TFileOpenHandle *fh = 0;
03949       while ((fh = (TFileOpenHandle *)nxr()))
03950          if (fh->Matches(name))
03951             if (fh->fFile)
03952                return fh->fFile->GetEndpointUrl();
03953    }
03954 
03955    // Check also the list of files open
03956    TSeqCollection *of = gROOT->GetListOfFiles();
03957    if (of && (of->GetSize() > 0)) {
03958       TIter nxf(of);
03959       TFile *f = 0;
03960       while ((f = (TFile *)nxf()))
03961          if (f->Matches(name))
03962             return f->GetEndpointUrl();
03963    }
03964 
03965    // Information not yet available
03966    return (const TUrl *)0;
03967 }
03968 
03969 //______________________________________________________________________________
03970 void TFile::CpProgress(Long64_t bytesread, Long64_t size, TStopwatch &watch)
03971 {
03972    // Print file copy progress.
03973 
03974    fprintf(stderr, "[TFile::Cp] Total %.02f MB\t|", (Double_t)size/1048576);
03975 
03976    for (int l = 0; l < 20; l++) {
03977       if (size > 0) {
03978          if (l < 20*bytesread/size)
03979             fprintf(stderr, "=");
03980          else if (l == 20*bytesread/size)
03981             fprintf(stderr, ">");
03982          else if (l > 20*bytesread/size)
03983             fprintf(stderr, ".");
03984       } else
03985          fprintf(stderr, "=");
03986    }
03987    // Allow to update the GUI while uploading files
03988    gSystem->ProcessEvents();
03989    watch.Stop();
03990    Double_t lCopy_time = watch.RealTime();
03991    fprintf(stderr, "| %.02f %% [%.01f MB/s]\r",
03992            100.0*(size?(bytesread/size):1), bytesread/lCopy_time/1048576.);
03993    watch.Continue();
03994 }
03995 
03996 //______________________________________________________________________________
03997 Bool_t TFile::Cp(const char *src, const char *dst, Bool_t progressbar,
03998                  UInt_t buffersize)
03999 {
04000    // Allows to copy file from src to dst URL. Returns kTRUE in case of success,
04001    // kFALSE otherwise.
04002 
04003    Bool_t rmdestiferror = kFALSE;
04004    TStopwatch watch;
04005    Bool_t success = kFALSE;
04006 
04007    TUrl sURL(src, kTRUE);
04008    TUrl dURL(dst, kTRUE);
04009 
04010    TString oopt = "RECREATE";
04011    TString ourl = dURL.GetUrl();
04012 
04013    // Files will be open in RAW mode
04014    TString raw = "filetype=raw";
04015 
04016    // Set optimization options for the source file
04017    TString opt = sURL.GetOptions();
04018    if (opt != "") opt += "&";
04019    opt += raw;
04020    // Netx-related options:
04021    //    cachesz = 4*buffersize     -> 4 buffers as peak mem usage
04022    //    readaheadsz = 2*buffersize -> Keep at max 4*buffersize bytes outstanding when reading
04023    //    rmpolicy = 1               -> Remove from the cache the blk with the least offset
04024    opt += Form("&cachesz=%d&readaheadsz=%d&rmpolicy=1", 4*buffersize, 2*buffersize);
04025    sURL.SetOptions(opt);
04026 
04027    // Set optimization options for the destination file
04028    opt = dURL.GetOptions();
04029    if (opt != "") opt += "&";
04030    opt += raw;
04031    dURL.SetOptions(opt);
04032 
04033    char *copybuffer = 0;
04034 
04035    TFile *sfile = 0;
04036    TFile *dfile = 0;
04037 
04038    // Open source file
04039    if (!(sfile = TFile::Open(sURL.GetUrl(), "READ"))) {
04040       ::Error("TFile::Cp", "cannot open source file %s", src);
04041       goto copyout;
04042    }
04043    // "RECREATE" does not work always well with XROOTD
04044    // namely when some pieces of the path are missing;
04045    // we force "NEW" in such a case
04046    if (TFile::GetType(ourl, "") == TFile::kNet)
04047       if (gSystem->AccessPathName(ourl)) {
04048          oopt = "NEW";
04049          // Force creation of the missing parts of the path
04050          opt += "&mkpath=1";
04051          dURL.SetOptions(opt);
04052       }
04053 
04054    // Open destination file
04055    if (!(dfile = TFile::Open(dURL.GetUrl(), oopt))) {
04056       ::Error("TFile::Cp", "cannot open destination file %s", dst);
04057       goto copyout;
04058    }
04059 
04060    // Probably we created a new file
04061    // We have to remove it in case of errors
04062    rmdestiferror = kTRUE;
04063 
04064    sfile->Seek(0);
04065    dfile->Seek(0);
04066 
04067    copybuffer = new char[buffersize];
04068    if (!copybuffer) {
04069       ::Error("TFile::Cp", "cannot allocate the copy buffer");
04070       goto copyout;
04071    }
04072 
04073    Bool_t   readop;
04074    Bool_t   writeop;
04075    Long64_t read;
04076    Long64_t written;
04077    Long64_t totalread;
04078    Long64_t filesize;
04079    Long64_t b00;
04080    filesize  = sfile->GetSize();
04081    totalread = 0;
04082    watch.Start();
04083 
04084    b00 = sfile->GetBytesRead();
04085 
04086    do {
04087       if (progressbar) CpProgress(totalread, filesize,watch);
04088 
04089       Long64_t b1 = sfile->GetBytesRead() - b00;
04090 
04091       Long64_t readsize;
04092       if (filesize - b1 > (Long64_t)buffersize) {
04093          readsize = buffersize;
04094       } else {
04095          readsize = filesize - b1;
04096       }
04097 
04098       if (readsize == 0) break;
04099 
04100       Long64_t b0 = sfile->GetBytesRead();
04101       sfile->Seek(totalread,TFile::kBeg);
04102       readop = sfile->ReadBuffer(copybuffer, (Int_t)readsize);
04103       read   = sfile->GetBytesRead() - b0;
04104       if ((read <= 0) || readop) {
04105          ::Error("TFile::Cp", "cannot read from source file %s. readsize=%lld read=%lld readop=%d",
04106                               src, readsize, read, readop);
04107          goto copyout;
04108       }
04109 
04110       Long64_t w0 = dfile->GetBytesWritten();
04111       writeop = dfile->WriteBuffer(copybuffer, (Int_t)read);
04112       written = dfile->GetBytesWritten() - w0;
04113       if ((written != read) || writeop) {
04114          ::Error("TFile::Cp", "cannot write %lld bytes to destination file %s", read, dst);
04115          goto copyout;
04116       }
04117       totalread += read;
04118    } while (read == (Long64_t)buffersize);
04119 
04120    if (progressbar) {
04121       CpProgress(totalread, filesize,watch);
04122       fprintf(stderr, "\n");
04123    }
04124 
04125    success = kTRUE;
04126 
04127 copyout:
04128    if (sfile) sfile->Close();
04129    if (dfile) dfile->Close();
04130 
04131    if (sfile) delete sfile;
04132    if (dfile) delete dfile;
04133    if (copybuffer) delete[] copybuffer;
04134 
04135    if (rmdestiferror && (success != kTRUE))
04136       gSystem->Unlink(dst);
04137 
04138    watch.Stop();
04139    watch.Reset();
04140 
04141    return success;
04142 }
04143 
04144 //______________________________________________________________________________
04145 //The next statement is not active anymore on Linux.
04146 //Using posix_fadvise introduces a performance penalty (10 %) on optimized files
04147 //and in addition it destroys the information of TTreePerfStats
04148 #if defined(R__neverLINUX) && !defined(R__WINGCC)
04149 Bool_t TFile::ReadBufferAsync(Long64_t offset, Int_t len)
04150 {
04151    // Read specified byte range asynchronously. Actually we tell the kernel
04152    // which blocks we are going to read so it can start loading these blocks
04153    // in the buffer cache.
04154 
04155    // Shortcut to avoid having to implement dummy ReadBufferAsync() in all
04156    // I/O plugins. Override ReadBufferAsync() in plugins if async is supported.
04157    if (IsA() != TFile::Class())
04158       return kTRUE;
04159 
04160    int advice = POSIX_FADV_WILLNEED;
04161    if (len == 0) {
04162       // according POSIX spec if len is zero, all data following offset
04163       // is specified. Nevertheless ROOT uses zero to probe readahead
04164       // capadilites.
04165       advice = POSIX_FADV_NORMAL;
04166    }
04167    Double_t start = 0;
04168    if (gPerfStats != 0) start = TTimeStamp();
04169 #if defined(R__SEEK64)
04170    Int_t result = posix_fadvise64(fD, offset, len, advice);
04171 #else
04172    Int_t result = posix_fadvise(fD, offset, len, advice);
04173 #endif
04174    if (gPerfStats != 0) {
04175       gPerfStats->FileReadEvent(this, len, start);
04176    }
04177    return (result != 0);
04178 }
04179 #else
04180 Bool_t TFile::ReadBufferAsync(Long64_t, Int_t)
04181 {
04182    // Not supported yet on non Linux systems.
04183 
04184    return kTRUE;
04185 }
04186 #endif
04187 
04188 //______________________________________________________________________________
04189 Int_t TFile::GetBytesToPrefetch() const
04190 {
04191    // Max number of bytes to prefetch. By default this is 75% of the
04192    // read cache size. But specific TFile implementations may need to change it
04193 
04194    TFileCacheRead *cr = 0;
04195    if ((cr = GetCacheRead())) {
04196       Int_t bytes = cr->GetBufferSize() / 4 * 3;
04197       return ((bytes < 0) ? 0 : bytes);
04198    }
04199    return 0;
04200 }

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