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