// @(#)root/rfio:$Name: $:$Id: TRFIOFile.cxx,v 1.24 2003/05/05 09:36:27 rdm Exp $
// Author: Fons Rademakers 20/01/99
/*************************************************************************
* Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
* All rights reserved. *
* *
* For the licensing terms see $ROOTSYS/LICENSE. *
* For the list of contributors see $ROOTSYS/README/CREDITS. *
*************************************************************************/
//////////////////////////////////////////////////////////////////////////
// //
// TRFIOFile //
// //
// A TRFIOFile is like a normal TFile except that it reads and writes //
// its data via a rfiod server (for more on the rfiod daemon see //
// http://wwwinfo.cern.ch/pdp/serv/shift.html). TRFIOFile file names //
// are in standard URL format with protocol "rfio". The following are //
// valid TRFIOFile URL's: //
// //
// rfio:/afs/cern.ch/user/r/rdm/galice.root //
// where galice.root is a symlink of the type /shift/.../... //
// rfio:na49db1:/data1/raw.root //
// //
//////////////////////////////////////////////////////////////////////////
#include "TRFIOFile.h"
#include "TSystem.h"
#include "TROOT.h"
#include <sys/stat.h>
#include <sys/types.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)
#define HAS_DIRENT
#endif
#endif
#ifdef HAS_DIRENT
#include <dirent.h>
#else
struct dirent {
ino_t d_ino;
off_t d_reclen;
unsigned short d_namlen;
char d_name[232]; // from Castor_limits.h
};
#endif
extern "C" {
int rfio_open(const char *filepath, int flags, int mode);
int rfio_close(int s);
int rfio_read(int s, void *ptr, int size);
int rfio_write(int s, const void *ptr, int size);
int rfio_lseek(int s, int offset, int how);
int rfio_access(const char *filepath, int mode);
int rfio_unlink(const char *filepath);
int rfio_parse(const char *name, char **host, char **path);
int rfio_stat(const char *path, struct stat *statbuf);
int rfio_fstat(int s, struct stat *statbuf);
void rfio_perror(const char *msg);
char *rfio_serror();
int rfiosetopt(int opt, int *pval, int len);
int rfio_mkdir(const char *path, int mode);
void *rfio_opendir(const char *dirpath);
int rfio_closedir(void *dirp);
void *rfio_readdir(void *dirp);
#ifdef R__WIN32
int *C__serrno(void);
int *C__rfio_errno (void);
#endif
};
#ifndef RFIO_READOPT
#define RFIO_READOPT 1
#endif
#ifdef R__WIN32
// Thread safe rfio_errno. Note, C__rfio_errno is defined in Cglobals.c rather
// than rfio/error.c.
#define rfio_errno (*C__rfio_errno())
// Thread safe serrno. Note, C__serrno is defined in Cglobals.c rather
// rather than serror.c.
#define serrno (*C__serrno())
#else
extern int rfio_errno;
extern int serrno;
#endif
ClassImp(TRFIOFile)
ClassImp(TRFIOSystem)
//______________________________________________________________________________
TRFIOFile::TRFIOFile(const char *url, Option_t *option, const char *ftitle,
Int_t compress)
: TFile(url, "NET", ftitle, compress), fUrl(url)
{
// Create a RFIO file object. A RFIO file is the same as a TFile
// except that it is being accessed via a rfiod server. The url
// argument must be of the form: rfio:/path/file.root (where file.root
// is a symlink of type /shift/aaa/bbb/ccc) or rfio:server:/path/file.root.
// If the file specified in the URL does not exist, is not accessable
// or can not be created the kZombie bit will be set in the TRFIOFile
// object. Use IsZombie() to see if the file is accessable.
// For a description of the option and other arguments see the TFile ctor.
// The preferred interface to this constructor is via TFile::Open().
fOffset = 0;
fOption = option;
fOption.ToUpper();
// tell RFIO to not read large buffers, ROOT does own buffering
Int_t readopt = 0;
::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";
}
TString stmp;
char *fname;
if ((fname = gSystem->ExpandPathName(fUrl.GetFile()))) {
if (!strstr(fname, ":/")) {
char *host;
char *name;
if (::rfio_parse(fname, &host, &name))
stmp = Form("%s:%s", host, name);
else
stmp = fname;
} else
stmp = fname;
delete [] fname;
fname = (char *)stmp.Data();
} else {
Error("TRFIOFile", "error expanding path %s", fUrl.GetFile());
goto zombie;
}
if (recreate) {
if (::rfio_access(fname, kFileExists) == 0)
::rfio_unlink(fname);
recreate = kFALSE;
create = kTRUE;
fOption = "CREATE";
}
if (create && ::rfio_access(fname, kFileExists) == 0) {
Error("TRFIOFile", "file %s already exists", fname);
goto zombie;
}
if (update) {
if (::rfio_access(fname, kFileExists) != 0) {
update = kFALSE;
create = kTRUE;
}
if (update && ::rfio_access(fname, kWritePermission) != 0) {
Error("TRFIOFile", "no write permission, could not open file %s", fname);
goto zombie;
}
}
if (read) {
if (::rfio_access(fname, kFileExists) != 0) {
Error("TRFIOFile", "file %s does not exist", fname);
goto zombie;
}
if (::rfio_access(fname, kReadPermission) != 0) {
Error("TRFIOFile", "no read permission, could not open file %s", fname);
goto zombie;
}
}
// Connect to file system stream
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("TRFIOFile", "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("TRFIOFile", "file %s can not be opened for reading", fname);
goto zombie;
}
fWritable = kFALSE;
}
Init(create);
return;
zombie:
// error in file opening occured, make this object a zombie
MakeZombie();
gDirectory = gROOT;
}
//______________________________________________________________________________
TRFIOFile::~TRFIOFile()
{
// RFIO file dtor. Close and flush directory structure.
Close();
}
//______________________________________________________________________________
Int_t TRFIOFile::SysOpen(const char *pathname, Int_t flags, UInt_t mode)
{
// Interface to system open. All arguments like in "man 2 open".
Int_t ret = ::rfio_open((char *)pathname, flags, (Int_t) mode);
if (ret < 0)
gSystem->SetErrorStr(::rfio_serror());
return ret;
}
//______________________________________________________________________________
Int_t TRFIOFile::SysClose(Int_t fd)
{
// Interface to system close. All arguments like in "man 2 close".
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)
{
// Interface to system read. All arguments like in "man 2 read".
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)
{
// Interface to system write. All arguments like in "man 2 write".
fOffset += len;
Int_t ret = ::rfio_write(fd, (char *)buf, len);
if (ret < 0)
gSystem->SetErrorStr(::rfio_serror());
return ret;
}
//______________________________________________________________________________
Seek_t TRFIOFile::SysSeek(Int_t fd, Seek_t offset, Int_t whence)
{
// Interface to system lseek. All arguments like in "man 2 lseek"
// except that the offset and return value are Long_t to be able to
// handle 64 bit file systems.
if (whence == SEEK_SET && offset == fOffset) return offset;
Seek_t ret = ::rfio_lseek(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, Long_t *size, Long_t *flags,
Long_t *modtime)
{
// Interface to TSystem:GetPathInfo(). Generally implemented via
// stat() or fstat().
struct stat statbuf;
if (::rfio_fstat(fd, &statbuf) >= 0) {
if (id)
#if defined(R__KCC) && defined(R__LINUX)
*id = (statbuf.st_dev.__val[0] << 24) + statbuf.st_ino;
#else
*id = (statbuf.st_dev << 24) + statbuf.st_ino;
#endif
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;
}
//______________________________________________________________________________
Bool_t TRFIOFile::ReadBuffer(char *buf, Int_t len)
{
// Read specified byte range from remote file via rfiod daemon.
// Returns kTRUE in case of error.
if (fCache) {
Int_t st;
Seek_t off = fOffset;
if ((st = fCache->ReadBuffer(fOffset, buf, len)) < 0) {
Error("ReadBuffer", "error reading from cache");
return kTRUE;
}
if (st > 0) {
// fOffset might have been changed via TCache::ReadBuffer(), reset it
Seek(off + len);
return kFALSE;
}
}
return TFile::ReadBuffer(buf, len);
}
//______________________________________________________________________________
Bool_t TRFIOFile::WriteBuffer(const char *buf, Int_t len)
{
// Write specified byte range to remote file via rootd daemon.
// Returns kTRUE in case of error.
if (!IsOpen() || !fWritable) return kTRUE;
if (fCache) {
Int_t st;
Seek_t off = fOffset;
if ((st = fCache->WriteBuffer(fOffset, buf, len)) < 0) {
Error("WriteBuffer", "error writing to cache");
return kTRUE;
}
if (st > 0) {
// fOffset might have been changed via TCache::WriteBuffer(), reset it
Seek(off + len);
return kFALSE;
}
}
return TFile::WriteBuffer(buf, len);
}
//______________________________________________________________________________
Int_t TRFIOFile::GetErrno() const
{
// Method returning rfio_errno. For RFIO files must use this
// function since we need to check rfio_errno then serrno and finally errno.
if (rfio_errno)
return rfio_errno;
if (serrno)
return serrno;
return TSystem::GetErrno();
}
//______________________________________________________________________________
void TRFIOFile::ResetErrno() const
{
// Method resetting the rfio_errno, serrno and errno.
rfio_errno = 0;
serrno = 0;
TSystem::ResetErrno();
}
//______________________________________________________________________________
TRFIOSystem::TRFIOSystem() : TSystem("-rfio", "RFIO Helper System")
{
// Create helper class that allows directory access via rfiod.
// name must start with '-' to bypass the TSystem singleton check
SetName("rfio");
fDirp = 0;
}
//______________________________________________________________________________
Int_t TRFIOSystem::MakeDirectory(const char *dir)
{
// Make a directory via rfiod.
TUrl url(dir);
Int_t ret = ::rfio_mkdir(url.GetFile(), 0755);
if (ret < 0)
gSystem->SetErrorStr(::rfio_serror());
return ret;
}
//______________________________________________________________________________
void *TRFIOSystem::OpenDirectory(const char *dir)
{
// Open a directory via rfiod. Returns an opaque pointer to a dir
// structure. Returns 0 in case of error.
if (fDirp) {
Error("OpenDirectory", "invalid directory pointer (should never happen)");
fDirp = 0;
}
TUrl url(dir);
struct stat finfo;
if (::rfio_stat(url.GetFile(), &finfo) < 0)
return 0;
if ((finfo.st_mode & S_IFMT) != S_IFDIR)
return 0;
fDirp = (void*) ::rfio_opendir(url.GetFile());
if (!fDirp)
gSystem->SetErrorStr(::rfio_serror());
return fDirp;
}
//______________________________________________________________________________
void TRFIOSystem::FreeDirectory(void *dirp)
{
// Free directory via rfiod.
if (dirp != fDirp) {
Error("FreeDirectory", "invalid directory pointer (should never happen)");
return;
}
if (dirp)
::rfio_closedir(dirp);
fDirp = 0;
}
//______________________________________________________________________________
const char *TRFIOSystem::GetDirEntry(void *dirp)
{
// Get directory entry via rfiod. Returns 0 in case no more entries.
if (dirp != fDirp) {
Error("GetDirEntry", "invalid directory pointer (should never happen)");
return 0;
}
struct dirent *dp;
if (dirp) {
dp = (struct dirent *) ::rfio_readdir(dirp);
if (!dp)
return 0;
return dp->d_name;
}
return 0;
}
//______________________________________________________________________________
Int_t TRFIOSystem::GetPathInfo(const char *path, Long_t *id, Long_t *size,
Long_t *flags, Long_t *modtime)
{
// Get info about a file: id, size, flags, modification time.
// Id is 0 for RFIO file
// Size is the file size
// Flags is file type: 0 is regular file, bit 0 set executable,
// bit 1 set directory, bit 2 set special file
// (socket, fifo, pipe, etc.)
// Modtime is modification time.
// The function returns 0 in case of success and 1 if the file could
// not be stat'ed.
TUrl url(path);
struct stat statbuf;
if (path && ::rfio_stat(url.GetFile(), &statbuf) >= 0) {
if (id)
*id = 0;
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;
}
//______________________________________________________________________________
Bool_t TRFIOSystem::AccessPathName(const char *path, EAccessMode mode)
{
// Returns FALSE if one can access a file using the specified access mode.
// Mode is the same as for the Unix access(2) function.
// Attention, bizarre convention of return value!!
if (::rfio_access(path, mode) == 0)
return kFALSE;
gSystem->SetErrorStr(::rfio_serror());
return kTRUE;
}
ROOT page - Class index - Top of the page
This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.