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