Logo ROOT   6.14/05
Reference Guide
TFile.cxx
Go to the documentation of this file.
1 // @(#)root/io:$Id: 3a19890259ad6443ee313e090166614971ad4296 $
2 // Author: Rene Brun 28/11/94
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 /**
13  \defgroup IO Input/Output Library
14 
15  The library collecting the ROOT classes dedicated to data input and output.
16 
17 */
18 
19 /**
20 \file TFile.cxx
21 \class TFile
22 \ingroup IO
23 
24 A ROOT file is a suite of consecutive data records (TKey instances) with
25 a well defined format.
26 
27 If the key is located past the 32 bit file limit (> 2 GB) then some fields will
28 be 8 instead of 4 bytes:
29 
30 Byte Range | Member Name | Description
31 ----------------|-----------|--------------
32 1->4 | Nbytes | Length of compressed object (in bytes)
33 5->6 | Version | TKey version identifier
34 7->10 | ObjLen | Length of uncompressed object
35 11->14 | Datime | Date and time when object was written to file
36 15->16 | KeyLen | Length of the key structure (in bytes)
37 17->18 | Cycle | Cycle of key
38 19->22 [19->26] | SeekKey | Pointer to record itself (consistency check)
39 23->26 [27->34] | SeekPdir | Pointer to directory header
40 27->27 [35->35] | lname | Number of bytes in the class name
41 28->.. [36->..] | ClassName | Object Class Name
42 ..->.. | lname | Number of bytes in the object name
43 ..->.. | Name | lName bytes with the name of the object
44 ..->.. | lTitle | Number of bytes in the object title
45 ..->.. | Title | Title of the object
46 -----> | DATA | Data bytes associated to the object
47 
48 The first data record starts at byte fBEGIN (currently set to kBEGIN).
49 Bytes 1->kBEGIN contain the file description, when fVersion >= 1000000
50 it is a large file (> 2 GB) and the offsets will be 8 bytes long and
51 fUnits will be set to 8:
52 Byte Range | Record Name | Description
53 ----------------|-------------|------------
54 1->4 | "root" | Root file identifier
55 5->8 | fVersion | File format version
56 9->12 | fBEGIN | Pointer to first data record
57 13->16 [13->20] | fEND | Pointer to first free word at the EOF
58 17->20 [21->28] | fSeekFree | Pointer to FREE data record
59 21->24 [29->32] | fNbytesFree | Number of bytes in FREE data record
60 25->28 [33->36] | nfree | Number of free data records
61 29->32 [37->40] | fNbytesName | Number of bytes in TNamed at creation time
62 33->33 [41->41] | fUnits | Number of bytes for file pointers
63 34->37 [42->45] | fCompress | Compression level and algorithm
64 38->41 [46->53] | fSeekInfo | Pointer to TStreamerInfo record
65 42->45 [54->57] | fNbytesInfo | Number of bytes in TStreamerInfo record
66 46->63 [58->75] | fUUID | Universal Unique ID
67 
68 Begin_Macro
69 ../../../tutorials/io/file.C
70 End_Macro
71 The structure of a directory is shown in TDirectoryFile::TDirectoryFile
72 */
73 
74 #include <ROOT/RConfig.h>
75 
76 #ifdef R__LINUX
77 // for posix_fadvise
78 #ifndef _XOPEN_SOURCE
79 #define _XOPEN_SOURCE 600
80 #endif
81 #endif
82 #include <fcntl.h>
83 #include <errno.h>
84 #include <sys/stat.h>
85 #ifndef WIN32
86 # include <unistd.h>
87 #else
88 # define ssize_t int
89 # include <io.h>
90 # include <sys/types.h>
91 #endif
92 
93 #include "Bytes.h"
94 #include "Compression.h"
95 #include "Riostream.h"
96 #include "RConfigure.h"
97 #include "Strlen.h"
98 #include "TArrayC.h"
99 #include "TClass.h"
100 #include "TClassEdit.h"
101 #include "TClassTable.h"
102 #include "TDatime.h"
103 #include "TError.h"
104 #include "TFile.h"
105 #include "TFileCacheRead.h"
106 #include "TFileCacheWrite.h"
107 #include "TFree.h"
108 #include "TInterpreter.h"
109 #include "TKey.h"
110 #include "TMakeProject.h"
111 #include "TPluginManager.h"
112 #include "TProcessUUID.h"
113 #include "TRegexp.h"
114 #include "TPRegexp.h"
115 #include "TROOT.h"
116 #include "TStreamerInfo.h"
117 #include "TStreamerElement.h"
118 #include "TSystem.h"
119 #include "TTimeStamp.h"
120 #include "TVirtualPerfStats.h"
121 #include "TArchiveFile.h"
122 #include "TEnv.h"
123 #include "TVirtualMonitoring.h"
124 #include "TVirtualMutex.h"
125 #include "TMathBase.h"
126 #include "TObjString.h"
127 #include "TStopwatch.h"
128 #include "compiledata.h"
129 #include <cmath>
130 #include <set>
131 #include "TSchemaRule.h"
132 #include "TSchemaRuleSet.h"
133 #include "TThreadSlots.h"
134 #include "TGlobal.h"
135 #include "TMath.h"
136 #include "ROOT/RMakeUnique.hxx"
138 
139 using std::sqrt;
140 
141 std::atomic<Long64_t> TFile::fgBytesRead{0};
142 std::atomic<Long64_t> TFile::fgBytesWrite{0};
143 std::atomic<Long64_t> TFile::fgFileCounter{0};
144 std::atomic<Int_t> TFile::fgReadCalls{0};
153 #ifdef R__USE_IMT
156 #endif
158 const Int_t kBEGIN = 100;
159 
160 ClassImp(TFile);
161 
162 //*-*x17 macros/layout_file
163 // Needed to add the "fake" global gFile to the list of globals.
164 namespace {
165 static struct AddPseudoGlobals {
166 AddPseudoGlobals() {
167  // User "gCling" as synonym for "libCore static initialization has happened".
168  // This code here must not trigger it.
171 }
172 } gAddPseudoGlobals;
173 }
174 ////////////////////////////////////////////////////////////////////////////////
175 /// File default Constructor.
177 TFile::TFile() : TDirectoryFile(), fInfoCache(0)
178 {
179  fD = -1;
180  fFree = 0;
181  fWritten = 0;
182  fSumBuffer = 0;
183  fSum2Buffer = 0;
184  fClassIndex = 0;
185  fCompress = 0;
186  fProcessIDs = 0;
187  fNProcessIDs = 0;
188  fOffset = 0;
189  fArchive = 0;
190  fCacheRead = 0;
191  fCacheReadMap = new TMap();
192  fCacheWrite = 0;
193  fArchiveOffset = 0;
194  fReadCalls = 0;
195  fInfoCache = 0;
196  fOpenPhases = 0;
198  fIsRootFile = kTRUE;
199  fIsArchive = kFALSE;
200  fInitDone = kFALSE;
201  fMustFlush = kTRUE;
202  fIsPcmFile = kFALSE;
203  fAsyncHandle = 0;
206 
207  fBEGIN = 0;
208  fEND = 0;
209  fBytesRead = 0;
210  fBytesReadExtra = 0;
211  fBytesWrite = 0;
212  fCompress = 0;
213  fNbytesFree = 0;
214  fNbytesInfo = 0;
215  fSeekFree = 0;
216  fSeekInfo = 0;
217  fUnits = 0;
218  fVersion = 0;
219 
220  if (gDebug)
221  Info("TFile", "default ctor");
222 }
223 
224 ////////////////////////////////////////////////////////////////////////////////
225 /// Opens or creates a local ROOT file.
226 ///
227 /// \param[in] fname1 The name of the file
228 /// \param[in] option Specifies the mode in which the file is opened
229 /// \param[in] ftitle The title of the file
230 /// \param[in] compress Specifies the compression algorithm and level
231 ///
232 /// It is recommended to specify fname1 as "<file>.root". The suffix ".root"
233 /// will be used by object browsers to automatically identify the file as
234 /// a ROOT file. If the constructor fails in any way IsZombie() will
235 /// return true. Use IsOpen() to check if the file is (still) open.
236 /// To open non-local files use the static TFile::Open() method, that
237 /// will take care of opening the files using the correct remote file
238 /// access plugin.
239 ///
240 /// Option | Description
241 /// -------|------------
242 /// NEW or CREATE | Create a new file and open it for writing, if the file already exists the file is not opened.
243 /// RECREATE | Create a new file, if the file already exists it will be overwritten.
244 /// UPDATE | Open an existing file for writing. If no file exists, it is created.
245 /// READ | Open an existing file for reading (default).
246 /// NET | Used by derived remote file access classes, not a user callable option.
247 /// WEB | Used by derived remote http access class, not a user callable option.
248 ///
249 /// If option = "" (default), READ is assumed.
250 /// The file can be specified as a URL of the form:
251 ///
252 /// file:///user/rdm/bla.root or file:/user/rdm/bla.root
253 ///
254 /// The file can also be a member of an archive, in which case it is
255 /// specified as:
256 ///
257 /// multi.zip#file.root or multi.zip#0
258 ///
259 /// which will open file.root which is a member of the file multi.zip
260 /// archive or member 1 from the archive. For more on archive file
261 /// support see the TArchiveFile class.
262 /// TFile and its remote access plugins can also be used to open any
263 /// file, i.e. also non ROOT files, using:
264 ///
265 /// file.tar?filetype=raw
266 ///
267 /// This is convenient because the many remote file access plugins allow
268 /// easy access to/from the many different mass storage systems.
269 /// The title of the file (ftitle) will be shown by the ROOT browsers.
270 /// A ROOT file (like a Unix file system) may contain objects and
271 /// directories. There are no restrictions for the number of levels
272 /// of directories.
273 /// A ROOT file is designed such that one can write in the file in pure
274 /// sequential mode (case of BATCH jobs). In this case, the file may be
275 /// read sequentially again without using the file index written
276 /// at the end of the file. In case of a job crash, all the information
277 /// on the file is therefore protected.
278 /// A ROOT file can be used interactively. In this case, one has the
279 /// possibility to delete existing objects and add new ones.
280 /// When an object is deleted from the file, the freed space is added
281 /// into the FREE linked list (fFree). The FREE list consists of a chain
282 /// of consecutive free segments on the file. At the same time, the first
283 /// 4 bytes of the freed record on the file are overwritten by GAPSIZE
284 /// where GAPSIZE = -(Number of bytes occupied by the record).
285 /// Option compress is used to specify the compression level and algorithm:
286 ///
287 /// compress = 100 * algorithm + level
288 ///
289 /// Level | Explanation
290 /// ------|-------------
291 /// 0 | objects written to this file will not be compressed.
292 /// 1 | minimal compression level but fast.
293 /// ... | ....
294 /// 9 | maximal compression level but slower and might use more memory.
295 /// (For the currently supported algorithms, the maximum level is 9)
296 /// If compress is negative it indicates the compression level is not set yet.
297 /// The enumeration ROOT::ECompressionAlgorithm associates each
298 /// algorithm with a number. There is a utility function to help
299 /// to set the value of compress. For example,
300 /// ROOT::CompressionSettings(ROOT::kLZMA, 1)
301 /// will build an integer which will set the compression to use
302 /// the LZMA algorithm and compression level 1. These are defined
303 /// in the header file <em>Compression.h</em>.
304 /// Note that the compression settings may be changed at any time.
305 /// The new compression settings will only apply to branches created
306 /// or attached after the setting is changed and other objects written
307 /// after the setting is changed.
308 /// In case the file does not exist or is not a valid ROOT file,
309 /// it is made a Zombie. One can detect this situation with a code like:
310 /// ~~~{.cpp}
311 /// TFile f("file.root");
312 /// if (f.IsZombie()) {
313 /// std::cout << "Error opening file" << std::endl;
314 /// exit(-1);
315 /// }
316 /// ~~~
317 /// When opening the file, the system checks the validity of this directory.
318 /// If something wrong is detected, an automatic Recovery is performed. In
319 /// this case, the file is scanned sequentially reading all logical blocks
320 /// and attempting to rebuild a correct directory (see TFile::Recover).
321 /// One can disable the automatic recovery procedure when reading one
322 /// or more files by setting the environment variable "TFile.Recover: 0"
323 /// in the system.rootrc file.
324 ///
326 TFile::TFile(const char *fname1, Option_t *option, const char *ftitle, Int_t compress)
327  : TDirectoryFile(), fUrl(fname1,kTRUE), fInfoCache(0), fOpenPhases(0)
328 {
329  if (!gROOT)
330  ::Fatal("TFile::TFile", "ROOT system not initialized");
331 
332  // store name without the options as name and title
333  TString sfname1 = fname1;
335  if (sfname1.Index("?") != kNPOS) {
336  TString s = sfname1(0, sfname1.Index("?"));
337  SetName(s);
339  } else
340  SetName(fname1);
341 
342  SetTitle(ftitle);
343 
344  // accept also URL like "file:..." syntax
345  fname1 = fUrl.GetFile();
346 
347  // if option contains filetype=raw then go into raw file mode
348  fIsRootFile = kTRUE;
349  if (strstr(fUrl.GetOptions(), "filetype=raw"))
351 
352  // if option contains filetype=pcm then go into ROOT PCM file mode
353  fIsPcmFile = kFALSE;
354  if (strstr(fUrl.GetOptions(), "filetype=pcm"))
355  fIsPcmFile = kTRUE;
356 
357  // Init initialization control flag
358  fInitDone = kFALSE;
359  fMustFlush = kTRUE;
360 
361  // We are opening synchronously
362  fAsyncHandle = 0;
364 
365  TDirectoryFile::Build(this, 0);
366 
367  fD = -1;
368  fFree = 0;
369  fVersion = gROOT->GetVersionInt(); //ROOT version in integer format
370  fUnits = 4;
371  fOption = option;
372  fCompress = compress;
373  fWritten = 0;
374  fSumBuffer = 0;
375  fSum2Buffer = 0;
376  fBytesRead = 0;
377  fBytesReadExtra = 0;
378  fBytesWrite = 0;
379  fClassIndex = 0;
380  fSeekInfo = 0;
381  fNbytesInfo = 0;
382  fProcessIDs = 0;
383  fNProcessIDs = 0;
384  fOffset = 0;
385  fCacheRead = 0;
386  fCacheReadMap = new TMap();
387  fCacheWrite = 0;
388  fReadCalls = 0;
390 
391  fOption.ToUpper();
392 
393  fArchiveOffset = 0;
394  fIsArchive = kFALSE;
395  fArchive = 0;
396  if (fIsRootFile && !fIsPcmFile && fOption != "NEW" && fOption != "CREATE"
397  && fOption != "RECREATE") {
398  // If !gPluginMgr then we are at startup and cannot handle plugins
399  // as TArchiveFile yet.
401  if (fArchive) {
402  fname1 = fArchive->GetArchiveName();
403  // if no archive member is specified then this TFile is just used
404  // to read the archive contents
405  if (!strlen(fArchive->GetMemberName()))
406  fIsArchive = kTRUE;
407  }
408  }
409 
410  if (fOption == "NET")
411  return;
412 
413  if (fOption == "WEB") {
414  fOption = "READ";
415  fWritable = kFALSE;
416  return;
417  }
418 
419  if (fOption == "NEW")
420  fOption = "CREATE";
421 
422  Bool_t create = (fOption == "CREATE") ? kTRUE : kFALSE;
423  Bool_t recreate = (fOption == "RECREATE") ? kTRUE : kFALSE;
424  Bool_t update = (fOption == "UPDATE") ? kTRUE : kFALSE;
425  Bool_t read = (fOption == "READ") ? kTRUE : kFALSE;
426  if (!create && !recreate && !update && !read) {
427  read = kTRUE;
428  fOption = "READ";
429  }
430 
431  Bool_t devnull = kFALSE;
432 
433  if (!fname1 || !fname1[0]) {
434  Error("TFile", "file name is not specified");
435  goto zombie;
436  }
437 
438  // support dumping to /dev/null on UNIX
439  if (!strcmp(fname1, "/dev/null") &&
441  devnull = kTRUE;
442  create = kTRUE;
443  recreate = kFALSE;
444  update = kFALSE;
445  read = kFALSE;
446  fOption = "CREATE";
447  SetBit(kDevNull);
448  }
449 
450  const char *fname;
451  if ((fname = gSystem->ExpandPathName(fname1))) {
452  SetName(fname);
453  delete [] fname;
454  fRealName = GetName();
455  fname = fRealName.Data();
456  } else {
457  Error("TFile", "error expanding path %s", fname1);
458  goto zombie;
459  }
460 
461  if (recreate) {
462  if (!gSystem->AccessPathName(fname, kFileExists)) {
463  if (gSystem->Unlink(fname) != 0) {
464  SysError("TFile", "could not delete %s (errno: %d)",
465  fname, gSystem->GetErrno());
466  goto zombie;
467  }
468  }
469  recreate = kFALSE;
470  create = kTRUE;
471  fOption = "CREATE";
472  }
473  if (create && !devnull && !gSystem->AccessPathName(fname, kFileExists)) {
474  Error("TFile", "file %s already exists", fname);
475  goto zombie;
476  }
477  if (update) {
478  if (gSystem->AccessPathName(fname, kFileExists)) {
479  update = kFALSE;
480  create = kTRUE;
481  }
482  if (update && gSystem->AccessPathName(fname, kWritePermission)) {
483  Error("TFile", "no write permission, could not open file %s", fname);
484  goto zombie;
485  }
486  }
487  if (read) {
488  if (gSystem->AccessPathName(fname, kFileExists)) {
489  Error("TFile", "file %s does not exist", fname);
490  goto zombie;
491  }
492  if (gSystem->AccessPathName(fname, kReadPermission)) {
493  Error("TFile", "no read permission, could not open file %s", fname);
494  goto zombie;
495  }
496  }
497 
498  // Connect to file system stream
499  if (create || update) {
500 #ifndef WIN32
501  fD = SysOpen(fname, O_RDWR | O_CREAT, 0644);
502 #else
503  fD = SysOpen(fname, O_RDWR | O_CREAT | O_BINARY, S_IREAD | S_IWRITE);
504 #endif
505  if (fD == -1) {
506  SysError("TFile", "file %s can not be opened", fname);
507  goto zombie;
508  }
509  fWritable = kTRUE;
510  } else {
511 #ifndef WIN32
512  fD = SysOpen(fname, O_RDONLY, 0644);
513 #else
514  fD = SysOpen(fname, O_RDONLY | O_BINARY, S_IREAD | S_IWRITE);
515 #endif
516  if (fD == -1) {
517  SysError("TFile", "file %s can not be opened for reading", fname);
518  goto zombie;
519  }
520  fWritable = kFALSE;
521  }
522 
523  Init(create);
524 
525  return;
526 
527 zombie:
528  // error in file opening occurred, make this object a zombie
529  {
531  gROOT->GetListOfClosedObjects()->Add(this);
532  }
533  MakeZombie();
534  gDirectory = gROOT;
535 }
536 
537 ////////////////////////////////////////////////////////////////////////////////
538 /// TFile objects can not be copied.
541 {
542  MayNotUse("TFile::TFile(const TFile &)");
543 }
544 
545 ////////////////////////////////////////////////////////////////////////////////
546 /// File destructor.
549 {
550  Close();
551 
552  // In case where the TFile is still open at 'tear-down' time the order of operation will be
553  // call Close("nodelete")
554  // then later call delete TFile
555  // which means that at this point we might still have object held and those
556  // might requires a 'valid' TFile object in their desctructor (for example,
557  // TTree call's GetReadCache which expects a non-null fCacheReadMap).
558  // So delete the objects (if any) now.
559 
560  if (fList)
561  fList->Delete("slow");
562 
568  SafeDelete(fFree);
572 
573  {
575  gROOT->GetListOfClosedObjects()->Remove(this);
576  gROOT->GetUUIDs()->RemoveUUID(GetUniqueID());
577  }
578 
579  if (IsOnHeap()) {
580  // Delete object from CINT symbol table so it can not be used anymore.
581  // CINT object are always on the heap.
582  gInterpreter->ResetGlobalVar(this);
583  }
584 
585  if (gDebug)
586  Info("~TFile", "dtor called for %s [%lx]", GetName(),(Long_t)this);
587 }
588 
589 ////////////////////////////////////////////////////////////////////////////////
590 /// Initialize a TFile object.
591 ///
592 /// \param[in] create Create a new file.
593 ///
594 /// TFile implementations providing asynchronous open functionality need to
595 /// override this method to run the appropriate checks before calling this
596 /// standard initialization part. See TXNetFile::Init for an example.
598 void TFile::Init(Bool_t create)
599 {
600  if (fInitDone)
601  // Already called once
602  return;
603  fInitDone = kTRUE;
604 
605  if (!fIsRootFile) {
606  gDirectory = gROOT;
607  return;
608  }
609 
610  if (fArchive) {
611  if (fOption != "READ") {
612  Error("Init", "archive %s can only be opened in read mode", GetName());
613  delete fArchive;
614  fArchive = 0;
615  fIsArchive = kFALSE;
616  goto zombie;
617  }
618 
620 
621  if (fIsArchive) return;
622 
623  // Make sure the anchor is in the name
624  if (!fNoAnchorInName)
625  if (!strchr(GetName(),'#'))
627 
628  if (fArchive->SetCurrentMember() != -1)
630  else {
631  Error("Init", "member %s not found in archive %s",
633  delete fArchive;
634  fArchive = 0;
635  fIsArchive = kFALSE;
636  goto zombie;
637  }
638  }
639 
640  Int_t nfree;
641  fBEGIN = (Long64_t)kBEGIN; //First used word in file following the file header
642 
643  // make newly opened file the current file and directory
644  cd();
645 
646  if (create) {
647  //*-*---------------NEW file
648  fFree = new TList;
649  fEND = fBEGIN; //Pointer to end of file
650  new TFree(fFree, fBEGIN, Long64_t(kStartBigFile)); //Create new free list
651 
652  //*-* Write Directory info
653  Int_t namelen= TNamed::Sizeof();
654  Int_t nbytes = namelen + TDirectoryFile::Sizeof();
655  TKey *key = new TKey(fName, fTitle, IsA(), nbytes, this);
656  fNbytesName = key->GetKeylen() + namelen;
657  fSeekDir = key->GetSeekKey();
658  fSeekFree = 0;
659  fNbytesFree = 0;
660  WriteHeader();
661  char *buffer = key->GetBuffer();
662  TNamed::FillBuffer(buffer);
664  key->WriteFile();
665  delete key;
666  } else {
667  //*-*----------------UPDATE
668  //char *header = new char[kBEGIN];
669  char *header = new char[kBEGIN+200];
670  Seek(0);
671  //ReadBuffer(header, kBEGIN);
672  if (ReadBuffer(header, kBEGIN+200)) {
673  // ReadBuffer returns kTRUE in case of failure.
674  Error("Init","%s failed to read the file type data.",
675  GetName());
676  delete [] header;
677  goto zombie;
678  }
679 
680  // make sure this is a ROOT file
681  if (strncmp(header, "root", 4)) {
682  Error("Init", "%s not a ROOT file", GetName());
683  delete [] header;
684  goto zombie;
685  }
686 
687  char *buffer = header + 4; // skip the "root" file identifier
688  frombuf(buffer, &fVersion);
689  Int_t headerLength;
690  frombuf(buffer, &headerLength);
691  fBEGIN = (Long64_t)headerLength;
692  if (fVersion < 1000000) { //small file
693  Int_t send,sfree,sinfo;
694  frombuf(buffer, &send); fEND = (Long64_t)send;
695  frombuf(buffer, &sfree); fSeekFree= (Long64_t)sfree;
696  frombuf(buffer, &fNbytesFree);
697  frombuf(buffer, &nfree);
698  frombuf(buffer, &fNbytesName);
699  frombuf(buffer, &fUnits );
700  frombuf(buffer, &fCompress);
701  frombuf(buffer, &sinfo); fSeekInfo = (Long64_t)sinfo;
702  frombuf(buffer, &fNbytesInfo);
703  } else { // new format to support large files
704  frombuf(buffer, &fEND);
705  frombuf(buffer, &fSeekFree);
706  frombuf(buffer, &fNbytesFree);
707  frombuf(buffer, &nfree);
708  frombuf(buffer, &fNbytesName);
709  frombuf(buffer, &fUnits );
710  frombuf(buffer, &fCompress);
711  frombuf(buffer, &fSeekInfo);
712  frombuf(buffer, &fNbytesInfo);
713  }
714  if (fBEGIN < 0 || fBEGIN > fEND) {
715  // humm fBEGIN is wrong ....
716  Error("Init","file %s has an incorrect header length (%lld) or incorrect end of file length (%lld)",
717  GetName(),fBEGIN,fEND);
718  goto zombie;
719  }
720  fSeekDir = fBEGIN;
721  //*-*-------------Read Free segments structure if file is writable
722  if (fWritable) {
723  fFree = new TList;
724  if (fSeekFree > fBEGIN) {
725  ReadFree();
726  } else {
727  Warning("Init","file %s probably not closed, cannot read free segments",GetName());
728  }
729  }
730  //*-*-------------Read directory info
731  // buffer_keyloc is the start of the key record.
732  char *buffer_keyloc = 0;
733 
735  if ( (nbytes + fBEGIN) > fEND) {
736  // humm fBEGIN is wrong ....
737  Error("Init","file %s has an incorrect header length (%lld) or incorrect end of file length (%lld)",
738  GetName(),fBEGIN+nbytes,fEND);
739  goto zombie;
740  }
741  if (nbytes+fBEGIN > kBEGIN+200) {
742  delete [] header;
743  header = new char[nbytes];
744  buffer = header;
745  Seek(fBEGIN);
746  if (ReadBuffer(buffer,nbytes)) {
747  // ReadBuffer returns kTRUE in case of failure.
748  Error("Init","%s failed to read the file header information at %lld (size=%d)",
749  GetName(),fBEGIN,nbytes);
750  delete [] header;
751  goto zombie;
752  }
753  buffer = header+fNbytesName;
754  buffer_keyloc = header;
755  } else {
756  buffer = header+fBEGIN+fNbytesName;
757  buffer_keyloc = header+fBEGIN;
758  }
759  Version_t version,versiondir;
760  frombuf(buffer,&version); versiondir = version%1000;
761  fDatimeC.ReadBuffer(buffer);
762  fDatimeM.ReadBuffer(buffer);
763  frombuf(buffer, &fNbytesKeys);
764  frombuf(buffer, &fNbytesName);
765  if (version > 1000) {
766  frombuf(buffer, &fSeekDir);
767  frombuf(buffer, &fSeekParent);
768  frombuf(buffer, &fSeekKeys);
769  } else {
770  Int_t sdir,sparent,skeys;
771  frombuf(buffer, &sdir); fSeekDir = (Long64_t)sdir;
772  frombuf(buffer, &sparent); fSeekParent = (Long64_t)sparent;
773  frombuf(buffer, &skeys); fSeekKeys = (Long64_t)skeys;
774  }
775  if (versiondir > 1) fUUID.ReadBuffer(buffer);
776 
777  //*-*---------read TKey::FillBuffer info
778  buffer_keyloc += sizeof(Int_t); // Skip NBytes;
779  Version_t keyversion;
780  frombuf(buffer_keyloc, &keyversion);
781  // Skip ObjLen, DateTime, KeyLen, Cycle, SeekKey, SeekPdir
782  if (keyversion > 1000) {
783  // Large files
784  buffer_keyloc += 2*sizeof(Int_t)+2*sizeof(Short_t)+2*sizeof(Long64_t);
785  } else {
786  buffer_keyloc += 2*sizeof(Int_t)+2*sizeof(Short_t)+2*sizeof(Int_t);
787  }
788  TString cname;
789  cname.ReadBuffer(buffer_keyloc);
790  cname.ReadBuffer(buffer_keyloc); // fName.ReadBuffer(buffer); file may have been renamed
791  fTitle.ReadBuffer(buffer_keyloc);
792  delete [] header;
793  if (fNbytesName < 10 || fNbytesName > 10000) {
794  Error("Init","cannot read directory info of file %s", GetName());
795  goto zombie;
796  }
797 
798  //*-* -------------Check if file is truncated
799  Long64_t size;
800  if ((size = GetSize()) == -1) {
801  Error("Init", "cannot stat the file %s", GetName());
802  goto zombie;
803  }
804 
805  //*-* -------------Check if, in case of inconsistencies, we are requested to
806  //*-* -------------attempt recovering the file
807  Bool_t tryrecover = (gEnv->GetValue("TFile.Recover", 1) == 1) ? kTRUE : kFALSE;
808 
809  //*-* -------------Read keys of the top directory
810  if (fSeekKeys > fBEGIN && fEND <= size) {
811  //normal case. Recover only if file has no keys
813  gDirectory = this;
814  if (!GetNkeys()) {
815  if (tryrecover) {
816  Recover();
817  } else {
818  Error("Init", "file %s has no keys", GetName());
819  goto zombie;
820  }
821  }
822  } else if ((fBEGIN+nbytes == fEND) && (fEND == size)) {
823  //the file might be open by another process and nothing written to the file yet
824  Warning("Init","file %s has no keys", GetName());
825  gDirectory = this;
826  } else {
827  //something had been written to the file. Trailer is missing, must recover
828  if (fEND > size) {
829  if (tryrecover) {
830  Error("Init","file %s is truncated at %lld bytes: should be %lld, "
831  "trying to recover", GetName(), size, fEND);
832  } else {
833  Error("Init","file %s is truncated at %lld bytes: should be %lld",
834  GetName(), size, fEND);
835  goto zombie;
836  }
837  } else {
838  if (tryrecover) {
839  Warning("Init","file %s probably not closed, "
840  "trying to recover", GetName());
841  } else {
842  Warning("Init","file %s probably not closed", GetName());
843  goto zombie;
844  }
845  }
846  Int_t nrecov = Recover();
847  if (nrecov) {
848  Warning("Init", "successfully recovered %d keys", nrecov);
849  } else {
850  Warning("Init", "no keys recovered, file has been made a Zombie");
851  goto zombie;
852  }
853  }
854  }
855 
856  {
858  gROOT->GetListOfFiles()->Add(this);
859  gROOT->GetUUIDs()->AddUUID(fUUID,this);
860  }
861 
862  // Create StreamerInfo index
863  {
864  Int_t lenIndex = gROOT->GetListOfStreamerInfo()->GetSize()+1;
865  if (lenIndex < 5000) lenIndex = 5000;
866  fClassIndex = new TArrayC(lenIndex);
867  if (fgReadInfo) {
868  if (fSeekInfo > fBEGIN) {
870  if (IsZombie()) {
872  gROOT->GetListOfFiles()->Remove(this);
873  goto zombie;
874  }
875  } else if (fVersion != gROOT->GetVersionInt() && fVersion > 30000) {
876  // Don't complain about missing streamer info for empty files.
877  if (fKeys->GetSize()) {
878  Warning("Init","no StreamerInfo found in %s therefore preventing schema evolution when reading this file.",GetName());
879  }
880  }
881  }
882  }
883 
884  // Count number of TProcessIDs in this file
885  {
886  TIter next(fKeys);
887  TKey *key;
888  while ((key = (TKey*)next())) {
889  if (!strcmp(key->GetClassName(),"TProcessID")) fNProcessIDs++;
890  }
892  }
893  return;
894 
895 zombie:
896  {
898  gROOT->GetListOfClosedObjects()->Add(this);
899  }
900  // error in file opening occurred, make this object a zombie
901  fWritable = kFALSE;
902  MakeZombie();
903  gDirectory = gROOT;
904 }
905 
906 ////////////////////////////////////////////////////////////////////////////////
907 /// Close a file.
908 ///
909 /// \param[in] option If option == "R", all TProcessIDs referenced by this file are deleted.
910 ///
911 /// Calling TFile::Close("R") might be necessary in case one reads a long list
912 /// of files having TRef, writing some of the referenced objects or TRef
913 /// to a new file. If the TRef or referenced objects of the file being closed
914 /// will not be referenced again, it is possible to minimize the size
915 /// of the TProcessID data structures in memory by forcing a delete of
916 /// the unused TProcessID.
918 void TFile::Close(Option_t *option)
919 {
920  TString opt = option;
921 
922  opt.ToLower();
923 
924  if (!IsOpen()) return;
925 
926  if (fIsArchive || !fIsRootFile) {
927  FlushWriteCache();
928  SysClose(fD);
929  fD = -1;
930 
931  if (gMonitoringWriter)
933 
934  return;
935  }
936 
937  if (IsWritable()) {
939  }
940 
941  // Finish any concurrent I/O operations before we close the file handles.
942  if (fCacheRead) fCacheRead->Close();
943  {
944  TIter iter(fCacheReadMap);
945  TObject *key = 0;
946  while ((key = iter()) != 0) {
947  TFileCacheRead *cache = dynamic_cast<TFileCacheRead *>(fCacheReadMap->GetValue(key));
948  cache->Close();
949  }
950  }
951 
952  // Delete all supported directories structures from memory
953  // If gDirectory points to this object or any of the nested
954  // TDirectoryFile, TDirectoryFile::Close will induce the proper cd.
955  fMustFlush = kFALSE; // Make sure there is only one Flush.
956  TDirectoryFile::Close(option);
957 
958  if (IsWritable()) {
959  TFree *f1 = (TFree*)fFree->First();
960  if (f1) {
961  WriteFree(); //*-*- Write free segments linked list
962  WriteHeader(); //*-*- Now write file header ; this forces a Flush/fsync
963  } else {
964  Flush();
965  }
966  }
967  fMustFlush = kTRUE;
968 
969  FlushWriteCache();
970 
971  if (gMonitoringWriter)
973 
974  delete fClassIndex;
975  fClassIndex = 0;
976 
977  // Delete free segments from free list (but don't delete list header)
978  if (fFree) {
979  fFree->Delete();
980  }
981 
982  if (IsOpen()) {
983  SysClose(fD);
984  fD = -1;
985  }
986 
987  fWritable = kFALSE;
988 
989  // delete the TProcessIDs
990  TList pidDeleted;
991  TIter next(fProcessIDs);
992  TProcessID *pid;
993  while ((pid = (TProcessID*)next())) {
994  if (!pid->DecrementCount()) {
995  if (pid != TProcessID::GetSessionProcessID()) pidDeleted.Add(pid);
996  } else if(opt.Contains("r")) {
997  pid->Clear();
998  }
999  }
1000  pidDeleted.Delete();
1001 
1002  if (!IsZombie()) {
1004  gROOT->GetListOfFiles()->Remove(this);
1005  gROOT->GetListOfBrowsers()->RecursiveRemove(this);
1006  gROOT->GetListOfClosedObjects()->Add(this);
1007  } else {
1008  // If we are a zombie, we are already in the list of closed objects.
1009  }
1010 }
1011 
1012 ////////////////////////////////////////////////////////////////////////////////
1013 /// Creates key for object and converts data to buffer.
1015 TKey* TFile::CreateKey(TDirectory* mother, const TObject* obj, const char* name, Int_t bufsize)
1016 {
1017  return new TKey(obj, name, bufsize, mother);
1018 }
1019 
1020 ////////////////////////////////////////////////////////////////////////////////
1021 /// Creates key for object and converts data to buffer.
1023 TKey* TFile::CreateKey(TDirectory* mother, const void* obj, const TClass* cl, const char* name, Int_t bufsize)
1024 {
1025  return new TKey(obj, cl, name, bufsize, mother);
1026 }
1027 
1028 ////////////////////////////////////////////////////////////////////////////////
1029 /// Return the current ROOT file if any.
1030 ///
1031 /// Note that if 'cd' has been called on a TDirectory that does not belong to a file,
1032 /// gFile will be unchanged and still points to the file of the previous current
1033 /// directory that was a file.
1036 {
1037  static TFile *currentFile = 0;
1038  if (!gThreadTsd)
1039  return currentFile;
1040  else
1041  return *(TFile**)(*gThreadTsd)(&currentFile,ROOT::kFileThreadSlot);
1042 }
1043 
1044 ////////////////////////////////////////////////////////////////////////////////
1045 /// Delete object namecycle.
1046 ///
1047 /// \param[in] namecycle Encodes the name and cycle of the objects to delete
1048 ///
1049 /// Namecycle identifies an object in the top directory of the file namecycle
1050 /// has the format <em>name;cycle</em>.
1051 /// - <em>name = *</em> means all objects
1052 /// - <em>cycle = *</em> means all cycles (memory and keys)
1053 /// - <em>cycle = ""</em> or cycle = 9999 ==> apply to a memory object
1054 /// When name=* use T* to delete subdirectories also
1055 ///
1056 /// Examples:
1057 /// name/cycle | Action
1058 /// -----------|-------
1059 /// foo | delete object named foo in memory
1060 /// foo;1 | delete cycle 1 of foo on file
1061 /// foo;* | delete all cycles of foo on disk and also from memory
1062 /// *;2 | delete all objects on file having the cycle 2
1063 /// *;* | delete all objects from memory and file
1064 /// T*;* | delete all objects from memory and file and all subdirectories
1066 void TFile::Delete(const char *namecycle)
1067 {
1068  if (gDebug)
1069  Info("Delete", "deleting name = %s", namecycle);
1070 
1071  TDirectoryFile::Delete(namecycle);
1072 }
1073 
1074 ////////////////////////////////////////////////////////////////////////////////
1075 /// Fill Graphics Structure and Paint.
1076 ///
1077 /// Loop on all objects (memory or file) and all subdirectories.
1079 void TFile::Draw(Option_t *option)
1080 {
1081  GetList()->R__FOR_EACH(TObject,Draw)(option);
1082 }
1083 
1084 ////////////////////////////////////////////////////////////////////////////////
1085 /// Draw map of objects in this file.
1087 void TFile::DrawMap(const char *keys, Option_t *option)
1088 {
1089  TPluginHandler *h;
1090  if ((h = gROOT->GetPluginManager()->FindHandler("TFileDrawMap"))) {
1091  if (h->LoadPlugin() == -1)
1092  return;
1093  h->ExecPlugin(3, this, keys, option);
1094  }
1095 }
1096 
1097 ////////////////////////////////////////////////////////////////////////////////
1098 /// Synchronize a file's in-memory and on-disk states.
1100 void TFile::Flush()
1101 {
1102  if (IsOpen() && fWritable) {
1103  FlushWriteCache();
1104  if (SysSync(fD) < 0) {
1105  // Write the system error only once for this file
1107  SysError("Flush", "error flushing file %s", GetName());
1108  }
1109  }
1110 }
1111 
1112 ////////////////////////////////////////////////////////////////////////////////
1113 /// Flush the write cache if active.
1114 ///
1115 /// Return kTRUE in case of error
1118 {
1119  if (fCacheWrite && IsOpen() && fWritable)
1120  return fCacheWrite->Flush();
1121  return kFALSE;
1122 }
1123 
1124 ////////////////////////////////////////////////////////////////////////////////
1125 /// Encode file output buffer.
1126 ///
1127 /// The file output buffer contains only the FREE data record.
1129 void TFile::FillBuffer(char *&buffer)
1130 {
1131  Version_t version = TFile::Class_Version();
1132  tobuf(buffer, version);
1133 }
1134 
1135 ////////////////////////////////////////////////////////////////////////////////
1136 /// Return the best buffer size of objects on this file.
1137 ///
1138 /// The best buffer size is estimated based on the current mean value
1139 /// and standard deviation of all objects written so far to this file.
1140 /// Returns mean value + one standard deviation.
1143 {
1144  if (!fWritten) return TBuffer::kInitialSize;
1145  Double_t mean = fSumBuffer/fWritten;
1146  Double_t rms2 = TMath::Abs(fSum2Buffer/fSumBuffer -mean*mean);
1147  return (Int_t)(mean + sqrt(rms2));
1148 }
1149 
1150 ////////////////////////////////////////////////////////////////////////////////
1151 /// Return the file compression factor.
1152 ///
1153 /// Add total number of compressed/uncompressed bytes for each key.
1154 /// Returns the ratio of the two.
1157 {
1158  Short_t keylen;
1159  UInt_t datime;
1160  Int_t nbytes, objlen, nwh = 64;
1161  char *header = new char[fBEGIN];
1162  char *buffer;
1163  Long64_t idcur = fBEGIN;
1164  Float_t comp,uncomp;
1165  comp = uncomp = fBEGIN;
1166 
1167  while (idcur < fEND-100) {
1168  Seek(idcur);
1169  if (ReadBuffer(header, nwh)) {
1170  // ReadBuffer returns kTRUE in case of failure.
1171 // Error("GetCompressionFactor","%s failed to read the key header information at %lld (size=%d).",
1172 // GetName(),idcur,nwh);
1173  break;
1174  }
1175  buffer=header;
1176  frombuf(buffer, &nbytes);
1177  if (nbytes < 0) {
1178  idcur -= nbytes;
1179  Seek(idcur);
1180  continue;
1181  }
1182  if (nbytes == 0) break; //this may happen when the file is corrupted
1183  Version_t versionkey;
1184  frombuf(buffer, &versionkey);
1185  frombuf(buffer, &objlen);
1186  frombuf(buffer, &datime);
1187  frombuf(buffer, &keylen);
1188  if (!objlen) objlen = nbytes-keylen;
1189  comp += nbytes;
1190  uncomp += keylen + objlen;
1191  idcur += nbytes;
1192  }
1193  delete [] header;
1194  return uncomp/comp;
1195 }
1196 
1197 ////////////////////////////////////////////////////////////////////////////////
1198 /// Method returning errno. Is overriden in TRFIOFile.
1200 Int_t TFile::GetErrno() const
1201 {
1202  return TSystem::GetErrno();
1203 }
1204 
1205 ////////////////////////////////////////////////////////////////////////////////
1206 /// Method resetting the errno. Is overridden in TRFIOFile.
1208 void TFile::ResetErrno() const
1209 {
1211 }
1212 
1213 ////////////////////////////////////////////////////////////////////////////////
1214 /// Return a pointer to the current read cache.
1217 {
1218  if (!tree) {
1219  if (!fCacheRead && fCacheReadMap->GetSize() == 1) {
1220  TIter next(fCacheReadMap);
1221  return (TFileCacheRead *)fCacheReadMap->GetValue(next());
1222  }
1223  return fCacheRead;
1224  }
1226  if (!cache) return fCacheRead;
1227  return cache;
1228 }
1229 
1230 ////////////////////////////////////////////////////////////////////////////////
1231 /// Return a pointer to the current write cache.
1234 {
1235  return fCacheWrite;
1236 }
1237 
1238 ////////////////////////////////////////////////////////////////////////////////
1239 /// Read the logical record header starting at a certain postion.
1240 ///
1241 /// \param[in] maxbytes Bytes which are read into buf.
1242 /// \param[out] nbytes Number of bytes in record if negative, this is a deleted
1243 /// record if 0, cannot read record, wrong value of argument first
1244 /// \param[out] objlen Uncompressed object size
1245 /// \param[out] keylen Length of logical record header
1246 ///
1247 /// The function reads nread bytes
1248 /// where nread is the minimum of maxbytes and the number of bytes
1249 /// before the end of file. The function returns nread.
1250 /// Note that the arguments objlen and keylen are returned only
1251 /// if maxbytes >=16
1253 Int_t TFile::GetRecordHeader(char *buf, Long64_t first, Int_t maxbytes, Int_t &nbytes, Int_t &objlen, Int_t &keylen)
1254 {
1255  nbytes = 0;
1256  objlen = 0;
1257  keylen = 0;
1258  if (first < fBEGIN) return 0;
1259  if (first > fEND) return 0;
1260  Seek(first);
1261  Int_t nread = maxbytes;
1262  if (first+maxbytes > fEND) nread = fEND-maxbytes;
1263  if (nread < 4) {
1264  Warning("GetRecordHeader","%s: parameter maxbytes = %d must be >= 4",
1265  GetName(), nread);
1266  return nread;
1267  }
1268  if (ReadBuffer(buf,nread)) {
1269  // ReadBuffer return kTRUE in case of failure.
1270  Warning("GetRecordHeader","%s: failed to read header data (maxbytes = %d)",
1271  GetName(), nread);
1272  return nread;
1273  }
1274  Version_t versionkey;
1275  Short_t klen;
1276  UInt_t datime;
1277  Int_t nb,olen;
1278  char *buffer = buf;
1279  frombuf(buffer,&nb);
1280  nbytes = nb;
1281  if (nb < 0) return nread;
1282  // const Int_t headerSize = Int_t(sizeof(nb) +sizeof(versionkey) +sizeof(olen) +sizeof(datime) +sizeof(klen));
1283  const Int_t headerSize = 16;
1284  if (nread < headerSize) return nread;
1285  frombuf(buffer, &versionkey);
1286  frombuf(buffer, &olen);
1287  frombuf(buffer, &datime);
1288  frombuf(buffer, &klen);
1289  if (!olen) olen = nbytes-klen;
1290  objlen = olen;
1291  keylen = klen;
1292  return nread;
1293 }
1294 
1295 ////////////////////////////////////////////////////////////////////////////////
1296 /// Returns the current file size. Returns -1 in case the file could not
1297 /// be stat'ed.
1299 Long64_t TFile::GetSize() const
1300 {
1301  Long64_t size;
1302 
1303  if (fArchive && fArchive->GetMember()) {
1304  size = fArchive->GetMember()->GetDecompressedSize();
1305  } else {
1306  Long_t id, flags, modtime;
1307  if (const_cast<TFile*>(this)->SysStat(fD, &id, &size, &flags, &modtime)) {
1308  Error("GetSize", "cannot stat the file %s", GetName());
1309  return -1;
1310  }
1311  }
1312  return size;
1313 }
1314 
1315 ////////////////////////////////////////////////////////////////////////////////
1316 /// Returns the cached list of StreamerInfos used in this file.
1319 {
1321 }
1322 
1323 ////////////////////////////////////////////////////////////////////////////////
1324 /// See documentation of GetStreamerInfoList for more details.
1325 /// This is an internal method which returns the list of streamer infos and also
1326 /// information about the success of the operation.
1329 {
1331 
1332  if (fIsPcmFile) return {nullptr, 1, hash}; // No schema evolution for ROOT PCM files.
1333 
1334  TList *list = 0;
1335  if (fSeekInfo) {
1336  TDirectory::TContext ctxt(this); // gFile and gDirectory used in ReadObj
1337  auto key = std::make_unique<TKey>(this);
1338  std::vector<char> buffer(fNbytesInfo+1);
1339  auto buf = buffer.data();
1340  Seek(fSeekInfo);
1341  if (ReadBuffer(buf,fNbytesInfo)) {
1342  // ReadBuffer returns kTRUE in case of failure.
1343  Warning("GetRecordHeader","%s: failed to read the StreamerInfo data from disk.",
1344  GetName());
1345  return {nullptr, 1, hash};
1346  }
1347 
1348 #ifdef R__USE_IMT
1349  if (lookupSICache) {
1350  hash = fgTsSIHashes.Hash(buf, fNbytesInfo);
1351  if (fgTsSIHashes.Find(hash)) {
1352  if (gDebug > 0) Info("GetStreamerInfo", "The streamer info record for file %s has already been treated, skipping it.", GetName());
1353  return {nullptr, 0, hash};
1354  }
1355  }
1356 #else
1357  (void) lookupSICache;
1358 #endif
1359  key->ReadKeyBuffer(buf);
1360  list = dynamic_cast<TList*>(key->ReadObjWithBuffer(buffer.data()));
1361  if (list) list->SetOwner();
1362  } else {
1363  list = (TList*)Get("StreamerInfo"); //for versions 2.26 (never released)
1364  }
1365 
1366  if (list == 0) {
1367  Info("GetStreamerInfoList", "cannot find the StreamerInfo record in file %s",
1368  GetName());
1369  return {nullptr, 1, hash};
1370  }
1371 
1372  return {list, 0, hash};
1373 }
1374 
1375 ////////////////////////////////////////////////////////////////////////////////
1376 /// Read the list of TStreamerInfo objects written to this file.
1377 ///
1378 /// The function returns a TList. It is the user's responsibility
1379 /// to delete the list created by this function.
1380 ///
1381 /// Note the list, in addition to TStreamerInfo object, contains sometimes
1382 /// a TList named 'listOfRules' and containing the schema evolution rules
1383 /// related to the file's content.
1384 ///
1385 /// Using the list, one can access additional information, e.g.:
1386 /// ~~~{.cpp}
1387 /// TFile f("myfile.root");
1388 /// auto list = f.GetStreamerInfoList();
1389 /// auto info = dynamic_cast<TStreamerInfo*>(list->FindObject("MyClass"));
1390 /// if (info) auto classversionid = info->GetClassVersion();
1391 /// delete list;
1392 /// ~~~
1393 ///
1396 {
1397  return GetStreamerInfoListImpl(/*lookupSICache*/ false).fList;
1398 }
1399 
1400 ////////////////////////////////////////////////////////////////////////////////
1401 /// List file contents.
1402 ///
1403 /// Indentation is used to identify the file tree.
1404 /// Subdirectories are listed first, then objects in memory,
1405 /// then objects on the file.
1407 void TFile::ls(Option_t *option) const
1408 {
1410  std::cout <<ClassName()<<"**\t\t"<<GetName()<<"\t"<<GetTitle()<<std::endl;
1412  TDirectoryFile::ls(option);
1414 }
1415 
1416 ////////////////////////////////////////////////////////////////////////////////
1417 /// Returns kTRUE in case file is open and kFALSE if file is not open.
1419 Bool_t TFile::IsOpen() const
1420 {
1421  return fD == -1 ? kFALSE : kTRUE;
1422 }
1423 
1424 ////////////////////////////////////////////////////////////////////////////////
1425 /// Mark unused bytes on the file.
1426 ///
1427 /// The list of free segments is in the fFree linked list.
1428 /// When an object is deleted from the file, the freed space is added
1429 /// into the FREE linked list (fFree). The FREE list consists of a chain
1430 /// of consecutive free segments on the file. At the same time, the first
1431 /// 4 bytes of the freed record on the file are overwritten by GAPSIZE
1432 /// where GAPSIZE = -(Number of bytes occupied by the record).
1435 {
1436  TFree *f1 = (TFree*)fFree->First();
1437  if (!f1) return;
1438  TFree *newfree = f1->AddFree(fFree,first,last);
1439  if(!newfree) return;
1440  Long64_t nfirst = newfree->GetFirst();
1441  Long64_t nlast = newfree->GetLast();
1442  Long64_t nbytesl= nlast-nfirst+1;
1443  if (nbytesl > 2000000000) nbytesl = 2000000000;
1444  Int_t nbytes = -Int_t (nbytesl);
1445  Int_t nb = sizeof(Int_t);
1446  char * buffer = new char[nb];
1447  char * psave = buffer;
1448  tobuf(buffer, nbytes);
1449  if (last == fEND-1) fEND = nfirst;
1450  Seek(nfirst);
1451  // We could not update the meta data for this block on the file.
1452  // This is not fatal as this only means that we won't get it 'right'
1453  // if we ever need to Recover the file before the block is actually
1454  // (attempted to be reused.
1455  // coverity[unchecked_value]
1456  WriteBuffer(psave, nb);
1457  if (fMustFlush) Flush();
1458  delete [] psave;
1459 }
1460 
1461 ////////////////////////////////////////////////////////////////////////////////
1462 /// List the contents of a file sequentially.
1463 /// For each logical record found, it prints:
1464 ///
1465 /// Date/Time Record_Adress Logical_Record_Length ClassName CompressionFactor
1466 ///
1467 /// Example of output
1468 ///
1469 /// 20010404/150437 At:64 N=150 TFile
1470 /// 20010404/150440 At:214 N=28326 TBasket CX = 1.13
1471 /// 20010404/150440 At:28540 N=29616 TBasket CX = 1.08
1472 /// 20010404/150440 At:58156 N=29640 TBasket CX = 1.08
1473 /// 20010404/150440 At:87796 N=29076 TBasket CX = 1.10
1474 /// 20010404/150440 At:116872 N=10151 TBasket CX = 3.15
1475 /// 20010404/150441 At:127023 N=28341 TBasket CX = 1.13
1476 /// 20010404/150441 At:155364 N=29594 TBasket CX = 1.08
1477 /// 20010404/150441 At:184958 N=29616 TBasket CX = 1.08
1478 /// 20010404/150441 At:214574 N=29075 TBasket CX = 1.10
1479 /// 20010404/150441 At:243649 N=9583 TBasket CX = 3.34
1480 /// 20010404/150442 At:253232 N=28324 TBasket CX = 1.13
1481 /// 20010404/150442 At:281556 N=29641 TBasket CX = 1.08
1482 /// 20010404/150442 At:311197 N=29633 TBasket CX = 1.08
1483 /// 20010404/150442 At:340830 N=29091 TBasket CX = 1.10
1484 /// 20010404/150442 At:369921 N=10341 TBasket CX = 3.09
1485 /// 20010404/150442 At:380262 N=509 TH1F CX = 1.93
1486 /// 20010404/150442 At:380771 N=1769 TH2F CX = 4.32
1487 /// 20010404/150442 At:382540 N=1849 TProfile CX = 1.65
1488 /// 20010404/150442 At:384389 N=18434 TNtuple CX = 4.51
1489 /// 20010404/150442 At:402823 N=307 KeysList
1490 /// 20010404/150443 At:403130 N=4548 StreamerInfo CX = 3.65
1491 /// 20010404/150443 At:407678 N=86 FreeSegments
1492 /// 20010404/150443 At:407764 N=1 END
1493 ///
1494 /// If the parameter opt contains "forComp", the Date/Time is ommitted
1495 /// and the decompressed size is also printed.
1496 ///
1497 /// Record_Adress Logical_Record_Length Key_Length Object_Record_Length ClassName CompressionFactor
1498 ///
1499 /// Example of output
1500 ///
1501 
1503 void TFile::Map(Option_t *opt)
1504 {
1505  TString options(opt);
1506  options.ToLower();
1507  bool forComp = options.Contains("forcomp");
1508 
1509  Short_t keylen,cycle;
1510  UInt_t datime;
1511  Int_t nbytes,date,time,objlen,nwheader;
1512  date = 0;
1513  time = 0;
1514  Long64_t seekkey,seekpdir;
1515  char *buffer;
1516  char nwhc;
1517  Long64_t idcur = fBEGIN;
1518 
1519  nwheader = 64;
1520  Int_t nread = nwheader;
1521 
1522  char header[kBEGIN];
1523  char classname[512];
1524 
1525  unsigned char nDigits = TMath::Log10(fEND) + 1;
1526 
1527  while (idcur < fEND) {
1528  Seek(idcur);
1529  if (idcur+nread >= fEND) nread = fEND-idcur-1;
1530  if (ReadBuffer(header, nread)) {
1531  // ReadBuffer returns kTRUE in case of failure.
1532  Warning("Map","%s: failed to read the key data from disk at %lld.",
1533  GetName(),idcur);
1534  break;
1535  }
1536 
1537  buffer=header;
1538  frombuf(buffer, &nbytes);
1539  if (!nbytes) {
1540  Printf("Address = %lld\tNbytes = %d\t=====E R R O R=======", idcur, nbytes);
1541  date = 0; time = 0;
1542  break;
1543  }
1544  if (nbytes < 0) {
1545  Printf("Address = %lld\tNbytes = %d\t=====G A P===========", idcur, nbytes);
1546  idcur -= nbytes;
1547  Seek(idcur);
1548  continue;
1549  }
1550  Version_t versionkey;
1551  frombuf(buffer, &versionkey);
1552  frombuf(buffer, &objlen);
1553  frombuf(buffer, &datime);
1554  frombuf(buffer, &keylen);
1555  frombuf(buffer, &cycle);
1556  if (versionkey > 1000) {
1557  frombuf(buffer, &seekkey);
1558  frombuf(buffer, &seekpdir);
1559  } else {
1560  Int_t skey,sdir;
1561  frombuf(buffer, &skey); seekkey = (Long64_t)skey;
1562  frombuf(buffer, &sdir); seekpdir = (Long64_t)sdir;
1563  }
1564  frombuf(buffer, &nwhc);
1565  for (int i = 0;i < nwhc; i++) frombuf(buffer, &classname[i]);
1566  classname[(int)nwhc] = '\0'; //cast to avoid warning with gcc3.4
1567  if (idcur == fSeekFree) strlcpy(classname,"FreeSegments",512);
1568  if (idcur == fSeekInfo) strlcpy(classname,"StreamerInfo",512);
1569  if (idcur == fSeekKeys) strlcpy(classname,"KeysList",512);
1570  TDatime::GetDateTime(datime, date, time);
1571  if (!forComp) {
1572  if (objlen != nbytes - keylen) {
1573  Float_t cx = Float_t(objlen + keylen) / Float_t(nbytes);
1574  Printf("%d/%06d At:%-*lld N=%-8d %-14s CX = %5.2f", date, time, nDigits + 1, idcur, nbytes, classname,
1575  cx);
1576  } else {
1577  Printf("%d/%06d At:%-*lld N=%-8d %-14s", date, time, nDigits + 1, idcur, nbytes, classname);
1578  }
1579  } else {
1580  // Printing to help compare two files.
1581  if (objlen != nbytes - keylen) {
1582  Float_t cx = Float_t(objlen + keylen) / Float_t(nbytes);
1583  Printf("At:%-*lld N=%-8d K=%-3d O=%-8d %-14s CX = %5.2f", nDigits+1, idcur, nbytes, keylen, objlen, classname, cx);
1584  } else {
1585  Printf("At:%-*lld N=%-8d K=%-3d O=%-8d %-14s CX = 1", nDigits+1, idcur, nbytes, keylen, objlen, classname);
1586  }
1587  }
1588  idcur += nbytes;
1589  }
1590  if (!forComp)
1591  Printf("%d/%06d At:%-*lld N=%-8d %-14s",date,time, nDigits+1, idcur,1,"END");
1592  else
1593  Printf("At:%-*lld N=%-8d K= O= %-14s", nDigits+1, idcur,1,"END");
1594 }
1595 
1596 ////////////////////////////////////////////////////////////////////////////////
1597 /// Paint all objects in the file.
1599 void TFile::Paint(Option_t *option)
1600 {
1601  GetList()->R__FOR_EACH(TObject,Paint)(option);
1602 }
1603 
1604 ////////////////////////////////////////////////////////////////////////////////
1605 /// Print all objects in the file.
1607 void TFile::Print(Option_t *option) const
1608 {
1609  Printf("TFile: name=%s, title=%s, option=%s", GetName(), GetTitle(), GetOption());
1610  GetList()->R__FOR_EACH(TObject,Print)(option);
1611 }
1612 
1613 ////////////////////////////////////////////////////////////////////////////////
1614 /// Read a buffer from the file at the offset 'pos' in the file.
1615 ///
1616 /// Returns kTRUE in case of failure.
1617 /// Compared to ReadBuffer(char*, Int_t), this routine does _not_
1618 /// change the cursor on the physical file representation (fD)
1619 /// if the data is in this TFile's cache.
1621 Bool_t TFile::ReadBuffer(char *buf, Long64_t pos, Int_t len)
1622 {
1623  if (IsOpen()) {
1624 
1625  SetOffset(pos);
1626 
1627  Int_t st;
1628  Double_t start = 0;
1629  if (gPerfStats != 0) start = TTimeStamp();
1630 
1631  if ((st = ReadBufferViaCache(buf, len))) {
1632  if (st == 2)
1633  return kTRUE;
1634  return kFALSE;
1635  }
1636 
1637  Seek(pos);
1638  ssize_t siz;
1639 
1640  while ((siz = SysRead(fD, buf, len)) < 0 && GetErrno() == EINTR)
1641  ResetErrno();
1642 
1643  if (siz < 0) {
1644  SysError("ReadBuffer", "error reading from file %s", GetName());
1645  return kTRUE;
1646  }
1647  if (siz != len) {
1648  Error("ReadBuffer", "error reading all requested bytes from file %s, got %ld of %d",
1649  GetName(), (Long_t)siz, len);
1650  return kTRUE;
1651  }
1652  fBytesRead += siz;
1653  fgBytesRead += siz;
1654  fReadCalls++;
1655  fgReadCalls++;
1656 
1657  if (gMonitoringWriter)
1659  if (gPerfStats != 0) {
1660  gPerfStats->FileReadEvent(this, len, start);
1661  }
1662  return kFALSE;
1663  }
1664  return kTRUE;
1665 }
1666 
1667 ////////////////////////////////////////////////////////////////////////////////
1668 /// Read a buffer from the file. This is the basic low level read operation.
1669 /// Returns kTRUE in case of failure.
1671 Bool_t TFile::ReadBuffer(char *buf, Int_t len)
1672 {
1673  if (IsOpen()) {
1674 
1675  Int_t st;
1676  if ((st = ReadBufferViaCache(buf, len))) {
1677  if (st == 2)
1678  return kTRUE;
1679  return kFALSE;
1680  }
1681 
1682  ssize_t siz;
1683  Double_t start = 0;
1684 
1685  if (gPerfStats != 0) start = TTimeStamp();
1686 
1687  while ((siz = SysRead(fD, buf, len)) < 0 && GetErrno() == EINTR)
1688  ResetErrno();
1689 
1690  if (siz < 0) {
1691  SysError("ReadBuffer", "error reading from file %s", GetName());
1692  return kTRUE;
1693  }
1694  if (siz != len) {
1695  Error("ReadBuffer", "error reading all requested bytes from file %s, got %ld of %d",
1696  GetName(), (Long_t)siz, len);
1697  return kTRUE;
1698  }
1699  fBytesRead += siz;
1700  fgBytesRead += siz;
1701  fReadCalls++;
1702  fgReadCalls++;
1703 
1704  if (gMonitoringWriter)
1706  if (gPerfStats != 0) {
1707  gPerfStats->FileReadEvent(this, len, start);
1708  }
1709  return kFALSE;
1710  }
1711  return kTRUE;
1712 }
1713 
1714 ////////////////////////////////////////////////////////////////////////////////
1715 /// Read the nbuf blocks described in arrays pos and len.
1716 ///
1717 /// The value pos[i] is the seek position of block i of length len[i].
1718 /// Note that for nbuf=1, this call is equivalent to TFile::ReafBuffer.
1719 /// This function is overloaded by TNetFile, TWebFile, etc.
1720 /// Returns kTRUE in case of failure.
1722 Bool_t TFile::ReadBuffers(char *buf, Long64_t *pos, Int_t *len, Int_t nbuf)
1723 {
1724  // called with buf=0, from TFileCacheRead to pass list of readahead buffers
1725  if (!buf) {
1726  for (Int_t j = 0; j < nbuf; j++) {
1727  if (ReadBufferAsync(pos[j], len[j])) {
1728  return kTRUE;
1729  }
1730  }
1731  return kFALSE;
1732  }
1733 
1734  Int_t k = 0;
1735  Bool_t result = kTRUE;
1736  TFileCacheRead *old = fCacheRead;
1737  fCacheRead = 0;
1738  Long64_t curbegin = pos[0];
1739  Long64_t cur;
1740  char *buf2 = 0;
1741  Int_t i = 0, n = 0;
1742  while (i < nbuf) {
1743  cur = pos[i]+len[i];
1744  Bool_t bigRead = kTRUE;
1745  if (cur -curbegin < fgReadaheadSize) {n++; i++; bigRead = kFALSE;}
1746  if (bigRead || (i>=nbuf)) {
1747  if (n == 0) {
1748  //if the block to read is about the same size as the read-ahead buffer
1749  //we read the block directly
1750  Seek(pos[i]);
1751  result = ReadBuffer(&buf[k], len[i]);
1752  if (result) break;
1753  k += len[i];
1754  i++;
1755  } else {
1756  //otherwise we read all blocks that fit in the read-ahead buffer
1757  Seek(curbegin);
1758  if (buf2 == 0) buf2 = new char[fgReadaheadSize];
1759  //we read ahead
1760  Long64_t nahead = pos[i-1]+len[i-1]-curbegin;
1761  result = ReadBuffer(buf2, nahead);
1762  if (result) break;
1763  //now copy from the read-ahead buffer to the cache
1764  Int_t kold = k;
1765  for (Int_t j=0;j<n;j++) {
1766  memcpy(&buf[k],&buf2[pos[i-n+j]-curbegin],len[i-n+j]);
1767  k += len[i-n+j];
1768  }
1769  Int_t nok = k-kold;
1770  Long64_t extra = nahead-nok;
1771  fBytesReadExtra += extra;
1772  fBytesRead -= extra;
1773  fgBytesRead -= extra;
1774  n = 0;
1775  }
1776  curbegin = i < nbuf ? pos[i] : 0;
1777  }
1778  }
1779  if (buf2) delete [] buf2;
1780  fCacheRead = old;
1781  return result;
1782 }
1783 
1784 ////////////////////////////////////////////////////////////////////////////////
1785 /// Read buffer via cache.
1786 ///
1787 /// Returns 0 if the requested block is not in the cache, 1 in case read via
1788 /// cache was successful, 2 in case read via cache failed.
1790 Int_t TFile::ReadBufferViaCache(char *buf, Int_t len)
1791 {
1792  Long64_t off = GetRelOffset();
1793  if (fCacheRead) {
1794  Int_t st = fCacheRead->ReadBuffer(buf, off, len);
1795  if (st < 0)
1796  return 2; // failure reading
1797  else if (st == 1) {
1798  // fOffset might have been changed via TFileCacheRead::ReadBuffer(), reset it
1799  SetOffset(off + len);
1800  return 1;
1801  }
1802  // fOffset might have been changed via TFileCacheRead::ReadBuffer(), reset it
1803  Seek(off);
1804  } else {
1805  // if write cache is active check if data still in write cache
1806  if (fWritable && fCacheWrite) {
1807  if (fCacheWrite->ReadBuffer(buf, off, len) == 0) {
1808  SetOffset(off + len);
1809  return 1;
1810  }
1811  // fOffset might have been changed via TFileCacheWrite::ReadBuffer(), reset it
1812  SetOffset(off);
1813  }
1814  }
1815 
1816  return 0;
1817 }
1818 
1819 ////////////////////////////////////////////////////////////////////////////////
1820 /// Read the FREE linked list.
1821 ///
1822 /// Every file has a linked list (fFree) of free segments.
1823 /// This linked list has been written on the file via WriteFree
1824 /// as a single data record.
1826 void TFile::ReadFree()
1827 {
1828  // Avoid problem with file corruption.
1829  if (fNbytesFree < 0 || fNbytesFree > fEND) {
1830  fNbytesFree = 0;
1831  return;
1832  }
1833  TKey *headerfree = new TKey(fSeekFree, fNbytesFree, this);
1834  headerfree->ReadFile();
1835  char *buffer = headerfree->GetBuffer();
1836  headerfree->ReadKeyBuffer(buffer);
1837  buffer = headerfree->GetBuffer();
1838  while (1) {
1839  TFree *afree = new TFree();
1840  afree->ReadBuffer(buffer);
1841  fFree->Add(afree);
1842  if (afree->GetLast() > fEND) break;
1843  }
1844  delete headerfree;
1845 }
1846 
1847 ////////////////////////////////////////////////////////////////////////////////
1848 /// The TProcessID with number pidf is read from this file.
1849 ///
1850 /// If the object is not already entered in the gROOT list, it is added.
1853 {
1854  TProcessID *pid = 0;
1855  TObjArray *pids = GetListOfProcessIDs();
1856  if (pidf < pids->GetSize()) pid = (TProcessID *)pids->UncheckedAt(pidf);
1857  if (pid) {
1858  pid->CheckInit();
1859  return pid;
1860  }
1861 
1862  //check if fProcessIDs[uid] is set in file
1863  //if not set, read the process uid from file
1864  char pidname[32];
1865  snprintf(pidname,32,"ProcessID%d",pidf);
1866  pid = (TProcessID *)Get(pidname);
1867  if (gDebug > 0) {
1868  printf("ReadProcessID, name=%s, file=%s, pid=%lx\n",pidname,GetName(),(Long_t)pid);
1869  }
1870  if (!pid) {
1871  //file->Error("ReadProcessID","Cannot find %s in file %s",pidname,file->GetName());
1872  return pid;
1873  }
1874 
1875  //check that a similar pid is not already registered in fgPIDs
1876  TObjArray *pidslist = TProcessID::GetPIDs();
1877  TIter next(pidslist);
1878  TProcessID *p;
1879  bool found = false;
1881  while ((p = (TProcessID*)next())) {
1882  if (!strcmp(p->GetTitle(),pid->GetTitle())) {
1883  found = true;
1884  break;
1885  }
1886  }
1888 
1889  if (found) {
1890  delete pid;
1891  pids->AddAtAndExpand(p,pidf);
1892  p->IncrementCount();
1893  return p;
1894  }
1895 
1896  pids->AddAtAndExpand(pid,pidf);
1897  pid->IncrementCount();
1898 
1900  pidslist->Add(pid);
1901  Int_t ind = pidslist->IndexOf(pid);
1902  pid->SetUniqueID((UInt_t)ind);
1904 
1905  return pid;
1906 }
1907 
1908 
1909 ////////////////////////////////////////////////////////////////////////////////
1910 /// Attempt to recover file if not correctly closed
1911 ///
1912 /// The function returns the number of keys that have been recovered.
1913 /// If no keys can be recovered, the file will be declared Zombie by
1914 /// the calling function. This function is automatically called when
1915 /// opening a file.
1916 /// If the file is open in read only mode, the file is not modified.
1917 /// If open in update mode and the function finds something to recover,
1918 /// a new directory header is written to the file. When opening the file gain
1919 /// no message from Recover will be reported.
1920 /// If keys have been recovered, the file is usable and you can safely
1921 /// read the corresponding objects.
1922 /// If the file is not usable (a zombie), you can test for this case
1923 /// with code like:
1924 ///
1925 /// ~~~{.cpp}
1926 /// TFile f("myfile.root");
1927 /// if (f.IsZombie()) {<actions to take if file is unusable>}
1928 /// ~~~
1929 ///
1930 /// If the file has been recovered, the bit kRecovered is set in the TFile object in memory.
1931 /// You can test if the file has been recovered with
1932 ///
1933 /// if (f.TestBit(TFile::kRecovered)) {... the file has been recovered}
1934 ///
1935 /// When writing TTrees to a file, it is important to save the Tree header
1936 /// at regular intervals (see TTree::AutoSave). If a file containing a Tree
1937 /// is recovered, the last Tree header written to the file will be used.
1938 /// In this case all the entries in all the branches written before writing
1939 /// the header are valid entries.
1940 /// One can disable the automatic recovery procedure by setting
1941 ///
1942 /// TFile.Recover 0
1943 ///
1944 /// in the <em>system.rootrc</em> file.
1947 {
1948  Short_t keylen,cycle;
1949  UInt_t datime;
1950  Int_t nbytes,date,time,objlen,nwheader;
1951  Long64_t seekkey,seekpdir;
1952  char header[1024];
1953  char *buffer, *bufread;
1954  char nwhc;
1955  Long64_t idcur = fBEGIN;
1956 
1957  Long64_t size;
1958  if ((size = GetSize()) == -1) {
1959  Error("Recover", "cannot stat the file %s", GetName());
1960  return 0;
1961  }
1962 
1963  fEND = Long64_t(size);
1964 
1965  if (fWritable && !fFree) fFree = new TList;
1966 
1967  TKey *key;
1968  Int_t nrecov = 0;
1969  nwheader = 1024;
1970  Int_t nread = nwheader;
1971 
1972  while (idcur < fEND) {
1973  Seek(idcur);
1974  if (idcur+nread >= fEND) nread = fEND-idcur-1;
1975  if (ReadBuffer(header, nread)) {
1976  // ReadBuffer returns kTRUE in case of failure.
1977  Error("Recover","%s: failed to read the key data from disk at %lld.",
1978  GetName(),idcur);
1979  break;
1980  }
1981  buffer = header;
1982  bufread = header;
1983  frombuf(buffer, &nbytes);
1984  if (!nbytes) {
1985  Error("Recover","Address = %lld\tNbytes = %d\t=====E R R O R=======", idcur, nbytes);
1986  break;
1987  }
1988  if (nbytes < 0) {
1989  idcur -= nbytes;
1990  if (fWritable) new TFree(fFree,idcur,idcur-nbytes-1);
1991  Seek(idcur);
1992  continue;
1993  }
1994  Version_t versionkey;
1995  frombuf(buffer, &versionkey);
1996  frombuf(buffer, &objlen);
1997  frombuf(buffer, &datime);
1998  frombuf(buffer, &keylen);
1999  frombuf(buffer, &cycle);
2000  if (versionkey > 1000) {
2001  frombuf(buffer, &seekkey);
2002  frombuf(buffer, &seekpdir);
2003  } else {
2004  Int_t skey,sdir;
2005  frombuf(buffer, &skey); seekkey = (Long64_t)skey;
2006  frombuf(buffer, &sdir); seekpdir = (Long64_t)sdir;
2007  }
2008  frombuf(buffer, &nwhc);
2009  char *classname = 0;
2010  if (nwhc <= 0 || nwhc > 100) break;
2011  classname = new char[nwhc+1];
2012  int i, nwhci = nwhc;
2013  for (i = 0;i < nwhc; i++) frombuf(buffer, &classname[i]);
2014  classname[nwhci] = '\0';
2015  TDatime::GetDateTime(datime, date, time);
2016  TClass *tclass = TClass::GetClass(classname);
2017  if (seekpdir == fSeekDir && tclass && !tclass->InheritsFrom(TFile::Class())
2018  && strcmp(classname,"TBasket")) {
2019  key = new TKey(this);
2020  key->ReadKeyBuffer(bufread);
2021  if (!strcmp(key->GetName(),"StreamerInfo")) {
2022  fSeekInfo = seekkey;
2024  fNbytesInfo = nbytes;
2025  } else {
2026  AppendKey(key);
2027  nrecov++;
2028  SetBit(kRecovered);
2029  Info("Recover", "%s, recovered key %s:%s at address %lld",GetName(),key->GetClassName(),key->GetName(),idcur);
2030  }
2031  }
2032  delete [] classname;
2033  idcur += nbytes;
2034  }
2035  if (fWritable) {
2036  Long64_t max_file_size = Long64_t(kStartBigFile);
2037  if (max_file_size < fEND) max_file_size = fEND+1000000000;
2038  TFree *last = (TFree*)fFree->Last();
2039  if (last) {
2040  last->AddFree(fFree,fEND,max_file_size);
2041  } else {
2042  new TFree(fFree,fEND,max_file_size);
2043  }
2044  if (nrecov) Write();
2045  }
2046  return nrecov;
2047 }
2048 
2049 ////////////////////////////////////////////////////////////////////////////////
2050 /// Reopen a file with a different access mode.
2051 ///
2052 /// For example, it is possible to change from READ to
2053 /// UPDATE or from NEW, CREATE, RECREATE, UPDATE to READ. Thus the
2054 /// mode argument can be either "READ" or "UPDATE". The method returns
2055 /// 0 in case the mode was successfully modified, 1 in case the mode
2056 /// did not change (was already as requested or wrong input arguments)
2057 /// and -1 in case of failure, in which case the file cannot be used
2058 /// anymore. The current directory (gFile) is changed to this file.
2061 {
2062  cd();
2063 
2064  TString opt = mode;
2065  opt.ToUpper();
2066 
2067  if (opt != "READ" && opt != "UPDATE") {
2068  Error("ReOpen", "mode must be either READ or UPDATE, not %s", opt.Data());
2069  return 1;
2070  }
2071 
2072  if (opt == fOption || (opt == "UPDATE" && fOption == "CREATE"))
2073  return 1;
2074 
2075  if (opt == "READ") {
2076  // switch to READ mode
2077 
2078  // flush data still in the pipeline and close the file
2079  if (IsOpen() && IsWritable()) {
2081 
2082  // save directory key list and header
2083  Save();
2084 
2085  TFree *f1 = (TFree*)fFree->First();
2086  if (f1) {
2087  WriteFree(); // write free segments linked list
2088  WriteHeader(); // now write file header
2089  }
2090 
2091  FlushWriteCache();
2092 
2093  // delete free segments from free list
2094  if (fFree) {
2095  fFree->Delete();
2096  SafeDelete(fFree);
2097  }
2098 
2099  SysClose(fD);
2100  fD = -1;
2101 
2103  }
2104 
2105  // open in READ mode
2106  fOption = opt; // set fOption before SysOpen() for TNetFile
2107 #ifndef WIN32
2108  fD = SysOpen(fRealName, O_RDONLY, 0644);
2109 #else
2110  fD = SysOpen(fRealName, O_RDONLY | O_BINARY, S_IREAD | S_IWRITE);
2111 #endif
2112  if (fD == -1) {
2113  SysError("ReOpen", "file %s can not be opened in read mode", GetName());
2114  return -1;
2115  }
2117 
2118  } else {
2119  // switch to UPDATE mode
2120 
2121  // close readonly file
2122  if (IsOpen()) {
2123  SysClose(fD);
2124  fD = -1;
2125  }
2126 
2127  // open in UPDATE mode
2128  fOption = opt; // set fOption before SysOpen() for TNetFile
2129 #ifndef WIN32
2130  fD = SysOpen(fRealName, O_RDWR | O_CREAT, 0644);
2131 #else
2132  fD = SysOpen(fRealName, O_RDWR | O_CREAT | O_BINARY, S_IREAD | S_IWRITE);
2133 #endif
2134  if (fD == -1) {
2135  SysError("ReOpen", "file %s can not be opened in update mode", GetName());
2136  return -1;
2137  }
2138  SetWritable(kTRUE);
2139 
2140  fFree = new TList;
2141  if (fSeekFree > fBEGIN)
2142  ReadFree();
2143  else
2144  Warning("ReOpen","file %s probably not closed, cannot read free segments", GetName());
2145  }
2146 
2147  return 0;
2148 }
2149 
2150 ////////////////////////////////////////////////////////////////////////////////
2151 /// Set position from where to start reading.
2153 void TFile::SetOffset(Long64_t offset, ERelativeTo pos)
2154 {
2155  switch (pos) {
2156  case kBeg:
2157  fOffset = offset + fArchiveOffset;
2158  break;
2159  case kCur:
2160  fOffset += offset;
2161  break;
2162  case kEnd:
2163  // this option is not used currently in the ROOT code
2164  if (fArchiveOffset)
2165  Error("SetOffset", "seeking from end in archive is not (yet) supported");
2166  fOffset = fEND + offset; // is fEND really EOF or logical EOF?
2167  break;
2168  }
2169 }
2170 
2171 ////////////////////////////////////////////////////////////////////////////////
2172 /// Seek to a specific position in the file. Pos it either kBeg, kCur or kEnd.
2174 void TFile::Seek(Long64_t offset, ERelativeTo pos)
2175 {
2176  int whence = 0;
2177  switch (pos) {
2178  case kBeg:
2179  whence = SEEK_SET;
2180  offset += fArchiveOffset;
2181  break;
2182  case kCur:
2183  whence = SEEK_CUR;
2184  break;
2185  case kEnd:
2186  whence = SEEK_END;
2187  // this option is not used currently in the ROOT code
2188  if (fArchiveOffset)
2189  Error("Seek", "seeking from end in archive is not (yet) supported");
2190  break;
2191  }
2192  Long64_t retpos;
2193  if ((retpos = SysSeek(fD, offset, whence)) < 0)
2194  SysError("Seek", "cannot seek to position %lld in file %s, retpos=%lld",
2195  offset, GetName(), retpos);
2196 
2197  // used by TFileCacheRead::ReadBuffer()
2198  fOffset = retpos;
2199 }
2200 
2201 ////////////////////////////////////////////////////////////////////////////////
2202 /// See comments for function SetCompressionSettings
2203 ///
2205 void TFile::SetCompressionAlgorithm(Int_t algorithm)
2206 {
2207  if (algorithm < 0 || algorithm >= ROOT::kUndefinedCompressionAlgorithm) algorithm = 0;
2208  if (fCompress < 0) {
2209  // if the level is not defined yet use 1 as a default
2210  fCompress = 100 * algorithm + 1;
2211  } else {
2212  int level = fCompress % 100;
2213  fCompress = 100 * algorithm + level;
2214  }
2215 }
2216 
2217 ////////////////////////////////////////////////////////////////////////////////
2218 /// See comments for function SetCompressionSettings
2221 {
2222  if (level < 0) level = 0;
2223  if (level > 99) level = 99;
2224  if (fCompress < 0) {
2225  // if the algorithm is not defined yet use 0 as a default
2226  fCompress = level;
2227  } else {
2228  int algorithm = fCompress / 100;
2229  if (algorithm >= ROOT::kUndefinedCompressionAlgorithm) algorithm = 0;
2230  fCompress = 100 * algorithm + level;
2231  }
2232 }
2233 
2234 ////////////////////////////////////////////////////////////////////////////////
2235 /// Used to specify the compression level and algorithm.
2236 ///
2237 /// See the TFile constructor for the details.
2239 void TFile::SetCompressionSettings(Int_t settings)
2240 {
2241  fCompress = settings;
2242 }
2243 
2244 ////////////////////////////////////////////////////////////////////////////////
2245 /// Set a pointer to the read cache.
2246 ///
2247 /// <b>This relinquishes ownership</b> of the previous cache, so if you do not
2248 /// already have a pointer to the previous cache (and there was a previous
2249 /// cache), you ought to retrieve (and delete it if needed) using:
2250 ///
2251 /// TFileCacheRead *older = myfile->GetCacheRead();
2252 ///
2253 /// The action specifies how to behave when detaching a cache from the
2254 /// the TFile. If set to (default) kDisconnect, the contents of the cache
2255 /// will be flushed when it is removed from the file, and it will disconnect
2256 /// the cache object from the file. In almost all cases, this is what you want.
2257 /// If you want to disconnect the cache temporarily from this tree and re-attach
2258 /// later to the same fil, you can set action to kDoNotDisconnect. This will allow
2259 /// things like prefetching to continue in the background while it is no longer the
2260 /// default cache for the TTree. Except for a few expert use cases, kDisconnect is
2261 /// likely the correct setting.
2262 ///
2263 /// WARNING: if action=kDoNotDisconnect, you MUST delete the cache before TFile.
2264 ///
2267 {
2268  if (tree) {
2269  if (cache) fCacheReadMap->Add(tree, cache);
2270  else {
2271  // The only addition to fCacheReadMap is via an interface that takes
2272  // a TFileCacheRead* so the C-cast is safe.
2274  fCacheReadMap->Remove(tree);
2275  if (tpf && (tpf->GetFile() == this) && (action != kDoNotDisconnect)) tpf->SetFile(0, action);
2276  }
2277  }
2278  if (cache) cache->SetFile(this, action);
2279  else if (!tree && fCacheRead && (action != kDoNotDisconnect)) fCacheRead->SetFile(0, action);
2280  // For backward compatibility the last Cache set is the default cache.
2281  fCacheRead = cache;
2282 }
2283 
2284 ////////////////////////////////////////////////////////////////////////////////
2285 /// Set a pointer to the write cache.
2286 ///
2287 /// If file is null the existing write cache is deleted.
2290 {
2291  if (!cache && fCacheWrite) delete fCacheWrite;
2292  fCacheWrite = cache;
2293 }
2294 
2295 ////////////////////////////////////////////////////////////////////////////////
2296 /// Return the size in bytes of the file header.
2298 Int_t TFile::Sizeof() const
2299 {
2300  return 0;
2301 }
2302 
2303 ////////////////////////////////////////////////////////////////////////////////
2304 /// Stream a TFile object.
2305 
2306 void TFile::Streamer(TBuffer &b)
2307 {
2308  if (b.IsReading()) {
2309  b.ReadVersion(); //Version_t v = b.ReadVersion();
2310  } else {
2311  b.WriteVersion(TFile::IsA());
2312  }
2313 }
2314 
2315 ////////////////////////////////////////////////////////////////////////////////
2316 /// Increment statistics for buffer sizes of objects in this file.
2318 void TFile::SumBuffer(Int_t bufsize)
2319 {
2320  fWritten++;
2321  fSumBuffer += double(bufsize);
2322  fSum2Buffer += double(bufsize) * double(bufsize); // avoid reaching MAXINT for temporary
2323 }
2324 
2325 ////////////////////////////////////////////////////////////////////////////////
2326 /// Write memory objects to this file.
2327 ///
2328 /// Loop on all objects in memory (including subdirectories).
2329 /// A new key is created in the KEYS linked list for each object.
2330 /// The list of keys is then saved on the file (via WriteKeys)
2331 /// as a single data record.
2332 /// For values of opt see TObject::Write().
2333 /// The directory header info is rewritten on the directory header record.
2334 /// The linked list of FREE segments is written.
2335 /// The file header is written (bytes 1->fBEGIN).
2337 Int_t TFile::Write(const char *, Int_t opt, Int_t bufsiz)
2338 {
2339  if (!IsWritable()) {
2340  if (!TestBit(kWriteError)) {
2341  // Do not print the warning if we already had a SysError.
2342  Warning("Write", "file %s not opened in write mode", GetName());
2343  }
2344  return 0;
2345  }
2346 
2347  if (gDebug) {
2348  if (!GetTitle() || strlen(GetTitle()) == 0)
2349  Info("Write", "writing name = %s", GetName());
2350  else
2351  Info("Write", "writing name = %s title = %s", GetName(), GetTitle());
2352  }
2353 
2354  fMustFlush = kFALSE;
2355  Int_t nbytes = TDirectoryFile::Write(0, opt, bufsiz); // Write directory tree
2357  WriteFree(); // Write free segments linked list
2358  WriteHeader(); // Now write file header
2359  fMustFlush = kTRUE;
2360 
2361  return nbytes;
2362 }
2363 
2364 ////////////////////////////////////////////////////////////////////////////////
2365 /// One can not save a const TDirectory object.
2367 Int_t TFile::Write(const char *n, Int_t opt, Int_t bufsize) const
2368 {
2369  Error("Write const","A const TFile object should not be saved. We try to proceed anyway.");
2370  return const_cast<TFile*>(this)->Write(n, opt, bufsize);
2371 }
2372 
2373 ////////////////////////////////////////////////////////////////////////////////
2374 /// Write a buffer to the file. This is the basic low level write operation.
2375 /// Returns kTRUE in case of failure.
2377 Bool_t TFile::WriteBuffer(const char *buf, Int_t len)
2378 {
2379  if (IsOpen() && fWritable) {
2380 
2381  Int_t st;
2382  if ((st = WriteBufferViaCache(buf, len))) {
2383  if (st == 2)
2384  return kTRUE;
2385  return kFALSE;
2386  }
2387 
2388  ssize_t siz;
2390  while ((siz = SysWrite(fD, buf, len)) < 0 && GetErrno() == EINTR)
2391  ResetErrno();
2393  if (siz < 0) {
2394  // Write the system error only once for this file
2396  SysError("WriteBuffer", "error writing to file %s (%ld)", GetName(), (Long_t)siz);
2397  return kTRUE;
2398  }
2399  if (siz != len) {
2401  Error("WriteBuffer", "error writing all requested bytes to file %s, wrote %ld of %d",
2402  GetName(), (Long_t)siz, len);
2403  return kTRUE;
2404  }
2405  fBytesWrite += siz;
2406  fgBytesWrite += siz;
2407 
2408  if (gMonitoringWriter)
2410 
2411  return kFALSE;
2412  }
2413  return kTRUE;
2414 }
2415 
2416 ////////////////////////////////////////////////////////////////////////////////
2417 /// Write buffer via cache. Returns 0 if cache is not active, 1 in case
2418 /// write via cache was successful, 2 in case write via cache failed.
2420 Int_t TFile::WriteBufferViaCache(const char *buf, Int_t len)
2421 {
2422  if (!fCacheWrite) return 0;
2423 
2424  Int_t st;
2425  Long64_t off = GetRelOffset();
2426  if ((st = fCacheWrite->WriteBuffer(buf, off, len)) < 0) {
2428  Error("WriteBuffer", "error writing to cache");
2429  return 2;
2430  }
2431  if (st > 0) {
2432  // fOffset might have been changed via TFileCacheWrite::WriteBuffer(), reset it
2433  Seek(off + len);
2434  return 1;
2435  }
2436  return 0;
2437 }
2438 
2439 ////////////////////////////////////////////////////////////////////////////////
2440 /// Write FREE linked list on the file.
2441 /// The linked list of FREE segments (fFree) is written as a single data
2442 /// record.
2444 void TFile::WriteFree()
2445 {
2446  //*-* Delete old record if it exists
2447  if (fSeekFree != 0) {
2449  }
2450 
2451  Bool_t largeFile = (fEND > TFile::kStartBigFile);
2452 
2453  auto createKey = [this]() {
2454  Int_t nbytes = 0;
2455  TFree *afree;
2456  TIter next (fFree);
2457  while ((afree = (TFree*) next())) {
2458  nbytes += afree->Sizeof();
2459  }
2460  if (!nbytes) return (TKey*)nullptr;
2461 
2462  TKey *key = new TKey(fName,fTitle,IsA(),nbytes,this);
2463 
2464  if (key->GetSeekKey() == 0) {
2465  delete key;
2466  return (TKey*)nullptr;
2467  }
2468  return key;
2469  };
2470 
2471  TKey *key = createKey();
2472  if (!key) return;
2473 
2474  if (!largeFile && (fEND > TFile::kStartBigFile)) {
2475  // The free block list is large enough to bring the file to larger
2476  // than 2Gb, the references/offsets are now 64bits in the output
2477  // so we need to redo the calculattion since the list of free block
2478  // information will not fit in the original size.
2479  key->Delete();
2480  delete key;
2481 
2482  key = createKey();
2483  if (!key) return;
2484  }
2485 
2486  Int_t nbytes = key->GetObjlen();
2487  char *buffer = key->GetBuffer();
2488  char *start = buffer;
2489 
2490  TIter next (fFree);
2491  TFree *afree;
2492  while ((afree = (TFree*) next())) {
2493  // We could 'waste' time here and double check that
2494  // (buffer+afree->Sizeof() < (start+nbytes)
2495  afree->FillBuffer(buffer);
2496  }
2497  auto actualBytes = buffer-start;
2498  if ( actualBytes != nbytes ) {
2499  if (actualBytes < nbytes) {
2500  // Most likely one of the 'free' segment was used to store this
2501  // TKey, so we had one less TFree to store than we planned.
2502  memset(buffer,0,nbytes-actualBytes);
2503  } else {
2504  Error("WriteFree","The free block list TKey wrote more data than expected (%d vs %ld). Most likely there has been an out-of-bound write.",nbytes,(long int)actualBytes);
2505  }
2506  }
2507  fNbytesFree = key->GetNbytes();
2508  fSeekFree = key->GetSeekKey();
2509  key->WriteFile();
2510  delete key;
2511 }
2512 
2513 ////////////////////////////////////////////////////////////////////////////////
2514 /// Write File Header.
2516 void TFile::WriteHeader()
2517 {
2519  TFree *lastfree = (TFree*)fFree->Last();
2520  if (lastfree) fEND = lastfree->GetFirst();
2521  const char *root = "root";
2522  char *psave = new char[fBEGIN];
2523  char *buffer = psave;
2524  Int_t nfree = fFree->GetSize();
2525  memcpy(buffer, root, 4); buffer += 4;
2526  Int_t version = fVersion;
2527  if (version <1000000 && fEND > kStartBigFile) {version += 1000000; fUnits = 8;}
2528  tobuf(buffer, version);
2529  tobuf(buffer, (Int_t)fBEGIN);
2530  if (version < 1000000) {
2531  tobuf(buffer, (Int_t)fEND);
2532  tobuf(buffer, (Int_t)fSeekFree);
2533  tobuf(buffer, fNbytesFree);
2534  tobuf(buffer, nfree);
2535  tobuf(buffer, fNbytesName);
2536  tobuf(buffer, fUnits);
2537  tobuf(buffer, fCompress);
2538  tobuf(buffer, (Int_t)fSeekInfo);
2539  tobuf(buffer, fNbytesInfo);
2540  } else {
2541  tobuf(buffer, fEND);
2542  tobuf(buffer, fSeekFree);
2543  tobuf(buffer, fNbytesFree);
2544  tobuf(buffer, nfree);
2545  tobuf(buffer, fNbytesName);
2546  tobuf(buffer, fUnits);
2547  tobuf(buffer, fCompress);
2548  tobuf(buffer, fSeekInfo);
2549  tobuf(buffer, fNbytesInfo);
2550  }
2551  fUUID.FillBuffer(buffer);
2552  Int_t nbytes = buffer - psave;
2553  Seek(0);
2554  WriteBuffer(psave, nbytes);
2555  Flush(); // Intentionally not conditional on fMustFlush, this is the 'obligatory' flush.
2556  delete [] psave;
2557 }
2558 
2559 ////////////////////////////////////////////////////////////////////////////////
2560 /// Generate source code necessary to access the objects stored in the file.
2561 ///
2562 /// Generate code in directory dirname for all classes specified in
2563 /// argument classes If classes = "*" (default and currently the
2564 /// only supported value), the function generates an include file
2565 /// for each class in the StreamerInfo list for which a TClass
2566 /// object does not exist.
2567 ///
2568 /// The code generated includes:
2569 /// - <em>dirnameProjectHeaders.h</em>, which contains one #include statement per generated header file
2570 /// - <em>dirnameProjectSource.cxx</em>,which contains all the constructors and destructors implementation.
2571 /// and one header per class that is not nested inside another class.
2572 /// The header file name is the fully qualified name of the class after all the special characters
2573 /// "<>,:" are replaced by underscored. For example for std::pair<edm::Vertex,int> the file name is
2574 /// pair_edm__Vertex_int_.h
2575 ///
2576 /// In the generated classes, map, multimap when the first template parameter is a class
2577 /// are replaced by a vector of pair. set and multiset when the tempalte parameter
2578 /// is a class are replaced by a vector. This is required since we do not have the
2579 /// code needed to order and/or compare the object of the classes.
2580 /// This is a quick explanation of the options available:
2581 /// Option | Details
2582 /// -------|--------
2583 /// new (default) | A new directory dirname is created. If dirname already exist, an error message is printed and the function returns.
2584 /// recreate | If dirname does not exist, it is created (like in "new"). If dirname already exist, all existing files in dirname are deleted before creating the new files.
2585 /// update | New classes are added to the existing directory. Existing classes with the same name are replaced by the new definition. If the directory dirname doest not exist, same effect as "new".
2586 /// genreflex | Use genreflex rather than rootcint to generate the dictionary.
2587 /// par | Create a PAR file with the minimal set of code needed to read the content of the ROOT file. The name of the PAR file is basename(dirname), with extension '.par' enforced; the PAR file will be created at dirname(dirname).
2588 ///
2589 /// If, in addition to one of the 3 above options, the option "+" is specified,
2590 /// the function will generate:
2591 /// - a script called MAKEP to build the shared lib
2592 /// - a dirnameLinkDef.h file
2593 /// - rootcint will be run to generate a dirnameProjectDict.cxx file
2594 /// - dirnameProjectDict.cxx will be compiled with the current options in compiledata.h
2595 /// - a shared lib dirname.so will be created.
2596 /// If the option "++" is specified, the generated shared lib is dynamically
2597 /// linked with the current executable module.
2598 /// If the option "+" and "nocompile" are specified, the utility files are generated
2599 /// as in the option "+" but they are not executed.
2600 /// Example:
2601 /// file.MakeProject("demo","*","recreate++");
2602 /// - creates a new directory demo unless it already exist
2603 /// - clear the previous directory content
2604 /// - generate the xxx.h files for all classes xxx found in this file
2605 /// and not yet known to the CINT dictionary.
2606 /// - creates the build script MAKEP
2607 /// - creates a LinkDef.h file
2608 /// - runs rootcint generating demoProjectDict.cxx
2609 /// - compiles demoProjectDict.cxx into demoProjectDict.o
2610 /// - generates a shared lib demo.so
2611 /// - dynamically links the shared lib demo.so to the executable
2612 /// If only the option "+" had been specified, one can still link the
2613 /// shared lib to the current executable module with:
2614 ///
2615 /// gSystem->load("demo/demo.so");
2616 ///
2617 /// The following feature is not yet enabled:
2618 /// One can restrict the list of classes to be generated by using expressions like:
2619 ///
2620 /// classes = "Ali*" generate code only for classes starting with Ali
2621 /// classes = "myClass" generate code for class MyClass only.
2622 ///
2624 void TFile::MakeProject(const char *dirname, const char * /*classes*/,
2625  Option_t *option)
2626 {
2627  TString opt = option;
2628  opt.ToLower();
2629  Bool_t makepar = kFALSE;
2630  TString parname, pardir;
2631  if (opt.Contains("par")) {
2632  // Create a PAR file
2633  parname = gSystem->BaseName(dirname);
2634  if (parname.EndsWith(".par")) parname.ReplaceAll(".par","");
2635  pardir = gSystem->DirName(dirname);
2636  // Cleanup or prepare the dirs
2637  TString path, filepath;
2638  void *dir = gSystem->OpenDirectory(pardir);
2639  if (dir) {
2640  path.Form("%s/%s", pardir.Data(), parname.Data());
2641  void *dirp = gSystem->OpenDirectory(path);
2642  if (dirp) {
2643  path += "/PROOF-INF";
2644  void *dirinf = gSystem->OpenDirectory(path);
2645  const char *afile = 0;
2646  if (dirinf) {
2647  while ((afile = gSystem->GetDirEntry(dirinf))) {
2648  if (strcmp(afile,".") == 0) continue;
2649  if (strcmp(afile,"..") == 0) continue;
2650  filepath.Form("%s/%s", path.Data(), afile);
2651  if (gSystem->Unlink(filepath))
2652  Warning("MakeProject", "1: problems unlinking '%s' ('%s', '%s')", filepath.Data(), path.Data(), afile);
2653  }
2654  gSystem->FreeDirectory(dirinf);
2655  }
2656  gSystem->Unlink(path);
2657  path.Form("%s/%s", pardir.Data(), parname.Data());
2658  while ((afile = gSystem->GetDirEntry(dirp))) {
2659  if (strcmp(afile,".") == 0) continue;
2660  if (strcmp(afile,"..") == 0) continue;
2661  filepath.Form("%s/%s", path.Data(), afile);
2662  if (gSystem->Unlink(filepath))
2663  Warning("MakeProject", "2: problems unlinking '%s' ('%s', '%s')", filepath.Data(), path.Data(), afile);
2664  }
2665  gSystem->FreeDirectory(dirp);
2666  if (gSystem->Unlink(path))
2667  Warning("MakeProject", "problems unlinking '%s'", path.Data());
2668  }
2669  }
2670  // Make sure that the relevant dirs exists: this is mandatory, so we fail if unsuccessful
2671  path.Form("%s/%s/PROOF-INF", pardir.Data(), parname.Data());
2672  if (gSystem->mkdir(path, kTRUE)) {
2673  Error("MakeProject", "problems creating '%s'", path.Data());
2674  return;
2675  }
2676  makepar = kTRUE;
2677 
2678  } else {
2679  void *dir = gSystem->OpenDirectory(dirname);
2680  TString dirpath;
2681 
2682  if (opt.Contains("update")) {
2683  // check that directory exist, if not create it
2684  if (dir == 0) {
2685  gSystem->mkdir(dirname);
2686  }
2687 
2688  } else if (opt.Contains("recreate")) {
2689  // check that directory exist, if not create it
2690  if (dir == 0) {
2691  if (gSystem->mkdir(dirname) < 0) {
2692  Error("MakeProject","cannot create directory '%s'",dirname);
2693  return;
2694  }
2695  }
2696  // clear directory
2697  while (dir) {
2698  const char *afile = gSystem->GetDirEntry(dir);
2699  if (afile == 0) break;
2700  if (strcmp(afile,".") == 0) continue;
2701  if (strcmp(afile,"..") == 0) continue;
2702  dirpath.Form("%s/%s",dirname,afile);
2703  gSystem->Unlink(dirpath);
2704  }
2705 
2706  } else {
2707  // new is assumed
2708  // if directory already exist, print error message and return
2709  if (dir) {
2710  Error("MakeProject","cannot create directory %s, already existing",dirname);
2711  gSystem->FreeDirectory(dir);
2712  return;
2713  }
2714  if (gSystem->mkdir(dirname) < 0) {
2715  Error("MakeProject","cannot create directory '%s'",dirname);
2716  return;
2717  }
2718  }
2719  if (dir) {
2720  gSystem->FreeDirectory(dir);
2721  }
2722  }
2723  Bool_t genreflex = opt.Contains("genreflex");
2724 
2725  // we are now ready to generate the classes
2726  // loop on all TStreamerInfo
2727  TList *filelist = (TList*)GetStreamerInfoCache();
2728  if (filelist) filelist = (TList*)filelist->Clone();
2729  if (filelist == 0) {
2730  Error("MakeProject","file %s has no StreamerInfo", GetName());
2731  return;
2732  }
2733 
2734  TString clean_dirname(dirname);
2735  if (makepar) clean_dirname.Form("%s/%s", pardir.Data(), parname.Data());
2736  if (clean_dirname[clean_dirname.Length()-1]=='/') {
2737  clean_dirname.Remove(clean_dirname.Length()-1);
2738  } else if (clean_dirname[clean_dirname.Length()-1]=='\\') {
2739  clean_dirname.Remove(clean_dirname.Length()-1);
2740  if (clean_dirname[clean_dirname.Length()-1]=='\\') {
2741  clean_dirname.Remove(clean_dirname.Length()-1);
2742  }
2743  }
2744  TString subdirname( gSystem->BaseName(clean_dirname) );
2745  if (makepar) subdirname = parname;
2746  if (subdirname == "") {
2747  Error("MakeProject","Directory name must not be empty.");
2748  return;
2749  }
2750 
2751  // Start the source file
2752  TString spath; spath.Form("%s/%sProjectSource.cxx",clean_dirname.Data(),subdirname.Data());
2753  FILE *sfp = fopen(spath.Data(),"w");
2754  if (sfp ==0) {
2755  Error("MakeProject","Unable to create the source file %s.",spath.Data());
2756  return;
2757  }
2758  fprintf(sfp, "namespace std {}\nusing namespace std;\n");
2759  fprintf(sfp, "#include \"%sProjectHeaders.h\"\n\n",subdirname.Data() );
2760  if (!genreflex) fprintf(sfp, "#include \"%sLinkDef.h\"\n\n",subdirname.Data() );
2761  fprintf(sfp, "#include \"%sProjectDict.cxx\"\n\n",subdirname.Data() );
2762  fprintf(sfp, "struct DeleteObjectFunctor {\n");
2763  fprintf(sfp, " template <typename T>\n");
2764  fprintf(sfp, " void operator()(const T *ptr) const {\n");
2765  fprintf(sfp, " delete ptr;\n");
2766  fprintf(sfp, " }\n");
2767  fprintf(sfp, " template <typename T, typename Q>\n");
2768  fprintf(sfp, " void operator()(const std::pair<T,Q> &) const {\n");
2769  fprintf(sfp, " // Do nothing\n");
2770  fprintf(sfp, " }\n");
2771  fprintf(sfp, " template <typename T, typename Q>\n");
2772  fprintf(sfp, " void operator()(const std::pair<T,Q*> &ptr) const {\n");
2773  fprintf(sfp, " delete ptr.second;\n");
2774  fprintf(sfp, " }\n");
2775  fprintf(sfp, " template <typename T, typename Q>\n");
2776  fprintf(sfp, " void operator()(const std::pair<T*,Q> &ptr) const {\n");
2777  fprintf(sfp, " delete ptr.first;\n");
2778  fprintf(sfp, " }\n");
2779  fprintf(sfp, " template <typename T, typename Q>\n");
2780  fprintf(sfp, " void operator()(const std::pair<T*,Q*> &ptr) const {\n");
2781  fprintf(sfp, " delete ptr.first;\n");
2782  fprintf(sfp, " delete ptr.second;\n");
2783  fprintf(sfp, " }\n");
2784  fprintf(sfp, "};\n\n");
2785  fclose( sfp );
2786 
2787  // loop on all TStreamerInfo classes to check for empty classes
2788  // and enums listed either as data member or template parameters,
2789  // and filter out 'duplicates' classes/streamerInfos.
2790  TStreamerInfo *info;
2791  TIter flnext(filelist);
2792  TList extrainfos;
2793  TList *list = new TList();
2794  while ((info = (TStreamerInfo*)flnext())) {
2795  if (info->IsA() != TStreamerInfo::Class()) {
2796  continue;
2797  }
2798  if (strstr(info->GetName(),"@@")) {
2799  // Skip schema evolution support streamerInfo
2800  continue;
2801  }
2802  TClass *cl = TClass::GetClass(info->GetName());
2803  if (cl) {
2804  if (cl->HasInterpreterInfo()) continue; // skip known classes
2805  }
2806  // Find and use the proper rules for the TStreamerInfos.
2807  TMakeProject::GenerateMissingStreamerInfos( &extrainfos, info->GetName() );
2808  TIter enext( info->GetElements() );
2809  TStreamerElement *el;
2811  if (cl && cl->GetSchemaRules()) {
2812  rules = cl->GetSchemaRules()->FindRules(cl->GetName(), info->GetClassVersion());
2813  }
2814  while( (el=(TStreamerElement*)enext()) ) {
2815  for(auto rule : rules) {
2816  if( rule->IsRenameRule() || rule->IsAliasRule() )
2817  continue;
2818  // Check whether this is an 'attribute' rule.
2819  if ( rule->HasTarget( el->GetName()) && rule->GetAttributes()[0] != 0 ) {
2820  TString attr( rule->GetAttributes() );
2821  attr.ToLower();
2822  if (attr.Contains("owner")) {
2823  if (attr.Contains("notowner")) {
2824  el->SetBit(TStreamerElement::kDoNotDelete);
2825  } else {
2826  el->ResetBit(TStreamerElement::kDoNotDelete);
2827  }
2828  }
2829  }
2830  }
2832  }
2833  TVirtualStreamerInfo *alternate = (TVirtualStreamerInfo*)list->FindObject(info->GetName());
2834  if (alternate) {
2835  if ((info->GetClass() && info->GetClassVersion() == info->GetClass()->GetClassVersion())
2836  || (info->GetClassVersion() > alternate->GetClassVersion()) ) {
2837  list->AddAfter(alternate, info);
2838  list->Remove(alternate);
2839  } // otherwise ignore this info as not being the official one.
2840  } else {
2841  list->Add(info);
2842  }
2843  }
2844  // Now transfer the new StreamerInfo onto the main list and
2845  // to the owning list.
2846  TIter nextextra(&extrainfos);
2847  while ((info = (TStreamerInfo*)nextextra())) {
2848  list->Add(info);
2849  filelist->Add(info);
2850  }
2851 
2852  // loop on all TStreamerInfo classes
2853  TIter next(list);
2854  Int_t ngener = 0;
2855  while ((info = (TStreamerInfo*)next())) {
2856  if (info->IsA() != TStreamerInfo::Class()) {
2857  continue;
2858  }
2859  if (info->GetClassVersion()==-4) continue; // Skip outer level namespace
2860  TIter subnext(list);
2861  TStreamerInfo *subinfo;
2862  TList subClasses;
2863  Int_t len = strlen(info->GetName());
2864  while ((subinfo = (TStreamerInfo*)subnext())) {
2865  if (subinfo->IsA() != TStreamerInfo::Class()) {
2866  continue;
2867  }
2868  if (strncmp(info->GetName(),subinfo->GetName(),len)==0) {
2869  // The 'sub' StreamerInfo start with the main StreamerInfo name,
2870  // it subinfo is likely to be a nested class.
2871  const Int_t sublen = strlen(subinfo->GetName());
2872  if ( (sublen > len) && subinfo->GetName()[len+1]==':'
2873  && !subClasses.FindObject(subinfo->GetName()) /* We need to insure uniqueness */)
2874  {
2875  subClasses.Add(subinfo);
2876  }
2877  }
2878  }
2879  ngener += info->GenerateHeaderFile(clean_dirname.Data(),&subClasses,&extrainfos);
2880  subClasses.Clear("nodelete");
2881  }
2882  TString path;
2883  path.Form("%s/%sProjectHeaders.h",clean_dirname.Data(),subdirname.Data());
2884  FILE *allfp = fopen(path,"a");
2885  if (!allfp) {
2886  Error("MakeProject","Cannot open output file:%s\n",path.Data());
2887  } else {
2888  fprintf(allfp,"#include \"%sProjectInstances.h\"\n", subdirname.Data());
2889  fclose(allfp);
2890  }
2891 
2892  printf("MakeProject has generated %d classes in %s\n",ngener,clean_dirname.Data());
2893 
2894  // generate the shared lib
2895  if (!opt.Contains("+") && !makepar) {
2896  delete list;
2897  filelist->Delete();
2898  delete filelist;
2899  return;
2900  }
2901 
2902  // Makefiles files
2903  FILE *fpMAKE = 0;
2904  if (!makepar) {
2905  // Create the MAKEP file by looping on all *.h files
2906  // delete MAKEP if it already exists
2907 #ifdef WIN32
2908  path.Form("%s/makep.cmd",clean_dirname.Data());
2909 #else
2910  path.Form("%s/MAKEP",clean_dirname.Data());
2911 #endif
2912 #ifdef R__WINGCC
2913  fpMAKE = fopen(path,"wb");
2914 #else
2915  fpMAKE = fopen(path,"w");
2916 #endif
2917  if (!fpMAKE) {
2918  Error("MakeProject", "cannot open file %s", path.Data());
2919  delete list;
2920  filelist->Delete();
2921  delete filelist;
2922  return;
2923  }
2924  }
2925 
2926  // Add rootcint/genreflex statement generating ProjectDict.cxx
2927  FILE *ifp = 0;
2928  path.Form("%s/%sProjectInstances.h",clean_dirname.Data(),subdirname.Data());
2929 #ifdef R__WINGCC
2930  ifp = fopen(path,"wb");
2931 #else
2932  ifp = fopen(path,"w");
2933 #endif
2934  if (!ifp) {
2935  Error("MakeProject", "cannot open path file %s", path.Data());
2936  delete list;
2937  filelist->Delete();
2938  delete filelist;
2939  fclose(fpMAKE);
2940  return;
2941  }
2942 
2943  if (!makepar) {
2944  if (genreflex) {
2945  fprintf(fpMAKE,"genreflex %sProjectHeaders.h -o %sProjectDict.cxx --comments --iocomments %s ",subdirname.Data(),subdirname.Data(),gSystem->GetIncludePath());
2946  path.Form("%s/%sSelection.xml",clean_dirname.Data(),subdirname.Data());
2947  } else {
2948  fprintf(fpMAKE,"rootcint -v1 -f %sProjectDict.cxx -c %s ",subdirname.Data(),gSystem->GetIncludePath());
2949  path.Form("%s/%sLinkDef.h",clean_dirname.Data(),subdirname.Data());
2950  }
2951  } else {
2952  path.Form("%s/%sLinkDef.h",clean_dirname.Data(),subdirname.Data());
2953  }
2954 
2955  // Create the LinkDef.h or xml selection file by looping on all *.h files
2956  // replace any existing file.
2957 #ifdef R__WINGCC
2958  FILE *fp = fopen(path,"wb");
2959 #else
2960  FILE *fp = fopen(path,"w");
2961 #endif
2962  if (!fp) {
2963  Error("MakeProject", "cannot open path file %s", path.Data());
2964  delete list;
2965  filelist->Delete();
2966  delete filelist;
2967  fclose(fpMAKE);
2968  fclose(ifp);
2969  return;
2970  }
2971  if (genreflex) {
2972  fprintf(fp,"<lcgdict>\n");
2973  fprintf(fp,"\n");
2974  } else {
2975  fprintf(fp,"#ifdef __CINT__\n");
2976  fprintf(fp,"\n");
2977  }
2978 
2979  TString tmp;
2980  TString instances;
2981  TString selections;
2982  next.Reset();
2983  while ((info = (TStreamerInfo*)next())) {
2984  if (info->IsA() != TStreamerInfo::Class()) {
2985  continue;
2986  }
2987  TClass *cl = TClass::GetClass(info->GetName());
2988  if (cl) {
2989  if (cl->HasInterpreterInfo()) continue; // skip known classes
2990  if (cl->GetSchemaRules()) {
2991  auto rules = cl->GetSchemaRules()->FindRules(cl->GetName(), info->GetClassVersion());
2992  TString strrule;
2993  for(auto rule : rules) {
2994  strrule.Clear();
2995  if (genreflex) {
2996  rule->AsString(strrule,"x");
2997  strrule.Append("\n");
2998  if ( selections.Index(strrule) == kNPOS ) {
2999  selections.Append(strrule);
3000  }
3001  } else {
3002  rule->AsString(strrule);
3003  if (strncmp(strrule.Data(),"type=",5)==0) {
3004  strrule.Remove(0,5);
3005  }
3006  fprintf(fp,"#pragma %s;\n",strrule.Data());
3007  }
3008  }
3009  }
3010 
3011  }
3012  if ((info->GetClass() && info->GetClass()->GetCollectionType()) || TClassEdit::IsSTLCont(info->GetName())) {
3013  std::vector<std::string> inside;
3014  int nestedLoc;
3015  TClassEdit::GetSplit( info->GetName(), inside, nestedLoc, TClassEdit::kLong64 );
3016  Int_t stlkind = TClassEdit::STLKind(inside[0]);
3017  TClass *key = TClass::GetClass(inside[1].c_str());
3018  if (key) {
3019  TString what;
3020  switch ( stlkind ) {
3021  case ROOT::kSTLmap:
3022  case ROOT::kSTLmultimap:
3023  if (TClass::GetClass(inside[1].c_str())) {
3024  what = "std::pair<";
3025  what += TMakeProject::UpdateAssociativeToVector( inside[1].c_str() );
3026  what += ",";
3027  what += TMakeProject::UpdateAssociativeToVector( inside[2].c_str() );
3028  if (what[what.Length()-1]=='>') {
3029  what += " >";
3030  } else {
3031  what += ">";
3032  }
3033  if (genreflex) {
3034  tmp.Form("<class name=\"%s\" />\n",what.Data());
3035  if ( selections.Index(tmp) == kNPOS ) {
3036  selections.Append(tmp);
3037  }
3038  tmp.Form("template class %s;\n",what.Data());
3039  if ( instances.Index(tmp) == kNPOS ) {
3040  instances.Append(tmp);
3041  }
3042  } else {
3043  what.ReplaceAll("std::","");
3044  TClass *paircl = TClass::GetClass(what.Data());
3045  if (paircl == 0 || !paircl->HasInterpreterInfo()) {
3046  fprintf(fp,"#pragma link C++ class %s+;\n",what.Data());
3047  }
3048  }
3049  break;
3050  }
3051  default:
3052  if (strncmp(key->GetName(),"pair<",strlen("pair<"))==0) {
3053  if (genreflex) {
3054  tmp.Form("<class name=\"%s\" />\n",key->GetName());
3055  if ( selections.Index(tmp) == kNPOS ) {
3056  selections.Append(tmp);
3057  }
3058  tmp.Form("template class %s;\n",key->GetName());
3059  if ( instances.Index(tmp) == kNPOS ) {
3060  instances.Append(tmp);
3061  }
3062  } else {
3063  what.ReplaceAll("std::","");
3064  fprintf(fp,"#pragma link C++ class %s+;\n",key->GetName());
3065  }
3066  }
3067  break;
3068  }
3069  }
3070  continue;
3071  }
3072  {
3074  if (genreflex) {
3075  tmp.Form("<class name=\"%s\" />\n",what.Data());
3076  if ( selections.Index(tmp) == kNPOS ) {
3077  selections.Append(tmp);
3078  }
3079  if (what[what.Length()-1] == '>') {
3080  tmp.Form("template class %s;\n",what.Data());
3081  if ( instances.Index(tmp) == kNPOS ) {
3082  instances.Append(tmp);
3083  }
3084  }
3085  } else {
3086  what.ReplaceAll("std::","");
3087  fprintf(fp,"#pragma link C++ class %s+;\n",what.Data());
3088  }
3089  }
3090  if (genreflex) {
3091  // Also request the dictionary for the STL container used as members ...
3092  TIter eliter( info->GetElements() );
3093  TStreamerElement *element;
3094  while( (element = (TStreamerElement*)eliter() ) ) {
3095  if (element->GetClass() && !element->GetClass()->IsLoaded() && element->GetClass()->GetCollectionProxy()) {
3096  TString what( TMakeProject::UpdateAssociativeToVector(element->GetClass()->GetName()) );
3097  tmp.Form("<class name=\"%s\" />\n",what.Data());
3098  if ( selections.Index(tmp) == kNPOS ) {
3099  selections.Append(tmp);
3100  }
3101  tmp.Form("template class %s;\n",what.Data());
3102  if ( instances.Index(tmp) == kNPOS ) {
3103  instances.Append(tmp);
3104  }
3105  }
3106  }
3107  }
3108  }
3109  if (genreflex) {
3110  fprintf(ifp,"#ifndef PROJECT_INSTANCES_H\n");
3111  fprintf(ifp,"#define PROJECT_INSTANCES_H\n");
3112  fprintf(ifp,"%s",instances.Data());
3113  fprintf(ifp,"#endif\n");
3114  fprintf(fp,"%s",selections.Data());
3115  fprintf(fp,"</lcgdict>\n");
3116  } else {
3117  fprintf(fp,"#endif\n");
3118  }
3119  fclose(fp);
3120  fclose(ifp);
3121 
3122  if (!makepar) {
3123  // add compilation line
3124  TString sdirname(subdirname);
3125 
3126  TString cmd = gSystem->GetMakeSharedLib();
3127  TString sources = TString::Format("%sProjectSource.cxx ", sdirname.Data());
3128  cmd.ReplaceAll("$SourceFiles",sources.Data());
3129  TString object = TString::Format("%sProjectSource.", sdirname.Data());
3130  object.Append( gSystem->GetObjExt() );
3131  cmd.ReplaceAll("$ObjectFiles", object.Data());
3132  cmd.ReplaceAll("$IncludePath",TString(gSystem->GetIncludePath()) + " -I" + clean_dirname.Data());
3133  cmd.ReplaceAll("$SharedLib",sdirname+"."+gSystem->GetSoExt());
3134  cmd.ReplaceAll("$LinkedLibs",gSystem->GetLibraries("","SDL"));
3135  cmd.ReplaceAll("$LibName",sdirname);
3136  cmd.ReplaceAll("$BuildDir",".");
3137  TString sOpt;
3138  TString rootbuild = ROOTBUILD;
3139  if (rootbuild.Index("debug",0,TString::kIgnoreCase)==kNPOS) {
3140  sOpt = gSystem->GetFlagsOpt();
3141  } else {
3142  sOpt = gSystem->GetFlagsDebug();
3143  }
3144  cmd.ReplaceAll("$Opt", sOpt);
3145 
3146  if (genreflex) {
3147  fprintf(fpMAKE,"-s %sSelection.xml \n",subdirname.Data());
3148  } else {
3149  fprintf(fpMAKE,"%sProjectHeaders.h ",subdirname.Data());
3150  fprintf(fpMAKE,"%sLinkDef.h \n",subdirname.Data());
3151  }
3152 
3153  fprintf(fpMAKE,"%s\n",cmd.Data());
3154 
3155  printf("%s/MAKEP file has been generated\n", clean_dirname.Data());
3156 
3157  fclose(fpMAKE);
3158 
3159  } else {
3160 
3161  // Create the Makefile
3162  TString filemake = TString::Format("%s/Makefile", clean_dirname.Data());
3163  if (MakeProjectParMake(parname, filemake.Data()) != 0) {
3164  Error("MakeProject", "problems creating PAR make file '%s'", filemake.Data());
3165  delete list;
3166  filelist->Delete();
3167  delete filelist;
3168  return;
3169  }
3170  // Get Makefile.arch
3171  TString mkarchsrc = TString::Format("%s/Makefile.arch", TROOT::GetEtcDir().Data());
3172  if (gSystem->ExpandPathName(mkarchsrc))
3173  Warning("MakeProject", "problems expanding '%s'", mkarchsrc.Data());
3174  TString mkarchdst = TString::Format("%s/Makefile.arch", clean_dirname.Data());
3175  if (gSystem->CopyFile(mkarchsrc.Data(), mkarchdst.Data(), kTRUE) != 0) {
3176  Error("MakeProject", "problems retrieving '%s' to '%s'", mkarchsrc.Data(), mkarchdst.Data());
3177  delete list;
3178  filelist->Delete();
3179  delete filelist;
3180  return;
3181  }
3182  // Create the Makefile
3183  TString proofinf = TString::Format("%s/PROOF-INF", clean_dirname.Data());
3184  if (MakeProjectParProofInf(parname, proofinf.Data()) != 0) {
3185  Error("MakeProject", "problems creating BUILD.sh and/or SETUP.C under '%s'", proofinf.Data());
3186  delete list;
3187  filelist->Delete();
3188  delete filelist;
3189  return;
3190  }
3191 
3192  // Make sure BUILD.sh is executable and create SETUP.C
3193  TString cmod = TString::Format("chmod +x %s/PROOF-INF/BUILD.sh", clean_dirname.Data());
3194 #ifndef WIN32
3195  gSystem->Exec(cmod.Data());
3196 #else
3197  // not really needed for Windows but it would work both both Unix and NT
3198  chmod(cmod.Data(), 00700);
3199 #endif
3200  Printf("Files Makefile, Makefile.arch, PROOF-INF/BUILD.sh and"
3201  " PROOF-INF/SETUP.C have been generated under '%s'", clean_dirname.Data());
3202 
3203  // Generate the PAR file, if not Windows
3204 #ifndef WIN32
3205  TString curdir = gSystem->WorkingDirectory();
3206  if (gSystem->ChangeDirectory(pardir)) {
3207  TString cmd = TString::Format("tar czvf %s.par %s", parname.Data(), parname.Data());
3208  gSystem->Exec(cmd.Data());
3209  if (gSystem->ChangeDirectory(curdir)) {
3210  Info("MakeProject", "PAR file %s.par generated", clean_dirname.Data());
3211  } else {
3212  Warning("MakeProject", "problems changing directory back to '%s'", curdir.Data());
3213  }
3214  } else {
3215  Error("MakeProject", "problems changing directory to '%s' - skipping PAR file generation", pardir.Data());
3216  }
3217 #else
3218  Warning("MakeProject", "on Windows systems the PAR file cannot be generated out of the package directory!");
3219 #endif
3220  }
3221 
3222 
3223  if (!makepar && !opt.Contains("nocompilation")) {
3224  // now execute the generated script compiling and generating the shared lib
3225  path = gSystem->WorkingDirectory();
3226  gSystem->ChangeDirectory(clean_dirname.Data());
3227 #ifndef WIN32
3228  gSystem->Exec("chmod +x MAKEP");
3229  int res = !gSystem->Exec("./MAKEP");
3230 #else
3231  // not really needed for Windows but it would work both both Unix and NT
3232  chmod("makep.cmd",00700);
3233  int res = !gSystem->Exec("MAKEP");
3234 #endif
3235  gSystem->ChangeDirectory(path);
3236  path.Form("%s/%s.%s",clean_dirname.Data(),subdirname.Data(),gSystem->GetSoExt());
3237  if (res) printf("Shared lib %s has been generated\n",path.Data());
3238 
3239  //dynamically link the generated shared lib
3240  if (opt.Contains("++")) {
3241  res = !gSystem->Load(path);
3242  if (res) printf("Shared lib %s has been dynamically linked\n",path.Data());
3243  }
3244  }
3245 
3246  extrainfos.Clear("nodelete");
3247  // filelist->Clear("nodetele");
3248  delete list;
3249  filelist->Delete();
3250  delete filelist;
3251 }
3252 
3253 ////////////////////////////////////////////////////////////////////////////////
3254 /// Create makefile at 'filemake' for PAR package 'pack'.
3255 ///
3256 /// Called by MakeProject when option 'par' is given.
3257 /// Return 0 on success, -1 on error.
3259 Int_t TFile::MakeProjectParMake(const char *pack, const char *filemake)
3260 {
3261  // Output file path must be defined
3262  if (!filemake || (filemake && strlen(filemake) <= 0)) {
3263  Error("MakeProjectParMake", "path for output file undefined!");
3264  return -1;
3265  }
3266 
3267  // Package name must be defined
3268  if (!pack || (pack && strlen(pack) <= 0)) {
3269  Error("MakeProjectParMake", "package name undefined!");
3270  return -1;
3271  }
3272 
3273 #ifdef R__WINGCC
3274  FILE *fmk = fopen(filemake, "wb");
3275 #else
3276  FILE *fmk = fopen(filemake, "w");
3277 #endif
3278  if (!fmk) {
3279  Error("MakeProjectParMake", "cannot create file '%s' (errno: %d)", filemake, TSystem::GetErrno());
3280  return -1;
3281  }
3282 
3283  // Fill the file now
3284  fprintf(fmk, "# Makefile for the ROOT test programs.\n");
3285  fprintf(fmk, "# This Makefile shows how to compile and link applications\n");
3286  fprintf(fmk, "# using the ROOT libraries on all supported platforms.\n");
3287  fprintf(fmk, "#\n");
3288  fprintf(fmk, "# Copyright (c) 2000 Rene Brun and Fons Rademakers\n");
3289  fprintf(fmk, "#\n");
3290  fprintf(fmk, "# Author: this makefile has been automatically generated via TFile::MakeProject\n");
3291  fprintf(fmk, "\n");
3292  fprintf(fmk, "include Makefile.arch\n");
3293  fprintf(fmk, "\n");
3294  fprintf(fmk, "#------------------------------------------------------------------------------\n");
3295  fprintf(fmk, "\n");
3296  fprintf(fmk, "PACKO = %sProjectSource.$(ObjSuf)\n", pack);
3297  fprintf(fmk, "PACKS = %sProjectSource.$(SrcSuf) %sProjectDict.$(SrcSuf)\n", pack, pack);
3298  fprintf(fmk, "PACKSO = lib%s.$(DllSuf)\n", pack);
3299  fprintf(fmk, "\n");
3300  fprintf(fmk, "ifeq ($(PLATFORM),win32)\n");
3301  fprintf(fmk, "PACKLIB = lib%s.lib\n", pack);
3302  fprintf(fmk, "else\n");
3303  fprintf(fmk, "PACKLIB = $(PACKSO)\n");
3304  fprintf(fmk, "endif\n");
3305  fprintf(fmk, "\n");
3306  fprintf(fmk, "OBJS = $(PACKO)\n");
3307  fprintf(fmk, "\n");
3308  fprintf(fmk, "PROGRAMS =\n");
3309  fprintf(fmk, "\n");
3310  fprintf(fmk, "#------------------------------------------------------------------------------\n");
3311  fprintf(fmk, "\n");
3312  fprintf(fmk, ".SUFFIXES: .$(SrcSuf) .$(ObjSuf) .$(DllSuf)\n");
3313  fprintf(fmk, "\n");
3314  fprintf(fmk, "all: $(PACKLIB)\n");
3315  fprintf(fmk, "\n");
3316  fprintf(fmk, "$(PACKSO): $(PACKO)\n");
3317  fprintf(fmk, "ifeq ($(ARCH),aix)\n");
3318  fprintf(fmk, "\t\t/usr/ibmcxx/bin/makeC++SharedLib $(OutPutOpt) $@ $(LIBS) -p 0 $^\n");
3319  fprintf(fmk, "else\n");
3320  fprintf(fmk, "ifeq ($(ARCH),aix5)\n");
3321  fprintf(fmk, "\t\t/usr/vacpp/bin/makeC++SharedLib $(OutPutOpt) $@ $(LIBS) -p 0 $^\n");
3322  fprintf(fmk, "else\n");
3323  fprintf(fmk, "ifeq ($(PLATFORM),macosx)\n");
3324  fprintf(fmk, "# We need to make both the .dylib and the .so\n");
3325  fprintf(fmk, "\t\t$(LD) $(SOFLAGS)$@ $(LDFLAGS) $^ $(OutPutOpt) $@ $(LIBS)\n");
3326  fprintf(fmk, "ifneq ($(subst $(MACOSX_MINOR),,1234),1234)\n");
3327  fprintf(fmk, "ifeq ($(MACOSX_MINOR),4)\n");
3328  fprintf(fmk, "\t\tln -sf $@ $(subst .$(DllSuf),.so,$@)\n");
3329  fprintf(fmk, "else\n");
3330  fprintf(fmk, "\t\t$(LD) -bundle -undefined $(UNDEFOPT) $(LDFLAGS) $^ \\\n");
3331  fprintf(fmk, "\t\t $(OutPutOpt) $(subst .$(DllSuf),.so,$@)\n");
3332  fprintf(fmk, "endif\n");
3333  fprintf(fmk, "endif\n");
3334  fprintf(fmk, "else\n");
3335  fprintf(fmk, "ifeq ($(PLATFORM),win32)\n");
3336  fprintf(fmk, "\t\tbindexplib $* $^ > $*.def\n");
3337  fprintf(fmk, "\t\tlib -nologo -MACHINE:IX86 $^ -def:$*.def \\\n");
3338  fprintf(fmk, "\t\t $(OutPutOpt)$(PACKLIB)\n");
3339  fprintf(fmk, "\t\t$(LD) $(SOFLAGS) $(LDFLAGS) $^ $*.exp $(LIBS) \\\n");
3340  fprintf(fmk, "\t\t $(OutPutOpt)$@\n");
3341  fprintf(fmk, "else\n");
3342  fprintf(fmk, "\t\t$(LD) $(SOFLAGS) $(LDFLAGS) $^ $(OutPutOpt) $@ $(LIBS) $(EXPLLINKLIBS)\n");
3343  fprintf(fmk, "endif\n");
3344  fprintf(fmk, "endif\n");
3345  fprintf(fmk, "endif\n");
3346  fprintf(fmk, "endif\n");
3347  fprintf(fmk, "\t\t@echo \"$@ done\"\n");
3348  fprintf(fmk, "\n");
3349  fprintf(fmk, "clean:\n");
3350  fprintf(fmk, "\t\t@rm -f $(OBJS) core\n");
3351  fprintf(fmk, "\n");
3352  fprintf(fmk, "distclean: clean\n");
3353  fprintf(fmk, "\t\t@rm -f $(PROGRAMS) $(PACKSO) $(PACKLIB) *Dict.* *.def *.exp \\\n");
3354  fprintf(fmk, "\t\t *.so *.lib *.dll *.d *.log .def so_locations\n");
3355  fprintf(fmk, "\t\t@rm -rf cxx_repository\n");
3356  fprintf(fmk, "\n");
3357  fprintf(fmk, "# Dependencies\n");
3358  fprintf(fmk, "\n");
3359  fprintf(fmk, "%sProjectSource.$(ObjSuf): %sProjectHeaders.h %sLinkDef.h %sProjectDict.$(SrcSuf)\n", pack, pack, pack, pack);
3360  fprintf(fmk, "\n");
3361  fprintf(fmk, "%sProjectDict.$(SrcSuf): %sProjectHeaders.h %sLinkDef.h\n", pack, pack, pack);
3362  fprintf(fmk, "\t\t@echo \"Generating dictionary $@...\"\n");
3363  fprintf(fmk, "\t\t@rootcint -f $@ -c $^\n");
3364  fprintf(fmk, "\n");
3365  fprintf(fmk, ".$(SrcSuf).$(ObjSuf):\n");
3366  fprintf(fmk, "\t\t$(CXX) $(CXXFLAGS) -c $<\n");
3367  fprintf(fmk, "\n");
3368 
3369  // Close the file
3370  fclose(fmk);
3371 
3372  // Done
3373  return 0;
3374 }
3375 
3376 ////////////////////////////////////////////////////////////////////////////////
3377 /// Create BUILD.sh and SETUP.C under 'proofinf' for PAR package 'pack'.
3378 /// Called by MakeProject when option 'par' is given.
3379 /// Return 0 on success, -1 on error.
3381 Int_t TFile::MakeProjectParProofInf(const char *pack, const char *proofinf)
3382 {
3383  // Output directory path must be defined ...
3384  if (!proofinf || (proofinf && strlen(proofinf) <= 0)) {
3385  Error("MakeProjectParProofInf", "directory path undefined!");
3386  return -1;
3387  }
3388 
3389  // ... and exist and be a directory
3390  Int_t rcst = 0;
3391  FileStat_t st;
3392  if ((rcst = gSystem->GetPathInfo(proofinf, st)) != 0 || !R_ISDIR(st.fMode)) {
3393  Error("MakeProjectParProofInf", "path '%s' %s", proofinf,
3394  ((rcst == 0) ? "is not a directory" : "does not exist"));
3395  return -1;
3396  }
3397 
3398  // Package name must be defined
3399  if (!pack || (pack && strlen(pack) <= 0)) {
3400  Error("MakeProjectParProofInf", "package name undefined!");
3401  return -1;
3402  }
3403 
3404  TString path;
3405 
3406  // The BUILD.sh first
3407  path.Form("%s/BUILD.sh", proofinf);
3408 #ifdef R__WINGCC
3409  FILE *f = fopen(path.Data(), "wb");
3410 #else
3411  FILE *f = fopen(path.Data(), "w");
3412 #endif
3413  if (!f) {
3414  Error("MakeProjectParProofInf", "cannot create file '%s' (errno: %d)",
3415  path.Data(), TSystem::GetErrno());
3416  return -1;
3417  }
3418 
3419  fprintf(f, "#! /bin/sh\n");
3420  fprintf(f, "# Build libEvent library.\n");
3421  fprintf(f, "\n");
3422  fprintf(f, "#\n");
3423  fprintf(f, "# The environment variables ROOTPROOFLITE and ROOTPROOFCLIENT can be used to\n");
3424  fprintf(f, "# adapt the script to the calling environment\n");
3425  fprintf(f, "#\n");
3426  fprintf(f, "# if test ! \"x$ROOTPROOFLITE\" = \"x\"; then\n");
3427  fprintf(f, "# echo \"event-BUILD: PROOF-Lite node (session has $ROOTPROOFLITE workers)\"\n");
3428  fprintf(f, "# elif test ! \"x$ROOTPROOFCLIENT\" = \"x\"; then\n");
3429  fprintf(f, "# echo \"event-BUILD: PROOF client\"\n");
3430  fprintf(f, "# else\n");
3431  fprintf(f, "# echo \"event-BUILD: standard PROOF node\"\n");
3432  fprintf(f, "# fi\n");
3433  fprintf(f, "\n");
3434  fprintf(f, "if [ \"\" = \"clean\" ]; then\n");
3435  fprintf(f, " make distclean\n");
3436  fprintf(f, " exit 0\n");
3437  fprintf(f, "fi\n");
3438  fprintf(f, "\n");
3439  fprintf(f, "make\n");
3440  fprintf(f, "rc=$?\n");
3441  fprintf(f, "echo \"rc=$?\"\n");
3442  fprintf(f, "if [ $? != \"0\" ] ; then\n");
3443  fprintf(f, " exit 1\n");
3444  fprintf(f, "fi\n");
3445  fprintf(f, "exit 0\n");
3446 
3447  // Close the file
3448  fclose(f);
3449 
3450  // Then SETUP.C
3451  path.Form("%s/SETUP.C", proofinf);
3452 #ifdef R__WINGCC
3453  f = fopen(path.Data(), "wb");
3454 #else
3455  f = fopen(path.Data(), "w");
3456 #endif
3457  if (!f) {
3458  Error("MakeProjectParProofInf", "cannot create file '%s' (errno: %d)",
3459  path.Data(), TSystem::GetErrno());
3460  return -1;
3461  }
3462 
3463  fprintf(f, "Int_t SETUP()\n");
3464  fprintf(f, "{\n");
3465  fprintf(f, "\n");
3466  fprintf(f, "//\n");
3467  fprintf(f, "// The environment variables ROOTPROOFLITE and ROOTPROOFCLIENT can be used to\n");
3468  fprintf(f, "// adapt the macro to the calling environment\n");
3469  fprintf(f, "//\n");
3470  fprintf(f, "// if (gSystem->Getenv(\"ROOTPROOFLITE\")) {\n");
3471  fprintf(f, "// Printf(\"event-SETUP: PROOF-Lite node (session has %%s workers)\",\n");
3472  fprintf(f, "// gSystem->Getenv(\"ROOTPROOFLITE\"));\n");
3473  fprintf(f, "// } else if (gSystem->Getenv(\"ROOTPROOFCLIENT\")) {\n");
3474  fprintf(f, "// Printf(\"event-SETUP: PROOF client\");\n");
3475  fprintf(f, "// } else {\n");
3476  fprintf(f, "// Printf(\"event-SETUP: standard PROOF node\");\n");
3477  fprintf(f, "// }\n");
3478  fprintf(f, "\n");
3479  fprintf(f, " if (gSystem->Load(\"lib%s\") == -1)\n", pack);
3480  fprintf(f, " return -1;\n");
3481  fprintf(f, " return 0;\n");
3482  fprintf(f, "}\n");
3483  fprintf(f, "\n");
3484 
3485  // Close the file
3486  fclose(f);
3487 
3488  // Done
3489  return 0;
3490 }
3491 
3492 ////////////////////////////////////////////////////////////////////////////////
3493 /// Read the list of StreamerInfo from this file.
3494 ///
3495 /// The key with name holding the list of TStreamerInfo objects is read.
3496 /// The corresponding TClass objects are updated.
3497 /// Note that this function is not called if the static member fgReadInfo is false.
3498 /// (see TFile::SetReadStreamerInfo)
3501 {
3502  auto listRetcode = GetStreamerInfoListImpl(/*lookupSICache*/ true);
3503  TList *list = listRetcode.fList;
3504  auto retcode = listRetcode.fReturnCode;
3505  if (!list) {
3506  if (retcode) MakeZombie();
3507  return;
3508  }
3509 
3510  list->SetOwner(kFALSE);
3511 
3512  if (gDebug > 0) Info("ReadStreamerInfo", "called for file %s",GetName());
3513 
3514  TStreamerInfo *info;
3515 
3516  Int_t version = fVersion;
3517  if (version > 1000000) version -= 1000000;
3518  if (version < 53419 || (59900 < version && version < 59907)) {
3519  // We need to update the fCheckSum field of the TStreamerBase.
3520 
3521  // loop on all TStreamerInfo classes
3522  TObjLink *lnk = list->FirstLink();
3523  while (lnk) {
3524  info = (TStreamerInfo*)lnk->GetObject();
3525  if (info == 0 || info->IsA() != TStreamerInfo::Class()) {
3526  lnk = lnk->Next();
3527  continue;
3528  }
3529  TIter next(info->GetElements());
3530  TStreamerElement *element;
3531  while ((element = (TStreamerElement*) next())) {
3532  TStreamerBase *base = dynamic_cast<TStreamerBase*>(element);
3533  if (!base) continue;
3534  if (base->GetBaseCheckSum() != 0) continue;
3535  TStreamerInfo *baseinfo = (TStreamerInfo*)list->FindObject(base->GetName());
3536  if (baseinfo) {
3537  base->SetBaseCheckSum(baseinfo->GetCheckSum());
3538  }
3539  }
3540  lnk = lnk->Next();
3541  }
3542  }
3543 
3544  // loop on all TStreamerInfo classes
3545  for (int mode=0;mode<2; ++mode) {
3546  // In order for the collection proxy to be initialized properly, we need
3547  // to setup the TStreamerInfo for non-stl class before the stl classes.
3548  TObjLink *lnk = list->FirstLink();
3549  while (lnk) {
3550  info = (TStreamerInfo*)lnk->GetObject();
3551  if (info == 0) {
3552  lnk = lnk->Next();
3553  continue;
3554  }
3555  if (info->IsA() != TStreamerInfo::Class()) {
3556  if (mode==1) {
3557  TObject *obj = (TObject*)info;
3558  if (strcmp(obj->GetName(),"listOfRules")==0) {
3559 #if 0
3560  // Completely ignore the rules for now.
3561  TList *listOfRules = (TList*)obj;
3562  TObjLink *rulelnk = listOfRules->FirstLink();
3563  while (rulelnk) {
3564  TObjString *rule = (TObjString*)rulelnk->GetObject();
3565  TClass::AddRule( rule->String().Data() );
3566  rulelnk = rulelnk->Next();
3567  }
3568 #endif
3569  } else {
3570  Warning("ReadStreamerInfo","%s has a %s in the list of TStreamerInfo.", GetName(), info->IsA()->GetName());
3571  }
3572  info->SetBit(kCanDelete);
3573  }
3574  lnk = lnk->Next();
3575  continue;
3576  }
3577  // This is a quick way (instead of parsing the name) to see if this is
3578  // the description of an STL container.
3579  if (info->GetElements()==0) {
3580  Warning("ReadStreamerInfo","The StreamerInfo for %s does not have a list of elements.",info->GetName());
3581  lnk = lnk->Next();
3582  continue;
3583  }
3584  TObject *element = info->GetElements()->UncheckedAt(0);
3585  Bool_t isstl = element && strcmp("This",element->GetName())==0;
3586 
3587  if ( (!isstl && mode ==0) || (isstl && mode ==1) ) {
3588  // Skip the STL container the first time around
3589  // Skip the regular classes the second time around;
3590  info->BuildCheck(this);
3591  Int_t uid = info->GetNumber();
3592  Int_t asize = fClassIndex->GetSize();
3593  if (uid >= asize && uid <100000) fClassIndex->Set(2*asize);
3594  if (uid >= 0 && uid < fClassIndex->GetSize()) fClassIndex->fArray[uid] = 1;
3595  else {
3596  printf("ReadStreamerInfo, class:%s, illegal uid=%d\n",info->GetName(),uid);
3597  }
3598  if (gDebug > 0) printf(" -class: %s version: %d info read at slot %d\n",info->GetName(), info->GetClassVersion(),uid);
3599  }
3600  lnk = lnk->Next();
3601  }
3602  }
3603  fClassIndex->fArray[0] = 0;
3604  list->Clear(); //this will delete all TStreamerInfo objects with kCanDelete bit set
3605  delete list;
3606 
3607 #ifdef R__USE_IMT
3608  // We are done processing the record, let future calls and other threads that it
3609  // has been done.
3610  fgTsSIHashes.Insert(listRetcode.fHash);
3611 #endif
3612 }
3613 
3614 ////////////////////////////////////////////////////////////////////////////////
3615 /// Specify if the streamerinfos must be read at file opening.
3616 ///
3617 /// If fgReadInfo is true (default) TFile::ReadStreamerInfo is called
3618 /// when opening the file.
3619 /// It may be interesting to set fgReadInfo to false to speedup the file
3620 /// opening time or in case libraries containing classes referenced
3621 /// by the file have not yet been loaded.
3622 /// if fgReadInfo is false, one can still read the StreamerInfo with
3623 /// myfile.ReadStreamerInfo();
3625 void TFile::SetReadStreamerInfo(Bool_t readinfo)
3626 {
3627  fgReadInfo = readinfo;
3628 }
3629 
3630 ////////////////////////////////////////////////////////////////////////////////
3631 /// If the streamerinfos are to be read at file opening.
3632 ///
3633 /// See TFile::SetReadStreamerInfo for more documentation.
3636 {
3637  return fgReadInfo;
3638 }
3639 
3640 ////////////////////////////////////////////////////////////////////////////////
3641 /// Show the StreamerInfo of all classes written to this file.
3644 {
3645  TList *list = GetStreamerInfoList();
3646  if (!list) return;
3647 
3648  list->ls();
3649  delete list;
3650 }
3651 
3652 ////////////////////////////////////////////////////////////////////////////////
3653 /// Check if the ProcessID pidd is already in the file,
3654 /// if not, add it and return the index number in the local file list.
3657 {
3658  TProcessID *pid = pidd;
3659  if (!pid) pid = TProcessID::GetPID();
3660  TObjArray *pids = GetListOfProcessIDs();
3661  Int_t npids = GetNProcessIDs();
3662  for (Int_t i=0;i<npids;i++) {
3663  if (pids->At(i) == pid) return (UShort_t)i;
3664  }
3665 
3667  pids->AddAtAndExpand(pid,npids);
3668  pid->IncrementCount();
3669  char name[32];
3670  snprintf(name,32,"ProcessID%d",npids);
3671  this->WriteTObject(pid,name);
3672  this->IncrementProcessIDs();
3673  if (gDebug > 0) {
3674  Info("WriteProcessID", "name=%s, file=%s", name, GetName());
3675  }
3676  return (UShort_t)npids;
3677 }
3678 
3679 
3680 ////////////////////////////////////////////////////////////////////////////////
3681 /// Write the list of TStreamerInfo as a single object in this file
3682 /// The class Streamer description for all classes written to this file
3683 /// is saved. See class TStreamerInfo.
3686 {
3687  //if (!gFile) return;
3688  if (!fWritable) return;
3689  if (!fClassIndex) return;
3690  if (fIsPcmFile) return; // No schema evolution for ROOT PCM files.
3691  if (fClassIndex->fArray[0] == 0
3692  && fSeekInfo != 0) {
3693  // No need to update the index if no new classes added to the file
3694  // but write once an empty StreamerInfo list to mark that there is no need
3695  // for StreamerInfos in this file.
3696  return;
3697  }
3698  if (gDebug > 0) Info("WriteStreamerInfo", "called for file %s",GetName());
3699 
3701 
3702  // build a temporary list with the marked files
3703  TIter next(gROOT->GetListOfStreamerInfo());
3704  TStreamerInfo *info;
3705  TList list;
3706  TList listOfRules;
3707  listOfRules.SetOwner(kTRUE);
3708  listOfRules.SetName("listOfRules");
3709  std::set<TClass*> classSet;
3710 
3711 
3712  while ((info = (TStreamerInfo*)next())) {
3713  Int_t uid = info->GetNumber();
3714  if (fClassIndex->fArray[uid]) {
3715  list.Add(info);
3716  if (gDebug > 0) printf(" -class: %s info number %d saved\n",info->GetName(),uid);
3717 
3718  // Add the IO customization rules to the list to be saved for the underlying
3719  // class but make sure to add them only once.
3720  TClass *clinfo = info->GetClass();
3721  if (clinfo && clinfo->GetSchemaRules()) {
3722  if ( classSet.find( clinfo ) == classSet.end() ) {
3723  if (gDebug > 0) printf(" -class: %s stored the I/O customization rules\n",info->GetName());
3724 
3725  TObjArrayIter it( clinfo->GetSchemaRules()->GetRules() );
3726  ROOT::TSchemaRule *rule;
3727  while( (rule = (ROOT::TSchemaRule*)it.Next()) ) {
3728  TObjString *obj = new TObjString();
3729  rule->AsString(obj->String());
3730  listOfRules.Add(obj);
3731  }
3732  classSet.insert(clinfo);
3733  }
3734  }
3735  }
3736  }
3737 
3738  // Write the StreamerInfo list even if it is empty.
3739  fClassIndex->fArray[0] = 2; //to prevent adding classes in TStreamerInfo::TagFile
3740 
3741  if (listOfRules.GetEntries()) {
3742  // Only add the list of rules if we have something to say.
3743  list.Add(&listOfRules);
3744  }
3745 
3746  //free previous StreamerInfo record
3748  //Create new key
3749  TKey key(&list,"StreamerInfo",GetBestBuffer(), this);
3750  fKeys->Remove(&key);
3751  fSeekInfo = key.GetSeekKey();
3752  fNbytesInfo = key.GetNbytes();
3753  SumBuffer(key.GetObjlen());
3754  key.WriteFile(0);
3755 
3756  fClassIndex->fArray[0] = 0;
3757 
3758  list.RemoveLast(); // remove the listOfRules.
3759 }
3760 
3761 ////////////////////////////////////////////////////////////////////////////////
3762 /// Open a file for reading through the file cache.
3763 ///
3764 /// The file will be downloaded to the cache and opened from there.
3765 /// If the download fails, it will be opened remotely.
3766 /// The file will be downloaded to the directory specified by SetCacheFileDir().
3768 TFile *TFile::OpenFromCache(const char *name, Option_t *, const char *ftitle,
3769  Int_t compress, Int_t netopt)
3770 {
3771  TFile *f = 0;
3772 
3773  if (fgCacheFileDir == "") {
3774  ::Warning("TFile::OpenFromCache",
3775  "you want to read through a cache, but you have no valid cache "
3776  "directory set - reading remotely");
3777  ::Info("TFile::OpenFromCache", "set cache directory using TFile::SetCacheFileDir()");
3778  } else {
3779  TUrl fileurl(name);
3780  TUrl tagurl;
3781 
3782  if ((!strcmp(fileurl.GetProtocol(), "file"))) {
3783  // it makes no sense to read local files through a file cache
3784  if (!fgCacheFileForce)
3785  ::Warning("TFile::OpenFromCache",
3786  "you want to read through a cache, but you are reading "
3787  "local files - CACHEREAD disabled");
3788  } else {
3789  // this is a remote file and worthwhile to be put into the local cache
3790  // now create cachepath to put it
3791  TString cachefilepath;
3792  TString cachefilepathbasedir;
3793  cachefilepath = fgCacheFileDir;
3794  cachefilepath += fileurl.GetFile();
3795  cachefilepathbasedir = gSystem->DirName(cachefilepath);
3796  if ((gSystem->mkdir(cachefilepathbasedir, kTRUE) < 0) &&
3797  (gSystem->AccessPathName(cachefilepathbasedir, kFileExists))) {
3798  ::Warning("TFile::OpenFromCache","you want to read through a cache, but I "
3799  "cannot create the directory %s - CACHEREAD disabled",
3800  cachefilepathbasedir.Data());
3801  } else {
3802  // check if this should be a zip file
3803  if (strlen(fileurl.GetAnchor())) {
3804  // remove the anchor and change the target name
3805  cachefilepath += "__";
3806  cachefilepath += fileurl.GetAnchor();
3807  fileurl.SetAnchor("");
3808  }
3809  if (strstr(name,"zip=")) {
3810  // filter out this option and change the target cache name
3811  TString urloptions = fileurl.GetOptions();
3812  TString newoptions;
3813  TObjArray *objOptions = urloptions.Tokenize("&");
3814  Int_t optioncount = 0;
3815  TString zipname;
3816  for (Int_t n = 0; n < objOptions->GetEntries(); n++) {
3817  TString loption = ((TObjString*)objOptions->At(n))->GetName();
3818  TObjArray *objTags = loption.Tokenize("=");
3819  if (objTags->GetEntries() == 2) {
3820  TString key = ((TObjString*)objTags->At(0))->GetName();
3821  TString value = ((TObjString*)objTags->At(1))->GetName();
3822  if (key.CompareTo("zip", TString::kIgnoreCase)) {
3823  if (optioncount!=0) {
3824  newoptions += "&";
3825  }
3826  newoptions += key;
3827  newoptions += "=";
3828  newoptions += value;
3829  ++optioncount;
3830  } else {
3831  zipname = value;
3832  }
3833  }
3834  delete objTags;
3835  }
3836  delete objOptions;
3837  fileurl.SetOptions(newoptions.Data());
3838  cachefilepath += "__";
3839  cachefilepath += zipname;
3840  fileurl.SetAnchor("");
3841  }
3842 
3843  Bool_t need2copy = kFALSE;
3844 
3845  // check if file is in the cache
3846  Long_t id;
3847  Long64_t size;
3848  Long_t flags;
3849  Long_t modtime;
3850  if (!gSystem->GetPathInfo(cachefilepath, &id, &size, &flags, &modtime)) {
3851  // file is in the cache
3852  if (!fgCacheFileDisconnected) {
3853  char cacheblock[256];
3854  char remotblock[256];
3855  // check the remote file for it's size and compare some magic bytes
3856  TString cfurl;
3857  cfurl = cachefilepath;
3858  cfurl += "?filetype=raw";
3859  TUrl rurl(name);
3860  TString ropt = rurl.GetOptions();
3861  ropt += "&filetype=raw";
3862  rurl.SetOptions(ropt);
3863 
3864  Bool_t forcedcache = fgCacheFileForce;
3866 
3867  TFile *cachefile = TFile::Open(cfurl, "READ");
3868  TFile *remotfile = TFile::Open(rurl.GetUrl(), "READ");
3869 
3870  fgCacheFileForce = forcedcache;
3871 
3872  if (!cachefile) {
3873  need2copy = kTRUE;
3874  ::Error("TFile::OpenFromCache",
3875  "cannot open the cache file to check cache consistency");
3876  return 0;
3877  }
3878 
3879  if (!remotfile) {
3880  ::Error("TFile::OpenFromCache",
3881  "cannot open the remote file to check cache consistency");
3882  return 0;
3883  }
3884 
3885  cachefile->Seek(0);
3886  remotfile->Seek(0);
3887 
3888  if ((!cachefile->ReadBuffer(cacheblock,256)) &&
3889  (!remotfile->ReadBuffer(remotblock,256))) {
3890  if (memcmp(cacheblock, remotblock, 256)) {
3891  ::Warning("TFile::OpenFromCache", "the header of the cache file "
3892  "differs from the remote file - forcing an update");
3893  need2copy = kTRUE;
3894  }
3895  } else {
3896  ::Warning("TFile::OpenFromCache", "the header of the cache and/or "
3897  "remote file are not readable - forcing an update");
3898  need2copy = kTRUE;
3899  }
3900 
3901  delete remotfile;
3902  delete cachefile;
3903  }
3904  } else {
3905  need2copy = kTRUE;
3906  }
3907 
3908  // try to fetch the file (disable now the forced caching)
3909  Bool_t forcedcache = fgCacheFileForce;
3911  if (need2copy && !TFile::Cp(name, cachefilepath)) {
3912  ::Warning("TFile::OpenFromCache", "you want to read through a cache, but I "
3913  "cannot make a cache copy of %s - CACHEREAD disabled",
3914  cachefilepathbasedir.Data());
3915  fgCacheFileForce = forcedcache;
3916  if (fgOpenTimeout != 0)
3917  return 0;
3918  } else {
3919  fgCacheFileForce = forcedcache;
3920  ::Info("TFile::OpenFromCache", "using local cache copy of %s [%s]",
3921  name, cachefilepath.Data());
3922  // finally we have the file and can open it locally
3923  fileurl.SetProtocol("file");
3924  fileurl.SetFile(cachefilepath);
3925 
3926  tagurl = fileurl;
3927  TString tagfile;
3928  tagfile = cachefilepath;
3929  tagfile += ".ROOT.cachefile";
3930  tagurl.SetFile(tagfile);
3931  // we symlink this file as a ROOT cached file
3932  gSystem->Symlink(gSystem->BaseName(cachefilepath), tagfile);
3933  return TFile::Open(fileurl.GetUrl(), "READ", ftitle, compress, netopt);
3934  }
3935  }
3936  }
3937  }
3938 
3939  // Failed
3940  return f;
3941 }
3942 
3943 ////////////////////////////////////////////////////////////////////////////////
3944 /// Create / open a file
3945 ///
3946 /// The type of the file can be either a
3947 /// TFile, TNetFile, TWebFile or any TFile derived class for which an
3948 /// plugin library handler has been registered with the plugin manager
3949 /// (for the plugin manager see the TPluginManager class). The returned
3950 /// type of TFile depends on the file name specified by 'url'.
3951 /// If 'url' is a '|'-separated list of file URLs, the 'URLs' are tried
3952 /// sequentially in the specified order until a successful open.
3953 /// If the file starts with "root:", "roots:" or "rootk:" a TNetFile object
3954 /// will be returned, with "http:" a TWebFile, with "file:" a local TFile,
3955 /// etc. (see the list of TFile plugin handlers in $ROOTSYS/etc/system.rootrc
3956 /// for regular expressions that will be checked) and as last a local file will
3957 /// be tried.
3958 /// Before opening a file via TNetFile a check is made to see if the URL
3959 /// specifies a local file. If that is the case the file will be opened
3960 /// via a normal TFile. To force the opening of a local file via a
3961 /// TNetFile use either TNetFile directly or specify as host "localhost".
3962 /// The netopt argument is only used by TNetFile. For the meaning of the
3963 /// options and other arguments see the constructors of the individual
3964 /// file classes. In case of error returns 0.
3965 ///
3966 /// For TFile implementations supporting asynchronous file open, see
3967 /// TFile::AsyncOpen(...), it is possible to request a timeout with the
3968 /// option <b>TIMEOUT=<secs></b>: the timeout must be specified in seconds and
3969 /// it will be internally checked with granularity of one millisec.
3970 /// For remote files there is the option: <b>CACHEREAD</b> opens an existing
3971 /// file for reading through the file cache. The file will be downloaded to
3972 /// the cache and opened from there. If the download fails, it will be opened remotely.
3973 /// The file will be downloaded to the directory specified by SetCacheFileDir().
3974 ///
3975 /// *The caller is responsible for deleting the pointer.*
3977 TFile *TFile::Open(const char *url, Option_t *options, const char *ftitle,
3978  Int_t compress, Int_t netopt)
3979 {
3980  TPluginHandler *h;
3981  TFile *f = 0;
3982  EFileType type = kFile;
3983 
3984  // Check input
3985  if (!url || strlen(url) <= 0) {
3986  ::Error("TFile::Open", "no url specified");
3987  return f;
3988  }
3989 
3990  TString expandedUrl(url);
3991  gSystem->ExpandPathName(expandedUrl);
3992 
3993  // If a timeout has been specified extract the value and try to apply it (it requires
3994  // support for asynchronous open, though; the following is completely transparent if
3995  // such support if not available for the required protocol)
3996  TString opts(options);
3997  Int_t ito = opts.Index("TIMEOUT=");
3998  if (ito != kNPOS) {
3999  TString sto = opts(ito + strlen("TIMEOUT="), opts.Length());
4000  while (!(sto.IsDigit()) && !(sto.IsNull())) { sto.Remove(sto.Length()-1,1); }
4001  if (!(sto.IsNull())) {
4002  // Timeout in millisecs
4003  Int_t toms = sto.Atoi() * 1000;
4004  if (gDebug > 0) ::Info("TFile::Open", "timeout of %d millisec requested", toms);
4005  // Remove from the options field
4006  sto.Insert(0, "TIMEOUT=");
4007  opts.ReplaceAll(sto, "");
4008  // Asynchrounous open
4009  TFileOpenHandle *fh = TFile::AsyncOpen(expandedUrl, opts, ftitle, compress, netopt);
4010  // Check the result in steps of 1 millisec
4012  aos = TFile::GetAsyncOpenStatus(fh);
4013  Int_t xtms = toms;
4014  while (aos != TFile::kAOSNotAsync && aos == TFile::kAOSInProgress && xtms > 0) {
4015  gSystem->Sleep(1);
4016  xtms -= 1;
4017  aos = TFile::GetAsyncOpenStatus(fh);
4018  }
4019  if (aos == TFile::kAOSNotAsync || aos == TFile::kAOSSuccess) {
4020  // Do open the file now
4021  f = TFile::Open(fh);
4022  if (gDebug > 0) {
4023  if (aos == TFile::kAOSSuccess)
4024  ::Info("TFile::Open", "waited %d millisec for asynchronous open", toms - xtms);
4025  else
4026  ::Info("TFile::Open", "timeout option not supported (requires asynchronous"
4027  " open support)");
4028  }
4029  } else {
4030  if (xtms <= 0)
4031  ::Error("TFile::Open", "timeout expired while opening '%s'", expandedUrl.Data());
4032  // Cleanup the request
4033  SafeDelete(fh);
4034  }
4035  // Done
4036  return f;
4037  } else {
4038  ::Warning("TFile::Open", "incomplete 'TIMEOUT=' option specification - ignored");
4039  opts.ReplaceAll("TIMEOUT=", "");
4040  }
4041  }
4042 
4043  // We will use this from now on
4044  const char *option = opts;
4045 
4046  // Many URLs? Redirect output and print errors in case of global failure
4047  TString namelist(expandedUrl);
4048  Ssiz_t ip = namelist.Index("|");
4049  Bool_t rediroutput = (ip != kNPOS &&
4050  ip != namelist.Length()-1 && gDebug <= 0) ? kTRUE : kFALSE;
4051  RedirectHandle_t rh;
4052  if (rediroutput) {
4053  TString outf = ".TFileOpen_";
4054  FILE *fout = gSystem->TempFileName(outf);
4055  if (fout) {
4056  fclose(fout);
4057  gSystem->RedirectOutput(outf, "w", &rh);
4058  }
4059  }
4060 
4061  // Try sequentially all names in 'names'
4062  TString name, n;
4063  Ssiz_t from = 0;
4064  while (namelist.Tokenize(n, from, "|") && !f) {
4065 
4066  // check if we read through a file cache
4067  if (!strcasecmp(option, "CACHEREAD") ||
4068  ((!strcasecmp(option,"READ") || !option[0]) && fgCacheFileForce)) {
4069  // Try opening the file from the cache
4070  if ((f = TFile::OpenFromCache(n, option, ftitle, compress, netopt)))
4071  return f;
4072  }
4073 
4075 
4076  // change names from e.g. /castor/cern.ch/alice/file.root to
4077  // castor:/castor/cern.ch/alice/file.root as recognized by the plugin manager
4078  TUrl urlname(n, kTRUE);
4079  name = urlname.GetUrl();
4080  // Check first if a pending async open request matches this one
4083  TFileOpenHandle *fh = 0;
4084  while ((fh = (TFileOpenHandle *)nxr()))
4085  if (fh->Matches(name))
4086  return TFile::Open(fh);
4087  }
4088 
4089  TString urlOptions(urlname.GetOptions());
4090  if (urlOptions.BeginsWith("pmerge") || urlOptions.Contains("&pmerge") || urlOptions.Contains(" pmerge")) {
4091  type = kMerge;
4092 
4093  // Pass the full name including the url options:
4094  f = (TFile*) gROOT->ProcessLineFast(TString::Format("new TParallelMergingFile(\"%s\",\"%s\",\"%s\",%d)",n.Data(),option,ftitle,compress));
4095 
4096  } else {
4097  // Resolve the file type; this also adjusts names
4098  TString lfname = gEnv->GetValue("Path.Localroot", "");
4099  type = GetType(name, option, &lfname);
4100 
4101  if (type == kLocal) {
4102 
4103  // Local files
4104  if (lfname.IsNull()) {
4105  urlname.SetHost("");
4106  urlname.SetProtocol("file");
4107  lfname = urlname.GetUrl();
4108  }
4109  f = new TFile(lfname.Data(), option, ftitle, compress);
4110 
4111  } else if (type == kNet) {
4112 
4113  // Network files
4114  if ((h = gROOT->GetPluginManager()->FindHandler("TFile", name))) {
4115  if (h->LoadPlugin() == -1)
4116  return 0;
4117  f = (TFile*) h->ExecPlugin(5, name.Data(), option, ftitle, compress, netopt);
4118  }
4119 
4120  } else if (type == kWeb) {
4121 
4122  // Web files
4123  if ((h = gROOT->GetPluginManager()->FindHandler("TFile", name))) {
4124  if (h->LoadPlugin() == -1)
4125  return 0;
4126  f = (TFile*) h->ExecPlugin(2, name.Data(), option);
4127  }
4128 
4129  } else if (type == kFile) {
4130 
4131  // 'file:' protocol
4132  if ((h = gROOT->GetPluginManager()->FindHandler("TFile", name)) &&
4133  h->LoadPlugin() == 0) {
4134  name.ReplaceAll("file:", "");
4135  f = (TFile*) h->ExecPlugin(4, name.Data(), option, ftitle, compress);
4136  } else
4137  f = new TFile(name.Data(), option, ftitle, compress);
4138 
4139  } else {
4140 
4141  // no recognized specification: try the plugin manager
4142  if ((h = gROOT->GetPluginManager()->FindHandler("TFile", name.Data()))) {
4143  if (h->LoadPlugin() == -1)
4144  return 0;
4145  TClass *cl = TClass::GetClass(h->GetClass());
4146  if (cl && cl->InheritsFrom("TNetFile"))
4147  f = (TFile*) h->ExecPlugin(5, name.Data(), option, ftitle, compress, netopt);
4148  else
4149  f = (TFile*) h->ExecPlugin(4, name.Data(), option, ftitle, compress);
4150  } else {
4151  // Just try to open it locally but via TFile::Open, so that we pick-up the correct
4152  // plug-in in the case file name contains information about a special backend (e.g.
4153  // "srm://srm.cern.ch//castor/cern.ch/grid/..." should be considered a castor file
4154  // /castor/cern.ch/grid/...").
4155  f = TFile::Open(urlname.GetFileAndOptions(), option, ftitle, compress);
4156  }
4157  }
4158  }
4159 
4160  if (f && f->IsZombie()) {
4161  TString newUrl = f->GetNewUrl();
4162  delete f;
4163  if( newUrl.Length() && gEnv->GetValue("TFile.CrossProtocolRedirects", 1) )
4164  f = TFile::Open( newUrl, option, ftitle, compress );
4165  else
4166  f = 0;
4167  }
4168  }
4169 
4170  if (rediroutput) {
4171  // Restore output to stdout
4172  gSystem->RedirectOutput(0, "", &rh);
4173  // If we failed print error messages
4174  if (!f)
4175  gSystem->ShowOutput(&rh);
4176  // Remove the file
4177  gSystem->Unlink(rh.fFile);
4178  }
4179 
4180  // if the file is writable, non local, and not opened in raw mode
4181  // we create a default write cache of 512 KBytes
4182  if (type != kLocal && type != kFile &&
4183  f && f->IsWritable() && !f->IsRaw()) {
4184  new TFileCacheWrite(f, 1);
4185  }
4186 
4187  return f;
4188 }
4189 
4190 ////////////////////////////////////////////////////////////////////////////////
4191 /// Submit an asynchronous open request.
4192 
4193 /// See TFile::Open(const char *, ...) for an
4194 /// explanation of the arguments. A handler is returned which is to be passed
4195 /// to TFile::Open(TFileOpenHandle *) to get the real TFile instance once
4196 /// the file is open.
4197 /// This call never blocks and it is provided to allow parallel submission
4198 /// of file opening operations expected to take a long time.
4199 /// TFile::Open(TFileOpenHandle *) may block if the file is not yet ready.
4200 /// The sequence
4201 ///
4202 /// TFile::Open(TFile::AsyncOpen(const char *, ...))
4203 ///
4204 /// is equivalent to
4205 ///
4206 /// TFile::Open(const char *, ...)
4207 ///
4208 /// To be effective, the underlying TFile implementation must be able to
4209 /// support asynchronous open functionality. Currently, only TXNetFile
4210 /// supports it. If the functionality is not implemented, this call acts
4211 /// transparently by returning an handle with the arguments for the
4212 /// standard synchronous open run by TFile::Open(TFileOpenHandle *).
4213 /// The retuned handle will be adopted by TFile after opening completion
4214 /// in TFile::Open(TFileOpenHandle *); if opening is not finalized the
4215 /// handle must be deleted by the caller.
4217 TFileOpenHandle *TFile::AsyncOpen(const char *url, Option_t *option,
4218  const char *ftitle, Int_t compress,
4219  Int_t netopt)
4220 {
4221  TFileOpenHandle *fh = 0;
4222  TPluginHandler *h;
4223  TFile *f = 0;
4224  Bool_t notfound = kTRUE;
4225 
4226  // Check input
4227  if (!url || strlen(url) <= 0) {
4228  ::Error("TFile::AsyncOpen", "no url specified");
4229  return fh;
4230  }
4231 
4232  // Many URLs? Redirect output and print errors in case of global failure
4233  TString namelist(url);
4234  gSystem->ExpandPathName(namelist);
4235  Ssiz_t ip = namelist.Index("|");
4236  Bool_t rediroutput = (ip != kNPOS &&
4237  ip != namelist.Length()-1 && gDebug <= 0) ? kTRUE : kFALSE;
4238  RedirectHandle_t rh;
4239  if (rediroutput) {
4240  TString outf = ".TFileAsyncOpen_";
4241  FILE *fout = gSystem->TempFileName(outf);
4242  if (fout) {
4243  fclose(fout);
4244  gSystem->RedirectOutput(outf, "w", &rh);
4245  }
4246  }
4247 
4248  // Try sequentially all names in 'names'
4249  TString name, n;
4250  Ssiz_t from = 0;
4251  while (namelist.Tokenize(n, from, "|") && !f) {
4252 
4253  // change names from e.g. /castor/cern.ch/alice/file.root to
4254  // castor:/castor/cern.ch/alice/file.root as recognized by the plugin manager
4255  TUrl urlname(n, kTRUE);
4256  name = urlname.GetUrl();
4257 
4258  // Resolve the file type; this also adjusts names
4259  EFileType type = GetType(name, option);
4260 
4261  // Here we send the asynchronous request if the functionality is implemented
4262  if (type == kNet) {
4263  // Network files
4264  if ((h = gROOT->GetPluginManager()->FindHandler("TFile", name)) &&
4265  (!strcmp(h->GetClass(),"TXNetFile") || !strcmp(h->GetClass(),"TNetXNGFile"))
4266  && h->LoadPlugin() == 0) {
4267  f = (TFile*) h->ExecPlugin(6, name.Data(), option, ftitle, compress, netopt, kTRUE);
4268  notfound = kFALSE;
4269  }
4270  }
4271  if ((h = gROOT->GetPluginManager()->FindHandler("TFile", name)) &&
4272  !strcmp(h->GetClass(),"TAlienFile") && h->LoadPlugin() == 0) {
4273  f = (TFile*) h->ExecPlugin(5, name.Data(), option, ftitle, compress, kTRUE);
4274  notfound = kFALSE;
4275  }
4276 
4277  }
4278 
4279  if (rediroutput) {
4280  // Restore output to stdout
4281  gSystem->RedirectOutput(0, "", &rh);
4282  // If we failed print error messages
4283  if (!notfound && !f)
4284  gSystem->ShowOutput(&rh);
4285  // Remove the file
4286  gSystem->Unlink(rh.fFile);
4287  }
4288 
4289  // Make sure that no error occurred
4290  if (notfound) {
4291  SafeDelete(f);
4292  // Save the arguments in the handler, so that a standard open can be
4293  // attempted later on
4294  fh = new TFileOpenHandle(name, option, ftitle, compress, netopt);
4295  } else if (f) {
4296  // Fill the opaque handler to be use to attach the file later on
4297  fh = new TFileOpenHandle(f);
4298  }
4299 
4300  // Record this request
4301  if (fh) {
4302  // Create the lst, if not done already
4303  if (!fgAsyncOpenRequests)
4304  fgAsyncOpenRequests = new TList;
4305  fgAsyncOpenRequests->Add(fh);
4306  }
4307 
4308  // We are done
4309  return fh;
4310 }
4311 
4312 ////////////////////////////////////////////////////////////////////////////////
4313 /// Waits for the completion of an asynchronous open request.
4314 ///
4315 /// Returns the pointer to the associated TFile, transferring ownership of the
4316 /// handle to the TFile instance.
4319 {
4320  TFile *f = 0;
4321 
4322  // Note that the request may have failed
4323  if (fh && fgAsyncOpenRequests) {
4324  // Remove it from the pending list: we need to do it at this level to avoid
4325  // recursive calls in the standard TFile::Open
4327  // Was asynchronous open functionality implemented?
4328  if ((f = fh->GetFile()) && !(f->IsZombie())) {
4329  // Yes: wait for the completion of the open phase, if needed
4330  Bool_t cr = (!strcmp(f->GetOption(),"CREATE") ||
4331  !strcmp(f->GetOption(),"RECREATE") ||
4332  !strcmp(f->GetOption(),"NEW")) ? kTRUE : kFALSE;
4333  f->Init(cr);
4334  } else {
4335  // No: process a standard open
4336  f = TFile::Open(fh->GetName(), fh->GetOpt(), fh->GetTitle(),
4337  fh->GetCompress(), fh->GetNetOpt());
4338  }
4339 
4340  // Adopt the handle instance in the TFile instance so that it gets
4341  // automatically cleaned up
4342  if (f) f->fAsyncHandle = fh;
4343  }
4344 
4345  // We are done
4346  return f;
4347 }
4348 
4349 ////////////////////////////////////////////////////////////////////////////////
4350 /// Interface to system open. All arguments like in POSIX open().
4352 Int_t TFile::SysOpen(const char *pathname, Int_t flags, UInt_t mode)
4353 {
4354 #if defined(R__WINGCC)
4355  // ALWAYS use binary mode - even cygwin text should be in unix format
4356  // although this is posix default it has to be set explicitly
4357  return ::open(pathname, flags | O_BINARY, mode);
4358 #elif defined(R__SEEK64)
4359  return ::open64(pathname, flags, mode);
4360 #else
4361  return ::open(pathname, flags, mode);
4362 #endif
4363 }
4364 
4365 ////////////////////////////////////////////////////////////////////////////////
4366 /// Interface to system close. All arguments like in POSIX close().
4369 {
4370  if (fd < 0) return 0;
4371  return ::close(fd);
4372 }
4373 
4374 ////////////////////////////////////////////////////////////////////////////////
4375 /// Interface to system read. All arguments like in POSIX read().
4377 Int_t TFile::SysRead(Int_t fd, void *buf, Int_t len)
4378 {
4379  return ::read(fd, buf, len);
4380 }
4381 
4382 ////////////////////////////////////////////////////////////////////////////////
4383 /// Interface to system write. All arguments like in POSIX write().
4385 Int_t TFile::SysWrite(Int_t fd, const void *buf, Int_t len)
4386 {
4387  return ::write(fd, buf, len);
4388 }
4389 ////////////////////////////////////////////////////////////////////////////////
4390 /// Interface to system lseek.
4391 ///
4392 /// All arguments like in POSIX lseek()
4393 /// except that the offset and return value are of a type which are
4394 /// able to handle 64 bit file systems.
4396 Long64_t TFile::SysSeek(Int_t fd, Long64_t offset, Int_t whence)
4397 {
4398 #if defined (R__SEEK64)
4399  return ::lseek64(fd, offset, whence);
4400 #elif defined(WIN32)
4401  return ::_lseeki64(fd, offset, whence);
4402 #else
4403  return ::lseek(fd, offset, whence);
4404 #endif
4405 }
4406 
4407 ////////////////////////////////////////////////////////////////////////////////
4408 /// Return file stat information.
4409 ///
4410 /// The interface and return value is
4411 /// identical to TSystem::GetPathInfo(). The function returns 0 in
4412 /// case of success and 1 if the file could not be stat'ed.
4414 Int_t TFile::SysStat(Int_t, Long_t *id, Long64_t *size, Long_t *flags,
4415  Long_t *modtime)
4416 {
4417  return gSystem->GetPathInfo(fRealName, id, size, flags, modtime);
4418 }
4419 
4420 ////////////////////////////////////////////////////////////////////////////////
4421 /// Interface to system fsync. All arguments like in POSIX fsync().
4424 {
4425  if (TestBit(kDevNull)) return 0;
4426 
4427 #ifndef WIN32
4428  return ::fsync(fd);
4429 #else
4430  return ::_commit(fd);
4431 #endif
4432 }
4433 
4434 ////////////////////////////////////////////////////////////////////////////////
4435 /// Return the total number of bytes written so far to the file.
4438 {
4440 }
4441 
4442 ////////////////////////////////////////////////////////////////////////////////
4443 /// Static function returning the total number of bytes read from all files.
4446 {
4447  return fgBytesRead;
4448 }
4449 
4450 ////////////////////////////////////////////////////////////////////////////////
4451 /// Static function returning the total number of bytes written to all files.
4452 /// Does not take into account what might still be in the write caches.
4455 {
4456  return fgBytesWrite;
4457 }
4458 
4459 ////////////////////////////////////////////////////////////////////////////////
4460 /// Static function returning the total number of read calls from all files.
4463 {
4464  return fgReadCalls;
4465 }
4466 
4467 ////////////////////////////////////////////////////////////////////////////////
4468 /// Static function returning the readahead buffer size.
4471 {
4472  return fgReadaheadSize;
4473 }
4474 
4475 //______________________________________________________________________________
4476 void TFile::SetReadaheadSize(Int_t bytes) { fgReadaheadSize = bytes; }
4477 
4478 //______________________________________________________________________________
4479 void TFile::SetFileBytesRead(Long64_t bytes) { fgBytesRead = bytes; }
4480 
4481 //______________________________________________________________________________
4482 void TFile::SetFileBytesWritten(Long64_t bytes) { fgBytesWrite = bytes; }
4483 
4484 //______________________________________________________________________________
4485 void TFile::SetFileReadCalls(Int_t readcalls) { fgReadCalls = readcalls; }
4486 
4487 //______________________________________________________________________________
4489 
4490 //______________________________________________________________________________
4492 
4493 ////////////////////////////////////////////////////////////////////////////////
4494 /// Sets the directory where to locally stage/cache remote files.
4495 /// If the directory is not writable by us return kFALSE.
4497 Bool_t TFile::SetCacheFileDir(std::string_view cachedir, Bool_t operatedisconnected,
4498  Bool_t forcecacheread )
4499 {
4500  TString cached = cachedir;
4501  if (!cached.EndsWith("/"))
4502  cached += "/";
4503 
4504  if (gSystem->AccessPathName(cached, kFileExists)) {
4505  // try to create it
4506  gSystem->mkdir(cached, kTRUE);
4507  if (gSystem->AccessPathName(cached, kFileExists)) {
4508  ::Error("TFile::SetCacheFileDir", "no sufficient permissions on cache directory %s or cannot create it", TString(cachedir).Data());
4509  fgCacheFileDir = "";
4510  return kFALSE;
4511  }
4512  gSystem->Chmod(cached, 0700);
4513  }
4514  if (gSystem->AccessPathName(cached, kWritePermission))
4515  gSystem->Chmod(cached, 0700);
4516  fgCacheFileDir = cached;
4517  fgCacheFileDisconnected = operatedisconnected;
4518  fgCacheFileForce = forcecacheread;
4519  return kTRUE;
4520 }
4521 
4522 ////////////////////////////////////////////////////////////////////////////////
4523 /// Get the directory where to locally stage/cache remote files.
4525 const char *TFile::GetCacheFileDir()
4526 {
4527  return fgCacheFileDir;
4528 }
4529 
4530 ////////////////////////////////////////////////////////////////////////////////
4531 /// Try to shrink the cache to the desired size.
4532 ///
4533 /// With the clenupinterval you can specify the minimum amount of time after
4534 /// the previous cleanup before the cleanup operation is repeated in
4535 /// the cache directory
4537 Bool_t TFile::ShrinkCacheFileDir(Long64_t shrinksize, Long_t cleanupinterval)
4538 {
4539  if (fgCacheFileDir == "") {
4540  return kFALSE;
4541  }
4542 
4543  // check the last clean-up in the cache
4544  Long_t id;
4545  Long64_t size;
4546  Long_t flags;
4547  Long_t modtime;
4548 
4549  TString cachetagfile = fgCacheFileDir;
4550  cachetagfile += ".tag.ROOT.cache";
4551  if (!gSystem->GetPathInfo(cachetagfile, &id, &size, &flags, &modtime)) {
4552  // check the time passed since last cache cleanup
4553  Long_t lastcleanuptime = ((Long_t)time(0) - modtime);
4554  if (lastcleanuptime < cleanupinterval) {
4555  ::Info("TFile::ShrinkCacheFileDir", "clean-up is skipped - last cleanup %lu seconds ago - you requested %lu", lastcleanuptime, cleanupinterval);
4556  return kTRUE;
4557  }
4558  }
4559 
4560  // (re-)create the cache tag file
4561  cachetagfile += "?filetype=raw";
4562  TFile *tagfile = 0;
4563 
4564  if (!(tagfile = TFile::Open(cachetagfile, "RECREATE"))) {
4565  ::Error("TFile::ShrinkCacheFileDir", "cannot create the cache tag file %s", cachetagfile.Data());
4566  return kFALSE;
4567  }
4568 
4569  // the shortest garbage collector in the world - one long line of PERL - unlinks files only,
4570  // if there is a symbolic link with '.ROOT.cachefile' for safety ;-)
4571 
4572  TString cmd;
4573 #if defined(R__WIN32)
4574  cmd = "echo <TFile::ShrinkCacheFileDir>: cleanup to be implemented";
4575 #elif defined(R__MACOSX)
4576  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);
4577 #else
4578  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);
4579 #endif
4580 
4581  tagfile->WriteBuffer(cmd, 4096);
4582  delete tagfile;
4583 
4584  if ((gSystem->Exec(cmd)) != 0) {
4585  ::Error("TFile::ShrinkCacheFileDir", "error executing clean-up script");
4586  return kFALSE;
4587  }
4588 
4589  return kTRUE;
4590 }
4591 
4592 ////////////////////////////////////////////////////////////////////////////////
4593 /// Sets open timeout time (in ms). Returns previous timeout value.
4596 {
4597  UInt_t to = fgOpenTimeout;
4598  fgOpenTimeout = timeout;
4599  return to;
4600 }
4601 
4602 ////////////////////////////////////////////////////////////////////////////////
4603 /// Returns open timeout (in ms).
4606 {
4607  return fgOpenTimeout;
4608 }
4609 
4610 ////////////////////////////////////////////////////////////////////////////////
4611 /// Sets only staged flag. Returns previous value of flag.
4612 /// When true we check before opening the file if it is staged, if not,
4613 /// the open fails.
4616 {
4617  Bool_t f = fgOnlyStaged;
4618  fgOnlyStaged = onlystaged;
4619  return f;
4620 }
4621 
4622 ////////////////////////////////////////////////////////////////////////////////
4623 /// Returns staged only flag.
4626 {
4627  return fgOnlyStaged;
4628 }
4629 
4630 ////////////////////////////////////////////////////////////////////////////////
4631 /// Return kTRUE if 'url' matches the coordinates of this file.
4632 ///
4633 /// The check is implementation dependent and may need to be overload
4634 /// by each TFile implementation relying on this check.
4635 /// The default implementation checks the file name only.
4637 Bool_t TFile::Matches(const char *url)
4638 {
4639  // Check the full URL, including port and FQDN.
4640  TUrl u(url);
4641 
4642  // Check
4643  if (!strcmp(u.GetFile(), fUrl.GetFile())) {
4644  // Check ports
4645  if (u.GetPort() == fUrl.GetPort()) {
4646  if (!strcmp(u.GetHostFQDN(), fUrl.GetHostFQDN())) {
4647  // Ok, coordinates match
4648  return kTRUE;
4649  }
4650  }
4651  }
4652 
4653  // Default is not matching
4654  return kFALSE;
4655 }
4656 
4657 ////////////////////////////////////////////////////////////////////////////////
4658 /// Return kTRUE if this async request matches the open request
4659 /// specified by 'url'
4661 Bool_t TFileOpenHandle::Matches(const char *url)
4662 {
4663  if (fFile) {
4664  return fFile->Matches(url);
4665  } else if (fName.Length() > 0){
4666  // Deep check of URLs
4667  TUrl u(url);
4668  TUrl uref(fName);
4669  if (!strcmp(u.GetFile(), uref.GetFile())) {
4670  // Check ports
4671  if (u.GetPort() == uref.GetPort()) {
4672  // Check also the host name
4673  if (!strcmp(u.GetHostFQDN(), uref.GetHostFQDN())) {
4674  // Ok, coordinates match
4675  return kTRUE;
4676  }
4677  }
4678  }
4679  }
4680 
4681  // Default is not matching
4682  return kFALSE;
4683 }
4684 
4685 ////////////////////////////////////////////////////////////////////////////////
4686 /// Resolve the file type as a function of the protocol field in 'name'
4687 ///
4688 /// If defined, the string 'prefix' is added when testing the locality of
4689 /// a 'name' with network-like structure (i.e. root://host//path); if the file
4690 /// is local, on return 'prefix' will contain the actual local path of the file.
4692 TFile::EFileType TFile::GetType(const char *name, Option_t *option, TString *prefix)
4693 {
4695 
4696  TPMERegexp re("^(root|xroot).*", "i");
4697  if (re.Match(name)) {
4698  //
4699  // Should be a network file ...
4700  type = kNet;
4701  // ... but make sure that is not local or that a remote-like connection
4702  // is forced. Treat it as local if:
4703  // i) the url points to the localhost, the file will be opened in
4704  // readonly mode and the current user has read access;
4705  // ii) the specified user is equal to the current user then open local
4706  // TFile.
4707  Bool_t localFile = kFALSE;
4708  TUrl url(name);
4709  //
4710  // Check whether we should try to optimize for local files
4711  Bool_t forceRemote = gEnv->GetValue("Path.ForceRemote", 0);
4712  forceRemote = (forceRemote) ? kTRUE : gEnv->GetValue("TFile.ForceRemote", 0);
4713  TString opts = url.GetOptions();
4714  if (opts.Contains("remote=1"))
4715  forceRemote = kTRUE;
4716  else if (opts.Contains("remote=0"))
4717  forceRemote = kFALSE;
4718  if (!forceRemote) {
4719  // Generic locality test
4720  localFile = gSystem->IsPathLocal(name);
4721  if (localFile) {
4722  // Local path including the prefix
4723  const char *fname = url.GetFileAndOptions();
4724  TString lfname;
4725  if (fname[0] == '/') {
4726  if (prefix)
4727  lfname.Form("%s%s", prefix->Data(), fname);
4728  else
4729  lfname = fname;
4730  } else if (fname[0] == '~' || fname[0] == '$') {
4731  lfname = fname;
4732  } else {
4733  lfname.Form("%s/%s", gSystem->HomeDirectory(), fname);
4734  }
4735  // If option "READ" test existence and access
4736  TString opt = option;
4737  Bool_t read = (opt.IsNull() ||
4738  !opt.CompareTo("READ", TString::kIgnoreCase)) ? kTRUE : kFALSE;
4739  if (read) {
4740  char *fn;
4741  if ((fn = gSystem->ExpandPathName(TUrl(lfname).GetFile()))) {
4743  localFile = kFALSE;
4744  delete [] fn;
4745  }
4746  }
4747  // Return full local path if requested (and if the case)
4748  if (localFile && prefix)
4749  *prefix = lfname;
4750  }
4751  }
4752  //
4753  // Adjust the type according to findings
4754  type = (localFile) ? kLocal : type;
4755  } else if (TPMERegexp("^(http[s]?|s3http[s]?|[a]?s3|gs|gshttp[s]?){1}:", "i").Match(name)) {
4756  //
4757  // Web file
4758  type = kWeb;
4759  } else if (!strncmp(name, "file:", 5)) {
4760  //
4761  // 'file' protocol
4762  type = kFile;
4763  }
4764  // We are done
4765  return type;
4766 }
4767 
4768 ////////////////////////////////////////////////////////////////////////////////
4769 /// Get status of the async open request related to 'name'.
4772 {
4773  // Check the list of pending async open requests
4776  TFileOpenHandle *fh = 0;
4777  while ((fh = (TFileOpenHandle *)nxr()))
4778  if (fh->Matches(name))
4779  return TFile::GetAsyncOpenStatus(fh);
4780  }
4781 
4782  // Check also the list of files open
4784  TSeqCollection *of = gROOT->GetListOfFiles();
4785  if (of && (of->GetSize() > 0)) {
4786  TIter nxf(of);
4787  TFile *f = 0;
4788  while ((f = (TFile *)nxf()))
4789  if (f->Matches(name))
4790  return f->GetAsyncOpenStatus();
4791  }
4792 
4793  // Default is synchronous mode
4794  return kAOSNotAsync;
4795 }
4796 
4797 ////////////////////////////////////////////////////////////////////////////////
4798 /// Get status of the async open request related to 'handle'.
4801 {
4802  if (handle && handle->fFile) {
4803  if (!handle->fFile->IsZombie())
4804  return handle->fFile->GetAsyncOpenStatus();
4805  else
4806  return TFile::kAOSFailure;
4807  }
4808 
4809  // Default is synchronous mode
4810  return TFile::kAOSNotAsync;
4811 }
4812 
4813 ////////////////////////////////////////////////////////////////////////////////
4814 /// Get final URL for file being opened asynchronously.
4815 /// Returns 0 is the information is not yet available.
4817 const TUrl *TFile::GetEndpointUrl(const char* name)
4818 {
4819  // Check the list of pending async open requests
4822  TFileOpenHandle *fh = 0;
4823  while ((fh = (TFileOpenHandle *)nxr()))
4824  if (fh->Matches(name))
4825  if (fh->fFile)
4826  return fh->fFile->GetEndpointUrl();
4827  }
4828 
4829  // Check also the list of files open
4831  TSeqCollection *of = gROOT->GetListOfFiles();
4832  if (of && (of->GetSize() > 0)) {
4833  TIter nxf(of);
4834  TFile *f = 0;
4835  while ((f = (TFile *)nxf()))
4836  if (f->Matches(name))
4837  return f->GetEndpointUrl();
4838  }
4839 
4840  // Information not yet available
4841  return (const TUrl *)0;
4842 }
4843 
4844 ////////////////////////////////////////////////////////////////////////////////
4845 /// Print file copy progress.
4847 void TFile::CpProgress(Long64_t bytesread, Long64_t size, TStopwatch &watch)
4848 {
4849  fprintf(stderr, "[TFile::Cp] Total %.02f MB\t|", (Double_t)size/1048576);
4850 
4851  for (int l = 0; l < 20; l++) {
4852  if (size > 0) {
4853  if (l < 20*bytesread/size)
4854  fprintf(stderr, "=");
4855  else if (l == 20*bytesread/size)
4856  fprintf(stderr, ">");
4857  else if (l > 20*bytesread/size)
4858  fprintf(stderr, ".");
4859  } else
4860  fprintf(stderr, "=");
4861  }
4862  // Allow to update the GUI while uploading files
4864  watch.Stop();
4865  Double_t lCopy_time = watch.RealTime();
4866  fprintf(stderr, "| %.02f %% [%.01f MB/s]\r",
4867  100.0*(size?(bytesread/((float)size)):1), (lCopy_time>0.)?bytesread/lCopy_time/1048576.:0.);
4868  watch.Continue();
4869 }
4870 
4871 ////////////////////////////////////////////////////////////////////////////////
4872 /// Allows to copy this file to the dst URL. Returns kTRUE in case of success,
4873 /// kFALSE otherwise.
4875 Bool_t TFile::Cp(const char *dst, Bool_t progressbar, UInt_t buffersize)
4876 {
4877  Bool_t rmdestiferror = kFALSE;
4878  TStopwatch watch;
4879  Bool_t success = kFALSE;
4880 
4881  TUrl dURL(dst, kTRUE);
4882 
4883  TString oopt = "RECREATE";
4884  TString ourl = dURL.GetUrl();
4885 
4886  // Files will be open in RAW mode
4887  TString raw = "filetype=raw";
4888 
4889  // Set optimization options for the destination file
4890  TString opt = dURL.GetOptions();
4891  if (opt != "") opt += "&";
4892  opt += raw;
4893 
4894  // AliEn files need to know where the source file is
4895  if (!strcmp(dURL.GetProtocol(), "alien"))
4896  opt += TString::Format("&source=%s", GetName());
4897 
4898  dURL.SetOptions(opt);
4899 
4900  char *copybuffer = 0;
4901 
4902  TFile *sfile = this;
4903  TFile *dfile = 0;
4904 
4905  // "RECREATE" does not work always well with XROOTD
4906  // namely when some pieces of the path are missing;
4907  // we force "NEW" in such a case
4908  if (TFile::GetType(ourl, "") == TFile::kNet) {
4909  if (gSystem->AccessPathName(ourl)) {
4910  oopt = "NEW";
4911  // Force creation of the missing parts of the path
4912  opt += "&mkpath=1";
4913  dURL.SetOptions(opt);
4914  }
4915  }
4916 
4917  // Open destination file
4918  if (!(dfile = TFile::Open(dURL.GetUrl(), oopt))) {
4919  ::Error("TFile::Cp", "cannot open destination file %s", dst);
4920  goto copyout;
4921  }
4922 
4923  // Probably we created a new file
4924  // We have to remove it in case of errors
4925  rmdestiferror = kTRUE;
4926 
4927  sfile->Seek(0);
4928  dfile->Seek(0);
4929 
4930  copybuffer = new char[buffersize];
4931  if (!copybuffer) {
4932  ::Error("TFile::Cp", "cannot allocate the copy buffer");
4933  goto copyout;
4934  }
4935 
4936  Bool_t readop;
4937  Bool_t writeop;
4938  Long64_t read;
4939  Long64_t written;
4940  Long64_t totalread;
4941  Long64_t filesize;
4942  Long64_t b00;
4943  filesize = sfile->GetSize();
4944  totalread = 0;
4945  watch.Start();
4946 
4947  b00 = sfile->GetBytesRead();
4948 
4949  do {
4950  if (progressbar) CpProgress(totalread, filesize,watch);
4951 
4952  Long64_t b1 = sfile->GetBytesRead() - b00;
4953 
4954  Long64_t readsize;
4955  if (filesize - b1 > (Long64_t)buffersize) {
4956  readsize = buffersize;
4957  } else {
4958  readsize = filesize - b1;
4959  }
4960 
4961  if (readsize == 0) break;
4962 
4963  Long64_t b0 = sfile->GetBytesRead();
4964  sfile->Seek(totalread,TFile::kBeg);
4965  readop = sfile->ReadBuffer(copybuffer, (Int_t)readsize);
4966  read = sfile->GetBytesRead() - b0;
4967  if ((read <= 0) || readop) {
4968  ::Error("TFile::Cp", "cannot read from source file %s. readsize=%lld read=%lld readop=%d",
4969  sfile->GetName(), readsize, read, readop);
4970  goto copyout;
4971  }
4972 
4973  Long64_t w0 = dfile->GetBytesWritten();
4974  writeop = dfile->WriteBuffer(copybuffer, (Int_t)read);
4975  written = dfile->GetBytesWritten() - w0;
4976  if ((written != read) || writeop) {
4977  ::Error("TFile::Cp", "cannot write %lld bytes to destination file %s", read, dst);
4978  goto copyout;
4979  }
4980  totalread += read;
4981  } while (read == (Long64_t)buffersize);
4982 
4983  if (progressbar) {
4984  CpProgress(totalread, filesize,watch);
4985  fprintf(stderr, "\n");
4986  }
4987 
4988  success = kTRUE;
4989 
4990 copyout:
4991  if (dfile) dfile->Close();
4992 
4993  if (dfile) delete dfile;
4994  if (copybuffer) delete[] copybuffer;
4995 
4996  if (rmdestiferror && (success != kTRUE))
4997  gSystem->Unlink(dst);
4998 
4999  watch.Stop();
5000  watch.Reset();
5001 
5002  return success;
5003 }
5004 
5005 ////////////////////////////////////////////////////////////////////////////////
5006 /// Allows to copy file from src to dst URL. Returns kTRUE in case of success,
5007 /// kFALSE otherwise.
5009 Bool_t TFile::Cp(const char *src, const char *dst, Bool_t progressbar,
5010  UInt_t buffersize)
5011 {
5012  TUrl sURL(src, kTRUE);
5013 
5014  // Files will be open in RAW mode
5015  TString raw = "filetype=raw";
5016 
5017  // Set optimization options for the source file
5018  TString opt = sURL.GetOptions();
5019  if (opt != "") opt += "&";
5020  opt += raw;
5021  // Netx-related options:
5022  // cachesz = 4*buffersize -> 4 buffers as peak mem usage
5023  // readaheadsz = 2*buffersize -> Keep at max 4*buffersize bytes outstanding when reading
5024  // rmpolicy = 1 -> Remove from the cache the blk with the least offset
5025  opt += TString::Format("&cachesz=%d&readaheadsz=%d&rmpolicy=1", 4*buffersize, 2*buffersize);
5026  sURL.SetOptions(opt);
5027 
5028  TFile *sfile = 0;
5029 
5030  Bool_t success = kFALSE;
5031 
5032  // Open source file
5033  if (!(sfile = TFile::Open(sURL.GetUrl(), "READ"))) {
5034  ::Error("TFile::Cp", "cannot open source file %s", src);
5035  } else {
5036  success = sfile->Cp(dst, progressbar, buffersize);
5037  }
5038 
5039  if (sfile) sfile->Close();
5040  if (sfile) delete sfile;
5041 
5042  return success;
5043 }
5044 
5045 //______________________________________________________________________________
5046 //The next statement is not active anymore on Linux.
5047 //Using posix_fadvise introduces a performance penalty (10 %) on optimized files
5048 //and in addition it destroys the information of TTreePerfStats
5049 #if defined(R__neverLINUX) && !defined(R__WINGCC)
5051 {
5052  // Read specified byte range asynchronously. Actually we tell the kernel
5053  // which blocks we are going to read so it can start loading these blocks
5054  // in the buffer cache.
5055 
5056  // Shortcut to avoid having to implement dummy ReadBufferAsync() in all
5057  // I/O plugins. Override ReadBufferAsync() in plugins if async is supported.
5058  if (IsA() != TFile::Class())
5059  return kTRUE;
5060 
5061  int advice = POSIX_FADV_WILLNEED;
5062  if (len == 0) {
5063  // according POSIX spec if len is zero, all data following offset
5064  // is specified. Nevertheless ROOT uses zero to probe readahead
5065  // capabilities.
5066  advice = POSIX_FADV_NORMAL;
5067  }
5068  Double_t start = 0;
5069  if (gPerfStats != 0) start = TTimeStamp();
5070 #if defined(R__SEEK64)
5071  Int_t result = posix_fadvise64(fD, offset, len, advice);
5072 #else
5073  Int_t result = posix_fadvise(fD, offset, len, advice);
5074 #endif
5075  if (gPerfStats != 0) {
5076  gPerfStats->FileReadEvent(this, len, start);
5077  }
5078  return (result != 0);
5079 }
5080 #else
5082 {
5083  // Not supported yet on non Linux systems.
5084 
5085  return kTRUE;
5086 }
5087 #endif
5088 
5089 ////////////////////////////////////////////////////////////////////////////////
5090 /// Max number of bytes to prefetch.
5091 ///
5092 /// By default this is 75% of the
5093 /// read cache size. But specific TFile implementations may need to change it
5096 {
5097  TFileCacheRead *cr = 0;
5098  if ((cr = GetCacheRead())) {
5099  Int_t bytes = cr->GetBufferSize() / 4 * 3;
5100  return ((bytes < 0) ? 0 : bytes);
5101  }
5102  return 0;
5103 }
TString fTitle
Definition: TNamed.h:33
virtual Bool_t SendFileCloseEvent(TFile *)
TDatime fDatimeM
Date and time of last modification.
Describe Streamer information for one class version.
Definition: TStreamerInfo.h:43
virtual Bool_t SendFileWriteProgress(TFile *)
void SetFile(const char *file)
Definition: TUrl.h:88
Long64_t GetRelOffset() const
Definition: TFile.h:234
virtual Bool_t cd(const char *path=0)
Change current directory to "this" directory.
virtual Int_t Sizeof() const
Return the size in bytes of the directory header.
static TProcessID * GetPID()
static: returns pointer to current TProcessID
Definition: TProcessID.cxx:341
virtual const char * BaseName(const char *pathname)
Base name of a file name. Base name of /user/root is root.
Definition: TSystem.cxx:932
Bool_t fIsArchive
!True if this is a pure archive file
Definition: TFile.h:96
static ROOT::TRWSpinLock fgRwLock
!Read-write lock to protect global PID list
Definition: TFile.h:110
virtual const char * GetName() const
Returns name of object.
Definition: TNamed.h:47
virtual void SysError(const char *method, const char *msgfmt,...) const
Issue system error message.
Definition: TObject.cxx:894
Bool_t fIsPcmFile
!True if the file is a ROOT pcm file.
Definition: TFile.h:101
virtual Bool_t AccessPathName(const char *path, EAccessMode mode=kFileExists)
Returns FALSE if one can access a file using the specified access mode.
Definition: TSystem.cxx:1276
virtual UInt_t GetUniqueID() const
Return the unique object id.
Definition: TObject.cxx:375
Bool_t IsReading() const
Definition: TBuffer.h:83
void frombuf(char *&buf, Bool_t *x)
Definition: Bytes.h:280
virtual void DrawMap(const char *keys="*", Option_t *option="")
Draw map of objects in this file.
Definition: TFile.cxx:1086
virtual Int_t Recover()
Attempt to recover file if not correctly closed.
Definition: TFile.cxx:1945
TFileCacheRead * fCacheRead
!Pointer to the read cache (if any)
Definition: TFile.h:92
An array of TObjects.
Definition: TObjArray.h:37
Char_t fUnits
Number of bytes for file pointers.
Definition: TFile.h:86
static Int_t DecreaseDirLevel()
Decrease the indentation level for ls().
Definition: TROOT.cxx:2727
const char * GetArchiveName() const
Definition: TArchiveFile.h:55
virtual Int_t SysStat(Int_t fd, Long_t *id, Long64_t *size, Long_t *flags, Long_t *modtime)
Return file stat information.
Definition: TFile.cxx:4413
virtual Bool_t ProcessEvents()
Process pending events (GUI, timers, sockets).
Definition: TSystem.cxx:424
virtual void Delete(Option_t *option="")
Remove all objects from the list AND delete all heap based objects.
Definition: TList.cxx:467
TObjArray * fProcessIDs
!Array of pointers to TProcessIDs
Definition: TFile.h:89
virtual const char * GetFlagsOpt() const
Return the optimization flags.
Definition: TSystem.cxx:3834
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition: TObject.cxx:854
Long64_t fBEGIN
First used byte in file.
Definition: TFile.h:72
Double_t RealTime()
Stop the stopwatch (if it is running) and return the realtime (in seconds) passed between the start a...
Definition: TStopwatch.cxx:110
ROOT::ESTLType IsSTLCont(std::string_view type)
type : type name: vector<list<classA,allocator>,allocator> result: 0 : not stl container code of cont...
void Set(Int_t n)
Set size of this array to n chars.
Definition: TArrayC.cxx:105
static Bool_t AddRule(const char *rule)
Add a schema evolution customization rule.
Definition: TClass.cxx:1801
virtual Bool_t IsPathLocal(const char *path)
Returns TRUE if the url in &#39;path&#39; points to the local file system.
Definition: TSystem.cxx:1285
long long Long64_t
Definition: RtypesCore.h:69
Long64_t GetLast() const
Definition: TFree.h:41
void Start(Bool_t reset=kTRUE)
Start the stopwatch.
Definition: TStopwatch.cxx:58
static Bool_t fgReadInfo
if true (default) ReadStreamerInfo is called when opening a file
Definition: TFile.h:128
virtual Long64_t SysSeek(Int_t fd, Long64_t offset, Int_t whence)
Interface to system lseek.
Definition: TFile.cxx:4395
Long64_t GetMemberFilePosition() const
Return position in archive of current member.
Long64_t fBytesWrite
Number of bytes written to this file.
Definition: TFile.h:69
EAsyncOpenStatus
Asynchronous open request status.
Definition: TFile.h:58
virtual const char * WorkingDirectory()
Return working directory.
Definition: TSystem.cxx:869
Long64_t fSeekParent
Location of parent directory on file.
short Version_t
Definition: RtypesCore.h:61
void SetProtocol(const char *proto, Bool_t setDefaultPort=kFALSE)
Set protocol and, optionally, change the port accordingly.
Definition: TUrl.cxx:520
virtual void FillBuffer(char *&buffer)
Encode file output buffer.
Definition: TFile.cxx:1128
Double_t fSumBuffer
Sum of buffer sizes of objects written so far.
Definition: TFile.h:67
static std::atomic< Long64_t > fgBytesRead
Number of bytes read by all TFile objects.
Definition: TFile.h:124
Collectable string class.
Definition: TObjString.h:28
Long64_t fSeekKeys
Location of Keys record on file.
virtual Int_t ReOpen(Option_t *mode)
Reopen a file with a different access mode.
Definition: TFile.cxx:2059
float Float_t
Definition: RtypesCore.h:53
const Int_t kBEGIN
Definition: TFile.cxx:157
Int_t fCompress
Compression level and algorithm.
Definition: TFile.h:78
TArrayC * fClassIndex
!Index of TStreamerInfo classes written to this file
Definition: TFile.h:88
Bool_t Matches(const char *name)
Return kTRUE if this async request matches the open request specified by &#39;url&#39;.
Definition: TFile.cxx:4660
static void IncrementFileCounter()
Definition: TFile.cxx:4490
virtual void ReadFree()
Read the FREE linked list.
Definition: TFile.cxx:1825
A cache when reading files over the network.
const char Option_t
Definition: RtypesCore.h:62
Int_t GetNetOpt() const
Definition: TFile.h:374
virtual void Save()
Save recursively all directory keys and headers.
int GetSplit(const char *type, std::vector< std::string > &output, int &nestedLoc, EModType mode=TClassEdit::kNone)
Stores in output (after emptying it) the split type.
Definition: TClassEdit.cxx:940
virtual void Flush()
Synchronize a file&#39;s in-memory and on-disk states.
Definition: TFile.cxx:1099
TList * fList
Definition: TDirectory.h:87
virtual void SetCacheRead(TFileCacheRead *cache, TObject *tree=0, ECacheAction action=kDisconnect)
Set a pointer to the read cache.
Definition: TFile.cxx:2265
static TList * fgAsyncOpenRequests
Definition: TFile.h:115
const Ssiz_t kNPOS
Definition: RtypesCore.h:111
virtual void SetOffset(Long64_t offset, ERelativeTo pos=kBeg)
Set position from where to start reading.
Definition: TFile.cxx:2152
This class represents a WWW compatible URL.
Definition: TUrl.h:35
virtual char * GetBuffer() const
Definition: TKey.h:74
TString & ReplaceAll(const TString &s1, const TString &s2)
Definition: TString.h:687
virtual void RemoveLast()
Remove the last object of the list.
Definition: TList.cxx:905
virtual TKey * CreateKey(TDirectory *mother, const TObject *obj, const char *name, Int_t bufsize)
Creates key for object and converts data to buffer.
Definition: TFile.cxx:1014
int GetPathInfo(const char *path, Long_t *id, Long_t *size, Long_t *flags, Long_t *modtime)
Get info about a file: id, size, flags, modification time.
Definition: TSystem.cxx:1374
unsigned short UShort_t
Definition: RtypesCore.h:36
Class holding info about the file being opened.
Definition: TFile.h:346
const char * GetProtocol() const
Definition: TUrl.h:67
static UInt_t fgOpenTimeout
Timeout for open operations in ms - 0 corresponds to blocking i/o.
Definition: TFile.h:120
virtual const char * GetClassName() const
Definition: TKey.h:71
virtual void SetOwner(Bool_t enable=kTRUE)
Set whether this collection is the owner (enable==true) of its content.
UInt_t GetBaseCheckSum()
virtual void Seek(Long64_t offset, ERelativeTo pos=kBeg)
Seek to a specific position in the file. Pos it either kBeg, kCur or kEnd.
Definition: TFile.cxx:2173
TObjArray * GetListOfProcessIDs() const
Definition: TFile.h:219
A ROOT file is a suite of consecutive data records (TKey instances) with a well defined format...
Definition: TFile.h:47
static void SetFileReadCalls(Int_t readcalls=0)
Definition: TFile.cxx:4484
virtual Int_t GetEntries() const
Definition: TCollection.h:177
virtual Bool_t ReadBuffer(char *buf, Int_t len)
Read a buffer from the file.
Definition: TFile.cxx:1670
virtual TObject * Last() const
Return the last object in the list. Returns 0 when list is empty.
Definition: TList.cxx:689
static Bool_t SetCacheFileDir(ROOT::Internal::TStringView cacheDir, Bool_t operateDisconnected=kTRUE, Bool_t forceCacheread=kFALSE)
Definition: TFile.h:315
virtual const char * HomeDirectory(const char *userName=0)
Return the user&#39;s home directory.
Definition: TSystem.cxx:885
void ReadBuffer(char *&buffer)
Stream UUID from input buffer.
Definition: TUUID.cxx:278
void ToUpper()
Change string to upper case.
Definition: TString.cxx:1113
Buffer base class used for serializing objects.
Definition: TBuffer.h:40
Bool_t HasInterpreterInfo() const
Definition: TClass.h:381
virtual TObject * Get(const char *namecycle)
Return pointer to object identified by namecycle.
virtual Bool_t ChangeDirectory(const char *path)
Change directory.
Definition: TSystem.cxx:860
const char * GetFileAndOptions() const
Return the file and its options (the string specified behind the ?).
Definition: TUrl.cxx:501
void Add(TObject *obj)
This function may not be used (but we need to provide it since it is a pure virtual in TCollection)...
Definition: TMap.cxx:53
static TArchiveFile * Open(const char *url, TFile *file)
Return proper archive file handler depending on passed url.
#define gROOT
Definition: TROOT.h:410
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition: TString.h:634
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition: TObject.h:172
virtual Long64_t GetBytesWritten() const
Return the total number of bytes written so far to the file.
Definition: TFile.cxx:4436
Int_t LoadPlugin()
Load the plugin library for this handler.
virtual int Load(const char *module, const char *entry="", Bool_t system=kFALSE)
Load a shared library.
Definition: TSystem.cxx:1829
#define O_BINARY
Definition: civetweb.c:652
Basic string class.
Definition: TString.h:131
static Bool_t ShrinkCacheFileDir(Long64_t shrinkSize, Long_t cleanupInteval=0)
Try to shrink the cache to the desired size.
Definition: TFile.cxx:4536
virtual Int_t Sizeof() const
Return size of the TNamed part of the TObject.
Definition: TNamed.cxx:173
#define f(i)
Definition: RSha256.hxx:104
void ToLower()
Change string to lower-case.
Definition: TString.cxx:1100
int Int_t
Definition: RtypesCore.h:41
virtual void FillBuffer(char *&buffer)
Encode TNamed into output buffer.
Definition: TNamed.cxx:104
virtual const char * DirName(const char *pathname)
Return the directory name in pathname.
Definition: TSystem.cxx:1004
bool Bool_t
Definition: RtypesCore.h:59
Iterator of object array.
Definition: TObjArray.h:122
R__EXTERN TVirtualMutex * gROOTMutex
Definition: TROOT.h:57
Int_t WriteBufferViaCache(const char *buf, Int_t len)
Write buffer via cache.
Definition: TFile.cxx:2419
virtual const char * GetSoExt() const
Get the shared library extension.
Definition: TSystem.cxx:3904
#define gInterpreter
Definition: TInterpreter.h:527
const char * GetOptions() const
Definition: TUrl.h:74
Int_t GenerateHeaderFile(const char *dirname, const TList *subClasses=0, const TList *extrainfos=0)
Generate header file for the class described by this TStreamerInfo the function is called by TFile::M...
TArchiveMember * GetMember() const
Definition: TArchiveFile.h:51
Long64_t fBytesReadExtra
Number of extra bytes (overhead) read by the readahead buffer.
Definition: TFile.h:71
virtual Int_t Write(const char *name=0, Int_t opt=0, Int_t bufsize=0)
Write all objects in memory to disk.
ERelativeTo
Definition: TFile.h:183
virtual const char * GetFlagsDebug() const
Return the debug flags.
Definition: TSystem.cxx:3826
TList * fInfoCache
!Cached list of the streamer infos in this file
Definition: TFile.h:106
virtual UInt_t WriteVersion(const TClass *cl, Bool_t useBcnt=kFALSE)=0
virtual TList * GetStreamerInfoList() final
Read the list of TStreamerInfo objects written to this file.
Definition: TFile.cxx:1394
TObject * At(Int_t idx) const
Definition: TObjArray.h:165
virtual void IgnoreInterrupt(Bool_t ignore=kTRUE)
If ignore is true ignore the interrupt signal, else restore previous behaviour.
Definition: TSystem.cxx:610
static void SetReadStreamerInfo(Bool_t readinfo=kTRUE)
Specify if the streamerinfos must be read at file opening.
Definition: TFile.cxx:3624
Long64_t fSeekInfo
Location on disk of StreamerInfo record.
Definition: TFile.h:75
Int_t fReadCalls
Number of read calls ( not counting the cache calls )
Definition: TFile.h:83
This class is a TS set of unsigned set.
TArchiveFile * fArchive
!Archive file from which we read this file
Definition: TFile.h:91
void ReadBuffer(char *&buffer)
Decode Date/Time from output buffer, used by I/O system.
Definition: TDatime.cxx:277
virtual TObject * Clone(const char *newname="") const
Make a clone of an collection using the Streamer facility.
static void SetReadaheadSize(Int_t bufsize=256000)
Definition: TFile.cxx:4475
TString & Insert(Ssiz_t pos, const char *s)
Definition: TString.h:644
virtual Int_t GetBytesInCache() const
Short_t Abs(Short_t d)
Definition: TMathBase.h:108
virtual Int_t GetNkeys() const
virtual void FillBuffer(char *&buffer)
Encode directory header into output buffer.
R__EXTERN void **(* gThreadTsd)(void *, Int_t)
Definition: TThreadSlots.h:40
void Reset()
Definition: TCollection.h:252
const char * GetHostFQDN() const
Return fully qualified domain name of url host.
Definition: TUrl.cxx:469
virtual int mkdir(const char *name, Bool_t recursive=kFALSE)
Make a file system directory.
Definition: TSystem.cxx:904
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition: TObject.cxx:694
const char * GetUrl(Bool_t withDeflt=kFALSE) const
Return full URL.
Definition: TUrl.cxx:387
virtual TObject * FindObject(const char *name) const
Delete a TObjLink object.
Definition: TList.cxx:574
void SumBuffer(Int_t bufsize)
Increment statistics for buffer sizes of objects in this file.
Definition: TFile.cxx:2317
if object in a list can be deleted
Definition: TObject.h:58
virtual void FillBuffer(char *&buffer)
Encode fre structure into output buffer.
Definition: TFree.cxx:109
static Int_t GetErrno()
Static function returning system error number.
Definition: TSystem.cxx:268