// @(#)root/net:$Name: $:$Id: TCastorFile.cxx,v 1.9 2005/08/18 00:24:38 rdm Exp $
// Author: Fons Rademakers + Jean-Damien Durand 17/09/2003 + Ben Couturier 31/05/2005
/*************************************************************************
* 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. *
*************************************************************************/
//////////////////////////////////////////////////////////////////////////
// //
// TCastorFile //
// //
// A TCastorFile is like a normal TNetFile except that it obtains the //
// remote node (disk server) via the CASTOR API, once the disk server //
// and the local file path are determined, the file will be accessed //
// via the rootd daemon. File names have to be specified like: //
// castor:/castor/cern.ch/user/r/rdm/bla.root. //
// //
// This class has been modified to be able to use a V1 or V2 stager. //
// It uses the V1 stager API by default, and it can connect to a new //
// CASTOR stager when defining the shell variable //
// RFIO_USE_CASTOR_V2=YES //
// or adding RFIO USE_CASTOR_V2 YES in /etc/castor.conf. //
// //
//////////////////////////////////////////////////////////////////////////
#include "TCastorFile.h"
#include "TError.h"
#include <stdlib.h>
#include <errno.h>
#ifdef _WIN32
#include <WinDef.h>
#include <WinSock2.h>
#endif
#ifdef R__CASTOR2
#include <stager_api.h> // For the new CASTOR 2 Stager
#endif
#define RFIO_KERNEL // Get access to extra symbols in the headers
#include <stage_api.h> // Dial with CASTOR stager
#include <rfio_api.h> // Util routines from rfio
#include <Cns_api.h> // Dial with CASTOR Name Server
#define RFIO_USE_CASTOR_V2 "RFIO_USE_CASTOR_V2"
extern "C" { char *getconfent(char *, char *, int); }
//______________________________________________________________________________
static int UseCastor2API()
{
// Function that checks whether we should use the old or new stager API.
char *p;
if (((p = getenv(RFIO_USE_CASTOR_V2)) == 0) &&
((p = getconfent("RFIO","USE_CASTOR_V2",0)) == 0)) {
// Variable not set: compat mode
return 0;
}
if ((strcmp(p,"YES") == 0) || (strcmp(p,"yes") == 0) || (atoi(p) == 1)) {
#ifdef R__CASTOR2
// Variable set to yes or 1 : new mode
return 1;
#else
// Variable set to yes or 1 but old CASTOR 1: compat mode + warning
static int once = 0;
if (!once) {
::Warning("UseCastor2API", "asked to use CASTOR 2, but linked with CASTOR 1");
once = 1;
}
return 0;
#endif
}
// Variable set but not to 1 : compat mode
return 0;
}
ClassImp(TCastorFile)
//______________________________________________________________________________
TCastorFile::TCastorFile(const char *url, Option_t *option, const char *ftitle,
Int_t compress, Int_t netopt)
: TNetFile(url, ftitle, compress, kFALSE)
{
// Create a TCastorFile. A TCastorFile is like a normal TNetFile except
// that it obtains the remote node (disk server) via the CASTOR API, once
// the disk server and the local file path are determined, the file will
// be accessed via the rootd daemon. File names have to be specified like:
// castor:/castor/cern.ch/user/r/rdm/bla.root.
// The other arguments are the same as for TNetFile and TFile.
fIsCastor = kFALSE;
fWrittenTo = kFALSE;
// file is always created by stage_out_hsm() and therefore
// exists when opened by rootd
TString opt = option;
opt.ToUpper();
if (opt == "NEW" || opt == "CREATE")
opt = "RECREATE";
Create(url, opt, netopt);
}
//______________________________________________________________________________
void TCastorFile::FindServerAndPath()
{
// Find the CASTOR disk server and internal file path.
if (!UseCastor2API()) {
struct stgcat_entry *stcp_output = 0;
if (rfio_HsmIf_IsHsmFile(fUrl.GetFile()) == RFIO_HSM_CNS) {
// This is a CASTOR file
int flags = O_RDONLY;
struct Cns_filestat st;
int rc;
char stageoutbuf[1025];
char stageerrbuf[1025];
// Check with internal stage limits - preventing overflow afterwards
if (strlen(fUrl.GetFile()) > STAGE_MAX_HSMLENGTH) {
serrno = ENAMETOOLONG;
Error("FindServerAndPath", "can't open %s, error %d (%s)", fUrl.GetFile(), serrno, sstrerror(serrno));
return;
}
// Prepare the flags
if (fOption == "CREATE" || fOption == "RECREATE" || fOption == "UPDATE")
flags |= O_RDWR;
if (fOption == "CREATE" || fOption == "RECREATE")
flags |= O_CREAT | O_TRUNC;
// Check if an existing file is going to be updated
memset(&st, 0, sizeof(st));
rc = Cns_stat(fUrl.GetFile(), &st);
// Make sure that filesize is 0 if file doesn't exist
// or that we will create (stage_out) if O_TRUNC.
if (rc == -1 || ((flags & O_TRUNC) != 0)) st.filesize = 0;
// Makes sure stage api does not write automatically to stdout/stderr
if (stage_setoutbuf(stageoutbuf, 1024) != 0) {
Error("FindServerAndPath", "can't open %s, stage_setoutbuf, error %d (%s)", fUrl.GetFile(), serrno, sstrerror(serrno));
return;
}
if (stage_seterrbuf(stageerrbuf, 1024) != 0) {
Error("FindServerAndPath", "can't open %s, stage_seterrbuf, error %d (%s)", fUrl.GetFile(), serrno, sstrerror(serrno));
return;
}
struct stgcat_entry stcp_input;
int nstcp_output;
memset(&stcp_input, 0, sizeof(struct stgcat_entry));
strcpy(stcp_input.u1.h.xfile, fUrl.GetFile());
if (flags == O_RDONLY || st.filesize > 0) {
// Do a recall
if (stage_in_hsm((u_signed64) 0, // Ebusy is possible...
(int) flags, // open flags
(char *) 0, // hostname
(char *) 0, // pooluser
(int) 1, // nstcp_input
(struct stgcat_entry *) &stcp_input, // stcp_input
(int *) &nstcp_output, // nstcp_output
(struct stgcat_entry **) &stcp_output, // stcp_output
(int) 0, // nstpp_input
(struct stgpath_entry *) 0 // stpp_input
) != 0) {
Error("FindServerAndPath", "can't open %s, stage_in_hsm error %d (%s)",
fUrl.GetFile(), serrno, sstrerror(serrno));
return;
}
} else {
// Do a creation
if (stage_out_hsm((u_signed64) 0, // Ebusy is possible...
(int) flags, // open flags
(mode_t) 0666, // open mode (c.f. also umask)
// Note: This is S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH, c.f. fopen(2)
(char *) 0, // hostname
(char *) 0, // pooluser
(int) 1, // nstcp_input
(struct stgcat_entry *) &stcp_input, // stcp_input
(int *) &nstcp_output, // nstcp_output
(struct stgcat_entry **) &stcp_output, // stcp_output
(int) 0, // nstpp_input
(struct stgpath_entry *) 0 // stpp_input
) != 0) {
Error("FindServerAndPath", "can't open %s, stage_out_hsm error %d (%s)",
fUrl.GetFile(), serrno, sstrerror(serrno));
return;
}
}
if ((nstcp_output != 1) || (stcp_output == 0) ||
(*(stcp_output->ipath) == '\0')) {
// Impossible
serrno = SEINTERNAL;
if (stcp_output != 0) free(stcp_output);
Error("FindServerAndPath", "can't open %s, error %d (%s)",
fUrl.GetFile(), serrno, sstrerror(serrno));
return;
}
// Parse orig string to get disk server host
char *filename;
char *realhost = 0;
rfio_parse(stcp_output->ipath, &realhost, &filename);
if (realhost == 0) {
serrno = SEINTERNAL;
Error("FindServerAndPath", "can't open %s, get disk server hostname from %s error %d (%s)",
fUrl.GetFile(), stcp_output->ipath, errno, sstrerror(serrno));
free(stcp_output);
return;
}
// Save real host and internal path
fDiskServer = realhost;
if (filename[0] != '/') {
// Make file 'local' to the host
fInternalPath = "/";
fInternalPath += filename;
} else
fInternalPath = filename;
if (st.filesize == 0) {
// Will force notification to stage when the file is closed
fWrittenTo = kTRUE;
}
}
// Set the protocol prefix for TNetFile.
// For the cern.ch domain we set the default authentication
// method to UidGid, i.e. as for rfiod; for this we need
// the full FQDN or address in "nnn.mmm.iii.jjj" form
// (it can be changed by a proper directive in $HOME/.rootauthrc)
TString r;
TString fqdn;
TInetAddress addr = gSystem->GetHostByName(fDiskServer);
if (addr.IsValid()) {
fqdn = addr.GetHostName();
if (fqdn == "UnNamedHost")
fqdn = addr.GetHostAddress();
if (fqdn.EndsWith(".cern.ch") || fqdn.BeginsWith("137.138."))
r = "rootug://";
else
r = "root://";
} else
r = "root://";
// Update fUrl with new path
r += fDiskServer + "/";
r += fInternalPath;
TUrl rurl(r);
fUrl = rurl;
// Now ipath is not null and contains the real internal path on the disk
// server 'host', e.g. it is fDiskServer:fInternalPath
fInternalPath = stcp_output->ipath;
free(stcp_output);
} else {
#ifdef R__CASTOR2
// We use the new stager API
int flags = O_RDONLY;
int rc;
struct stage_io_fileresp *response = 0;
char *requestId = 0, *url = 0;
char stageerrbuf[1025];
// Prepare the flags
if (fOption == "CREATE" || fOption == "RECREATE" || fOption == "UPDATE")
flags |= O_RDWR;
if (fOption == "CREATE" || fOption == "RECREATE")
flags |= O_CREAT | O_TRUNC;
stage_seterrbuf(stageerrbuf, 1024);
rc = stage_open(0,
MOVER_PROTOCOL_ROOT,
(fUrl.GetFile()),
flags,
(mode_t) 0666,
0,
&response,
&requestId,
0);
if (rc != 0) {
Error("FindServerAndPath", "stage_open failed: %s (%s)",
sstrerror(serrno), stageerrbuf);
if (response) free(response);
if (requestId) free(requestId);
return;
}
if (response == 0) {
Error("FindServerAndPath", "response was null for %s (Request %s) %d/%s",
fUrl.GetFile(), requestId,
serrno, sstrerror(serrno));
if (requestId) free(requestId);
return;
}
if (response->errorCode != 0) {
serrno = response->errorCode;
Error("FindServerAndPath", "error getting file %s (Request %s) %d/%s",
fUrl.GetFile(), requestId,
serrno, sstrerror(serrno));
free(response);
if (requestId) free(requestId);
return;
}
url = stage_geturl(response);
if (url == 0) {
Error("FindServerAndPath", "error getting file %s (Request %s) %d/%s",
fUrl.GetFile(), requestId,
serrno, sstrerror(serrno));
free(response);
if (requestId) free(requestId);
return;
}
TUrl rurl(url);
fUrl = rurl;
if (response) free(response);
if (url) free(url);
if (requestId) free(requestId);
#endif
}
fIsCastor = kTRUE;
}
//______________________________________________________________________________
Int_t TCastorFile::SysClose(Int_t fd)
{
// Close currently open file.
Int_t r = TNetFile::SysClose(fd);
if (!UseCastor2API()) {
if (fIsCastor && fWrittenTo) {
// CASTOR file was created or modified
rfio_HsmIf_reqtoput((char *)fInternalPath.Data());
fWrittenTo = kFALSE;
}
}
return r;
}
//______________________________________________________________________________
Bool_t TCastorFile::WriteBuffer(const char *buf, Int_t len)
{
// Write specified byte range to remote file via rootd daemon.
// Returns kTRUE in case of error.
if (TNetFile::WriteBuffer(buf, len))
return kTRUE;
if (!UseCastor2API()) {
if (fIsCastor && !fWrittenTo && len > 0) {
stage_hsm_t hsmfile;
// Change status of file in stage catalog from STAGED to STAGEOUT
memset(&hsmfile, 0, sizeof(hsmfile));
strcpy(hsmfile.upath, fInternalPath);
if (stage_updc_filchg(0, &hsmfile) < 0) {
Error("WriteBuffer", "error calling stage_updc_filchg");
return kTRUE;
}
fWrittenTo = kTRUE;
}
}
return kFALSE;
}
//______________________________________________________________________________
void TCastorFile::ConnectServer(Int_t *stat, EMessageTypes *kind, Int_t netopt,
Int_t tcpwindowsize, Bool_t forceOpen,
Bool_t forceRead)
{
// Connect to remote rootd server on CASTOR disk server.
FindServerAndPath();
TNetFile::ConnectServer(stat, kind, netopt, tcpwindowsize, forceOpen, forceRead);
}
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.