// @(#)root/gfal:$Name: $:$Id: TGFALFile.cxx,v 1.3 2006/02/24 08:55:26 brun Exp $
// Author: Fons Rademakers 8/12/2005
/*************************************************************************
* Copyright (C) 1995-2005, Rene Brun and Fons Rademakers. *
* All rights reserved. *
* *
* For the licensing terms see $ROOTSYS/LICENSE. *
* For the list of contributors see $ROOTSYS/README/CREDITS. *
*************************************************************************/
//////////////////////////////////////////////////////////////////////////
// //
// TGFALFile //
// //
// A TGFALFile is like a normal TFile except that it reads and writes //
// its data via the underlaying Grid access mechanism. //
// TGFALFile file names are either a logical file name, a guid, an //
// SURL or a TURL, like: //
// //
// gfal:/lfn/user/r/rdm/galice.root //
// //
// Grid storage interactions today require using several existing //
// software components: //
// - The replica catalog services to locate valid replicas of //
// files. //
// - The SRM software to ensure: //
// - files exist on disk (they are recalled from mass //
// storage if necessary) or //
// - space is allocated on disk for new files (they are possibly //
// migrated to mass storage later) //
// - A file access mechanism to access files from the storage //
// system on the worker node. //
// //
// The GFAL library hides these interactions and presents a Posix //
// interface for the I/O operations. The currently supported protocols //
// are: file for local access, dcap, gsidcap and kdcap (dCache access //
// protocol) and rfio (CASTOR access protocol). //
// //
// File naming convention: //
// A file name can be a Logical File Name (LFN), a Grid Unique //
// IDentifier (GUID), a file replica (SURL) or a Transport file //
// name (TURL): //
// //
// an LFN starts with lfn: //
// for example lfn:baud/testgfal15 //
// //
// a GUID starts with guid: //
// for example guid:2cd59291-7ae7-4778-af6d-b1f423719441 //
// //
// an SURL starts with srm:// //
// for example srm://wacdr002d.cern.ch:8443/castor/ //
// cern.ch/user/b/baud/testgfal15 //
// //
// a TURL starts with a protocol name: //
// for example rfio:////castor/cern.ch/user/b/baud/testgfal15 //
// //
// Note that for the TGFALFile plugin to work, all these pathnames //
// should be prepended by gfal:. //
// //
//////////////////////////////////////////////////////////////////////////
#include "TGFALFile.h"
#include "TROOT.h"
extern "C" {
#include <gfal_api.h>
}
ClassImp(TGFALFile)
ClassImp(TGFALSystem)
//______________________________________________________________________________
TGFALFile::TGFALFile(const char *url, Option_t *option, const char *ftitle,
Int_t compress)
: TFile(url, "NET", ftitle, compress), fUrl(url)
{
// Create a GFAL file object. A GFAL file is the same as a TFile
// except that it is being accessed via the underlaying Grid access
// mechanism. The url argument must be of the form: gfal:/lfn/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 TGFALFile
// 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().
fOption = option;
fOption.ToUpper();
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()))) {
stmp = fname;
delete [] fname;
fname = (char *)stmp.Data();
} else {
Error("TGFALFile", "error expanding path %s", fUrl.GetFile());
goto zombie;
}
if (recreate) {
if (::gfal_access(fname, kFileExists) == 0)
::gfal_unlink(fname);
recreate = kFALSE;
create = kTRUE;
fOption = "CREATE";
}
if (create && ::gfal_access(fname, kFileExists) == 0) {
Error("TGFALFile", "file %s already exists", fname);
goto zombie;
}
if (update) {
if (::gfal_access(fname, kFileExists) != 0) {
update = kFALSE;
create = kTRUE;
}
if (update && ::gfal_access(fname, kWritePermission) != 0) {
Error("TGFALFile", "no write permission, could not open file %s", fname);
goto zombie;
}
}
if (read) {
if (::gfal_access(fname, kFileExists) != 0) {
Error("TGFALFile", "file %s does not exist", fname);
goto zombie;
}
if (::gfal_access(fname, kReadPermission) != 0) {
Error("TGFALFile", "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("TGFALFile", "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("TGFALFile", "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;
}
//______________________________________________________________________________
TGFALFile::~TGFALFile()
{
// GFAL file dtor. Close and flush directory structure.
Close();
}
//______________________________________________________________________________
Int_t TGFALFile::SysOpen(const char *pathname, Int_t flags, UInt_t mode)
{
// Interface to system open. All arguments like in POSIX open.
Int_t ret = ::gfal_open64(pathname, flags, (Int_t) mode);
return ret;
}
//______________________________________________________________________________
Int_t TGFALFile::SysClose(Int_t fd)
{
// Interface to system close. All arguments like in POSIX close.
Int_t ret = ::gfal_close(fd);
return ret;
}
//______________________________________________________________________________
Int_t TGFALFile::SysRead(Int_t fd, void *buf, Int_t len)
{
// Interface to system read. All arguments like in POSIX read.
fOffset += len;
Int_t ret = ::gfal_read(fd, buf, len);
return ret;
}
//______________________________________________________________________________
Int_t TGFALFile::SysWrite(Int_t fd, const void *buf, Int_t len)
{
// Interface to system write. All arguments like in POSIX write.
fOffset += len;
Int_t ret = ::gfal_write(fd, buf, len);
return ret;
}
//______________________________________________________________________________
Long64_t TGFALFile::SysSeek(Int_t fd, Long64_t offset, Int_t whence)
{
// Interface to system lseek. All arguments like in POSIX 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;
Long64_t ret = ::gfal_lseek64(fd, offset, whence);
if (ret >= 0)
fOffset = ret;
return ret;
}
//______________________________________________________________________________
Int_t TGFALFile::SysStat(Int_t /*fd*/, Long_t *id, Long64_t *size, Long_t *flags,
Long_t *modtime)
{
// Interface to TSystem:GetPathInfo(). Generally implemented via
// stat() or fstat().
struct stat64 &statbuf = fStatBuffer;
if (fOption != "READ" || !fStatCached) {
// We are not in read mode, or the file status information is not yet
// in the cache. Update or read the status information with gfal_stat().
if (::gfal_stat64(fRealName, &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;
}
//______________________________________________________________________________
Bool_t TGFALFile::ReadBuffer(char *buf, Int_t len)
{
// Read specified byte range from remote file via GFAL.
// Returns kTRUE in case of error.
Int_t st;
if ((st = ReadBufferViaCache(buf, len))) {
if (st == 2)
return kTRUE;
return kFALSE;
}
return TFile::ReadBuffer(buf, len);
}
//______________________________________________________________________________
Bool_t TGFALFile::WriteBuffer(const char *buf, Int_t len)
{
// Write specified byte range to remote file via GFAL.
// Returns kTRUE in case of error.
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);
}
//______________________________________________________________________________
TGFALSystem::TGFALSystem() : TSystem("-gfal", "GFAL Helper System")
{
// Create helper class that allows directory access via GFAL.
// name must start with '-' to bypass the TSystem singleton check
SetName("gfal");
fDirp = 0;
}
//______________________________________________________________________________
Int_t TGFALSystem::MakeDirectory(const char *dir)
{
// Make a directory via GFAL.
TUrl url(dir);
Int_t ret = ::gfal_mkdir(url.GetFile(), 0755);
return ret;
}
//______________________________________________________________________________
void *TGFALSystem::OpenDirectory(const char *dir)
{
// Open a directory via GFAL. 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 stat64 finfo;
if (::gfal_stat64(url.GetFile(), &finfo) < 0)
return 0;
if ((finfo.st_mode & S_IFMT) != S_IFDIR)
return 0;
fDirp = (void*) ::gfal_opendir(url.GetFile());
return fDirp;
}
//______________________________________________________________________________
void TGFALSystem::FreeDirectory(void *dirp)
{
// Free directory via GFAL.
if (dirp != fDirp) {
Error("FreeDirectory", "invalid directory pointer (should never happen)");
return;
}
if (dirp)
::gfal_closedir((DIR*)dirp);
fDirp = 0;
}
//______________________________________________________________________________
const char *TGFALSystem::GetDirEntry(void *dirp)
{
// Get directory entry via GFAL. Returns 0 in case no more entries.
if (dirp != fDirp) {
Error("GetDirEntry", "invalid directory pointer (should never happen)");
return 0;
}
struct dirent64 *dp;
if (dirp) {
dp = ::gfal_readdir64((DIR*)dirp);
if (!dp)
return 0;
return dp->d_name;
}
return 0;
}
//______________________________________________________________________________
Int_t TGFALSystem::GetPathInfo(const char *path, FileStat_t &buf)
{
// Get info about a file. Info is returned in the form of a FileStat_t
// structure (see TSystem.h).
// The function returns 0 in case of success and 1 if the file could
// not be stat'ed.
TUrl url(path);
struct stat64 sbuf;
if (path && ::gfal_stat64(url.GetFile(), &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 TGFALSystem::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!!
TUrl url(path);
if (::gfal_access(url.GetFile(), mode) == 0)
return kFALSE;
return kTRUE;
}
ROOT page - Class index - Class Hierarchy - 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.