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