// @(#)root/base:$Name: $:$Id: TFile.cxx,v 1.6 2000/09/08 16:05:20 rdm Exp $
// Author: Rene Brun 28/11/94
/*************************************************************************
* Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
* All rights reserved. *
* *
* For the licensing terms see $ROOTSYS/LICENSE. *
* For the list of contributors see $ROOTSYS/README/CREDITS. *
*************************************************************************/
#include <iostream.h>
#include <fcntl.h>
#include <errno.h>
#ifndef WIN32
# include <unistd.h>
#else
# define ssize_t int
# include <io.h>
# include <sys/stat.h>
# include <sys/types.h>
#endif
#include "Strlen.h"
#include "TFile.h"
#include "TWebFile.h"
#include "TNetFile.h"
#include "TROOT.h"
#include "TFree.h"
#include "TKey.h"
#include "TDatime.h"
#include "TSystem.h"
#include "TError.h"
#include "Bytes.h"
#include "TInterpreter.h"
#include "TClassTable.h"
TFile *gFile; //Pointer to current file
const Int_t TFile::kBegin = 64;
const Char_t TFile::kUnits = 4;
Double_t TFile::fgBytesRead = 0;
Double_t TFile::fgBytesWrite = 0;
ClassImp(TFile)
//*-*x17 macros/layout_file
//______________________________________________________________________________
TFile::TFile() : TDirectory()
{
//*-*-*-*-*-*-*-*-*-*-*-*File default Constructor*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-* ========================
fD = -1;
fFree = 0;
fWritten = 0;
fSumBuffer = 0;
fSum2Buffer = 0;
if (gDebug)
cerr << "TFile default ctor" <<endl;
}
//1_____________________________________________________________________________
TFile::TFile(const char *fname1, Option_t *option, const char *ftitle, Int_t compress)
:TDirectory()
{
//*-*-*-*-*-*-*-*-*-*-*-*File Constructor*-*--*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-* ================
// If Option = NEW or CREATE create a new file and open it for writing,
// if the file already exists the file is
// not opened.
// = RECREATE create a new file, if the file already
// exists it will be overwritten.
// = UPDATE open an existing file for writing.
// if no file exists, it is created.
// = READ open an existing file for reading.
// If the constructor failed in any way IsZombie() will return true.
// Use IsOpen() to check if the file is (still) open.
//
// The parameter name is used to identify the file in the current job
// name may be different in a job writing the file and another job
// reading/writing the file.
// When the file is created, the name of the file seen from the file system
// is fname. It is recommended to specify fname as "file.root"
// The suffix root will be used by object browsers to automatically
// identify ROOT files.
// The title of the file (ftitle) will be shown by the ROOT browsers.
//
// A ROOT file (like a Unix file system) may contain objects and
// directories. There are no restrictions for the number of levels
// of directories.
//
// A ROOT file is designed such that one can write in the file in pure
// sequential mode (case of BATCH jobs). In this case, the file may be
// read sequentially again without using the file index written
// at the end of the file. In case of a job crash, all the information
// on the file is therefore protected.
// A ROOT file can be used interactively. In this case, one has the
// possibility to delete existing objects and add new ones.
// When an object is deleted from the file, the freed space is added
// into the FREE linked list (lFree). The FREE list consists of a chain
// of consecutive free segments on the file. At the same time, the first
// 4 bytes of the freed record on the file are overwritten by GAPSIZE
// where GAPSIZE = -(Number of bytes occupied by the record).
//
// compress = 0 objects written to this file will not be compressed.
// compress = 1 minimal compression level but fast.
// ....
// compress = 9 maximal compression level but slow.
//
// Note that the compression level may be changed at any time.
// The new compression level will only apply to newly written objects.
// The function TFile::Map shows the compression factor
// for each object written to this file.
// The function TFile::GetCompressionFactor returns the global
// compression factor for this file.
//
// A ROOT file is a suite of consecutive data records with the following
// format (see also the TKey class);
// TKey ---------------------
// byte 1->4 Nbytes = Length of compressed object (in bytes)
// 5->6 Version = TKey version identifier
// 7->10 ObjLen = Length of uncompressed object
// 11->14 Datime = Date and time when object was written to file
// 15->16 KeyLen = Length of the key structure (in bytes)
// 17->18 Cycle = Cycle of key
// 19->22 SeekKey = Pointer to record itself (consistency check)
// 23->26 SeekPdir = Pointer to directory header
// 27->27 lname = Number of bytes in the class name
// 28->.. ClassName = Object Class Name
// ..->.. lname = Number of bytes in the object name
// ..->.. Name = lName bytes with the name of the object
// ..->.. lTitle = Number of bytes in the object title
// ..->.. Title = Title of the object
// -----> DATA = Data bytes associated to the object
//
// The first data record starts at byte fBEGIN (currently set to kBegin)
// Bytes 1->kBegin contain the file description:
// byte 1->4 "root" = Root file identifier
// 5->8 fVersion = File format version
// 9->12 fBEGIN = Pointer to first data record
// 13->16 fEND = Pointer to first free word at the EOF
// 17->20 fSeekFree = Pointer to FREE data record
// 21->24 fNbytesFree = Number of bytes in FREE data record
// 25->28 nfree = Number of free data records
// 29->32 fNbytesName = Number of bytes in TNamed at creation time
// 33->33 fUnits = Number of bytes for file pointers
// 34->37 fCompress = Zip compression level
//
/*
*/
//
//
// The structure of a directory is shown in TDirectory::TDirectory
//
//
if (!gROOT)
::Fatal("TFile::TFile", "ROOT system not initialized");
gDirectory = 0;
SetName(fname1);
SetTitle(ftitle);
TDirectory::Build();
fD = -1;
fFile = this;
fFree = 0;
fVersion = gROOT->GetVersionInt(); //ROOT version in integer format
fUnits = kUnits;
fOption = option;
fCompress = compress;
fWritten = 0;
fSumBuffer = 0;
fSum2Buffer = 0;
fBytesRead = 0;
fBytesWrite = 0;
if (!fOption.CompareTo("NET", TString::kIgnoreCase))
return;
if (!fOption.CompareTo("WEB", TString::kIgnoreCase)) {
fOption = "READ";
fWritable = kFALSE;
return;
}
Bool_t create = kFALSE;
if (!fOption.CompareTo("NEW", TString::kIgnoreCase) ||
!fOption.CompareTo("CREATE", TString::kIgnoreCase))
create = kTRUE;
Bool_t recreate = fOption.CompareTo("RECREATE", TString::kIgnoreCase)
? kFALSE : kTRUE;
Bool_t update = fOption.CompareTo("UPDATE", TString::kIgnoreCase)
? kFALSE : kTRUE;
Bool_t read = fOption.CompareTo("READ", TString::kIgnoreCase)
? kFALSE : kTRUE;
if (!create && !recreate && !update && !read) {
read = kTRUE;
fOption = "READ";
}
const char *fname;
if ((fname = gSystem->ExpandPathName(fname1))) {
SetName(fname);
delete [] (char*)fname;
fname = GetName();
} else {
Error("TFile", "error expanding path %s", fname1);
goto zombie;
}
if (recreate) {
if (!gSystem->AccessPathName(fname, kFileExists))
gSystem->Unlink(fname);
recreate = kFALSE;
create = kTRUE;
fOption = "CREATE";
}
if (create && !gSystem->AccessPathName(fname, kFileExists)) {
Error("TFile", "file %s already exists", fname);
goto zombie;
}
if (update) {
if (gSystem->AccessPathName(fname, kFileExists)) {
update = kFALSE;
create = kTRUE;
}
if (update && gSystem->AccessPathName(fname, kWritePermission)) {
Error("TFile", "no write permission, could not open file %s", fname);
goto zombie;
}
}
if (read) {
if (gSystem->AccessPathName(fname, kFileExists)) {
Error("TFile", "file %s does not exist", fname);
goto zombie;
}
if (gSystem->AccessPathName(fname, kReadPermission)) {
Error("TFile", "no read permission, could not open file %s", fname);
goto zombie;
}
}
//*-*--------------Connect to file system stream
if (create || update) {
#ifndef WIN32
fD = SysOpen(fname, O_RDWR | O_CREAT, 0644);
#else
fD = SysOpen(fname, O_RDWR | O_CREAT | O_BINARY, S_IREAD | S_IWRITE);
#endif
if (fD == -1) {
SysError("TFile", "file %s can not be opened", fname);
goto zombie;
}
fWritable = kTRUE;
} else {
#ifndef WIN32
fD = SysOpen(fname, O_RDONLY, 0644);
#else
fD = SysOpen(fname, O_RDONLY | O_BINARY, S_IREAD | S_IWRITE);
#endif
if (fD == -1) {
SysError("TFile", "file %s can not be opened for reading", fname);
goto zombie;
}
fWritable = kFALSE;
}
Init(create);
return;
zombie:
// error in file opening occured, make this object a zombie
MakeZombie();
gDirectory = gROOT;
}
//______________________________________________________________________________
TFile::TFile(const TFile &file)
{
((TFile&)file).Copy(*this);
}
//______________________________________________________________________________
TFile::~TFile()
{
//*-*-*-*-*-*-*-*-*-*-*-*File destructor*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-* ===============
Close();
SafeDelete(fFree);
gROOT->GetListOfFiles()->Remove(this);
if (gDebug)
cerr <<"TFile dtor called for " << GetName() << endl;
}
//______________________________________________________________________________
void TFile::Init(Bool_t create)
{
// Initialize a TFile object.
Int_t max_file_size = 2000000000; // should rather check disk quota
Int_t nfree;
// make newly opened file the current file and directory
cd();
//*-*---------------NEW file
if (create) {
fFree = new TList;
fBEGIN = kBegin; //First used word in file following the file header
fEND = fBEGIN; //Pointer to end of file
new TFree(fBEGIN, max_file_size); //Create new free list
//*-* Write Directory info
Int_t namelen= TNamed::Sizeof();
Int_t nbytes = namelen + TDirectory::Sizeof();
TKey *key = new TKey(fName,fTitle,IsA(),nbytes);
fNbytesName = key->GetKeylen() + namelen;
fSeekDir = key->GetSeekKey();
fSeekFree = 0;
fNbytesFree = 0;
WriteHeader();
char *buffer = key->GetBuffer();
TNamed::FillBuffer(buffer);
TDirectory::FillBuffer(buffer);
key->WriteFile();
delete key;
}
//*-*----------------UPDATE
else {
char *header = new char[kBegin];
Seek(0);
ReadBuffer(header,kBegin);
// make sure this is a root file
if (strncmp(header, "root", 4)) {
Error("TFile", "%s not a ROOT file", fName.Data());
delete [] header;
goto zombie;
}
char *buffer = header + 4; // skip the "root" file identifier
frombuf(buffer, &fVersion);
frombuf(buffer, &fBEGIN);
frombuf(buffer, &fEND);
frombuf(buffer, &fSeekFree);
frombuf(buffer, &fNbytesFree);
frombuf(buffer, &nfree);
frombuf(buffer, &fNbytesName);
frombuf(buffer, &fUnits );
frombuf(buffer, &fCompress);
fSeekDir = fBEGIN;
delete [] header;
//*-*-------------Read Free segments structure if file is writable
if (fWritable) {
fFree = new TList;
if (fSeekFree > fBEGIN) {
ReadFree();
} else {
Warning("TFile","file %s probably not closed, cannot read free segments",GetName());
}
}
//*-*-------------Read directory info
Int_t nbytes = fNbytesName + TDirectory::Sizeof();
header = new char[nbytes];
buffer = header;
Seek(fBEGIN);
ReadBuffer(buffer,nbytes);
buffer = header+fNbytesName;
Version_t versiondir;
frombuf(buffer,&versiondir);
fDatimeC.ReadBuffer(buffer);
fDatimeM.ReadBuffer(buffer);
frombuf(buffer, &fNbytesKeys);
frombuf(buffer, &fNbytesName);
frombuf(buffer, &fSeekDir);
frombuf(buffer, &fSeekParent);
frombuf(buffer, &fSeekKeys);
//*-*---------read TKey::FillBuffer info
Int_t nk = sizeof(Int_t) +sizeof(Version_t) +2*sizeof(Int_t)+2*sizeof(Short_t)
+2*sizeof(Seek_t);
buffer = header+nk;
TString cname;
cname.ReadBuffer(buffer);
cname.ReadBuffer(buffer); // fName.ReadBuffer(buffer); file may have been renamed
fTitle.ReadBuffer(buffer);
delete [] header;
if (fNbytesName < 10 || fNbytesName > 1000) {
Error("Init","Cannot read directory info");
goto zombie;
}
//*-* -------------Read keys of the top directory
if (fSeekKeys > fBEGIN) {
TDirectory::ReadKeys();
gDirectory = this;
} else {
Warning("TFile","file %s probably not closed, trying to recover",GetName());
Recover();
}
}
gROOT->GetListOfFiles()->Add(this);
if (TClassTable::GetDict("TProof")) {
if (gROOT->ProcessLineFast("TProof::IsActive()"))
gROOT->ProcessLineFast(Form("TProof::This()->ConnectFile((TFile *)0x%lx);",
(Long_t)this));
}
return;
zombie:
// error in file opening occured, make this object a zombie
MakeZombie();
gDirectory = gROOT;
}
//______________________________________________________________________________
void TFile::Close(Option_t *)
{
//*-*-*-*-*-*-*-*-*-*-*-*Close a file*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-* ============
if (!IsOpen()) return;
TCollection::StartGarbageCollection();
TDirectory *cursav = gDirectory;
cd();
if (gFile == this) {
cursav = 0;
}
// Delete all supported directories structures from memory
TDirectory::Close();
cd(); // Close() sets gFile = 0
if (IsWritable()) {
TFree *f1 = (TFree*) GetListOfFree()->First();
if (f1) {
WriteFree(); //*-*- Write free segments linked list
WriteHeader(); //*-*- Now write file header
}
}
// Delete free segments from free list (but don't delete list header)
if (fFree) {
fFree->Delete();
}
if (IsOpen()) {
SysClose(fD);
fD = -1;
}
fWritable = kFALSE;
if (cursav)
cursav->cd();
else {
gFile = 0;
gDirectory = gROOT;
}
gROOT->GetListOfFiles()->Remove(this);
if (TClassTable::GetDict("TProof")) {
if (gROOT->ProcessLineFast("TProof::IsActive()"))
gROOT->ProcessLineFast(Form("TProof::This()->DisConnectFile((TFile *)0x%lx);",
(Long_t)this));
}
TCollection::EmptyGarbageCollection();
}
//______________________________________________________________________________
void TFile::Delete(const char *namecycle)
{
//*-*-*-*-*-*-*-*-*-*-*-*-*Delete object namecycle*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-* =======================
// namecycle identifies an object in the top directory of the file
// namecycle has the format name;cycle
// name = * means all
// cycle = * means all cycles (memory and keys)
// cycle = "" or cycle = 9999 ==> apply to a memory object
// When name=* use T* to delete subdirectories also
//
// examples:
// foo : delete object named foo in memory
// foo;1 : delete cycle 1 of foo on file
// foo;* : delete all cycles of foo on disk and also from memory
// *;2 : delete all objects on file having the cycle 2
// *;* : delete all objects from memory and file
// T*;* : delete all objects from memory and file and all subdirectories
//
if (gDebug)
Printf("TFile Deleting Name=%s",namecycle);
TDirectory::Delete(namecycle);
}
//______________________________________________________________________________
void TFile::Draw(Option_t *option)
{
//*-*-*-*-*-*-*-*-*-*-*-*Fill Graphics Structure and Paint-*-*-*-*-*-*-*-*-*-*
//*-* =================================
// Loop on all objects (memory or file) and all subdirectories
//
GetList()->ForEach(TObject,Draw)(option);
}
//______________________________________________________________________________
void TFile::Flush()
{
// Synchornize a file's in-core and on-disk states.
if (IsOpen() && fWritable) {
if (SysSync(fD) < 0)
SysError("Flush", "error flushing file %s", GetName());
}
}
//______________________________________________________________________________
void TFile::FillBuffer(char *&buffer)
{
//*-*-*-*-*-*-*-*-*-*-*-*Encode file output buffer*-*-*-*-*-*-*
//*-* =========================
// The file output buffer contains only the FREE data record
//
Version_t version = TFile::Class_Version();
tobuf(buffer, version);
}
//______________________________________________________________________________
Int_t TFile::GetBestBuffer()
{
//*-*-*-*-*-*-*-*Return the best buffer size of objects on this file*-*-*-*-*-*
//*-* ===================================================
//
// The best buffer size is estimated based on the current mean value
// and standard deviation of all objects written so far to this file.
// Returns mean value + one standard deviation.
//
if (!fWritten) return TBuffer::kInitialSize;
Double_t mean = fSumBuffer/fWritten;
Double_t rms2 = TMath::Abs(fSum2Buffer/fSumBuffer -mean*mean);
return (Int_t)(mean + TMath::Sqrt(rms2));
}
//______________________________________________________________________________
Float_t TFile::GetCompressionFactor()
{
//*-*-*-*-*-*-*-*-*-*Return the file compression factor*-*-*-*-*-*-*-*-*-*
//*-* =================================
//
// Add total number of compressed/uncompressed bytes for each key.
// return ratio of the two.
//
Short_t keylen;
UInt_t datime;
Int_t nbytes,objlen;
char *header = new char[kBegin];
char *buffer;
Seek_t idcur = fBEGIN;
Float_t comp,uncomp;
comp = uncomp = fBEGIN;
char nwh = 64;
while (idcur < fEND-100) {
Seek(idcur);
ReadBuffer(header,int(nwh));
buffer=header;
frombuf(buffer, &nbytes);
if (nbytes < 0) {
idcur -= nbytes;
Seek(idcur);
continue;
}
Version_t versionkey;
frombuf(buffer, &versionkey);
frombuf(buffer, &objlen);
frombuf(buffer, &datime);
frombuf(buffer, &keylen);
if (!objlen) objlen = nbytes-keylen;
comp += nbytes;
uncomp += keylen + objlen;
idcur += nbytes;
}
delete [] header;
return uncomp/comp;
}
//______________________________________________________________________________
Int_t TFile::GetRecordHeader(char *buf, Seek_t first, Int_t maxbytes, Int_t &nbytes, Int_t &objlen, Int_t &keylen)
{
//*-*-*-*-*-*-*-*-*Read the logical record header starting at position first
//*-* =========================================================
// maxbytes bytes are read into buf
// the function reads nread bytes where nread is the minimum of maxbytes
// and the number of bytes before the end of file.
// the function returns nread.
// In output arguments:
// nbytes : number of bytes in record
// if negative, this is a deleted record
// if 0, cannot read record, wrong value of argument first
// objlen : uncompressed object size
// keylen : length of logical record header
// Note that the arguments objlen and keylen are returned only if maxbytes >=16
if (first < fBEGIN) return 0;
if (first > fEND) return 0;
Seek(first);
Int_t nread = maxbytes;
if (first+maxbytes > fEND) nread = fEND-maxbytes;
if (nread < 4) {
Warning("GetRecordHeader","parameter maxbytes=%d must be >= 4",nread);
return nread;
}
ReadBuffer(buf,nread);
Version_t versionkey;
Short_t klen;
UInt_t datime;
Int_t nb,olen;
char *buffer = buf;
frombuf(buffer,&nb);
nbytes = nb;
if (nb < 0) return nread;
// const Int_t headerSize = Int_t(sizeof(nb) +sizeof(versionkey) +sizeof(olen) +sizeof(datime) +sizeof(klen));
const Int_t headerSize = 16;
if (nread < headerSize) return nread;
frombuf(buffer, &versionkey);
frombuf(buffer, &olen);
frombuf(buffer, &datime);
frombuf(buffer, &klen);
if (!olen) olen = nbytes-klen;
objlen = olen;
keylen = klen;
return nread;
}
//______________________________________________________________________________
void TFile::ls(Option_t *option)
{
//*-*-*-*-*-*-*-*-*-*-*-*List File contents*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-* ==================
// Indentation is used to identify the file tree
// Subdirectories are listed first
// then objects in memory
// then objects on the file
//
TROOT::IndentLevel();
cout <<ClassName()<<"**t\t"<<GetName()<<"t"<<GetTitle()<<endl;
TROOT::IncreaseDirLevel();
TDirectory::ls(option);
TROOT::DecreaseDirLevel();
}
//______________________________________________________________________________
Bool_t TFile::IsOpen() const
{
// Returns kTRUE in case file is open and kFALSE if file is not open.
return fD == -1 ? kFALSE : kTRUE;
}
//______________________________________________________________________________
void TFile::MakeFree(Seek_t first, Seek_t last)
{
//*-*-*-*-*-*-*-*-*-*-*-*Mark unused bytes on the file*-*-*-*-*-*-*-*-*-*-*
//*-* =============================
// The list of free segments is in the lFree linked list
// When an object is deleted from the file, the freed space is added
// into the FREE linked list (lFree). The FREE list consists of a chain
// of consecutive free segments on the file. At the same time, the first
// 4 bytes of the freed record on the file are overwritten by GAPSIZE
// where GAPSIZE = -(Number of bytes occupied by the record).
//
TFree *f1 = (TFree*) GetListOfFree()->First();
if (!f1) return;
TFree *newfree = f1->AddFree(first,last);
Seek_t nfirst = newfree->GetFirst();
Seek_t nlast = newfree->GetLast();
Int_t nbytes = Int_t (nfirst - nlast -1);
Int_t nb = sizeof(Int_t);
char * buffer = new char[nb];
char * psave = buffer;
tobuf(buffer, nbytes);
if (nlast == fEND-1) fEND = nfirst;
Seek(nfirst);
WriteBuffer(psave, nb);
Flush();
delete [] psave;
}
//______________________________________________________________________________
void TFile::Map()
{
//*-*-*-*-*-*-*-*-*-*List the contents of a file sequentially*-*-*-*-*-*
//*-* ========================================
//
// For each logical record found, it prints
// Date/Time Record_Adress Logical_Record_Length ClassName CompressionFactor
//
// Example of output
// 960122/105933 At:64 N=160 TFile
// 960122/105933 At:224 N=402 TH1F CX = 2.09
// 960122/105934 At:626 N=1369 TH2F CX = 5.57
// 960122/105934 At:1995 N=1761 TProfile CX = 1.63
// 960122/105936 At:3756 N=181640 THN CX = 1.10
// 960122/105936 At:185396 N=326 TFile
// 960122/105936 At:185722 N=98 TFile
//
Short_t keylen,cycle;
UInt_t datime;
Int_t nbytes,date,time,objlen,nwheader;
Seek_t seekkey,seekpdir;
char *header = new char[kBegin];
char *buffer;
char nwhc;
Seek_t idcur = fBEGIN;
nwheader = 64;
Int_t nread = nwheader;
while (idcur < fEND) {
Seek(idcur);
if (idcur+nread >= fEND) nread = fEND-idcur-1;
ReadBuffer(header,int(nread));
buffer=header;
frombuf(buffer, &nbytes);
if (!nbytes) {
Printf("Address = %dtNbytes = %dt=====E R R O R=======", idcur, nbytes);
break;
}
if (nbytes < 0) {
Printf("Address = %dtNbytes = %dt=====G A P===========", idcur, nbytes);
idcur -= nbytes;
Seek(idcur);
continue;
}
Version_t versionkey;
frombuf(buffer, &versionkey);
frombuf(buffer, &objlen);
frombuf(buffer, &datime);
frombuf(buffer, &keylen);
frombuf(buffer, &cycle);
frombuf(buffer, &seekkey);
frombuf(buffer, &seekpdir);
frombuf(buffer, &nwhc);
char *classname = new char[nwhc+1];
int i;
for (i = 0;i < nwhc; i++) frombuf(buffer, &classname[i]);
classname[nwhc] = '0';
TDatime::GetDateTime(datime, date, time);
if (objlen != nbytes-keylen) {
Float_t cx = Float_t(objlen+keylen)/Float_t(nbytes);
Printf("%d/%06d At:%-8d N=%-8d %-14s CX = %5.2f",date,time,idcur,nbytes,classname,cx);
} else {
Printf("%d/%06d At:%-8d N=%-8d %-14s",date,time,idcur,nbytes,classname);
}
delete [] classname;
idcur += nbytes;
}
delete [] header;
}
//______________________________________________________________________________
void TFile::Paint(Option_t *option)
{
//*-*-*-*-*-*-*-*-*-*-*-*Paint all objects in the file*-*-*-*-*-*-*-*-*-*-*
//*-* =============================
//
GetList()->ForEach(TObject,Paint)(option);
}
//______________________________________________________________________________
void TFile::Print(Option_t *option)
{
//*-*-*-*-*-*-*-*-*-*-*-*Print all objects in the file*-*-*-*-*-*-*-*-*-*-*
//*-* =============================
//
Printf("TFile: name=%s, title=%s, option=%s", GetName(), GetTitle(), GetOption());
GetList()->ForEach(TObject,Print)(option);
}
//______________________________________________________________________________
Bool_t TFile::ReadBuffer(char *buf, int len)
{
// Read a buffer from the file. This is the basic low level read operation.
// Returns kTRUE in case of failure.
if (IsOpen()) {
ssize_t siz;
while ((siz = SysRead(fD, buf, len)) < 0 && TSystem::GetErrno() == EINTR)
TSystem::ResetErrno();
if (siz < 0) {
SysError("ReadBuffer", "error reading from file %s", GetName());
return kTRUE;
}
if (siz != len) {
Error("ReadBuffer", "error reading all requested bytes from file %s, got %d of %d",
GetName(), siz, len);
return kTRUE;
}
fBytesRead += siz;
fgBytesRead += siz;
return kFALSE;
}
return kTRUE;
}
//______________________________________________________________________________
void TFile::ReadFree()
{
//*-*-*-*-*-*-*-*-*-*-*-*-*Read the FREE linked list*-*-*-*-*-*-*-*-*-*-*-*-*
//*-* =========================
// Every file has a linked list (fFree) of free segments
// This linked list has been written on the file via WriteFree
// as a single data record
//
TKey *headerfree = new TKey(fSeekFree,fNbytesFree);
headerfree->ReadFile();
char *buffer = headerfree->GetBuffer();
headerfree->ReadBuffer(buffer);
buffer = headerfree->GetBuffer();
while(1) {
TFree *afree = new TFree();
afree->ReadBuffer(buffer);
if (afree->GetLast() > fEND) break;
}
delete headerfree;
}
//______________________________________________________________________________
void TFile::Recover()
{
//*-*-*-*-*-*-*-*-*Attempt to recover file if not correctly closed*-*-*-*-*
//*-* ===============================================
Short_t keylen,cycle;
UInt_t datime;
Int_t nbytes,date,time,objlen,nwheader;
Seek_t seekkey,seekpdir;
char *header = new char[kBegin];
char *buffer, *bufread;
char nwhc;
Seek_t idcur = fBEGIN;
Long_t id, size, flags, modtime;
gSystem->GetPathInfo(GetName(),&id,&size,&flags,&modtime);
fEND = (Int_t)size;
if (fWritable && !fFree) fFree = new TList;
TKey *key;
Int_t nrecov = 0;
nwheader = 64;
Int_t nread = nwheader;
while (idcur < fEND) {
Seek(idcur);
if (idcur+nread >= fEND) nread = fEND-idcur-1;
ReadBuffer(header,int(nread));
buffer = header;
bufread = header;
frombuf(buffer, &nbytes);
if (!nbytes) {
Printf("Address = %dtNbytes = %dt=====E R R O R=======", idcur, nbytes);
break;
}
if (nbytes < 0) {
idcur -= nbytes;
if (fWritable) new TFree(idcur,idcur-nbytes-1);
Seek(idcur);
continue;
}
Version_t versionkey;
frombuf(buffer, &versionkey);
frombuf(buffer, &objlen);
frombuf(buffer, &datime);
frombuf(buffer, &keylen);
frombuf(buffer, &cycle);
frombuf(buffer, &seekkey);
frombuf(buffer, &seekpdir);
frombuf(buffer, &nwhc);
char *classname = new char[nwhc+1];
int i;
for (i = 0;i < nwhc; i++) frombuf(buffer, &classname[i]);
classname[nwhc] = '0';
TDatime::GetDateTime(datime, date, time);
if (!strcmp(classname,"TBasket")) {idcur += nbytes; continue;}
if (seekpdir != fSeekDir) {idcur += nbytes; continue;}
key = new TKey();
key->ReadBuffer(bufread);
AppendKey(key);
nrecov++;
delete [] classname;
idcur += nbytes;
}
if (fWritable) {
new TFree(fEND,2000000000);
if (nrecov) Write();
}
delete [] header;
if (nrecov) Warning("Recover", "successfully recovered %d keys", nrecov);
else Warning("Recover", "no keys recovered");
}
//______________________________________________________________________________
void TFile::Seek(Seek_t offset, ERelativeTo pos)
{
// Seek to a specific position in the file. Pos it either kBeg, kCur or kEnd.
int whence = 0;
switch (pos) {
case kBeg:
whence = SEEK_SET;
break;
case kCur:
whence = SEEK_CUR;
break;
case kEnd:
whence = SEEK_END;
break;
}
if (SysSeek(fD, offset, whence) < 0)
SysError("Seek", "cannot seek to position %d in file %s", offset, GetName());
}
//______________________________________________________________________________
void TFile::SetCompressionLevel(Int_t level)
{
//*-*-*-*-*-*-*-*-*-*Set level of compression for this file*-*-*-*-*-*-*-*
//*-* ======================================
//
// level = 0 objects written to this file will not be compressed.
// level = 1 minimal compression level but fast.
// ....
// level = 9 maximal compression level but slow.
//
// Note that the compression level may be changed at any time.
// The new compression level will only apply to newly written objects.
// The function TFile::Map shows the compression factor
// for each object written to this file.
// The function TFile::GetCompressionFactor returns the global
// compression factor for this file.
//
if (level < 0) level = 0;
if (level > 9) level = 9;
fCompress = level;
}
//______________________________________________________________________________
Int_t TFile::Sizeof() const
{
//*-*-*-*-*-*-*Return the size in bytes of the file header-*-*-*-*-*-*-*-*
//*-* ===========================================
return 0;
}
//_______________________________________________________________________
void TFile::Streamer(TBuffer &b)
{
// Stream a TFile object.
if (b.IsReading()) {
b.ReadVersion(); //Version_t v = b.ReadVersion();
} else {
b.WriteVersion(TFile::IsA());
}
}
//_______________________________________________________________________
void TFile::SumBuffer(Int_t bufsize)
{
//*-*-*-*-*Increment statistics for buffer sizes of objects in this file*-*-*
//*-* =============================================================
fWritten++;
fSumBuffer += bufsize;
fSum2Buffer += bufsize*bufsize;
}
//______________________________________________________________________________
Int_t TFile::Write(const char *, Int_t opt, Int_t bufsiz)
{
//*-*-*-*-*-*-*-*-*-*Write memory objects to this file*-*-*-*-*-*-*-*-*-*
//*-* =================================
// Loop on all objects in memory (including subdirectories).
// A new key is created in the KEYS linked list for each object.
// The list of keys is then saved on the file (via WriteKeys)
// as a single data record.
// For values of opt see TObject::Write().
// The directory header info is rewritten on the directory header record.
// The linked list of FREE segments is written.
// The file header is written (bytes 1->fBEGIN).
//
if (!IsWritable()) {
Warning("Write", "file not opened in write mode");
return 0;
}
TDirectory *cursav = gDirectory;
cd();
if (gDebug) {
if (!GetTitle() || strlen(GetTitle()) == 0)
Printf("TFile Writing Name=%s", GetName());
else
Printf("TFile Writing Name=%s Title=%s", GetName(), GetTitle());
}
Int_t nbytes = TDirectory::Write(0, opt, bufsiz); // Write directory tree
WriteFree(); // Write free segments linked list
WriteHeader(); // Now write file header
cursav->cd();
return nbytes;
}
//______________________________________________________________________________
Bool_t TFile::WriteBuffer(const char *buf, int len)
{
// Write a buffer to the file. This is the basic low level write operation.
// Returns kTRUE in case of failure.
if (IsOpen() && fWritable) {
ssize_t siz;
gSystem->IgnoreInterrupt();
while ((siz = SysWrite(fD, buf, len)) < 0 && TSystem::GetErrno() == EINTR)
TSystem::ResetErrno();
gSystem->IgnoreInterrupt(kFALSE);
if (siz < 0) {
SysError("WriteBuffer", "error writing to file %s", GetName());
return kTRUE;
}
if (siz != len) {
Error("WriteBuffer", "error writing all requested bytes to file %s, wrote %d of %d",
GetName(), siz, len);
return kTRUE;
}
fBytesWrite += siz;
fgBytesWrite += siz;
return kFALSE;
}
return kTRUE;
}
//______________________________________________________________________________
void TFile::WriteFree()
{
//*-*-*-*-*-*-*-*-*-*-*-*Write FREE linked list on the file *-*-*-*-*-*-*-*
//*-* ==================================
// The linked list of FREE segments (fFree) is written as a single data
// record
//
//*-* Delete old record if it exists
if (fSeekFree != 0){
MakeFree(fSeekFree, fSeekFree + fNbytesFree -1);
}
Int_t nbytes = 0;
TFree *afree;
TIter next (fFree);
while ((afree = (TFree*) next())) {
nbytes += afree->Sizeof();
}
if (!nbytes) return;
TKey *key = new TKey(fName,fTitle,IsA(),nbytes);
if (key->GetSeekKey() == 0) {
delete key;
return;
}
char *buffer = key->GetBuffer();
next.Reset();
while ((afree = (TFree*) next())) {
afree->FillBuffer(buffer);
}
fNbytesFree = key->GetNbytes();
fSeekFree = key->GetSeekKey();
key->WriteFile();
delete key;
}
//______________________________________________________________________________
void TFile::WriteHeader()
{
//*-*-*-*-*-*-*-*-*-*-*-*Write File Header*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-* =================
//
TFree *lastfree = (TFree*)GetListOfFree()->Last();
if (lastfree) fEND = lastfree->GetFirst();
const char *root = "root";
char *psave = new char[kBegin];
char *buffer = psave;
Int_t nfree = fFree->GetSize();
memcpy(buffer, root, 4); buffer += 4;
tobuf(buffer, fVersion);
tobuf(buffer, fBEGIN);
tobuf(buffer, fEND);
tobuf(buffer, fSeekFree);
tobuf(buffer, fNbytesFree);
tobuf(buffer, nfree);
tobuf(buffer, fNbytesName);
tobuf(buffer, fUnits);
tobuf(buffer, fCompress);
Int_t nbytes = buffer - psave;
Seek(0);
WriteBuffer(psave, nbytes);
Flush();
delete [] psave;
}
//______________________________________________________________________________
TFile *TFile::Open(const char *name, Option_t *option, const char *ftitle, Int_t compress)
{
// Static member function allowing the creation/opening of either a
// TFile, TNetFile, TWebFile or a TRFIOFile. The returned type of TFile
// depends on the file name. If the file starts with "root:" a TNetFile
// object will be returned, with "http:" a TWebFile, with "rfio:" a
// TRFIOFile and with "file:" or the default a local TFile. However,
// before opening a file via TNetFile a check is made to see if the URL
// specifies a local file. If that is the case the file will be opened
// via a normal TFile. To force the opening of a local file via a
// TNetFile use either TNetFile directly or specify as host "localhost".
// For the meaning of the options and other arguments see the constructors
// of the individual file classes.
TFile *f = 0;
if (!strncmp(name, "root:", 5)) {
TUrl url(name);
TInetAddress a(gSystem->GetHostByName(url.GetHost()));
TInetAddress b(gSystem->GetHostByName(gSystem->HostName()));
if (strcmp(a.GetHostName(), b.GetHostName()))
f = new TNetFile(name, option, ftitle, compress);
else {
const char *fname = url.GetFile();
if (fname[1] == '/' || fname[1] == '~' || fname[1] == '$')
f = new TFile(&fname[1], option, ftitle, compress);
else
f = new TFile(Form("%s%s", gSystem->HomeDirectory(), fname),
option, ftitle, compress);
}
} else if (!strncmp(name, "rfio:", 5)) {
if (gROOT->LoadClass("TRFIOFile", "RFIO")) return 0;
f = (TFile*) gROOT->ProcessLineFast(Form("new TRFIOFile("%s","%s","%s",%d)",
name, option, ftitle, compress));
} else if (!strncmp(name, "hpss:", 5)) {
} else if (!strncmp(name, "http:", 5))
f = new TWebFile(name);
else if (!strncmp(name, "file:", 5))
f = new TFile(name+5, option, ftitle, compress);
else
f = new TFile(name, option, ftitle, compress);
return f;
}
//______________________________________________________________________________
Int_t TFile::SysOpen(const char *pathname, Int_t flags, UInt_t mode)
{
// Interface to system open. All arguments like in "man 2 open".
return ::open(pathname, flags, mode);
}
//______________________________________________________________________________
Int_t TFile::SysClose(Int_t fd)
{
// Interface to system close. All arguments like in "man 2 close".
return ::close(fd);
}
//______________________________________________________________________________
Int_t TFile::SysRead(Int_t fd, void *buf, Int_t len)
{
// Interface to system read. All arguments like in "man 2 read".
return ::read(fd, buf, len);
}
//______________________________________________________________________________
Int_t TFile::SysWrite(Int_t fd, const void *buf, Int_t len)
{
// Interface to system write. All arguments like in "man 2 write".
return ::write(fd, buf, len);
}
//______________________________________________________________________________
Seek_t TFile::SysSeek(Int_t fd, Seek_t offset, Int_t whence)
{
// Interface to system lseek. All arguments like in "man 2 lseek"
// except that the offset and return value are Long_t to be able to
// handle 64 bit file systems.
return ::lseek(fd, offset, whence);
}
//______________________________________________________________________________
Int_t TFile::SysSync(Int_t fd)
{
// Interface to system fsync. All arguments like in "man 2 fsync".
#ifndef WIN32
return ::fsync(fd);
#else
return 0;
#endif
}
//______________________________________________________________________________
Double_t TFile::GetFileBytesRead() { return fgBytesRead; }
//______________________________________________________________________________
Double_t TFile::GetFileBytesWritten() { return fgBytesWrite; }
//______________________________________________________________________________
void TFile::SetFileBytesRead(Double_t bytes){ fgBytesRead = bytes; }
//______________________________________________________________________________
void TFile::SetFileBytesWritten(Double_t bytes){ fgBytesWrite = bytes; }
ROOT page - Class index - Top of the page
This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.