#include "TRFIOFile.h"
#include "TROOT.h"
#include <sys/stat.h>
#include <sys/types.h>
#include <stdlib.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
#include <rfio.h>
#include <rfio_api.h>
#include <serrno.h>
ClassImp(TRFIOFile)
ClassImp(TRFIOSystem)
TRFIOFile::TRFIOFile(const char *url, Option_t *option, const char *ftitle,
Int_t compress)
: TFile(url, "NET", ftitle, compress)
{
fOption = option;
fOption.ToUpper();
Int_t readopt = RFIO_READBUF;
::rfiosetopt(RFIO_READOPT, &readopt, 4);
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";
}
if (!strcmp(fUrl.GetProtocol(), "castor"))
fUrl.SetProtocol("rfio");
TString opt = fUrl.GetOptions();
if (opt.Contains("&filetype=raw")) {
opt.ReplaceAll("&filetype=raw", "");
fUrl.SetOptions(opt);
} else if (opt.Contains("filetype=raw")) {
opt.ReplaceAll("filetype=raw", "");
fUrl.SetOptions(opt);
}
Bool_t addSlash = kFALSE;
if ((strstr(url, ":/") && !strstr(url, "://")) ||
(strstr(url, ":///") && !strstr(url, ":////")))
addSlash = kTRUE;
TString fname;
if (!addSlash)
fname.Form("%s://%s", fUrl.GetProtocol(), fUrl.GetFile());
else
fname.Form("%s:///%s", fUrl.GetProtocol(), fUrl.GetFile());
if (strlen(fUrl.GetOptions()))
fname += Form("?%s", fUrl.GetOptions());
if (recreate) {
if (::rfio_access((char*)fname.Data(), kFileExists) == 0)
::rfio_unlink((char*)fname.Data());
recreate = kFALSE;
create = kTRUE;
fOption = "CREATE";
}
if (create && ::rfio_access((char*)fname.Data(), kFileExists) == 0) {
Error("TRFIOFile", "file %s already exists", fname.Data());
goto zombie;
}
if (update) {
if (::rfio_access((char*)fname.Data(), kFileExists) != 0) {
update = kFALSE;
create = kTRUE;
}
if (update && ::rfio_access((char*)fname.Data(), kWritePermission) != 0) {
Error("TRFIOFile", "no write permission, could not open file %s", fname.Data());
goto zombie;
}
}
fRealName = fname;
if (create || update) {
#ifndef WIN32
fD = SysOpen(fname.Data(), O_RDWR | O_CREAT, 0644);
#else
fD = SysOpen(fname.Data(), O_RDWR | O_CREAT | O_BINARY, S_IREAD | S_IWRITE);
#endif
if (fD == -1) {
SysError("TRFIOFile", "file %s can not be opened", fname.Data());
goto zombie;
}
fWritable = kTRUE;
} else {
#ifndef WIN32
fD = SysOpen(fname.Data(), O_RDONLY, 0644);
#else
fD = SysOpen(fname.Data(), O_RDONLY | O_BINARY, S_IREAD | S_IWRITE);
#endif
if (fD == -1) {
SysError("TRFIOFile", "file %s can not be opened for reading", fname.Data());
goto zombie;
}
fWritable = kFALSE;
}
Init(create);
return;
zombie:
MakeZombie();
gDirectory = gROOT;
}
TRFIOFile::~TRFIOFile()
{
Close();
}
Bool_t TRFIOFile::ReadBuffers(char *buf, Long64_t *pos, Int_t *len, Int_t nbuf)
{
static struct iovec64 *iov = 0;
static Int_t iovsize = 128;
Int_t n;
if (IsZombie()) {
Error("ReadBuffers", "cannot read because object is in 'zombie' state");
return kTRUE;
}
if (!IsOpen()) {
Error("ReadBuffers", "the remote file is not open");
return kTRUE;
}
if (!iov) {
if (nbuf > iovsize)
iovsize = nbuf;
iov = (struct iovec64*)malloc(sizeof(struct iovec64) * iovsize);
if (gDebug > 1)
Info("TRFIOFile", "allocating iovec64 with size %d", iovsize);
if (!iov) {
Error("TRFIOFile", "error allocating preseek vector of size %d",
sizeof(struct iovec64) * iovsize);
return kTRUE;
}
} else {
if (nbuf > iovsize) {
iovsize = nbuf;
iov = (struct iovec64*) realloc(iov, sizeof(struct iovec64) * iovsize);
if (gDebug > 1)
Info("TRFIOFile", "re-allocating iovec64 with size %d", iovsize);
if (!iov) {
Error("TRFIOFile", "error reallocating preseek vector of size %d",
sizeof(struct iovec64) * iovsize);
return kTRUE;
}
}
}
for (n = 0; n < nbuf; n++) {
if (gDebug>1)
Info("TFIOFile", "adding chunk %lld, %d %d", n, pos[n], len[n]);
iov[n].iov_base = pos[n] + fArchiveOffset;
iov[n].iov_len = len[n];
}
if (rfio_preseek64(fD, iov, nbuf) < 0) {
Error("TRFIOFile", "error doing rfio_preseek");
return kTRUE;
}
Int_t k = 0;
for (n = 0; n < nbuf; n++) {
if (rfio_lseek64(fD, (off_t) iov[n].iov_base, SEEK_SET) < 0) {
Error("TRFIOFile", "error doing rfio_lseek");
return kTRUE;
}
if (rfio_read(fD, buf+k, iov[n].iov_len) < 0) {
Error("TRFIOFile", "error doing rfio_read");
return kTRUE;
}
k += iov[n].iov_len;
}
fOffset += k;
fBytesRead += k;
#ifdef WIN32
SetFileBytesRead(GetFileBytesRead() + k);
SetFileReadCalls(GetFileReadCalls() + 1);
#else
fgBytesRead += k;
fgReadCalls++;
#endif
return kFALSE;
}
Int_t TRFIOFile::SysOpen(const char *pathname, Int_t flags, UInt_t mode)
{
Int_t ret = ::rfio_open64((char*)pathname, flags, (Int_t) mode);
if (ret < 0)
gSystem->SetErrorStr(::rfio_serror());
return ret;
}
Int_t TRFIOFile::SysClose(Int_t fd)
{
Int_t ret = ::rfio_close(fd);
if (ret < 0)
gSystem->SetErrorStr(::rfio_serror());
return ret;
}
Int_t TRFIOFile::SysRead(Int_t fd, void *buf, Int_t len)
{
fOffset += len;
Int_t ret = ::rfio_read(fd, (char *)buf, len);
if (ret < 0)
gSystem->SetErrorStr(::rfio_serror());
return ret;
}
Int_t TRFIOFile::SysWrite(Int_t fd, const void *buf, Int_t len)
{
fOffset += len;
Int_t ret = ::rfio_write(fd, (char *)buf, len);
if (ret < 0)
gSystem->SetErrorStr(::rfio_serror());
return ret;
}
Long64_t TRFIOFile::SysSeek(Int_t fd, Long64_t offset, Int_t whence)
{
if (whence == SEEK_SET && offset == fOffset) return offset;
Long64_t ret = ::rfio_lseek64(fd, offset, whence);
if (ret < 0)
gSystem->SetErrorStr(::rfio_serror());
else
fOffset = ret;
return ret;
}
Int_t TRFIOFile::SysStat(Int_t fd, Long_t *id, Long64_t *size, Long_t *flags,
Long_t *modtime)
{
struct stat64 statbuf;
if (::rfio_fstat64(fd, &statbuf) >= 0) {
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;
}
gSystem->SetErrorStr(::rfio_serror());
return 1;
}
Int_t TRFIOFile::GetErrno() const
{
if (rfio_errno)
return rfio_errno;
if (serrno)
return serrno;
return TSystem::GetErrno();
}
void TRFIOFile::ResetErrno() const
{
rfio_errno = 0;
serrno = 0;
TSystem::ResetErrno();
}
TRFIOSystem::TRFIOSystem() : TSystem("-rfio", "RFIO Helper System")
{
SetName("rfio");
fDirp = 0;
}
Int_t TRFIOSystem::MakeDirectory(const char *dir)
{
TUrl url(dir);
Int_t ret = ::rfio_mkdir((char*)url.GetFileAndOptions(), 0755);
if (ret < 0)
gSystem->SetErrorStr(::rfio_serror());
return ret;
}
void *TRFIOSystem::OpenDirectory(const char *dir)
{
if (fDirp) {
Error("OpenDirectory", "invalid directory pointer (should never happen)");
fDirp = 0;
}
TUrl url(dir);
struct stat finfo;
if (::rfio_stat((char*)url.GetFileAndOptions(), &finfo) < 0)
return 0;
if ((finfo.st_mode & S_IFMT) != S_IFDIR)
return 0;
fDirp = (void*) ::rfio_opendir((char*)url.GetFileAndOptions());
if (!fDirp)
gSystem->SetErrorStr(::rfio_serror());
return fDirp;
}
void TRFIOSystem::FreeDirectory(void *dirp)
{
if (dirp != fDirp) {
Error("FreeDirectory", "invalid directory pointer (should never happen)");
return;
}
if (dirp)
::rfio_closedir((DIR*)dirp);
fDirp = 0;
}
const char *TRFIOSystem::GetDirEntry(void *dirp)
{
if (dirp != fDirp) {
Error("GetDirEntry", "invalid directory pointer (should never happen)");
return 0;
}
struct dirent *dp;
if (dirp) {
dp = (struct dirent *) ::rfio_readdir((DIR*)dirp);
if (!dp)
return 0;
return dp->d_name;
}
return 0;
}
Int_t TRFIOSystem::GetPathInfo(const char *path, FileStat_t &buf)
{
TUrl url(path);
struct stat64 sbuf;
if (path && ::rfio_stat64((char*)url.GetFileAndOptions(), &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;
}
Bool_t TRFIOSystem::AccessPathName(const char *path, EAccessMode mode)
{
TUrl url(path);
if (::rfio_access((char*)url.GetFileAndOptions(), mode) == 0)
return kFALSE;
gSystem->SetErrorStr(::rfio_serror());
return kTRUE;
}
Int_t TRFIOSystem::Unlink(const char *path)
{
TUrl url(path);
struct stat finfo;
if (rfio_stat((char*)url.GetFileAndOptions(), &finfo) < 0)
return -1;
if (R_ISDIR(finfo.st_mode))
return rfio_rmdir((char*)url.GetFileAndOptions());
else
return rfio_unlink((char*)url.GetFileAndOptions());
}