#include "TDCacheFile.h"
#include "TError.h"
#include "TSystem.h"
#include "TROOT.h"
#include <cstdlib>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dcap.h>
#ifndef R__WIN32
#include <unistd.h>
#if defined(R__SUN) || defined(R__SGI) || defined(R__HPUX) || \
defined(R__AIX) || defined(R__LINUX) || defined(R__SOLARIS) || \
defined(R__ALPHA) || defined(R__HIUX) || defined(R__FBSD) || \
defined(R__MACOSX) || defined(R__HURD) || defined(R__OBSD)
#define HAS_DIRENT
#endif
#endif
#ifdef HAS_DIRENT
#include <dirent.h>
#endif
static const char* const DCACHE_PREFIX = "dcache:";
static const size_t DCACHE_PREFIX_LEN = strlen(DCACHE_PREFIX);
static const char* const DCAP_PREFIX = "dcap:";
static const size_t DCAP_PREFIX_LEN = strlen(DCAP_PREFIX);
ClassImp(TDCacheFile)
TDCacheFile::TDCacheFile(const char *path, Option_t *option,
const char *ftitle, Int_t compress):
TFile(path, "NET", ftitle, compress)
{
TString pathString = GetDcapPath(path);
path = pathString.Data();
fOffset = 0;
fOption = option;
fOption.ToUpper();
fStatCached = kFALSE;
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";
}
TString stmp;
TString stmp2;
const char *fname;
const char *fnameWithPrefix;
if (!strncmp(path, DCAP_PREFIX, DCAP_PREFIX_LEN)) {
fnameWithPrefix = fname = path;
} else {
char *tname;
if ((tname = gSystem->ExpandPathName(path))) {
stmp = tname;
stmp2 = DCACHE_PREFIX;
stmp2 += tname;
delete [] tname;
fname = stmp;
fnameWithPrefix = stmp2;
} else {
Error("TDCacheFile", "error expanding path %s", path);
goto zombie;
}
}
if (recreate) {
if (!gSystem->AccessPathName(fnameWithPrefix, kFileExists))
dc_unlink(fname);
recreate = kFALSE;
create = kTRUE;
fOption = "CREATE";
}
if (create && !gSystem->AccessPathName(fnameWithPrefix, kFileExists)) {
Error("TDCacheFile", "file %s already exists", fname);
goto zombie;
}
if (update) {
if (gSystem->AccessPathName(fnameWithPrefix, kFileExists)) {
update = kFALSE;
create = kTRUE;
}
if (update && gSystem->AccessPathName(fnameWithPrefix, kWritePermission)) {
Error("TDCacheFile", "no write permission, could not open file %s", fname);
goto zombie;
}
}
fRealName = fname;
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("TDCacheFile", "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) {
if (gSystem->AccessPathName(fnameWithPrefix, kFileExists)) {
Error("TDCacheFile", "file %s does not exist", fname);
goto zombie;
}
if (gSystem->AccessPathName(fnameWithPrefix, kReadPermission)) {
Error("TDCacheFile", "no read permission, could not open file %s", fname);
goto zombie;
}
SysError("TDCacheFile", "file %s can not be opened for reading", fname);
goto zombie;
}
fWritable = kFALSE;
}
if(read) {
dc_setBufferSize(fD, RAHEAD_BUFFER_SIZE);
}else{
dc_noBuffering(fD);
}
Init(create);
return;
zombie:
MakeZombie();
gDirectory = gROOT;
}
TDCacheFile::~TDCacheFile()
{
Close();
}
Bool_t TDCacheFile::ReadBuffer(char *buf, Int_t len)
{
Int_t st;
if ((st = ReadBufferViaCache(buf, len))) {
if (st == 2)
return kTRUE;
return kFALSE;
}
return TFile::ReadBuffer(buf, len);
}
Bool_t TDCacheFile::ReadBuffers(char *buf, Long64_t *pos, Int_t *len, Int_t nbuf)
{
#ifdef _IOVEC2_
iovec2 *vector;
vector = (iovec2 *)malloc(sizeof(iovec2)*nbuf);
Int_t total_len = 0;
for (Int_t i = 0; i < nbuf; i++) {
vector[i].buf = &buf[total_len];
vector[i].offset = pos[i];
vector[i].len = len[i];
total_len += len[i];
}
Int_t rc = dc_readv2(fD, vector, nbuf);
free(vector);
if (rc == 0) {
fBytesRead += total_len;
SetFileBytesRead(GetFileBytesRead() + total_len);
return kFALSE;
}
#endif
Int_t k = 0;
Bool_t result = kTRUE;
TFileCacheRead *old = fCacheRead;
fCacheRead = 0;
Long64_t low = pos[0];
Long64_t high = pos[nbuf-1] + len[nbuf-1] - pos[0];
Long64_t total = 0;
for(Int_t j=0; j < nbuf; j++) {
total += len[j];
}
if ( high / total < 10 ) {
char *temp = new char[high];
Seek(low);
result = ReadBuffer(temp,high);
if (result==0) {
for (Int_t i = 0; i < nbuf; i++) {
memcpy(&buf[k], &(temp[pos[i]-pos[0]]), len[i]);
k += len[i];
}
}
delete [] temp;
} else {
for (Int_t i = 0; i < nbuf; i++) {
Seek(pos[i]);
result = ReadBuffer(&buf[k], len[i]);
if (result) break;
k += len[i];
}
}
fCacheRead = old;
return result;
}
Bool_t TDCacheFile::WriteBuffer(const char *buf, Int_t len)
{
if (!IsOpen() || !fWritable) return kTRUE;
Int_t st;
if ((st = WriteBufferViaCache(buf, len))) {
if (st == 2)
return kTRUE;
return kFALSE;
}
return TFile::WriteBuffer(buf, len);
}
Bool_t TDCacheFile::Stage(const char *path, UInt_t after, const char *location)
{
TString pathString = GetDcapPath(path);
path = pathString.Data();
dc_errno = 0;
if (dc_stage(path, after, location) == 0)
return kTRUE;
if (dc_errno != 0)
gSystem->SetErrorStr(dc_strerror(dc_errno));
return kFALSE;
}
Bool_t TDCacheFile::CheckFile(const char *path, const char *location)
{
TString pathString = GetDcapPath(path);
path = pathString.Data();
dc_errno = 0;
if (dc_check(path, location) == 0)
return kTRUE;
if (dc_errno != 0)
gSystem->SetErrorStr(dc_strerror(dc_errno));
return kFALSE;
}
void TDCacheFile::SetOpenTimeout(UInt_t n)
{
dc_setOpenTimeout(n);
}
void TDCacheFile::SetOnError(OnErrorAction a)
{
dc_setOnError(a);
}
void TDCacheFile::SetReplyHostName(const char *host_name)
{
dc_setReplyHostName((char*)host_name);
}
const char *TDCacheFile::GetDcapVersion()
{
return getDcapVersion();
}
Int_t TDCacheFile::SysOpen(const char *pathname, Int_t flags, UInt_t mode)
{
dc_setClientActive();
dc_errno = 0;
Int_t rc = dc_open(pathname, flags, (Int_t) mode);
if (rc < 0) {
if (dc_errno != 0)
gSystem->SetErrorStr(dc_strerror(dc_errno));
}
return rc;
}
Int_t TDCacheFile::SysClose(Int_t fd)
{
dc_errno = 0;
Int_t rc = dc_close(fd);
if (rc < 0) {
if (dc_errno != 0)
gSystem->SetErrorStr(dc_strerror(dc_errno));
}
return rc;
}
Int_t TDCacheFile::SysRead(Int_t fd, void *buf, Int_t len)
{
fOffset += len;
dc_errno = 0;
Int_t rc = dc_read(fd, buf, len);
if (rc < 0) {
if (dc_errno != 0)
gSystem->SetErrorStr(dc_strerror(dc_errno));
}
return rc;
}
Int_t TDCacheFile::SysWrite(Int_t fd, const void *buf, Int_t len)
{
fOffset += len;
dc_errno = 0;
Int_t rc = dc_write(fd, (char *)buf, len);
if (rc < 0) {
if (dc_errno != 0)
gSystem->SetErrorStr(dc_strerror(dc_errno));
}
return rc;
}
Long64_t TDCacheFile::SysSeek(Int_t fd, Long64_t offset, Int_t whence)
{
if (whence == SEEK_SET && offset == fOffset) return offset;
dc_errno = 0;
Long64_t rc = dc_lseek64(fd, offset, whence);
if (rc < 0) {
if (dc_errno != 0)
gSystem->SetErrorStr(dc_strerror(dc_errno));
} else
fOffset = rc;
return rc;
}
Int_t TDCacheFile::SysSync(Int_t fd)
{
Int_t rc;
dc_errno = 0;
rc = dc_fsync(fd);
if (rc < 0) {
if (dc_errno != 0)
gSystem->SetErrorStr(dc_strerror(dc_errno));
}
return rc;
}
Int_t TDCacheFile::SysStat(Int_t, Long_t *id, Long64_t *size,
Long_t *flags, Long_t *modtime)
{
struct stat64 & statbuf = fStatBuffer;
if (fOption != "READ" || !fStatCached) {
const char *path = GetName();
TString pathString = GetDcapPath(path);
path = pathString.Data();
if (path && (dc_stat64(path, &statbuf) >= 0)) {
fStatCached = kTRUE;
}
}
if (fStatCached) {
if (id)
*id = (statbuf.st_dev << 24) + statbuf.st_ino;
if (size)
*size = statbuf.st_size;
if (modtime)
*modtime = statbuf.st_mtime;
if (flags) {
*flags = 0;
if (statbuf.st_mode & ((S_IEXEC)|(S_IEXEC>>3)|(S_IEXEC>>6)))
*flags |= 1;
if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
*flags |= 2;
if ((statbuf.st_mode & S_IFMT) != S_IFREG &&
(statbuf.st_mode & S_IFMT) != S_IFDIR)
*flags |= 4;
}
return 0;
}
return 1;
}
void TDCacheFile::ResetErrno() const
{
dc_errno = 0;
TSystem::ResetErrno();
}
TString TDCacheFile::GetDcapPath(const char *path)
{
if (!strncmp(path, DCACHE_PREFIX, DCACHE_PREFIX_LEN)) {
path += DCACHE_PREFIX_LEN;
}
if (!strncmp(path, DCAP_PREFIX, DCAP_PREFIX_LEN)) {
path += DCAP_PREFIX_LEN;
}
TString pathString(path);
if (!strncmp(path, "///", 3)) {
path += 2;
pathString = path;
}
if (!strncmp(path, "//", 2)) {
pathString = DCAP_PREFIX + pathString;
}
return pathString;
}
TDCacheSystem::TDCacheSystem() : TSystem("-DCache", "DCache Helper System")
{
SetName("DCache");
fDirp = 0;
}
int TDCacheSystem::MakeDirectory(const char *path)
{
Int_t rc;
dc_errno = 0;
TString pathString = TDCacheFile::GetDcapPath(path);
path = pathString.Data();
rc = dc_mkdir(path, 0755);
if (rc < 0) {
if (dc_errno != 0)
gSystem->SetErrorStr(dc_strerror(dc_errno));
}
return rc;
}
void *TDCacheSystem::OpenDirectory(const char *path)
{
dc_errno = 0;
TString pathString = TDCacheFile::GetDcapPath(path);
path = pathString.Data();
fDirp = dc_opendir(path);
if (fDirp == 0) {
if (dc_errno != 0)
gSystem->SetErrorStr(dc_strerror(dc_errno));
}
return fDirp;
}
void TDCacheSystem::FreeDirectory(void * dirp)
{
Int_t rc;
dc_errno = 0;
rc = dc_closedir((DIR *)dirp);
if (rc < 0) {
if (dc_errno != 0)
gSystem->SetErrorStr(dc_strerror(dc_errno));
}
fDirp = 0;
return;
}
const char *TDCacheSystem::GetDirEntry(void * dirp)
{
struct dirent *ent;
dc_errno = 0;
ent = dc_readdir((DIR *)dirp);
if (ent == 0) {
if (dc_errno != 0)
gSystem->SetErrorStr(dc_strerror(dc_errno));
}
return !ent ? 0 : ent->d_name;
}
Bool_t TDCacheSystem::AccessPathName(const char *path, EAccessMode mode)
{
TString pathString = TDCacheFile::GetDcapPath(path);
path = pathString.Data();
return dc_access(path, mode);
}
int TDCacheSystem::GetPathInfo(const char *path, FileStat_t &buf)
{
TString pathString = TDCacheFile::GetDcapPath(path);
path = pathString.Data();
struct stat64 sbuf;
if (path && (dc_stat64(path, &sbuf) >= 0)) {
buf.fDev = sbuf.st_dev;
buf.fIno = sbuf.st_ino;
buf.fMode = sbuf.st_mode;
buf.fUid = sbuf.st_uid;
buf.fGid = sbuf.st_gid;
buf.fSize = sbuf.st_size;
buf.fMtime = sbuf.st_mtime;
buf.fIsLink = kFALSE;
return 0;
}
return 1;
}