/*
<img src="gif/file_layout.gif">
*/
//End_Html
#include "RConfig.h"
#ifdef R__LINUX
#ifndef _XOPEN_SOURCE
#define _XOPEN_SOURCE 600
#endif
#endif
#include <fcntl.h>
#include <errno.h>
#include <sys/stat.h>
#ifndef WIN32
# include <unistd.h>
#else
# define ssize_t int
# include <io.h>
# include <sys/types.h>
#endif
#include "Bytes.h"
#include "Compression.h"
#include "Riostream.h"
#include "RConfigure.h"
#include "Strlen.h"
#include "TArrayC.h"
#include "TClass.h"
#include "TClassEdit.h"
#include "TClassTable.h"
#include "TDatime.h"
#include "TError.h"
#include "TFile.h"
#include "TFileCacheRead.h"
#include "TFileCacheWrite.h"
#include "TFree.h"
#include "TInterpreter.h"
#include "TKey.h"
#include "TMakeProject.h"
#include "TPluginManager.h"
#include "TProcessUUID.h"
#include "TRegexp.h"
#include "TPRegexp.h"
#include "TROOT.h"
#include "TStreamerInfo.h"
#include "TStreamerElement.h"
#include "TSystem.h"
#include "TTimeStamp.h"
#include "TVirtualPerfStats.h"
#include "TArchiveFile.h"
#include "TEnv.h"
#include "TVirtualMonitoring.h"
#include "TVirtualMutex.h"
#include "TMathBase.h"
#include "TObjString.h"
#include "TStopwatch.h"
#include "compiledata.h"
#include <cmath>
#include <set>
#include "TSchemaRule.h"
#include "TSchemaRuleSet.h"
#include "TThreadSlots.h"
#include "TGlobal.h"
using std::sqrt;
std::atomic<Long64_t> TFile::fgBytesRead{0};
std::atomic<Long64_t> TFile::fgBytesWrite{0};
std::atomic<Long64_t> TFile::fgFileCounter{0};
std::atomic<Int_t> TFile::fgReadCalls{0};
Int_t TFile::fgReadaheadSize = 256000;
Bool_t TFile::fgReadInfo = kTRUE;
TList *TFile::fgAsyncOpenRequests = 0;
TString TFile::fgCacheFileDir;
Bool_t TFile::fgCacheFileForce = kFALSE;
Bool_t TFile::fgCacheFileDisconnected = kTRUE;
UInt_t TFile::fgOpenTimeout = TFile::kEternalTimeout;
Bool_t TFile::fgOnlyStaged = 0;
const Int_t kBEGIN = 100;
ClassImp(TFile)
namespace {
static struct AddPseudoGlobals {
AddPseudoGlobals() {
TGlobalMappedFunction::Add(new TGlobalMappedFunction("gFile", "TFile*",
(TGlobalMappedFunction::GlobalFunc_t)&TFile::CurrentFile));
}
} gAddPseudoGlobals;
}
TFile::TFile() : TDirectoryFile(), fInfoCache(0)
{
fD = -1;
fFree = 0;
fWritten = 0;
fSumBuffer = 0;
fSum2Buffer = 0;
fClassIndex = 0;
fCompress = 0;
fProcessIDs = 0;
fNProcessIDs = 0;
fOffset = 0;
fArchive = 0;
fCacheRead = 0;
fCacheReadMap = new TMap();
fCacheWrite = 0;
fArchiveOffset = 0;
fReadCalls = 0;
fInfoCache = 0;
fOpenPhases = 0;
fNoAnchorInName = kFALSE;
fIsRootFile = kTRUE;
fIsArchive = kFALSE;
fInitDone = kFALSE;
fMustFlush = kTRUE;
fIsPcmFile = kFALSE;
fAsyncHandle = 0;
fAsyncOpenStatus = kAOSNotAsync;
SetBit(kBinaryFile, kTRUE);
fBEGIN = 0;
fEND = 0;
fBytesRead = 0;
fBytesReadExtra = 0;
fBytesWrite = 0;
fCompress = 0;
fNbytesFree = 0;
fNbytesInfo = 0;
fSeekFree = 0;
fSeekInfo = 0;
fUnits = 0;
fVersion = 0;
if (gDebug)
Info("TFile", "default ctor");
}
TFile::TFile(const char *fname1, Option_t *option, const char *ftitle, Int_t compress)
: TDirectoryFile(), fUrl(fname1,kTRUE), fInfoCache(0), fOpenPhases(0)
{
if (!gROOT)
::Fatal("TFile::TFile", "ROOT system not initialized");
TString sfname1 = fname1;
fNoAnchorInName = kFALSE;
if (sfname1.Index("?") != kNPOS) {
TString s = sfname1(0, sfname1.Index("?"));
SetName(s);
fNoAnchorInName = kTRUE;
} else
SetName(fname1);
SetTitle(ftitle);
fname1 = fUrl.GetFile();
fIsRootFile = kTRUE;
if (strstr(fUrl.GetOptions(), "filetype=raw"))
fIsRootFile = kFALSE;
fIsPcmFile = kFALSE;
if (strstr(fUrl.GetOptions(), "filetype=pcm"))
fIsPcmFile = kTRUE;
fInitDone = kFALSE;
fMustFlush = kTRUE;
fAsyncHandle = 0;
fAsyncOpenStatus = kAOSNotAsync;
TDirectoryFile::Build(this, 0);
fD = -1;
fFree = 0;
fVersion = gROOT->GetVersionInt();
fUnits = 4;
fOption = option;
fCompress = compress;
fWritten = 0;
fSumBuffer = 0;
fSum2Buffer = 0;
fBytesRead = 0;
fBytesReadExtra = 0;
fBytesWrite = 0;
fClassIndex = 0;
fSeekInfo = 0;
fNbytesInfo = 0;
fProcessIDs = 0;
fNProcessIDs = 0;
fOffset = 0;
fCacheRead = 0;
fCacheReadMap = new TMap();
fCacheWrite = 0;
fReadCalls = 0;
SetBit(kBinaryFile, kTRUE);
fOption.ToUpper();
fArchiveOffset = 0;
fIsArchive = kFALSE;
fArchive = 0;
if (fIsRootFile && !fIsPcmFile && fOption != "NEW" && fOption != "CREATE"
&& fOption != "RECREATE") {
fArchive = gPluginMgr ? TArchiveFile::Open(fUrl.GetUrl(), this) : 0;
if (fArchive) {
fname1 = fArchive->GetArchiveName();
if (!strlen(fArchive->GetMemberName()))
fIsArchive = kTRUE;
}
}
if (fOption == "NET")
return;
if (fOption == "WEB") {
fOption = "READ";
fWritable = kFALSE;
return;
}
if (fOption == "NEW")
fOption = "CREATE";
Bool_t create = (fOption == "CREATE") ? kTRUE : kFALSE;
Bool_t recreate = (fOption == "RECREATE") ? kTRUE : kFALSE;
Bool_t update = (fOption == "UPDATE") ? kTRUE : kFALSE;
Bool_t read = (fOption == "READ") ? kTRUE : kFALSE;
if (!create && !recreate && !update && !read) {
read = kTRUE;
fOption = "READ";
}
Bool_t devnull = kFALSE;
if (!fname1 || !fname1[0]) {
Error("TFile", "file name is not specified");
goto zombie;
}
if (!strcmp(fname1, "/dev/null") &&
!gSystem->AccessPathName(fname1, kWritePermission)) {
devnull = kTRUE;
create = kTRUE;
recreate = kFALSE;
update = kFALSE;
read = kFALSE;
fOption = "CREATE";
SetBit(kDevNull);
}
const char *fname;
if ((fname = gSystem->ExpandPathName(fname1))) {
SetName(fname);
delete [] fname;
fRealName = GetName();
fname = fRealName.Data();
} else {
Error("TFile", "error expanding path %s", fname1);
goto zombie;
}
if (recreate) {
if (!gSystem->AccessPathName(fname, kFileExists)) {
if (gSystem->Unlink(fname) != 0) {
SysError("TFile", "could not delete %s (errno: %d)",
fname, gSystem->GetErrno());
goto zombie;
}
}
recreate = kFALSE;
create = kTRUE;
fOption = "CREATE";
}
if (create && !devnull && !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;
}
}
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:
{
R__LOCKGUARD2(gROOTMutex);
gROOT->GetListOfClosedObjects()->Add(this);
}
MakeZombie();
gDirectory = gROOT;
}
TFile::TFile(const TFile &) : TDirectoryFile(), fInfoCache(0)
{
MayNotUse("TFile::TFile(const TFile &)");
}
TFile::~TFile()
{
Close();
SafeDelete(fAsyncHandle);
SafeDelete(fCacheRead);
SafeDelete(fCacheReadMap);
SafeDelete(fCacheWrite);
SafeDelete(fProcessIDs);
SafeDelete(fFree);
SafeDelete(fArchive);
SafeDelete(fInfoCache);
SafeDelete(fOpenPhases);
{
R__LOCKGUARD2(gROOTMutex);
gROOT->GetListOfClosedObjects()->Remove(this);
gROOT->GetUUIDs()->RemoveUUID(GetUniqueID());
}
if (IsOnHeap()) {
gInterpreter->ResetGlobalVar(this);
}
if (gDebug)
Info("~TFile", "dtor called for %s [%lx]", GetName(),(Long_t)this);
}
void TFile::Init(Bool_t create)
{
if (fInitDone)
return;
fInitDone = kTRUE;
if (!fIsRootFile) {
gDirectory = gROOT;
return;
}
if (fArchive) {
if (fOption != "READ") {
Error("Init", "archive %s can only be opened in read mode", GetName());
delete fArchive;
fArchive = 0;
fIsArchive = kFALSE;
goto zombie;
}
fArchive->OpenArchive();
if (fIsArchive) return;
if (!fNoAnchorInName)
if (!strchr(GetName(),'#'))
SetName(TString::Format("%s#%s", GetName(), fArchive->GetMemberName()));
if (fArchive->SetCurrentMember() != -1)
fArchiveOffset = fArchive->GetMemberFilePosition();
else {
Error("Init", "member %s not found in archive %s",
fArchive->GetMemberName(), fArchive->GetArchiveName());
delete fArchive;
fArchive = 0;
fIsArchive = kFALSE;
goto zombie;
}
}
Int_t nfree;
fBEGIN = (Long64_t)kBEGIN;
cd();
if (create) {
fFree = new TList;
fEND = fBEGIN;
new TFree(fFree, fBEGIN, Long64_t(kStartBigFile));
Int_t namelen= TNamed::Sizeof();
Int_t nbytes = namelen + TDirectoryFile::Sizeof();
TKey *key = new TKey(fName, fTitle, IsA(), nbytes, this);
fNbytesName = key->GetKeylen() + namelen;
fSeekDir = key->GetSeekKey();
fSeekFree = 0;
fNbytesFree = 0;
WriteHeader();
char *buffer = key->GetBuffer();
TNamed::FillBuffer(buffer);
TDirectoryFile::FillBuffer(buffer);
key->WriteFile();
delete key;
} else {
char *header = new char[kBEGIN+200];
Seek(0);
if (ReadBuffer(header, kBEGIN+200)) {
Error("Init","%s failed to read the file type data.",
GetName());
delete [] header;
goto zombie;
}
if (strncmp(header, "root", 4)) {
Error("Init", "%s not a ROOT file", GetName());
delete [] header;
goto zombie;
}
char *buffer = header + 4;
frombuf(buffer, &fVersion);
Int_t headerLength;
frombuf(buffer, &headerLength);
fBEGIN = (Long64_t)headerLength;
if (fVersion < 1000000) {
Int_t send,sfree,sinfo;
frombuf(buffer, &send); fEND = (Long64_t)send;
frombuf(buffer, &sfree); fSeekFree= (Long64_t)sfree;
frombuf(buffer, &fNbytesFree);
frombuf(buffer, &nfree);
frombuf(buffer, &fNbytesName);
frombuf(buffer, &fUnits );
frombuf(buffer, &fCompress);
frombuf(buffer, &sinfo); fSeekInfo = (Long64_t)sinfo;
frombuf(buffer, &fNbytesInfo);
} else {
frombuf(buffer, &fEND);
frombuf(buffer, &fSeekFree);
frombuf(buffer, &fNbytesFree);
frombuf(buffer, &nfree);
frombuf(buffer, &fNbytesName);
frombuf(buffer, &fUnits );
frombuf(buffer, &fCompress);
frombuf(buffer, &fSeekInfo);
frombuf(buffer, &fNbytesInfo);
}
if (fBEGIN < 0 || fBEGIN > fEND) {
Error("Init","file %s has an incorrect header length (%lld) or incorrect end of file length (%lld)",
GetName(),fBEGIN,fEND);
goto zombie;
}
fSeekDir = fBEGIN;
if (fWritable) {
fFree = new TList;
if (fSeekFree > fBEGIN) {
ReadFree();
} else {
Warning("Init","file %s probably not closed, cannot read free segments",GetName());
}
}
char *buffer_keyloc = 0;
Int_t nbytes = fNbytesName + TDirectoryFile::Sizeof();
if ( (nbytes + fBEGIN) > fEND) {
Error("Init","file %s has an incorrect header length (%lld) or incorrect end of file length (%lld)",
GetName(),fBEGIN+nbytes,fEND);
goto zombie;
}
if (nbytes+fBEGIN > kBEGIN+200) {
delete [] header;
header = new char[nbytes];
buffer = header;
Seek(fBEGIN);
if (ReadBuffer(buffer,nbytes)) {
Error("Init","%s failed to read the file header information at %lld (size=%d)",
GetName(),fBEGIN,nbytes);
delete [] header;
goto zombie;
}
buffer = header+fNbytesName;
buffer_keyloc = header;
} else {
buffer = header+fBEGIN+fNbytesName;
buffer_keyloc = header+fBEGIN;
}
Version_t version,versiondir;
frombuf(buffer,&version); versiondir = version%1000;
fDatimeC.ReadBuffer(buffer);
fDatimeM.ReadBuffer(buffer);
frombuf(buffer, &fNbytesKeys);
frombuf(buffer, &fNbytesName);
if (version > 1000) {
frombuf(buffer, &fSeekDir);
frombuf(buffer, &fSeekParent);
frombuf(buffer, &fSeekKeys);
} else {
Int_t sdir,sparent,skeys;
frombuf(buffer, &sdir); fSeekDir = (Long64_t)sdir;
frombuf(buffer, &sparent); fSeekParent = (Long64_t)sparent;
frombuf(buffer, &skeys); fSeekKeys = (Long64_t)skeys;
}
if (versiondir > 1) fUUID.ReadBuffer(buffer);
buffer_keyloc += sizeof(Int_t);
Version_t keyversion;
frombuf(buffer_keyloc, &keyversion);
if (keyversion > 1000) {
buffer_keyloc += 2*sizeof(Int_t)+2*sizeof(Short_t)+2*sizeof(Long64_t);
} else {
buffer_keyloc += 2*sizeof(Int_t)+2*sizeof(Short_t)+2*sizeof(Int_t);
}
TString cname;
cname.ReadBuffer(buffer_keyloc);
cname.ReadBuffer(buffer_keyloc);
fTitle.ReadBuffer(buffer_keyloc);
delete [] header;
if (fNbytesName < 10 || fNbytesName > 10000) {
Error("Init","cannot read directory info of file %s", GetName());
goto zombie;
}
Long64_t size;
if ((size = GetSize()) == -1) {
Error("Init", "cannot stat the file %s", GetName());
goto zombie;
}
Bool_t tryrecover = (gEnv->GetValue("TFile.Recover", 1) == 1) ? kTRUE : kFALSE;
if (fSeekKeys > fBEGIN && fEND <= size) {
TDirectoryFile::ReadKeys(kFALSE);
gDirectory = this;
if (!GetNkeys()) {
if (tryrecover) {
Recover();
} else {
Error("Init", "file %s has no keys", GetName());
goto zombie;
}
}
} else if ((fBEGIN+nbytes == fEND) && (fEND == size)) {
Warning("Init","file %s has no keys", GetName());
gDirectory = this;
} else {
if (fEND > size) {
if (tryrecover) {
Error("Init","file %s is truncated at %lld bytes: should be %lld, "
"trying to recover", GetName(), size, fEND);
} else {
Error("Init","file %s is truncated at %lld bytes: should be %lld",
GetName(), size, fEND);
goto zombie;
}
} else {
if (tryrecover) {
Warning("Init","file %s probably not closed, "
"trying to recover", GetName());
} else {
Warning("Init","file %s probably not closed", GetName());
goto zombie;
}
}
Int_t nrecov = Recover();
if (nrecov) {
Warning("Init", "successfully recovered %d keys", nrecov);
} else {
Warning("Init", "no keys recovered, file has been made a Zombie");
goto zombie;
}
}
}
{
R__LOCKGUARD2(gROOTMutex);
gROOT->GetListOfFiles()->Add(this);
gROOT->GetUUIDs()->AddUUID(fUUID,this);
}
{
Int_t lenIndex = gROOT->GetListOfStreamerInfo()->GetSize()+1;
if (lenIndex < 5000) lenIndex = 5000;
fClassIndex = new TArrayC(lenIndex);
if (fgReadInfo) {
if (fSeekInfo > fBEGIN) {
ReadStreamerInfo();
if (IsZombie()) {
R__LOCKGUARD2(gROOTMutex);
gROOT->GetListOfFiles()->Remove(this);
goto zombie;
}
} else if (fVersion != gROOT->GetVersionInt() && fVersion > 30000) {
Warning("Init","no StreamerInfo found in %s therefore preventing schema evolution when reading this file.",GetName());
}
}
}
{
TIter next(fKeys);
TKey *key;
while ((key = (TKey*)next())) {
if (!strcmp(key->GetClassName(),"TProcessID")) fNProcessIDs++;
}
fProcessIDs = new TObjArray(fNProcessIDs+1);
}
return;
zombie:
{
R__LOCKGUARD2(gROOTMutex);
gROOT->GetListOfClosedObjects()->Add(this);
}
fWritable = kFALSE;
MakeZombie();
gDirectory = gROOT;
}
void TFile::Close(Option_t *option)
{
TString opt = option;
opt.ToLower();
if (!IsOpen()) return;
if (fIsArchive || !fIsRootFile) {
FlushWriteCache();
SysClose(fD);
fD = -1;
if (gMonitoringWriter)
gMonitoringWriter->SendFileCloseEvent(this);
return;
}
if (IsWritable()) {
WriteStreamerInfo();
}
if (fCacheRead) fCacheRead->Close();
{
TIter iter(fCacheReadMap);
TObject *key = 0;
while ((key = iter()) != 0) {
TFileCacheRead *cache = dynamic_cast<TFileCacheRead *>(fCacheReadMap->GetValue(key));
cache->Close();
}
}
fMustFlush = kFALSE;
TDirectoryFile::Close();
if (IsWritable()) {
TFree *f1 = (TFree*)fFree->First();
if (f1) {
WriteFree();
WriteHeader();
} else {
Flush();
}
}
fMustFlush = kTRUE;
FlushWriteCache();
if (gMonitoringWriter)
gMonitoringWriter->SendFileCloseEvent(this);
delete fClassIndex;
fClassIndex = 0;
if (fFree) {
fFree->Delete();
}
if (IsOpen()) {
SysClose(fD);
fD = -1;
}
fWritable = kFALSE;
TList pidDeleted;
TIter next(fProcessIDs);
TProcessID *pid;
while ((pid = (TProcessID*)next())) {
if (!pid->DecrementCount()) {
if (pid != TProcessID::GetSessionProcessID()) pidDeleted.Add(pid);
} else if(opt.Contains("r")) {
pid->Clear();
}
}
pidDeleted.Delete();
if (!IsZombie()) {
R__LOCKGUARD2(gROOTMutex);
gROOT->GetListOfFiles()->Remove(this);
gROOT->GetListOfBrowsers()->RecursiveRemove(this);
gROOT->GetListOfClosedObjects()->Add(this);
} else {
}
}
TKey* TFile::CreateKey(TDirectory* mother, const TObject* obj, const char* name, Int_t bufsize)
{
return new TKey(obj, name, bufsize, mother);
}
TKey* TFile::CreateKey(TDirectory* mother, const void* obj, const TClass* cl, const char* name, Int_t bufsize)
{
return new TKey(obj, cl, name, bufsize, mother);
}
TFile *&TFile::CurrentFile()
{
static TFile *currentFile = 0;
if (!gThreadTsd)
return currentFile;
else
return *(TFile**)(*gThreadTsd)(¤tFile,ROOT::kFileThreadSlot);
}
void TFile::Delete(const char *namecycle)
{
if (gDebug)
Info("Delete", "deleting name = %s", namecycle);
TDirectoryFile::Delete(namecycle);
}
void TFile::Draw(Option_t *option)
{
GetList()->R__FOR_EACH(TObject,Draw)(option);
}
void TFile::DrawMap(const char *keys, Option_t *option)
{
TPluginHandler *h;
if ((h = gROOT->GetPluginManager()->FindHandler("TFileDrawMap"))) {
if (h->LoadPlugin() == -1)
return;
h->ExecPlugin(3, this, keys, option);
}
}
void TFile::Flush()
{
if (IsOpen() && fWritable) {
FlushWriteCache();
if (SysSync(fD) < 0) {
SetBit(kWriteError); SetWritable(kFALSE);
SysError("Flush", "error flushing file %s", GetName());
}
}
}
Bool_t TFile::FlushWriteCache()
{
if (fCacheWrite && IsOpen() && fWritable)
return fCacheWrite->Flush();
return kFALSE;
}
void TFile::FillBuffer(char *&buffer)
{
Version_t version = TFile::Class_Version();
tobuf(buffer, version);
}
Int_t TFile::GetBestBuffer() const
{
if (!fWritten) return TBuffer::kInitialSize;
Double_t mean = fSumBuffer/fWritten;
Double_t rms2 = TMath::Abs(fSum2Buffer/fSumBuffer -mean*mean);
return (Int_t)(mean + sqrt(rms2));
}
Float_t TFile::GetCompressionFactor()
{
Short_t keylen;
UInt_t datime;
Int_t nbytes, objlen, nwh = 64;
char *header = new char[fBEGIN];
char *buffer;
Long64_t idcur = fBEGIN;
Float_t comp,uncomp;
comp = uncomp = fBEGIN;
while (idcur < fEND-100) {
Seek(idcur);
if (ReadBuffer(header, nwh)) {
break;
}
buffer=header;
frombuf(buffer, &nbytes);
if (nbytes < 0) {
idcur -= nbytes;
Seek(idcur);
continue;
}
if (nbytes == 0) break;
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::GetErrno() const
{
return TSystem::GetErrno();
}
void TFile::ResetErrno() const
{
TSystem::ResetErrno();
}
TFileCacheRead *TFile::GetCacheRead(TObject* tree) const
{
if (!tree) {
if (!fCacheRead && fCacheReadMap->GetSize() == 1) {
TIter next(fCacheReadMap);
return (TFileCacheRead *)fCacheReadMap->GetValue(next());
}
return fCacheRead;
}
TFileCacheRead *cache = (TFileCacheRead *)fCacheReadMap->GetValue(tree);
if (!cache) return fCacheRead;
return cache;
}
TFileCacheWrite *TFile::GetCacheWrite() const
{
return fCacheWrite;
}
Int_t TFile::GetRecordHeader(char *buf, Long64_t first, Int_t maxbytes, Int_t &nbytes, Int_t &objlen, Int_t &keylen)
{
nbytes = 0;
objlen = 0;
keylen = 0;
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","%s: parameter maxbytes = %d must be >= 4",
GetName(), nread);
return nread;
}
if (ReadBuffer(buf,nread)) {
Warning("GetRecordHeader","%s: failed to read header data (maxbytes = %d)",
GetName(), nread);
return 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 = 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;
}
Long64_t TFile::GetSize() const
{
Long64_t size;
if (fArchive && fArchive->GetMember()) {
size = fArchive->GetMember()->GetDecompressedSize();
} else {
Long_t id, flags, modtime;
if (const_cast<TFile*>(this)->SysStat(fD, &id, &size, &flags, &modtime)) {
Error("GetSize", "cannot stat the file %s", GetName());
return -1;
}
}
return size;
}
const TList *TFile::GetStreamerInfoCache()
{
return fInfoCache ? fInfoCache : (fInfoCache=GetStreamerInfoList());
}
TList *TFile::GetStreamerInfoList()
{
if (fIsPcmFile) return 0;
TList *list = 0;
if (fSeekInfo) {
TDirectory::TContext ctxt(this);
TKey *key = new TKey(this);
char *buffer = new char[fNbytesInfo+1];
char *buf = buffer;
Seek(fSeekInfo);
if (ReadBuffer(buf,fNbytesInfo)) {
Warning("GetRecordHeader","%s: failed to read the StreamerInfo data from disk.",
GetName());
return 0;
}
key->ReadKeyBuffer(buf);
list = dynamic_cast<TList*>(key->ReadObjWithBuffer(buffer));
if (list) list->SetOwner();
delete [] buffer;
delete key;
} else {
list = (TList*)Get("StreamerInfo");
}
if (list == 0) {
Info("GetStreamerInfoList", "cannot find the StreamerInfo record in file %s",
GetName());
return 0;
}
return list;
}
void TFile::ls(Option_t *option) const
{
TROOT::IndentLevel();
std::cout <<ClassName()<<"**\t\t"<<GetName()<<"\t"<<GetTitle()<<std::endl;
TROOT::IncreaseDirLevel();
TDirectoryFile::ls(option);
TROOT::DecreaseDirLevel();
}
Bool_t TFile::IsOpen() const
{
return fD == -1 ? kFALSE : kTRUE;
}
void TFile::MakeFree(Long64_t first, Long64_t last)
{
TFree *f1 = (TFree*)fFree->First();
if (!f1) return;
TFree *newfree = f1->AddFree(fFree,first,last);
if(!newfree) return;
Long64_t nfirst = newfree->GetFirst();
Long64_t nlast = newfree->GetLast();
Long64_t nbytesl= nlast-nfirst+1;
if (nbytesl > 2000000000) nbytesl = 2000000000;
Int_t nbytes = -Int_t (nbytesl);
Int_t nb = sizeof(Int_t);
char * buffer = new char[nb];
char * psave = buffer;
tobuf(buffer, nbytes);
if (last == fEND-1) fEND = nfirst;
Seek(nfirst);
WriteBuffer(psave, nb);
if (fMustFlush) Flush();
delete [] psave;
}
void TFile::Map()
{
Short_t keylen,cycle;
UInt_t datime;
Int_t nbytes,date,time,objlen,nwheader;
date = 0;
time = 0;
Long64_t seekkey,seekpdir;
char *buffer;
char nwhc;
Long64_t idcur = fBEGIN;
nwheader = 64;
Int_t nread = nwheader;
char header[kBEGIN];
char classname[512];
while (idcur < fEND) {
Seek(idcur);
if (idcur+nread >= fEND) nread = fEND-idcur-1;
if (ReadBuffer(header, nread)) {
Warning("Map","%s: failed to read the key data from disk at %lld.",
GetName(),idcur);
break;
}
buffer=header;
frombuf(buffer, &nbytes);
if (!nbytes) {
Printf("Address = %lld\tNbytes = %d\t=====E R R O R=======", idcur, nbytes);
date = 0; time = 0;
break;
}
if (nbytes < 0) {
Printf("Address = %lld\tNbytes = %d\t=====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);
if (versionkey > 1000) {
frombuf(buffer, &seekkey);
frombuf(buffer, &seekpdir);
} else {
Int_t skey,sdir;
frombuf(buffer, &skey); seekkey = (Long64_t)skey;
frombuf(buffer, &sdir); seekpdir = (Long64_t)sdir;
}
frombuf(buffer, &nwhc);
for (int i = 0;i < nwhc; i++) frombuf(buffer, &classname[i]);
classname[(int)nwhc] = '\0';
if (idcur == fSeekFree) strlcpy(classname,"FreeSegments",512);
if (idcur == fSeekInfo) strlcpy(classname,"StreamerInfo",512);
if (idcur == fSeekKeys) strlcpy(classname,"KeysList",512);
TDatime::GetDateTime(datime, date, time);
if (objlen != nbytes-keylen) {
Float_t cx = Float_t(objlen+keylen)/Float_t(nbytes);
Printf("%d/%06d At:%lld N=%-8d %-14s CX = %5.2f",date,time,idcur,nbytes,classname,cx);
} else {
Printf("%d/%06d At:%lld N=%-8d %-14s",date,time,idcur,nbytes,classname);
}
idcur += nbytes;
}
Printf("%d/%06d At:%lld N=%-8d %-14s",date,time,idcur,1,"END");
}
void TFile::Paint(Option_t *option)
{
GetList()->R__FOR_EACH(TObject,Paint)(option);
}
void TFile::Print(Option_t *option) const
{
Printf("TFile: name=%s, title=%s, option=%s", GetName(), GetTitle(), GetOption());
GetList()->R__FOR_EACH(TObject,Print)(option);
}
Bool_t TFile::ReadBuffer(char *buf, Long64_t pos, Int_t len)
{
if (IsOpen()) {
SetOffset(pos);
Int_t st;
Double_t start = 0;
if (gPerfStats != 0) start = TTimeStamp();
if ((st = ReadBufferViaCache(buf, len))) {
if (st == 2)
return kTRUE;
return kFALSE;
}
Seek(pos);
ssize_t siz;
while ((siz = SysRead(fD, buf, len)) < 0 && GetErrno() == EINTR)
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 %ld of %d",
GetName(), (Long_t)siz, len);
return kTRUE;
}
fBytesRead += siz;
fgBytesRead += siz;
fReadCalls++;
fgReadCalls++;
if (gMonitoringWriter)
gMonitoringWriter->SendFileReadProgress(this);
if (gPerfStats != 0) {
gPerfStats->FileReadEvent(this, len, start);
}
return kFALSE;
}
return kTRUE;
}
Bool_t TFile::ReadBuffer(char *buf, Int_t len)
{
if (IsOpen()) {
Int_t st;
if ((st = ReadBufferViaCache(buf, len))) {
if (st == 2)
return kTRUE;
return kFALSE;
}
ssize_t siz;
Double_t start = 0;
if (gPerfStats != 0) start = TTimeStamp();
while ((siz = SysRead(fD, buf, len)) < 0 && GetErrno() == EINTR)
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 %ld of %d",
GetName(), (Long_t)siz, len);
return kTRUE;
}
fBytesRead += siz;
fgBytesRead += siz;
fReadCalls++;
fgReadCalls++;
if (gMonitoringWriter)
gMonitoringWriter->SendFileReadProgress(this);
if (gPerfStats != 0) {
gPerfStats->FileReadEvent(this, len, start);
}
return kFALSE;
}
return kTRUE;
}
Bool_t TFile::ReadBuffers(char *buf, Long64_t *pos, Int_t *len, Int_t nbuf)
{
if (!buf) {
for (Int_t j = 0; j < nbuf; j++) {
if (ReadBufferAsync(pos[j], len[j])) {
return kTRUE;
}
}
return kFALSE;
}
Int_t k = 0;
Bool_t result = kTRUE;
TFileCacheRead *old = fCacheRead;
fCacheRead = 0;
Long64_t curbegin = pos[0];
Long64_t cur;
char *buf2 = 0;
Int_t i = 0, n = 0;
while (i < nbuf) {
cur = pos[i]+len[i];
Bool_t bigRead = kTRUE;
if (cur -curbegin < fgReadaheadSize) {n++; i++; bigRead = kFALSE;}
if (bigRead || (i>=nbuf)) {
if (n == 0) {
Seek(pos[i]);
result = ReadBuffer(&buf[k], len[i]);
if (result) break;
k += len[i];
i++;
} else {
Seek(curbegin);
if (buf2 == 0) buf2 = new char[fgReadaheadSize];
Long64_t nahead = pos[i-1]+len[i-1]-curbegin;
result = ReadBuffer(buf2, nahead);
if (result) break;
Int_t kold = k;
for (Int_t j=0;j<n;j++) {
memcpy(&buf[k],&buf2[pos[i-n+j]-curbegin],len[i-n+j]);
k += len[i-n+j];
}
Int_t nok = k-kold;
Long64_t extra = nahead-nok;
fBytesReadExtra += extra;
fBytesRead -= extra;
fgBytesRead -= extra;
n = 0;
}
curbegin = pos[i];
}
}
if (buf2) delete [] buf2;
fCacheRead = old;
return result;
}
Int_t TFile::ReadBufferViaCache(char *buf, Int_t len)
{
Long64_t off = GetRelOffset();
if (fCacheRead) {
Int_t st = fCacheRead->ReadBuffer(buf, off, len);
if (st < 0)
return 2;
else if (st == 1) {
SetOffset(off + len);
return 1;
}
Seek(off);
} else {
if (fWritable && fCacheWrite) {
if (fCacheWrite->ReadBuffer(buf, off, len) == 0) {
SetOffset(off + len);
return 1;
}
SetOffset(off);
}
}
return 0;
}
void TFile::ReadFree()
{
if (fNbytesFree < 0 || fNbytesFree > fEND) {
fNbytesFree = 0;
return;
}
TKey *headerfree = new TKey(fSeekFree, fNbytesFree, this);
headerfree->ReadFile();
char *buffer = headerfree->GetBuffer();
headerfree->ReadKeyBuffer(buffer);
buffer = headerfree->GetBuffer();
while (1) {
TFree *afree = new TFree();
afree->ReadBuffer(buffer);
fFree->Add(afree);
if (afree->GetLast() > fEND) break;
}
delete headerfree;
}
TProcessID *TFile::ReadProcessID(UShort_t pidf)
{
TProcessID *pid = 0;
TObjArray *pids = GetListOfProcessIDs();
if (pidf < pids->GetSize()) pid = (TProcessID *)pids->UncheckedAt(pidf);
if (pid) {
pid->CheckInit();
return pid;
}
char pidname[32];
snprintf(pidname,32,"ProcessID%d",pidf);
pid = (TProcessID *)Get(pidname);
if (gDebug > 0) {
printf("ReadProcessID, name=%s, file=%s, pid=%lx\n",pidname,GetName(),(Long_t)pid);
}
if (!pid) {
return pid;
}
TObjArray *pidslist = TProcessID::GetPIDs();
TIter next(pidslist);
TProcessID *p;
while ((p = (TProcessID*)next())) {
if (!strcmp(p->GetTitle(),pid->GetTitle())) {
delete pid;
pids->AddAtAndExpand(p,pidf);
p->IncrementCount();
return p;
}
}
pids->AddAtAndExpand(pid,pidf);
pid->IncrementCount();
pidslist->Add(pid);
Int_t ind = pidslist->IndexOf(pid);
pid->SetUniqueID((UInt_t)ind);
return pid;
}
Int_t TFile::Recover()
{
Short_t keylen,cycle;
UInt_t datime;
Int_t nbytes,date,time,objlen,nwheader;
Long64_t seekkey,seekpdir;
char header[1024];
char *buffer, *bufread;
char nwhc;
Long64_t idcur = fBEGIN;
Long64_t size;
if ((size = GetSize()) == -1) {
Error("Recover", "cannot stat the file %s", GetName());
return 0;
}
fEND = Long64_t(size);
if (fWritable && !fFree) fFree = new TList;
TKey *key;
Int_t nrecov = 0;
nwheader = 1024;
Int_t nread = nwheader;
while (idcur < fEND) {
Seek(idcur);
if (idcur+nread >= fEND) nread = fEND-idcur-1;
if (ReadBuffer(header, nread)) {
Error("Recover","%s: failed to read the key data from disk at %lld.",
GetName(),idcur);
break;
}
buffer = header;
bufread = header;
frombuf(buffer, &nbytes);
if (!nbytes) {
Error("Recover","Address = %lld\tNbytes = %d\t=====E R R O R=======", idcur, nbytes);
break;
}
if (nbytes < 0) {
idcur -= nbytes;
if (fWritable) new TFree(fFree,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);
if (versionkey > 1000) {
frombuf(buffer, &seekkey);
frombuf(buffer, &seekpdir);
} else {
Int_t skey,sdir;
frombuf(buffer, &skey); seekkey = (Long64_t)skey;
frombuf(buffer, &sdir); seekpdir = (Long64_t)sdir;
}
frombuf(buffer, &nwhc);
char *classname = 0;
if (nwhc <= 0 || nwhc > 100) break;
classname = new char[nwhc+1];
int i, nwhci = nwhc;
for (i = 0;i < nwhc; i++) frombuf(buffer, &classname[i]);
classname[nwhci] = '\0';
TDatime::GetDateTime(datime, date, time);
TClass *tclass = TClass::GetClass(classname);
if (seekpdir == fSeekDir && tclass && !tclass->InheritsFrom(TFile::Class())
&& strcmp(classname,"TBasket")) {
key = new TKey(this);
key->ReadKeyBuffer(bufread);
if (!strcmp(key->GetName(),"StreamerInfo")) {
fSeekInfo = seekkey;
SafeDelete(fInfoCache);
fNbytesInfo = nbytes;
} else {
AppendKey(key);
nrecov++;
SetBit(kRecovered);
Info("Recover", "%s, recovered key %s:%s at address %lld",GetName(),key->GetClassName(),key->GetName(),idcur);
}
}
delete [] classname;
idcur += nbytes;
}
if (fWritable) {
Long64_t max_file_size = Long64_t(kStartBigFile);
if (max_file_size < fEND) max_file_size = fEND+1000000000;
TFree *last = (TFree*)fFree->Last();
if (last) {
last->AddFree(fFree,fEND,max_file_size);
} else {
new TFree(fFree,fEND,max_file_size);
}
if (nrecov) Write();
}
return nrecov;
}
Int_t TFile::ReOpen(Option_t *mode)
{
cd();
TString opt = mode;
opt.ToUpper();
if (opt != "READ" && opt != "UPDATE") {
Error("ReOpen", "mode must be either READ or UPDATE, not %s", opt.Data());
return 1;
}
if (opt == fOption || (opt == "UPDATE" && fOption == "CREATE"))
return 1;
if (opt == "READ") {
if (IsOpen() && IsWritable()) {
WriteStreamerInfo();
Save();
TFree *f1 = (TFree*)fFree->First();
if (f1) {
WriteFree();
WriteHeader();
}
FlushWriteCache();
if (fFree) {
fFree->Delete();
SafeDelete(fFree);
}
SysClose(fD);
fD = -1;
SetWritable(kFALSE);
}
fOption = opt;
#ifndef WIN32
fD = SysOpen(fRealName, O_RDONLY, 0644);
#else
fD = SysOpen(fRealName, O_RDONLY | O_BINARY, S_IREAD | S_IWRITE);
#endif
if (fD == -1) {
SysError("ReOpen", "file %s can not be opened in read mode", GetName());
return -1;
}
SetWritable(kFALSE);
} else {
if (IsOpen()) {
SysClose(fD);
fD = -1;
}
fOption = opt;
#ifndef WIN32
fD = SysOpen(fRealName, O_RDWR | O_CREAT, 0644);
#else
fD = SysOpen(fRealName, O_RDWR | O_CREAT | O_BINARY, S_IREAD | S_IWRITE);
#endif
if (fD == -1) {
SysError("ReOpen", "file %s can not be opened in update mode", GetName());
return -1;
}
SetWritable(kTRUE);
fFree = new TList;
if (fSeekFree > fBEGIN)
ReadFree();
else
Warning("ReOpen","file %s probably not closed, cannot read free segments", GetName());
}
return 0;
}
void TFile::SetOffset(Long64_t offset, ERelativeTo pos)
{
switch (pos) {
case kBeg:
fOffset = offset + fArchiveOffset;
break;
case kCur:
fOffset += offset;
break;
case kEnd:
if (fArchiveOffset)
Error("SetOffset", "seeking from end in archive is not (yet) supported");
fOffset = fEND + offset;
break;
}
}
void TFile::Seek(Long64_t offset, ERelativeTo pos)
{
int whence = 0;
switch (pos) {
case kBeg:
whence = SEEK_SET;
offset += fArchiveOffset;
break;
case kCur:
whence = SEEK_CUR;
break;
case kEnd:
whence = SEEK_END;
if (fArchiveOffset)
Error("Seek", "seeking from end in archive is not (yet) supported");
break;
}
Long64_t retpos;
if ((retpos = SysSeek(fD, offset, whence)) < 0)
SysError("Seek", "cannot seek to position %lld in file %s, retpos=%lld",
offset, GetName(), retpos);
fOffset = retpos;
}
void TFile::SetCompressionAlgorithm(Int_t algorithm)
{
if (algorithm < 0 || algorithm >= ROOT::kUndefinedCompressionAlgorithm) algorithm = 0;
if (fCompress < 0) {
fCompress = 100 * algorithm + 1;
} else {
int level = fCompress % 100;
fCompress = 100 * algorithm + level;
}
}
void TFile::SetCompressionLevel(Int_t level)
{
if (level < 0) level = 0;
if (level > 99) level = 99;
if (fCompress < 0) {
fCompress = level;
} else {
int algorithm = fCompress / 100;
if (algorithm >= ROOT::kUndefinedCompressionAlgorithm) algorithm = 0;
fCompress = 100 * algorithm + level;
}
}
void TFile::SetCompressionSettings(Int_t settings)
{
fCompress = settings;
}
void TFile::SetCacheRead(TFileCacheRead *cache, TObject* tree, ECacheAction action)
{
if (tree) {
if (cache) fCacheReadMap->Add(tree, cache);
else {
TFileCacheRead* tpf = (TFileCacheRead *)fCacheReadMap->GetValue(tree);
fCacheReadMap->RemoveEntry(tree);
if (tpf && (tpf->GetFile() == this) && (action != kDoNotDisconnect)) tpf->SetFile(0, action);
}
}
if (cache) cache->SetFile(this, action);
else if (!tree && fCacheRead && (action != kDoNotDisconnect)) fCacheRead->SetFile(0, action);
fCacheRead = cache;
}
void TFile::SetCacheWrite(TFileCacheWrite *cache)
{
if (!cache && fCacheWrite) delete fCacheWrite;
fCacheWrite = cache;
}
Int_t TFile::Sizeof() const
{
return 0;
}
void TFile::Streamer(TBuffer &b)
{
if (b.IsReading()) {
b.ReadVersion();
} else {
b.WriteVersion(TFile::IsA());
}
}
void TFile::SumBuffer(Int_t bufsize)
{
fWritten++;
fSumBuffer += bufsize;
fSum2Buffer += bufsize*bufsize;
}
Int_t TFile::Write(const char *, Int_t opt, Int_t bufsiz)
{
if (!IsWritable()) {
if (!TestBit(kWriteError)) {
Warning("Write", "file %s not opened in write mode", GetName());
}
return 0;
}
if (gDebug) {
if (!GetTitle() || strlen(GetTitle()) == 0)
Info("Write", "writing name = %s", GetName());
else
Info("Write", "writing name = %s title = %s", GetName(), GetTitle());
}
fMustFlush = kFALSE;
Int_t nbytes = TDirectoryFile::Write(0, opt, bufsiz);
WriteStreamerInfo();
WriteFree();
WriteHeader();
fMustFlush = kTRUE;
return nbytes;
}
Int_t TFile::Write(const char *n, Int_t opt, Int_t bufsize) const
{
Error("Write const","A const TFile object should not be saved. We try to proceed anyway.");
return const_cast<TFile*>(this)->Write(n, opt, bufsize);
}
Bool_t TFile::WriteBuffer(const char *buf, Int_t len)
{
if (IsOpen() && fWritable) {
Int_t st;
if ((st = WriteBufferViaCache(buf, len))) {
if (st == 2)
return kTRUE;
return kFALSE;
}
ssize_t siz;
gSystem->IgnoreInterrupt();
while ((siz = SysWrite(fD, buf, len)) < 0 && GetErrno() == EINTR)
ResetErrno();
gSystem->IgnoreInterrupt(kFALSE);
if (siz < 0) {
SetBit(kWriteError); SetWritable(kFALSE);
SysError("WriteBuffer", "error writing to file %s (%ld)", GetName(), (Long_t)siz);
return kTRUE;
}
if (siz != len) {
SetBit(kWriteError);
Error("WriteBuffer", "error writing all requested bytes to file %s, wrote %ld of %d",
GetName(), (Long_t)siz, len);
return kTRUE;
}
fBytesWrite += siz;
fgBytesWrite += siz;
if (gMonitoringWriter)
gMonitoringWriter->SendFileWriteProgress(this);
return kFALSE;
}
return kTRUE;
}
Int_t TFile::WriteBufferViaCache(const char *buf, Int_t len)
{
if (!fCacheWrite) return 0;
Int_t st;
Long64_t off = GetRelOffset();
if ((st = fCacheWrite->WriteBuffer(buf, off, len)) < 0) {
SetBit(kWriteError);
Error("WriteBuffer", "error writing to cache");
return 2;
}
if (st > 0) {
Seek(off + len);
return 1;
}
return 0;
}
void TFile::WriteFree()
{
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,this);
if (key->GetSeekKey() == 0) {
delete key;
return;
}
char *buffer = key->GetBuffer();
char *start = buffer;
next.Reset();
while ((afree = (TFree*) next())) {
afree->FillBuffer(buffer);
}
if ( (buffer-start)!=nbytes ) {
memset(buffer,0,nbytes-(buffer-start));
}
fNbytesFree = key->GetNbytes();
fSeekFree = key->GetSeekKey();
key->WriteFile();
delete key;
}
void TFile::WriteHeader()
{
SafeDelete(fInfoCache);
TFree *lastfree = (TFree*)fFree->Last();
if (lastfree) fEND = lastfree->GetFirst();
const char *root = "root";
char *psave = new char[fBEGIN];
char *buffer = psave;
Int_t nfree = fFree->GetSize();
memcpy(buffer, root, 4); buffer += 4;
Int_t version = fVersion;
if (version <1000000 && fEND > kStartBigFile) {version += 1000000; fUnits = 8;}
tobuf(buffer, version);
tobuf(buffer, (Int_t)fBEGIN);
if (version < 1000000) {
tobuf(buffer, (Int_t)fEND);
tobuf(buffer, (Int_t)fSeekFree);
tobuf(buffer, fNbytesFree);
tobuf(buffer, nfree);
tobuf(buffer, fNbytesName);
tobuf(buffer, fUnits);
tobuf(buffer, fCompress);
tobuf(buffer, (Int_t)fSeekInfo);
tobuf(buffer, fNbytesInfo);
} else {
tobuf(buffer, fEND);
tobuf(buffer, fSeekFree);
tobuf(buffer, fNbytesFree);
tobuf(buffer, nfree);
tobuf(buffer, fNbytesName);
tobuf(buffer, fUnits);
tobuf(buffer, fCompress);
tobuf(buffer, fSeekInfo);
tobuf(buffer, fNbytesInfo);
}
fUUID.FillBuffer(buffer);
Int_t nbytes = buffer - psave;
Seek(0);
WriteBuffer(psave, nbytes);
Flush();
delete [] psave;
}
void TFile::MakeProject(const char *dirname, const char * ,
Option_t *option)
{
TString opt = option;
opt.ToLower();
Bool_t makepar = kFALSE;
TString parname, pardir;
if (opt.Contains("par")) {
parname = gSystem->BaseName(dirname);
if (parname.EndsWith(".par")) parname.ReplaceAll(".par","");
pardir = gSystem->DirName(dirname);
TString path, filepath;
void *dir = gSystem->OpenDirectory(pardir);
if (dir) {
path.Form("%s/%s", pardir.Data(), parname.Data());
void *dirp = gSystem->OpenDirectory(path);
if (dirp) {
path += "/PROOF-INF";
void *dirinf = gSystem->OpenDirectory(path);
const char *afile = 0;
if (dirinf) {
while ((afile = gSystem->GetDirEntry(dirinf))) {
if (strcmp(afile,".") == 0) continue;
if (strcmp(afile,"..") == 0) continue;
filepath.Form("%s/%s", path.Data(), afile);
if (gSystem->Unlink(filepath))
Warning("MakeProject", "1: problems unlinking '%s' ('%s', '%s')", filepath.Data(), path.Data(), afile);
}
gSystem->FreeDirectory(dirinf);
}
gSystem->Unlink(path);
path.Form("%s/%s", pardir.Data(), parname.Data());
while ((afile = gSystem->GetDirEntry(dirp))) {
if (strcmp(afile,".") == 0) continue;
if (strcmp(afile,"..") == 0) continue;
filepath.Form("%s/%s", path.Data(), afile);
if (gSystem->Unlink(filepath))
Warning("MakeProject", "2: problems unlinking '%s' ('%s', '%s')", filepath.Data(), path.Data(), afile);
}
gSystem->FreeDirectory(dirp);
if (gSystem->Unlink(path))
Warning("MakeProject", "problems unlinking '%s'", path.Data());
}
}
path.Form("%s/%s/PROOF-INF", pardir.Data(), parname.Data());
if (gSystem->mkdir(path, kTRUE)) {
Error("MakeProject", "problems creating '%s'", path.Data());
return;
}
makepar = kTRUE;
} else {
void *dir = gSystem->OpenDirectory(dirname);
TString dirpath;
if (opt.Contains("update")) {
if (dir == 0) {
gSystem->mkdir(dirname);
}
} else if (opt.Contains("recreate")) {
if (dir == 0) {
if (gSystem->mkdir(dirname) < 0) {
Error("MakeProject","cannot create directory '%s'",dirname);
return;
}
}
while (dir) {
const char *afile = gSystem->GetDirEntry(dir);
if (afile == 0) break;
if (strcmp(afile,".") == 0) continue;
if (strcmp(afile,"..") == 0) continue;
dirpath.Form("%s/%s",dirname,afile);
gSystem->Unlink(dirpath);
}
} else {
if (dir) {
Error("MakeProject","cannot create directory %s, already existing",dirname);
gSystem->FreeDirectory(dir);
return;
}
if (gSystem->mkdir(dirname) < 0) {
Error("MakeProject","cannot create directory '%s'",dirname);
return;
}
}
if (dir) {
gSystem->FreeDirectory(dir);
}
}
Bool_t genreflex = opt.Contains("genreflex");
TList *filelist = (TList*)GetStreamerInfoCache();
if (filelist) filelist = (TList*)filelist->Clone();
if (filelist == 0) {
Error("MakeProject","file %s has no StreamerInfo", GetName());
return;
}
TString clean_dirname(dirname);
if (makepar) clean_dirname.Form("%s/%s", pardir.Data(), parname.Data());
if (clean_dirname[clean_dirname.Length()-1]=='/') {
clean_dirname.Remove(clean_dirname.Length()-1);
} else if (clean_dirname[clean_dirname.Length()-1]=='\\') {
clean_dirname.Remove(clean_dirname.Length()-1);
if (clean_dirname[clean_dirname.Length()-1]=='\\') {
clean_dirname.Remove(clean_dirname.Length()-1);
}
}
TString subdirname( gSystem->BaseName(clean_dirname) );
if (makepar) subdirname = parname;
if (subdirname == "") {
Error("MakeProject","Directory name must not be empty.");
return;
}
TString spath; spath.Form("%s/%sProjectSource.cxx",clean_dirname.Data(),subdirname.Data());
FILE *sfp = fopen(spath.Data(),"w");
if (sfp ==0) {
Error("MakeProject","Unable to create the source file %s.",spath.Data());
return;
}
fprintf(sfp, "namespace std {}\nusing namespace std;\n");
fprintf(sfp, "#include \"%sProjectHeaders.h\"\n\n",subdirname.Data() );
if (!genreflex) fprintf(sfp, "#include \"%sLinkDef.h\"\n\n",subdirname.Data() );
fprintf(sfp, "#include \"%sProjectDict.cxx\"\n\n",subdirname.Data() );
fprintf(sfp, "struct DeleteObjectFunctor {\n");
fprintf(sfp, " template <typename T>\n");
fprintf(sfp, " void operator()(const T *ptr) const {\n");
fprintf(sfp, " delete ptr;\n");
fprintf(sfp, " }\n");
fprintf(sfp, " template <typename T, typename Q>\n");
fprintf(sfp, " void operator()(const std::pair<T,Q> &) const {\n");
fprintf(sfp, " // Do nothing\n");
fprintf(sfp, " }\n");
fprintf(sfp, " template <typename T, typename Q>\n");
fprintf(sfp, " void operator()(const std::pair<T,Q*> &ptr) const {\n");
fprintf(sfp, " delete ptr.second;\n");
fprintf(sfp, " }\n");
fprintf(sfp, " template <typename T, typename Q>\n");
fprintf(sfp, " void operator()(const std::pair<T*,Q> &ptr) const {\n");
fprintf(sfp, " delete ptr.first;\n");
fprintf(sfp, " }\n");
fprintf(sfp, " template <typename T, typename Q>\n");
fprintf(sfp, " void operator()(const std::pair<T*,Q*> &ptr) const {\n");
fprintf(sfp, " delete ptr.first;\n");
fprintf(sfp, " delete ptr.second;\n");
fprintf(sfp, " }\n");
fprintf(sfp, "};\n\n");
fclose( sfp );
TStreamerInfo *info;
TIter flnext(filelist);
TList extrainfos;
TList *list = new TList();
while ((info = (TStreamerInfo*)flnext())) {
if (info->IsA() != TStreamerInfo::Class()) {
continue;
}
if (strstr(info->GetName(),"@@")) {
continue;
}
TClass *cl = TClass::GetClass(info->GetName());
if (cl) {
if (cl->HasInterpreterInfo()) continue;
}
TMakeProject::GenerateMissingStreamerInfos( &extrainfos, info->GetName() );
TIter enext( info->GetElements() );
TStreamerElement *el;
const ROOT::TSchemaMatch* rules = 0;
if (cl && cl->GetSchemaRules()) {
rules = cl->GetSchemaRules()->FindRules(cl->GetName(), info->GetClassVersion());
}
while( (el=(TStreamerElement*)enext()) ) {
if (rules) {
for(Int_t art = 0; art < rules->GetEntries(); ++art) {
ROOT::TSchemaRule *rule = (ROOT::TSchemaRule*)rules->At(art);
if( rule->IsRenameRule() || rule->IsAliasRule() )
continue;
if ( rule->HasTarget( el->GetName()) && rule->GetAttributes()[0] != 0 ) {
TString attr( rule->GetAttributes() );
attr.ToLower();
if (attr.Contains("owner")) {
if (attr.Contains("notowner")) {
el->SetBit(TStreamerElement::kDoNotDelete);
} else {
el->ResetBit(TStreamerElement::kDoNotDelete);
}
}
}
}
}
TMakeProject::GenerateMissingStreamerInfos(&extrainfos, el);
}
delete rules;
TVirtualStreamerInfo *alternate = (TVirtualStreamerInfo*)list->FindObject(info->GetName());
if (alternate) {
if ((info->GetClass() && info->GetClassVersion() == info->GetClass()->GetClassVersion())
|| (info->GetClassVersion() > alternate->GetClassVersion()) ) {
list->AddAfter(alternate, info);
list->Remove(alternate);
}
} else {
list->Add(info);
}
}
TIter nextextra(&extrainfos);
while ((info = (TStreamerInfo*)nextextra())) {
list->Add(info);
filelist->Add(info);
}
TIter next(list);
Int_t ngener = 0;
while ((info = (TStreamerInfo*)next())) {
if (info->IsA() != TStreamerInfo::Class()) {
continue;
}
if (info->GetClassVersion()==-4) continue;
TIter subnext(list);
TStreamerInfo *subinfo;
TList subClasses;
Int_t len = strlen(info->GetName());
while ((subinfo = (TStreamerInfo*)subnext())) {
if (subinfo->IsA() != TStreamerInfo::Class()) {
continue;
}
if (strncmp(info->GetName(),subinfo->GetName(),len)==0) {
const Int_t sublen = strlen(subinfo->GetName());
if ( (sublen > len) && subinfo->GetName()[len+1]==':'
&& !subClasses.FindObject(subinfo->GetName()) )
{
subClasses.Add(subinfo);
}
}
}
ngener += info->GenerateHeaderFile(clean_dirname.Data(),&subClasses,&extrainfos);
subClasses.Clear("nodelete");
}
TString path;
path.Form("%s/%sProjectHeaders.h",clean_dirname.Data(),subdirname.Data());
FILE *allfp = fopen(path,"a");
if (!allfp) {
Error("MakeProject","Cannot open output file:%s\n",path.Data());
} else {
fprintf(allfp,"#include \"%sProjectInstances.h\"\n", subdirname.Data());
fclose(allfp);
}
printf("MakeProject has generated %d classes in %s\n",ngener,clean_dirname.Data());
if (!opt.Contains("+") && !makepar) {
delete list;
filelist->Delete();
delete filelist;
return;
}
FILE *fpMAKE = 0;
if (!makepar) {
#ifdef WIN32
path.Form("%s/makep.cmd",clean_dirname.Data());
#else
path.Form("%s/MAKEP",clean_dirname.Data());
#endif
#ifdef R__WINGCC
fpMAKE = fopen(path,"wb");
#else
fpMAKE = fopen(path,"w");
#endif
if (!fpMAKE) {
Error("MakeProject", "cannot open file %s", path.Data());
delete list;
filelist->Delete();
delete filelist;
return;
}
}
FILE *ifp = 0;
path.Form("%s/%sProjectInstances.h",clean_dirname.Data(),subdirname.Data());
#ifdef R__WINGCC
ifp = fopen(path,"wb");
#else
ifp = fopen(path,"w");
#endif
if (!ifp) {
Error("MakeProject", "cannot open path file %s", path.Data());
delete list;
filelist->Delete();
delete filelist;
fclose(fpMAKE);
return;
}
if (!makepar) {
if (genreflex) {
fprintf(fpMAKE,"genreflex %sProjectHeaders.h -o %sProjectDict.cxx --comments --iocomments %s ",subdirname.Data(),subdirname.Data(),gSystem->GetIncludePath());
path.Form("%s/%sSelection.xml",clean_dirname.Data(),subdirname.Data());
} else {
fprintf(fpMAKE,"rootcint -f %sProjectDict.cxx -c %s ",subdirname.Data(),gSystem->GetIncludePath());
path.Form("%s/%sLinkDef.h",clean_dirname.Data(),subdirname.Data());
}
} else {
path.Form("%s/%sLinkDef.h",clean_dirname.Data(),subdirname.Data());
}
#ifdef R__WINGCC
FILE *fp = fopen(path,"wb");
#else
FILE *fp = fopen(path,"w");
#endif
if (!fp) {
Error("MakeProject", "cannot open path file %s", path.Data());
delete list;
filelist->Delete();
delete filelist;
fclose(fpMAKE);
fclose(ifp);
return;
}
if (genreflex) {
fprintf(fp,"<lcgdict>\n");
fprintf(fp,"\n");
} else {
fprintf(fp,"#ifdef __CINT__\n");
fprintf(fp,"\n");
}
TString tmp;
TString instances;
TString selections;
next.Reset();
while ((info = (TStreamerInfo*)next())) {
if (info->IsA() != TStreamerInfo::Class()) {
continue;
}
TClass *cl = TClass::GetClass(info->GetName());
if (cl) {
if (cl->HasInterpreterInfo()) continue;
const ROOT::TSchemaMatch* rules = 0;
if (cl->GetSchemaRules()) {
rules = cl->GetSchemaRules()->FindRules(cl->GetName(), info->GetClassVersion());
TString strrule;
if (rules) {
for(Int_t art = 0; art < rules->GetEntries(); ++art) {
ROOT::TSchemaRule *rule = (ROOT::TSchemaRule*)rules->At(art);
strrule.Clear();
if (genreflex) {
rule->AsString(strrule,"x");
strrule.Append("\n");
if ( selections.Index(strrule) == kNPOS ) {
selections.Append(strrule);
}
} else {
rule->AsString(strrule);
if (strncmp(strrule.Data(),"type=",5)==0) {
strrule.Remove(0,5);
}
fprintf(fp,"#pragma %s;\n",strrule.Data());
}
}
}
delete rules;
}
}
if (TClassEdit::IsSTLCont(info->GetName())) {
std::vector<std::string> inside;
int nestedLoc;
TClassEdit::GetSplit( info->GetName(), inside, nestedLoc, TClassEdit::kLong64 );
Int_t stlkind = TClassEdit::STLKind(inside[0].c_str());
TClass *key = TClass::GetClass(inside[1].c_str());
if (key) {
TString what;
switch ( stlkind ) {
case ROOT::kSTLmap:
case ROOT::kSTLmultimap:
if (TClass::GetClass(inside[1].c_str())) {
what = "std::pair<";
what += TMakeProject::UpdateAssociativeToVector( inside[1].c_str() );
what += ",";
what += TMakeProject::UpdateAssociativeToVector( inside[2].c_str() );
if (what[what.Length()-1]=='>') {
what += " >";
} else {
what += ">";
}
if (genreflex) {
tmp.Form("<class name=\"%s\" />\n",what.Data());
if ( selections.Index(tmp) == kNPOS ) {
selections.Append(tmp);
}
tmp.Form("template class %s;\n",what.Data());
if ( instances.Index(tmp) == kNPOS ) {
instances.Append(tmp);
}
} else {
what.ReplaceAll("std::","");
TClass *paircl = TClass::GetClass(what.Data());
if (paircl == 0 || !paircl->HasInterpreterInfo()) {
fprintf(fp,"#pragma link C++ class %s+;\n",what.Data());
}
}
break;
}
default:
if (strncmp(key->GetName(),"pair<",strlen("pair<"))==0) {
if (genreflex) {
tmp.Form("<class name=\"%s\" />\n",key->GetName());
if ( selections.Index(tmp) == kNPOS ) {
selections.Append(tmp);
}
tmp.Form("template class %s;\n",key->GetName());
if ( instances.Index(tmp) == kNPOS ) {
instances.Append(tmp);
}
} else {
what.ReplaceAll("std::","");
fprintf(fp,"#pragma link C++ class %s+;\n",key->GetName());
}
}
break;
}
}
continue;
}
{
TString what(TMakeProject::UpdateAssociativeToVector(info->GetName()).Data());
if (genreflex) {
tmp.Form("<class name=\"%s\" />\n",what.Data());
if ( selections.Index(tmp) == kNPOS ) {
selections.Append(tmp);
}
if (what[what.Length()-1] == '>') {
tmp.Form("template class %s;\n",what.Data());
if ( instances.Index(tmp) == kNPOS ) {
instances.Append(tmp);
}
}
} else {
what.ReplaceAll("std::","");
fprintf(fp,"#pragma link C++ class %s+;\n",what.Data());
}
}
if (genreflex) {
TIter eliter( info->GetElements() );
TStreamerElement *element;
while( (element = (TStreamerElement*)eliter() ) ) {
if (element->GetClass() && !element->GetClass()->IsLoaded() && element->GetClass()->GetCollectionProxy()) {
TString what( TMakeProject::UpdateAssociativeToVector(element->GetClass()->GetName()) );
tmp.Form("<class name=\"%s\" />\n",what.Data());
if ( selections.Index(tmp) == kNPOS ) {
selections.Append(tmp);
}
tmp.Form("template class %s;\n",what.Data());
if ( instances.Index(tmp) == kNPOS ) {
instances.Append(tmp);
}
}
}
}
}
if (genreflex) {
fprintf(ifp,"#ifndef PROJECT_INSTANCES_H\n");
fprintf(ifp,"#define PROJECT_INSTANCES_H\n");
fprintf(ifp,"%s",instances.Data());
fprintf(ifp,"#endif\n");
fprintf(fp,"%s",selections.Data());
fprintf(fp,"</lcgdict>\n");
} else {
fprintf(fp,"#endif\n");
}
fclose(fp);
fclose(ifp);
if (!makepar) {
TString sdirname(subdirname);
TString cmd = gSystem->GetMakeSharedLib();
TString sources = TString::Format("%sProjectSource.cxx ", sdirname.Data());
cmd.ReplaceAll("$SourceFiles",sources.Data());
TString object = TString::Format("%sProjectSource.", sdirname.Data());
object.Append( gSystem->GetObjExt() );
cmd.ReplaceAll("$ObjectFiles", object.Data());
cmd.ReplaceAll("$IncludePath",TString(gSystem->GetIncludePath()) + " -I" + clean_dirname.Data());
cmd.ReplaceAll("$SharedLib",sdirname+"."+gSystem->GetSoExt());
cmd.ReplaceAll("$LinkedLibs",gSystem->GetLibraries("","SDL"));
cmd.ReplaceAll("$LibName",sdirname);
cmd.ReplaceAll("$BuildDir",".");
TString sOpt;
TString rootbuild = ROOTBUILD;
if (rootbuild.Index("debug",0,TString::kIgnoreCase)==kNPOS) {
sOpt = gSystem->GetFlagsOpt();
} else {
sOpt = gSystem->GetFlagsDebug();
}
cmd.ReplaceAll("$Opt", sOpt);
if (genreflex) {
fprintf(fpMAKE,"-s %sSelection.xml \n",subdirname.Data());
} else {
fprintf(fpMAKE,"%sProjectHeaders.h ",subdirname.Data());
fprintf(fpMAKE,"%sLinkDef.h \n",subdirname.Data());
}
fprintf(fpMAKE,"%s\n",cmd.Data());
printf("%s/MAKEP file has been generated\n", clean_dirname.Data());
fclose(fpMAKE);
} else {
TString filemake = TString::Format("%s/Makefile", clean_dirname.Data());
if (MakeProjectParMake(parname, filemake.Data()) != 0) {
Error("MakeProject", "problems creating PAR make file '%s'", filemake.Data());
delete list;
filelist->Delete();
delete filelist;
return;
}
#ifdef ROOTETCDIR
TString mkarchsrc = TString::Format("%s/Makefile.arch", ROOTETCDIR);
#else
TString mkarchsrc("$(ROOTSYS)/etc/Makefile.arch");
#endif
if (gSystem->ExpandPathName(mkarchsrc))
Warning("MakeProject", "problems expanding '%s'", mkarchsrc.Data());
TString mkarchdst = TString::Format("%s/Makefile.arch", clean_dirname.Data());
if (gSystem->CopyFile(mkarchsrc.Data(), mkarchdst.Data(), kTRUE) != 0) {
Error("MakeProject", "problems retrieving '%s' to '%s'", mkarchsrc.Data(), mkarchdst.Data());
delete list;
filelist->Delete();
delete filelist;
return;
}
TString proofinf = TString::Format("%s/PROOF-INF", clean_dirname.Data());
if (MakeProjectParProofInf(parname, proofinf.Data()) != 0) {
Error("MakeProject", "problems creating BUILD.sh and/or SETUP.C under '%s'", proofinf.Data());
delete list;
filelist->Delete();
delete filelist;
return;
}
TString cmod = TString::Format("chmod +x %s/PROOF-INF/BUILD.sh", clean_dirname.Data());
#ifndef WIN32
gSystem->Exec(cmod.Data());
#else
chmod(cmod.Data(), 00700);
#endif
Printf("Files Makefile, Makefile.arch, PROOF-INF/BUILD.sh and"
" PROOF-INF/SETUP.C have been generated under '%s'", clean_dirname.Data());
#ifndef WIN32
TString curdir = gSystem->WorkingDirectory();
if (gSystem->ChangeDirectory(pardir)) {
TString cmd = TString::Format("tar czvf %s.par %s", parname.Data(), parname.Data());
gSystem->Exec(cmd.Data());
if (gSystem->ChangeDirectory(curdir)) {
Info("MakeProject", "PAR file %s.par generated", clean_dirname.Data());
} else {
Warning("MakeProject", "problems changing directory back to '%s'", curdir.Data());
}
} else {
Error("MakeProject", "problems changing directory to '%s' - skipping PAR file generation", pardir.Data());
}
#else
Warning("MakeProject", "on Windows systems the PAR file cannot be generated out of the package directory!");
#endif
}
if (!makepar && !opt.Contains("nocompilation")) {
path = gSystem->WorkingDirectory();
gSystem->ChangeDirectory(clean_dirname.Data());
#ifndef WIN32
gSystem->Exec("chmod +x MAKEP");
int res = !gSystem->Exec("./MAKEP");
#else
chmod("makep.cmd",00700);
int res = !gSystem->Exec("MAKEP");
#endif
gSystem->ChangeDirectory(path);
path.Form("%s/%s.%s",clean_dirname.Data(),subdirname.Data(),gSystem->GetSoExt());
if (res) printf("Shared lib %s has been generated\n",path.Data());
if (opt.Contains("++")) {
res = !gSystem->Load(path);
if (res) printf("Shared lib %s has been dynamically linked\n",path.Data());
}
}
extrainfos.Clear("nodelete");
delete list;
filelist->Delete();
delete filelist;
}
Int_t TFile::MakeProjectParMake(const char *pack, const char *filemake)
{
if (!filemake || (filemake && strlen(filemake) <= 0)) {
Error("MakeProjectParMake", "path for output file undefined!");
return -1;
}
if (!pack || (pack && strlen(pack) <= 0)) {
Error("MakeProjectParMake", "package name undefined!");
return -1;
}
#ifdef R__WINGCC
FILE *fmk = fopen(filemake, "wb");
#else
FILE *fmk = fopen(filemake, "w");
#endif
if (!fmk) {
Error("MakeProjectParMake", "cannot create file '%s' (errno: %d)", filemake, TSystem::GetErrno());
return -1;
}
fprintf(fmk, "# Makefile for the ROOT test programs.\n");
fprintf(fmk, "# This Makefile shows how to compile and link applications\n");
fprintf(fmk, "# using the ROOT libraries on all supported platforms.\n");
fprintf(fmk, "#\n");
fprintf(fmk, "# Copyright (c) 2000 Rene Brun and Fons Rademakers\n");
fprintf(fmk, "#\n");
fprintf(fmk, "# Author: this makefile has been automatically generated via TFile::MakeProject\n");
fprintf(fmk, "\n");
fprintf(fmk, "include Makefile.arch\n");
fprintf(fmk, "\n");
fprintf(fmk, "#------------------------------------------------------------------------------\n");
fprintf(fmk, "\n");
fprintf(fmk, "PACKO = %sProjectSource.$(ObjSuf)\n", pack);
fprintf(fmk, "PACKS = %sProjectSource.$(SrcSuf) %sProjectDict.$(SrcSuf)\n", pack, pack);
fprintf(fmk, "PACKSO = lib%s.$(DllSuf)\n", pack);
fprintf(fmk, "\n");
fprintf(fmk, "ifeq ($(PLATFORM),win32)\n");
fprintf(fmk, "PACKLIB = lib%s.lib\n", pack);
fprintf(fmk, "else\n");
fprintf(fmk, "PACKLIB = $(PACKSO)\n");
fprintf(fmk, "endif\n");
fprintf(fmk, "\n");
fprintf(fmk, "OBJS = $(PACKO)\n");
fprintf(fmk, "\n");
fprintf(fmk, "PROGRAMS =\n");
fprintf(fmk, "\n");
fprintf(fmk, "#------------------------------------------------------------------------------\n");
fprintf(fmk, "\n");
fprintf(fmk, ".SUFFIXES: .$(SrcSuf) .$(ObjSuf) .$(DllSuf)\n");
fprintf(fmk, "\n");
fprintf(fmk, "all: $(PACKLIB)\n");
fprintf(fmk, "\n");
fprintf(fmk, "$(PACKSO): $(PACKO)\n");
fprintf(fmk, "ifeq ($(ARCH),aix)\n");
fprintf(fmk, "\t\t/usr/ibmcxx/bin/makeC++SharedLib $(OutPutOpt) $@ $(LIBS) -p 0 $^\n");
fprintf(fmk, "else\n");
fprintf(fmk, "ifeq ($(ARCH),aix5)\n");
fprintf(fmk, "\t\t/usr/vacpp/bin/makeC++SharedLib $(OutPutOpt) $@ $(LIBS) -p 0 $^\n");
fprintf(fmk, "else\n");
fprintf(fmk, "ifeq ($(PLATFORM),macosx)\n");
fprintf(fmk, "# We need to make both the .dylib and the .so\n");
fprintf(fmk, "\t\t$(LD) $(SOFLAGS)$@ $(LDFLAGS) $^ $(OutPutOpt) $@ $(LIBS)\n");
fprintf(fmk, "ifneq ($(subst $(MACOSX_MINOR),,1234),1234)\n");
fprintf(fmk, "ifeq ($(MACOSX_MINOR),4)\n");
fprintf(fmk, "\t\tln -sf $@ $(subst .$(DllSuf),.so,$@)\n");
fprintf(fmk, "else\n");
fprintf(fmk, "\t\t$(LD) -bundle -undefined $(UNDEFOPT) $(LDFLAGS) $^ \\\n");
fprintf(fmk, "\t\t $(OutPutOpt) $(subst .$(DllSuf),.so,$@)\n");
fprintf(fmk, "endif\n");
fprintf(fmk, "endif\n");
fprintf(fmk, "else\n");
fprintf(fmk, "ifeq ($(PLATFORM),win32)\n");
fprintf(fmk, "\t\tbindexplib $* $^ > $*.def\n");
fprintf(fmk, "\t\tlib -nologo -MACHINE:IX86 $^ -def:$*.def \\\n");
fprintf(fmk, "\t\t $(OutPutOpt)$(PACKLIB)\n");
fprintf(fmk, "\t\t$(LD) $(SOFLAGS) $(LDFLAGS) $^ $*.exp $(LIBS) \\\n");
fprintf(fmk, "\t\t $(OutPutOpt)$@\n");
fprintf(fmk, "else\n");
fprintf(fmk, "\t\t$(LD) $(SOFLAGS) $(LDFLAGS) $^ $(OutPutOpt) $@ $(LIBS) $(EXPLLINKLIBS)\n");
fprintf(fmk, "endif\n");
fprintf(fmk, "endif\n");
fprintf(fmk, "endif\n");
fprintf(fmk, "endif\n");
fprintf(fmk, "\t\t@echo \"$@ done\"\n");
fprintf(fmk, "\n");
fprintf(fmk, "clean:\n");
fprintf(fmk, "\t\t@rm -f $(OBJS) core\n");
fprintf(fmk, "\n");
fprintf(fmk, "distclean: clean\n");
fprintf(fmk, "\t\t@rm -f $(PROGRAMS) $(PACKSO) $(PACKLIB) *Dict.* *.def *.exp \\\n");
fprintf(fmk, "\t\t *.so *.lib *.dll *.d *.log .def so_locations\n");
fprintf(fmk, "\t\t@rm -rf cxx_repository\n");
fprintf(fmk, "\n");
fprintf(fmk, "# Dependencies\n");
fprintf(fmk, "\n");
fprintf(fmk, "%sProjectSource.$(ObjSuf): %sProjectHeaders.h %sLinkDef.h %sProjectDict.$(SrcSuf)\n", pack, pack, pack, pack);
fprintf(fmk, "\n");
fprintf(fmk, "%sProjectDict.$(SrcSuf): %sProjectHeaders.h %sLinkDef.h\n", pack, pack, pack);
fprintf(fmk, "\t\t@echo \"Generating dictionary $@...\"\n");
fprintf(fmk, "\t\t@rootcint -f $@ -c $^\n");
fprintf(fmk, "\n");
fprintf(fmk, ".$(SrcSuf).$(ObjSuf):\n");
fprintf(fmk, "\t\t$(CXX) $(CXXFLAGS) -c $<\n");
fprintf(fmk, "\n");
fclose(fmk);
return 0;
}
Int_t TFile::MakeProjectParProofInf(const char *pack, const char *proofinf)
{
if (!proofinf || (proofinf && strlen(proofinf) <= 0)) {
Error("MakeProjectParProofInf", "directory path undefined!");
return -1;
}
Int_t rcst = 0;
FileStat_t st;
if ((rcst = gSystem->GetPathInfo(proofinf, st)) != 0 || !R_ISDIR(st.fMode)) {
Error("MakeProjectParProofInf", "path '%s' %s", proofinf,
((rcst == 0) ? "is not a directory" : "does not exist"));
return -1;
}
if (!pack || (pack && strlen(pack) <= 0)) {
Error("MakeProjectParProofInf", "package name undefined!");
return -1;
}
TString path;
path.Form("%s/BUILD.sh", proofinf);
#ifdef R__WINGCC
FILE *f = fopen(path.Data(), "wb");
#else
FILE *f = fopen(path.Data(), "w");
#endif
if (!f) {
Error("MakeProjectParProofInf", "cannot create file '%s' (errno: %d)",
path.Data(), TSystem::GetErrno());
return -1;
}
fprintf(f, "#! /bin/sh\n");
fprintf(f, "# Build libEvent library.\n");
fprintf(f, "\n");
fprintf(f, "#\n");
fprintf(f, "# The environment variables ROOTPROOFLITE and ROOTPROOFCLIENT can be used to\n");
fprintf(f, "# adapt the script to the calling environment\n");
fprintf(f, "#\n");
fprintf(f, "# if test ! \"x$ROOTPROOFLITE\" = \"x\"; then\n");
fprintf(f, "# echo \"event-BUILD: PROOF-Lite node (session has $ROOTPROOFLITE workers)\"\n");
fprintf(f, "# elif test ! \"x$ROOTPROOFCLIENT\" = \"x\"; then\n");
fprintf(f, "# echo \"event-BUILD: PROOF client\"\n");
fprintf(f, "# else\n");
fprintf(f, "# echo \"event-BUILD: standard PROOF node\"\n");
fprintf(f, "# fi\n");
fprintf(f, "\n");
fprintf(f, "if [ \"\" = \"clean\" ]; then\n");
fprintf(f, " make distclean\n");
fprintf(f, " exit 0\n");
fprintf(f, "fi\n");
fprintf(f, "\n");
fprintf(f, "make\n");
fprintf(f, "rc=$?\n");
fprintf(f, "echo \"rc=$?\"\n");
fprintf(f, "if [ $? != \"0\" ] ; then\n");
fprintf(f, " exit 1\n");
fprintf(f, "fi\n");
fprintf(f, "exit 0\n");
fclose(f);
path.Form("%s/SETUP.C", proofinf);
#ifdef R__WINGCC
f = fopen(path.Data(), "wb");
#else
f = fopen(path.Data(), "w");
#endif
if (!f) {
Error("MakeProjectParProofInf", "cannot create file '%s' (errno: %d)",
path.Data(), TSystem::GetErrno());
return -1;
}
fprintf(f, "Int_t SETUP()\n");
fprintf(f, "{\n");
fprintf(f, "\n");
fprintf(f, "//\n");
fprintf(f, "// The environment variables ROOTPROOFLITE and ROOTPROOFCLIENT can be used to\n");
fprintf(f, "// adapt the macro to the calling environment\n");
fprintf(f, "//\n");
fprintf(f, "// if (gSystem->Getenv(\"ROOTPROOFLITE\")) {\n");
fprintf(f, "// Printf(\"event-SETUP: PROOF-Lite node (session has %%s workers)\",\n");
fprintf(f, "// gSystem->Getenv(\"ROOTPROOFLITE\"));\n");
fprintf(f, "// } else if (gSystem->Getenv(\"ROOTPROOFCLIENT\")) {\n");
fprintf(f, "// Printf(\"event-SETUP: PROOF client\");\n");
fprintf(f, "// } else {\n");
fprintf(f, "// Printf(\"event-SETUP: standard PROOF node\");\n");
fprintf(f, "// }\n");
fprintf(f, "\n");
fprintf(f, " if (gSystem->Load(\"lib%s\") == -1)\n", pack);
fprintf(f, " return -1;\n");
fprintf(f, " return 0;\n");
fprintf(f, "}\n");
fprintf(f, "\n");
fclose(f);
return 0;
}
void TFile::ReadStreamerInfo()
{
TList *list = GetStreamerInfoList();
if (!list) {
MakeZombie();
return;
}
list->SetOwner(kFALSE);
if (gDebug > 0) Info("ReadStreamerInfo", "called for file %s",GetName());
TStreamerInfo *info;
Int_t version = fVersion;
if (version > 1000000) version -= 1000000;
if (version < 53419 || (59900 < version && version < 59907)) {
TObjLink *lnk = list->FirstLink();
while (lnk) {
info = (TStreamerInfo*)lnk->GetObject();
if (info == 0 || info->IsA() != TStreamerInfo::Class()) {
lnk = lnk->Next();
continue;
}
TIter next(info->GetElements());
TStreamerElement *element;
while ((element = (TStreamerElement*) next())) {
TStreamerBase *base = dynamic_cast<TStreamerBase*>(element);
if (!base) continue;
if (base->GetBaseCheckSum() != 0) continue;
TStreamerInfo *baseinfo = (TStreamerInfo*)list->FindObject(base->GetName());
if (baseinfo) {
base->SetBaseCheckSum(baseinfo->GetCheckSum());
}
}
lnk = lnk->Next();
}
}
for (int mode=0;mode<2; ++mode) {
TObjLink *lnk = list->FirstLink();
while (lnk) {
info = (TStreamerInfo*)lnk->GetObject();
if (info == 0) {
lnk = lnk->Next();
continue;
}
if (info->IsA() != TStreamerInfo::Class()) {
if (mode==1) {
TObject *obj = (TObject*)info;
if (strcmp(obj->GetName(),"listOfRules")==0) {
#if 0
TList *listOfRules = (TList*)obj;
TObjLink *rulelnk = listOfRules->FirstLink();
while (rulelnk) {
TObjString *rule = (TObjString*)rulelnk->GetObject();
TClass::AddRule( rule->String().Data() );
rulelnk = rulelnk->Next();
}
#endif
} else {
Warning("ReadStreamerInfo","%s has a %s in the list of TStreamerInfo.", GetName(), info->IsA()->GetName());
}
info->SetBit(kCanDelete);
}
lnk = lnk->Next();
continue;
}
if (info->GetElements()==0) {
Warning("ReadStreamerInfo","The StreamerInfo for %s does not have a list of elements.",info->GetName());
lnk = lnk->Next();
continue;
}
TObject *element = info->GetElements()->UncheckedAt(0);
Bool_t isstl = element && strcmp("This",element->GetName())==0;
if ( (!isstl && mode ==0) || (isstl && mode ==1) ) {
info->BuildCheck(this);
Int_t uid = info->GetNumber();
Int_t asize = fClassIndex->GetSize();
if (uid >= asize && uid <100000) fClassIndex->Set(2*asize);
if (uid >= 0 && uid < fClassIndex->GetSize()) fClassIndex->fArray[uid] = 1;
else {
printf("ReadStreamerInfo, class:%s, illegal uid=%d\n",info->GetName(),uid);
}
if (gDebug > 0) printf(" -class: %s version: %d info read at slot %d\n",info->GetName(), info->GetClassVersion(),uid);
}
lnk = lnk->Next();
}
}
fClassIndex->fArray[0] = 0;
list->Clear();
delete list;
}
void TFile::SetReadStreamerInfo(Bool_t readinfo)
{
fgReadInfo = readinfo;
}
Bool_t TFile::GetReadStreamerInfo()
{
return fgReadInfo;
}
void TFile::ShowStreamerInfo()
{
TList *list = GetStreamerInfoList();
if (!list) return;
list->ls();
delete list;
}
UShort_t TFile::WriteProcessID(TProcessID *pidd)
{
TProcessID *pid = pidd;
if (!pid) pid = TProcessID::GetPID();
TObjArray *pids = GetListOfProcessIDs();
Int_t npids = GetNProcessIDs();
for (Int_t i=0;i<npids;i++) {
if (pids->At(i) == pid) return (UShort_t)i;
}
this->SetBit(TFile::kHasReferences);
pids->AddAtAndExpand(pid,npids);
pid->IncrementCount();
char name[32];
snprintf(name,32,"ProcessID%d",npids);
this->WriteTObject(pid,name);
this->IncrementProcessIDs();
if (gDebug > 0) {
Info("WriteProcessID", "name=%s, file=%s", name, GetName());
}
return (UShort_t)npids;
}
void TFile::WriteStreamerInfo()
{
if (!fWritable) return;
if (!fClassIndex) return;
if (fIsPcmFile) return;
if (fClassIndex->fArray[0] == 0) return;
if (gDebug > 0) Info("WriteStreamerInfo", "called for file %s",GetName());
SafeDelete(fInfoCache);
TIter next(gROOT->GetListOfStreamerInfo());
TStreamerInfo *info;
TList list;
TList listOfRules;
listOfRules.SetOwner(kTRUE);
listOfRules.SetName("listOfRules");
std::set<TClass*> classSet;
while ((info = (TStreamerInfo*)next())) {
Int_t uid = info->GetNumber();
if (fClassIndex->fArray[uid]) {
list.Add(info);
if (gDebug > 0) printf(" -class: %s info number %d saved\n",info->GetName(),uid);
TClass *clinfo = info->GetClass();
if (clinfo && clinfo->GetSchemaRules()) {
if ( classSet.find( clinfo ) == classSet.end() ) {
if (gDebug > 0) printf(" -class: %s stored the I/O customization rules\n",info->GetName());
TObjArrayIter it( clinfo->GetSchemaRules()->GetRules() );
ROOT::TSchemaRule *rule;
while( (rule = (ROOT::TSchemaRule*)it.Next()) ) {
TObjString *obj = new TObjString();
rule->AsString(obj->String());
listOfRules.Add(obj);
}
classSet.insert(clinfo);
}
}
}
}
fClassIndex->fArray[0] = 2;
if (listOfRules.GetEntries()) {
list.Add(&listOfRules);
}
Int_t compress = fCompress;
fCompress = 1;
if (fSeekInfo) MakeFree(fSeekInfo,fSeekInfo+fNbytesInfo-1);
TKey key(&list,"StreamerInfo",GetBestBuffer(), this);
fKeys->Remove(&key);
fSeekInfo = key.GetSeekKey();
fNbytesInfo = key.GetNbytes();
SumBuffer(key.GetObjlen());
key.WriteFile(0);
fClassIndex->fArray[0] = 0;
fCompress = compress;
list.RemoveLast();
}
TFile *TFile::OpenFromCache(const char *name, Option_t *, const char *ftitle,
Int_t compress, Int_t netopt)
{
TFile *f = 0;
if (fgCacheFileDir == "") {
::Warning("TFile::OpenFromCache",
"you want to read through a cache, but you have no valid cache "
"directory set - reading remotely");
::Info("TFile::OpenFromCache", "set cache directory using TFile::SetCacheFileDir()");
} else {
TUrl fileurl(name);
TUrl tagurl;
if ((!strcmp(fileurl.GetProtocol(), "file"))) {
if (!fgCacheFileForce)
::Warning("TFile::OpenFromCache",
"you want to read through a cache, but you are reading "
"local files - CACHEREAD disabled");
} else {
TString cachefilepath;
TString cachefilepathbasedir;
cachefilepath = fgCacheFileDir;
cachefilepath += fileurl.GetFile();
cachefilepathbasedir = gSystem->DirName(cachefilepath);
if ((gSystem->mkdir(cachefilepathbasedir, kTRUE) < 0) &&
(gSystem->AccessPathName(cachefilepathbasedir, kFileExists))) {
::Warning("TFile::OpenFromCache","you want to read through a cache, but I "
"cannot create the directory %s - CACHEREAD disabled",
cachefilepathbasedir.Data());
} else {
if (strlen(fileurl.GetAnchor())) {
cachefilepath += "__";
cachefilepath += fileurl.GetAnchor();
fileurl.SetAnchor("");
}
if (strstr(name,"zip=")) {
TString urloptions = fileurl.GetOptions();
TString newoptions;
TObjArray *objOptions = urloptions.Tokenize("&");
Int_t optioncount = 0;
TString zipname;
for (Int_t n = 0; n < objOptions->GetEntries(); n++) {
TString loption = ((TObjString*)objOptions->At(n))->GetName();
TObjArray *objTags = loption.Tokenize("=");
if (objTags->GetEntries() == 2) {
TString key = ((TObjString*)objTags->At(0))->GetName();
TString value = ((TObjString*)objTags->At(1))->GetName();
if (key.CompareTo("zip", TString::kIgnoreCase)) {
if (optioncount!=0) {
newoptions += "&";
}
newoptions += key;
newoptions += "=";
newoptions += value;
++optioncount;
} else {
zipname = value;
}
}
delete objTags;
}
delete objOptions;
fileurl.SetOptions(newoptions.Data());
cachefilepath += "__";
cachefilepath += zipname;
fileurl.SetAnchor("");
}
Bool_t need2copy = kFALSE;
Long_t id;
Long64_t size;
Long_t flags;
Long_t modtime;
if (!gSystem->GetPathInfo(cachefilepath, &id, &size, &flags, &modtime)) {
if (!fgCacheFileDisconnected) {
char cacheblock[256];
char remotblock[256];
TString cfurl;
cfurl = cachefilepath;
cfurl += "?filetype=raw";
TUrl rurl(name);
TString ropt = rurl.GetOptions();
ropt += "&filetype=raw";
rurl.SetOptions(ropt);
Bool_t forcedcache = fgCacheFileForce;
fgCacheFileForce = kFALSE;
TFile *cachefile = TFile::Open(cfurl, "READ");
TFile *remotfile = TFile::Open(rurl.GetUrl(), "READ");
fgCacheFileForce = forcedcache;
if (!cachefile) {
need2copy = kTRUE;
::Error("TFile::OpenFromCache",
"cannot open the cache file to check cache consistency");
return 0;
}
if (!remotfile) {
::Error("TFile::OpenFromCache",
"cannot open the remote file to check cache consistency");
return 0;
}
cachefile->Seek(0);
remotfile->Seek(0);
if ((!cachefile->ReadBuffer(cacheblock,256)) &&
(!remotfile->ReadBuffer(remotblock,256))) {
if (memcmp(cacheblock, remotblock, 256)) {
::Warning("TFile::OpenFromCache", "the header of the cache file "
"differs from the remote file - forcing an update");
need2copy = kTRUE;
}
} else {
::Warning("TFile::OpenFromCache", "the header of the cache and/or "
"remote file are not readable - forcing an update");
need2copy = kTRUE;
}
delete remotfile;
delete cachefile;
}
} else {
need2copy = kTRUE;
}
Bool_t forcedcache = fgCacheFileForce;
fgCacheFileForce = kFALSE;
if (need2copy && !TFile::Cp(name, cachefilepath)) {
::Warning("TFile::OpenFromCache", "you want to read through a cache, but I "
"cannot make a cache copy of %s - CACHEREAD disabled",
cachefilepathbasedir.Data());
fgCacheFileForce = forcedcache;
if (fgOpenTimeout != 0)
return 0;
} else {
fgCacheFileForce = forcedcache;
::Info("TFile::OpenFromCache", "using local cache copy of %s [%s]",
name, cachefilepath.Data());
fileurl.SetProtocol("file");
fileurl.SetFile(cachefilepath);
tagurl = fileurl;
TString tagfile;
tagfile = cachefilepath;
tagfile += ".ROOT.cachefile";
tagurl.SetFile(tagfile);
gSystem->Symlink(gSystem->BaseName(cachefilepath), tagfile);
return TFile::Open(fileurl.GetUrl(), "READ", ftitle, compress, netopt);
}
}
}
}
return f;
}
TFile *TFile::Open(const char *url, Option_t *options, const char *ftitle,
Int_t compress, Int_t netopt)
{
TPluginHandler *h;
TFile *f = 0;
EFileType type = kFile;
if (!url || strlen(url) <= 0) {
::Error("TFile::Open", "no url specified");
return f;
}
TString expandedUrl(url);
gSystem->ExpandPathName(expandedUrl);
TString opts(options);
Int_t ito = opts.Index("TIMEOUT=");
if (ito != kNPOS) {
TString sto = opts(ito + strlen("TIMEOUT="), opts.Length());
while (!(sto.IsDigit()) && !(sto.IsNull())) { sto.Remove(sto.Length()-1,1); }
if (!(sto.IsNull())) {
Int_t toms = sto.Atoi() * 1000;
if (gDebug > 0) ::Info("TFile::Open", "timeout of %d millisec requested", toms);
sto.Insert(0, "TIMEOUT=");
opts.ReplaceAll(sto, "");
TFileOpenHandle *fh = TFile::AsyncOpen(expandedUrl, opts, ftitle, compress, netopt);
TFile::EAsyncOpenStatus aos = TFile::kAOSNotAsync;
aos = TFile::GetAsyncOpenStatus(fh);
Int_t xtms = toms;
while (aos != TFile::kAOSNotAsync && aos == TFile::kAOSInProgress && xtms > 0) {
gSystem->Sleep(1);
xtms -= 1;
aos = TFile::GetAsyncOpenStatus(fh);
}
if (aos == TFile::kAOSNotAsync || aos == TFile::kAOSSuccess) {
f = TFile::Open(fh);
if (gDebug > 0) {
if (aos == TFile::kAOSSuccess)
::Info("TFile::Open", "waited %d millisec for asynchronous open", toms - xtms);
else
::Info("TFile::Open", "timeout option not supported (requires asynchronous"
" open support)");
}
} else {
if (xtms <= 0)
::Error("TFile::Open", "timeout expired while opening '%s'", expandedUrl.Data());
SafeDelete(fh);
}
return f;
} else {
::Warning("TFile::Open", "incomplete 'TIMEOUT=' option specification - ignored");
opts.ReplaceAll("TIMEOUT=", "");
}
}
const char *option = opts;
TString namelist(expandedUrl);
Ssiz_t ip = namelist.Index("|");
Bool_t rediroutput = (ip != kNPOS &&
ip != namelist.Length()-1 && gDebug <= 0) ? kTRUE : kFALSE;
RedirectHandle_t rh;
if (rediroutput) {
TString outf = ".TFileOpen_";
FILE *fout = gSystem->TempFileName(outf);
if (fout) {
fclose(fout);
gSystem->RedirectOutput(outf, "w", &rh);
}
}
TString name, n;
Ssiz_t from = 0;
while (namelist.Tokenize(n, from, "|") && !f) {
if (!strcasecmp(option, "CACHEREAD") ||
((!strcasecmp(option,"READ") || !option[0]) && fgCacheFileForce)) {
if ((f = TFile::OpenFromCache(n, option, ftitle, compress, netopt)))
return f;
}
IncrementFileCounter();
TUrl urlname(n, kTRUE);
name = urlname.GetUrl();
if (fgAsyncOpenRequests && (fgAsyncOpenRequests->GetSize() > 0)) {
TIter nxr(fgAsyncOpenRequests);
TFileOpenHandle *fh = 0;
while ((fh = (TFileOpenHandle *)nxr()))
if (fh->Matches(name))
return TFile::Open(fh);
}
TString urlOptions(urlname.GetOptions());
if (urlOptions.BeginsWith("pmerge") || urlOptions.Contains("&pmerge") || urlOptions.Contains(" pmerge")) {
type = kMerge;
f = (TFile*) gROOT->ProcessLineFast(TString::Format("new TParallelMergingFile(\"%s\",\"%s\",\"%s\",%d)",n.Data(),option,ftitle,compress));
} else {
TString lfname = gEnv->GetValue("Path.Localroot", "");
type = GetType(name, option, &lfname);
if (type == kLocal) {
if (lfname.IsNull()) {
urlname.SetHost("");
urlname.SetProtocol("file");
lfname = urlname.GetUrl();
}
f = new TFile(lfname.Data(), option, ftitle, compress);
} else if (type == kNet) {
if ((h = gROOT->GetPluginManager()->FindHandler("TFile", name))) {
if (h->LoadPlugin() == -1)
return 0;
f = (TFile*) h->ExecPlugin(5, name.Data(), option, ftitle, compress, netopt);
}
} else if (type == kWeb) {
if ((h = gROOT->GetPluginManager()->FindHandler("TFile", name))) {
if (h->LoadPlugin() == -1)
return 0;
f = (TFile*) h->ExecPlugin(2, name.Data(), option);
}
} else if (type == kFile) {
if ((h = gROOT->GetPluginManager()->FindHandler("TFile", name)) &&
h->LoadPlugin() == 0) {
name.ReplaceAll("file:", "");
f = (TFile*) h->ExecPlugin(4, name.Data(), option, ftitle, compress);
} else
f = new TFile(name.Data(), option, ftitle, compress);
} else {
if ((h = gROOT->GetPluginManager()->FindHandler("TFile", name.Data()))) {
if (h->LoadPlugin() == -1)
return 0;
TClass *cl = TClass::GetClass(h->GetClass());
if (cl && cl->InheritsFrom("TNetFile"))
f = (TFile*) h->ExecPlugin(5, name.Data(), option, ftitle, compress, netopt);
else
f = (TFile*) h->ExecPlugin(4, name.Data(), option, ftitle, compress);
} else {
f = TFile::Open(urlname.GetFileAndOptions(), option, ftitle, compress);
}
}
}
if (f && f->IsZombie()) {
TString newUrl = f->GetNewUrl();
delete f;
if( newUrl.Length() && gEnv->GetValue("TFile.CrossProtocolRedirects", 1) )
f = TFile::Open( newUrl, option, ftitle, compress );
else
f = 0;
}
}
if (rediroutput) {
gSystem->RedirectOutput(0, "", &rh);
if (!f)
gSystem->ShowOutput(&rh);
gSystem->Unlink(rh.fFile);
}
if (type != kLocal && type != kFile &&
f && f->IsWritable() && !f->IsRaw()) {
new TFileCacheWrite(f, 1);
}
return f;
}
TFileOpenHandle *TFile::AsyncOpen(const char *url, Option_t *option,
const char *ftitle, Int_t compress,
Int_t netopt)
{
TFileOpenHandle *fh = 0;
TPluginHandler *h;
TFile *f = 0;
Bool_t notfound = kTRUE;
if (!url || strlen(url) <= 0) {
::Error("TFile::AsyncOpen", "no url specified");
return fh;
}
TString namelist(url);
gSystem->ExpandPathName(namelist);
Ssiz_t ip = namelist.Index("|");
Bool_t rediroutput = (ip != kNPOS &&
ip != namelist.Length()-1 && gDebug <= 0) ? kTRUE : kFALSE;
RedirectHandle_t rh;
if (rediroutput) {
TString outf = ".TFileAsyncOpen_";
FILE *fout = gSystem->TempFileName(outf);
if (fout) {
fclose(fout);
gSystem->RedirectOutput(outf, "w", &rh);
}
}
TString name, n;
Ssiz_t from = 0;
while (namelist.Tokenize(n, from, "|") && !f) {
TUrl urlname(n, kTRUE);
name = urlname.GetUrl();
EFileType type = GetType(name, option);
if (type == kNet) {
if ((h = gROOT->GetPluginManager()->FindHandler("TFile", name)) &&
(!strcmp(h->GetClass(),"TXNetFile") || !strcmp(h->GetClass(),"TNetXNGFile"))
&& h->LoadPlugin() == 0) {
f = (TFile*) h->ExecPlugin(6, name.Data(), option, ftitle, compress, netopt, kTRUE);
notfound = kFALSE;
}
}
if ((h = gROOT->GetPluginManager()->FindHandler("TFile", name)) &&
!strcmp(h->GetClass(),"TAlienFile") && h->LoadPlugin() == 0) {
f = (TFile*) h->ExecPlugin(5, name.Data(), option, ftitle, compress, kTRUE);
notfound = kFALSE;
}
}
if (rediroutput) {
gSystem->RedirectOutput(0, "", &rh);
if (!notfound && !f)
gSystem->ShowOutput(&rh);
gSystem->Unlink(rh.fFile);
}
if (notfound) {
SafeDelete(f);
fh = new TFileOpenHandle(name, option, ftitle, compress, netopt);
} else if (f) {
fh = new TFileOpenHandle(f);
}
if (fh) {
if (!fgAsyncOpenRequests)
fgAsyncOpenRequests = new TList;
fgAsyncOpenRequests->Add(fh);
}
return fh;
}
TFile *TFile::Open(TFileOpenHandle *fh)
{
TFile *f = 0;
if (fh && fgAsyncOpenRequests) {
fgAsyncOpenRequests->Remove(fh);
if ((f = fh->GetFile()) && !(f->IsZombie())) {
Bool_t cr = (!strcmp(f->GetOption(),"CREATE") ||
!strcmp(f->GetOption(),"RECREATE") ||
!strcmp(f->GetOption(),"NEW")) ? kTRUE : kFALSE;
f->Init(cr);
} else {
f = TFile::Open(fh->GetName(), fh->GetOpt(), fh->GetTitle(),
fh->GetCompress(), fh->GetNetOpt());
}
if (f) f->fAsyncHandle = fh;
}
return f;
}
Int_t TFile::SysOpen(const char *pathname, Int_t flags, UInt_t mode)
{
#if defined(R__WINGCC)
return ::open(pathname, flags | O_BINARY, mode);
#elif defined(R__SEEK64)
return ::open64(pathname, flags, mode);
#else
return ::open(pathname, flags, mode);
#endif
}
Int_t TFile::SysClose(Int_t fd)
{
if (fd < 0) return 0;
return ::close(fd);
}
Int_t TFile::SysRead(Int_t fd, void *buf, Int_t len)
{
return ::read(fd, buf, len);
}
Int_t TFile::SysWrite(Int_t fd, const void *buf, Int_t len)
{
return ::write(fd, buf, len);
}
Long64_t TFile::SysSeek(Int_t fd, Long64_t offset, Int_t whence)
{
#if defined (R__SEEK64)
return ::lseek64(fd, offset, whence);
#elif defined(WIN32)
return ::_lseeki64(fd, offset, whence);
#else
return ::lseek(fd, offset, whence);
#endif
}
Int_t TFile::SysStat(Int_t, Long_t *id, Long64_t *size, Long_t *flags,
Long_t *modtime)
{
return gSystem->GetPathInfo(fRealName, id, size, flags, modtime);
}
Int_t TFile::SysSync(Int_t fd)
{
if (TestBit(kDevNull)) return 0;
#ifndef WIN32
return ::fsync(fd);
#else
return ::_commit(fd);
#endif
}
Long64_t TFile::GetBytesWritten() const
{
return fCacheWrite ? fCacheWrite->GetBytesInCache() + fBytesWrite : fBytesWrite;
}
Long64_t TFile::GetFileBytesRead()
{
return fgBytesRead;
}
Long64_t TFile::GetFileBytesWritten()
{
return fgBytesWrite;
}
Int_t TFile::GetFileReadCalls()
{
return fgReadCalls;
}
Int_t TFile::GetReadaheadSize()
{
return fgReadaheadSize;
}
void TFile::SetReadaheadSize(Int_t bytes) { fgReadaheadSize = bytes; }
void TFile::SetFileBytesRead(Long64_t bytes) { fgBytesRead = bytes; }
void TFile::SetFileBytesWritten(Long64_t bytes) { fgBytesWrite = bytes; }
void TFile::SetFileReadCalls(Int_t readcalls) { fgReadCalls = readcalls; }
Long64_t TFile::GetFileCounter() { return fgFileCounter; }
void TFile::IncrementFileCounter() { fgFileCounter++; }
Bool_t TFile::SetCacheFileDir(const char *cachedir, Bool_t operatedisconnected,
Bool_t forcecacheread )
{
TString cached = cachedir;
if (!cached.EndsWith("/"))
cached += "/";
if (gSystem->AccessPathName(cached, kFileExists)) {
gSystem->mkdir(cached, kTRUE);
if (gSystem->AccessPathName(cached, kFileExists)) {
::Error("TFile::SetCacheFileDir", "no suffcient permissions on cache directory %s or cannot create it", cachedir);
fgCacheFileDir = "";
return kFALSE;
}
gSystem->Chmod(cached, 0700);
}
if (gSystem->AccessPathName(cached, kWritePermission))
gSystem->Chmod(cached, 0700);
fgCacheFileDir = cached;
fgCacheFileDisconnected = operatedisconnected;
fgCacheFileForce = forcecacheread;
return kTRUE;
}
const char *TFile::GetCacheFileDir()
{
return fgCacheFileDir;
}
Bool_t TFile::ShrinkCacheFileDir(Long64_t shrinksize, Long_t cleanupinterval)
{
if (fgCacheFileDir == "") {
return kFALSE;
}
Long_t id;
Long64_t size;
Long_t flags;
Long_t modtime;
TString cachetagfile = fgCacheFileDir;
cachetagfile += ".tag.ROOT.cache";
if (!gSystem->GetPathInfo(cachetagfile, &id, &size, &flags, &modtime)) {
Long_t lastcleanuptime = ((Long_t)time(0) - modtime);
if (lastcleanuptime < cleanupinterval) {
::Info("TFile::ShrinkCacheFileDir", "clean-up is skipped - last cleanup %lu seconds ago - you requested %lu", lastcleanuptime, cleanupinterval);
return kTRUE;
}
}
cachetagfile += "?filetype=raw";
TFile *tagfile = 0;
if (!(tagfile = TFile::Open(cachetagfile, "RECREATE"))) {
::Error("TFile::ShrinkCacheFileDir", "cannot create the cache tag file %s", cachetagfile.Data());
return kFALSE;
}
TString cmd;
#if defined(R__WIN32)
cmd = "echo <TFile::ShrinkCacheFileDir>: cleanup to be implemented";
#elif defined(R__MACOSX)
cmd.Format("perl -e 'my $cachepath = \"%s\"; my $cachesize = %lld;my $findcommand=\"find $cachepath -type f -exec stat -f \\\"\\%%a::\\%%N::\\%%z\\\" \\{\\} \\\\\\;\";my $totalsize=0;open FIND, \"$findcommand | sort -k 1 |\";while (<FIND>) { my ($accesstime, $filename, $filesize) = split \"::\",$_; $totalsize += $filesize;if ($totalsize > $cachesize) {if ( ( -e \"${filename}.ROOT.cachefile\" ) && ( -e \"${filename}\" ) ) {unlink \"$filename.ROOT.cachefile\";unlink \"$filename\";}}}close FIND;' ", fgCacheFileDir.Data(),shrinksize);
#else
cmd.Format("perl -e 'my $cachepath = \"%s\"; my $cachesize = %lld;my $findcommand=\"find $cachepath -type f -exec stat -c \\\"\\%%x::\\%%n::\\%%s\\\" \\{\\} \\\\\\;\";my $totalsize=0;open FIND, \"$findcommand | sort -k 1 |\";while (<FIND>) { my ($accesstime, $filename, $filesize) = split \"::\",$_; $totalsize += $filesize;if ($totalsize > $cachesize) {if ( ( -e \"${filename}.ROOT.cachefile\" ) && ( -e \"${filename}\" ) ) {unlink \"$filename.ROOT.cachefile\";unlink \"$filename\";}}}close FIND;' ", fgCacheFileDir.Data(),shrinksize);
#endif
tagfile->WriteBuffer(cmd, 4096);
delete tagfile;
if ((gSystem->Exec(cmd)) != 0) {
::Error("TFile::ShrinkCacheFileDir", "error executing clean-up script");
return kFALSE;
}
return kTRUE;
}
UInt_t TFile::SetOpenTimeout(UInt_t timeout)
{
UInt_t to = fgOpenTimeout;
fgOpenTimeout = timeout;
return to;
}
UInt_t TFile::GetOpenTimeout()
{
return fgOpenTimeout;
}
Bool_t TFile::SetOnlyStaged(Bool_t onlystaged)
{
Bool_t f = fgOnlyStaged;
fgOnlyStaged = onlystaged;
return f;
}
Bool_t TFile::GetOnlyStaged()
{
return fgOnlyStaged;
}
Bool_t TFile::Matches(const char *url)
{
TUrl u(url);
if (!strcmp(u.GetFile(), fUrl.GetFile())) {
if (u.GetPort() == fUrl.GetPort()) {
if (!strcmp(u.GetHostFQDN(), fUrl.GetHostFQDN())) {
return kTRUE;
}
}
}
return kFALSE;
}
Bool_t TFileOpenHandle::Matches(const char *url)
{
if (fFile) {
return fFile->Matches(url);
} else if (fName.Length() > 0){
TUrl u(url);
TUrl uref(fName);
if (!strcmp(u.GetFile(), uref.GetFile())) {
if (u.GetPort() == uref.GetPort()) {
if (!strcmp(u.GetHostFQDN(), uref.GetHostFQDN())) {
return kTRUE;
}
}
}
}
return kFALSE;
}
TFile::EFileType TFile::GetType(const char *name, Option_t *option, TString *prefix)
{
EFileType type = kDefault;
TPMERegexp re("^(root|xroot).*", "i");
if (re.Match(name)) {
type = kNet;
Bool_t localFile = kFALSE;
TUrl url(name);
Bool_t forceRemote = gEnv->GetValue("Path.ForceRemote", 0);
forceRemote = (forceRemote) ? kTRUE : gEnv->GetValue("TFile.ForceRemote", 0);
TString opts = url.GetOptions();
if (opts.Contains("remote=1"))
forceRemote = kTRUE;
else if (opts.Contains("remote=0"))
forceRemote = kFALSE;
if (!forceRemote) {
localFile = gSystem->IsPathLocal(name);
if (localFile) {
const char *fname = url.GetFileAndOptions();
TString lfname;
if (fname[0] == '/') {
if (prefix)
lfname.Form("%s%s", prefix->Data(), fname);
else
lfname = fname;
} else if (fname[0] == '~' || fname[0] == '$') {
lfname = fname;
} else {
lfname.Form("%s/%s", gSystem->HomeDirectory(), fname);
}
TString opt = option;
Bool_t read = (opt.IsNull() ||
!opt.CompareTo("READ", TString::kIgnoreCase)) ? kTRUE : kFALSE;
if (read) {
char *fn;
if ((fn = gSystem->ExpandPathName(TUrl(lfname).GetFile()))) {
if (gSystem->AccessPathName(fn, kReadPermission))
localFile = kFALSE;
delete [] fn;
}
}
if (localFile && prefix)
*prefix = lfname;
}
}
type = (localFile) ? kLocal : type;
} else if (TPMERegexp("^(http[s]?|s3http[s]?|[a]?s3|gs|gshttp[s]?){1}:", "i").Match(name)) {
type = kWeb;
} else if (!strncmp(name, "file:", 5)) {
type = kFile;
}
return type;
}
TFile::EAsyncOpenStatus TFile::GetAsyncOpenStatus(const char* name)
{
if (fgAsyncOpenRequests && (fgAsyncOpenRequests->GetSize() > 0)) {
TIter nxr(fgAsyncOpenRequests);
TFileOpenHandle *fh = 0;
while ((fh = (TFileOpenHandle *)nxr()))
if (fh->Matches(name))
return TFile::GetAsyncOpenStatus(fh);
}
R__LOCKGUARD2(gROOTMutex);
TSeqCollection *of = gROOT->GetListOfFiles();
if (of && (of->GetSize() > 0)) {
TIter nxf(of);
TFile *f = 0;
while ((f = (TFile *)nxf()))
if (f->Matches(name))
return f->GetAsyncOpenStatus();
}
return kAOSNotAsync;
}
TFile::EAsyncOpenStatus TFile::GetAsyncOpenStatus(TFileOpenHandle *handle)
{
if (handle && handle->fFile) {
if (!handle->fFile->IsZombie())
return handle->fFile->GetAsyncOpenStatus();
else
return TFile::kAOSFailure;
}
return TFile::kAOSNotAsync;
}
const TUrl *TFile::GetEndpointUrl(const char* name)
{
if (fgAsyncOpenRequests && (fgAsyncOpenRequests->GetSize() > 0)) {
TIter nxr(fgAsyncOpenRequests);
TFileOpenHandle *fh = 0;
while ((fh = (TFileOpenHandle *)nxr()))
if (fh->Matches(name))
if (fh->fFile)
return fh->fFile->GetEndpointUrl();
}
R__LOCKGUARD2(gROOTMutex);
TSeqCollection *of = gROOT->GetListOfFiles();
if (of && (of->GetSize() > 0)) {
TIter nxf(of);
TFile *f = 0;
while ((f = (TFile *)nxf()))
if (f->Matches(name))
return f->GetEndpointUrl();
}
return (const TUrl *)0;
}
void TFile::CpProgress(Long64_t bytesread, Long64_t size, TStopwatch &watch)
{
fprintf(stderr, "[TFile::Cp] Total %.02f MB\t|", (Double_t)size/1048576);
for (int l = 0; l < 20; l++) {
if (size > 0) {
if (l < 20*bytesread/size)
fprintf(stderr, "=");
else if (l == 20*bytesread/size)
fprintf(stderr, ">");
else if (l > 20*bytesread/size)
fprintf(stderr, ".");
} else
fprintf(stderr, "=");
}
gSystem->ProcessEvents();
watch.Stop();
Double_t lCopy_time = watch.RealTime();
fprintf(stderr, "| %.02f %% [%.01f MB/s]\r",
100.0*(size?(bytesread/((float)size)):1), (lCopy_time>0.)?bytesread/lCopy_time/1048576.:0.);
watch.Continue();
}
Bool_t TFile::Cp(const char *dst, Bool_t progressbar, UInt_t buffersize)
{
Bool_t rmdestiferror = kFALSE;
TStopwatch watch;
Bool_t success = kFALSE;
TUrl dURL(dst, kTRUE);
TString oopt = "RECREATE";
TString ourl = dURL.GetUrl();
TString raw = "filetype=raw";
TString opt = dURL.GetOptions();
if (opt != "") opt += "&";
opt += raw;
if (!strcmp(dURL.GetProtocol(), "alien"))
opt += TString::Format("&source=%s", GetName());
dURL.SetOptions(opt);
char *copybuffer = 0;
TFile *sfile = this;
TFile *dfile = 0;
if (TFile::GetType(ourl, "") == TFile::kNet) {
if (gSystem->AccessPathName(ourl)) {
oopt = "NEW";
opt += "&mkpath=1";
dURL.SetOptions(opt);
}
}
if (!(dfile = TFile::Open(dURL.GetUrl(), oopt))) {
::Error("TFile::Cp", "cannot open destination file %s", dst);
goto copyout;
}
rmdestiferror = kTRUE;
sfile->Seek(0);
dfile->Seek(0);
copybuffer = new char[buffersize];
if (!copybuffer) {
::Error("TFile::Cp", "cannot allocate the copy buffer");
goto copyout;
}
Bool_t readop;
Bool_t writeop;
Long64_t read;
Long64_t written;
Long64_t totalread;
Long64_t filesize;
Long64_t b00;
filesize = sfile->GetSize();
totalread = 0;
watch.Start();
b00 = sfile->GetBytesRead();
do {
if (progressbar) CpProgress(totalread, filesize,watch);
Long64_t b1 = sfile->GetBytesRead() - b00;
Long64_t readsize;
if (filesize - b1 > (Long64_t)buffersize) {
readsize = buffersize;
} else {
readsize = filesize - b1;
}
if (readsize == 0) break;
Long64_t b0 = sfile->GetBytesRead();
sfile->Seek(totalread,TFile::kBeg);
readop = sfile->ReadBuffer(copybuffer, (Int_t)readsize);
read = sfile->GetBytesRead() - b0;
if ((read <= 0) || readop) {
::Error("TFile::Cp", "cannot read from source file %s. readsize=%lld read=%lld readop=%d",
sfile->GetName(), readsize, read, readop);
goto copyout;
}
Long64_t w0 = dfile->GetBytesWritten();
writeop = dfile->WriteBuffer(copybuffer, (Int_t)read);
written = dfile->GetBytesWritten() - w0;
if ((written != read) || writeop) {
::Error("TFile::Cp", "cannot write %lld bytes to destination file %s", read, dst);
goto copyout;
}
totalread += read;
} while (read == (Long64_t)buffersize);
if (progressbar) {
CpProgress(totalread, filesize,watch);
fprintf(stderr, "\n");
}
success = kTRUE;
copyout:
if (dfile) dfile->Close();
if (dfile) delete dfile;
if (copybuffer) delete[] copybuffer;
if (rmdestiferror && (success != kTRUE))
gSystem->Unlink(dst);
watch.Stop();
watch.Reset();
return success;
}
Bool_t TFile::Cp(const char *src, const char *dst, Bool_t progressbar,
UInt_t buffersize)
{
TUrl sURL(src, kTRUE);
TString raw = "filetype=raw";
TString opt = sURL.GetOptions();
if (opt != "") opt += "&";
opt += raw;
opt += TString::Format("&cachesz=%d&readaheadsz=%d&rmpolicy=1", 4*buffersize, 2*buffersize);
sURL.SetOptions(opt);
TFile *sfile = 0;
Bool_t success = kFALSE;
if (!(sfile = TFile::Open(sURL.GetUrl(), "READ"))) {
::Error("TFile::Cp", "cannot open source file %s", src);
} else {
success = sfile->Cp(dst, progressbar, buffersize);
}
if (sfile) sfile->Close();
if (sfile) delete sfile;
return success;
}
#if defined(R__neverLINUX) && !defined(R__WINGCC)
Bool_t TFile::ReadBufferAsync(Long64_t offset, Int_t len)
{
if (IsA() != TFile::Class())
return kTRUE;
int advice = POSIX_FADV_WILLNEED;
if (len == 0) {
advice = POSIX_FADV_NORMAL;
}
Double_t start = 0;
if (gPerfStats != 0) start = TTimeStamp();
#if defined(R__SEEK64)
Int_t result = posix_fadvise64(fD, offset, len, advice);
#else
Int_t result = posix_fadvise(fD, offset, len, advice);
#endif
if (gPerfStats != 0) {
gPerfStats->FileReadEvent(this, len, start);
}
return (result != 0);
}
#else
Bool_t TFile::ReadBufferAsync(Long64_t, Int_t)
{
return kTRUE;
}
#endif
Int_t TFile::GetBytesToPrefetch() const
{
TFileCacheRead *cr = 0;
if ((cr = GetCacheRead())) {
Int_t bytes = cr->GetBufferSize() / 4 * 3;
return ((bytes < 0) ? 0 : bytes);
}
return 0;
}