#include "NetErrors.h"
#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
#include <Cglobals.h>
#include <rfio_constants.h>
#define RFIO_USE_CASTOR_V2 "RFIO_USE_CASTOR_V2"
#define RFIO_HSM_BASETYPE 0x0
#define RFIO_HSM_CNS RFIO_HSM_BASETYPE+1
extern "C" { int rfio_HsmIf_reqtoput (char *); }
extern "C" { int DLL_DECL rfio_parse(char *, char **, char **); }
extern "C" { int rfio_HsmIf_IsHsmFile (const char *); }
extern "C" { char *getconfent(char *, char *, int); }
#ifdef R__CASTOR2
extern int tStageHostKey;
extern int tStagePortKey;
extern int tSvcClassKey;
extern int tCastorVersionKey;
extern "C" { int DLL_DECL use_castor2_api(); }
static int UseCastor2API()
{
int version = use_castor2_api();
return version;
}
#else
static int UseCastor2API()
{
char *p;
if (((p = getenv(RFIO_USE_CASTOR_V2)) == 0) &&
((p = getconfent("RFIO","USE_CASTOR_V2",0)) == 0)) {
return 0;
}
if ((strcmp(p,"YES") == 0) || (strcmp(p,"yes") == 0) || (atoi(p) == 1)) {
static int once = 0;
if (!once) {
::Warning("UseCastor2API", "asked to use CASTOR 2, but linked with CASTOR 1");
once = 1;
}
return 0;
}
return 0;
}
#endif
static const char *GetAuthProto(TString &url)
{
const Int_t rootNumSec = 6;
const char *protoSec[rootNumSec] = {"rootup", "roots", "rootk",
"rootg", "rooth", "rootug" };
TString p = url;
Int_t ii = p.Index("&rootAuth=");
if (ii != kNPOS) {
Int_t jj = p.Index("&", ii+1);
if (jj != kNPOS)
p.Remove(jj);
p.Remove(0,ii);
url.ReplaceAll(p, "");
p.ReplaceAll("&rootAuth=", "");
}
if (p.Length() <= 0)
p = getenv("ROOTCASTORAUTH");
Int_t sec = -1;
if (p.Length() > 0 && p.IsDigit()) {
sec = p.Atoi();
if (sec < 0 || sec > (rootNumSec - 1))
sec = -1;
}
return ((sec > -1 && sec < rootNumSec) ? protoSec[sec] : "root");
}
ClassImp(TCastorFile)
TCastorFile::TCastorFile(const char *url, Option_t *option, const char *ftitle,
Int_t compress, Int_t netopt)
: TNetFile(url, ftitle, compress, kFALSE)
{
fIsCastor = kFALSE;
fWrittenTo = kFALSE;
TString u(url);
fAuthProto = GetAuthProto(u);
fUrl.SetUrl(u);
if (gDebug > 0)
Info("TCastorFile","fAuthProto = %s, u: %s", fAuthProto.Data(), u.Data());
TString opt = option;
opt.ToUpper();
if (opt == "NEW" || opt == "CREATE")
opt = "RECREATE";
Create(url, opt, netopt);
}
void TCastorFile::FindServerAndPath()
{
TString castorturl;
char *host=0;
char *name=0;
if (!strcmp(fUrl.GetProtocol(),"castor"))
castorturl = Form("%s://%s", "rfio", fUrl.GetFile());
else
castorturl = Form("%s://%s", fUrl.GetProtocol(), fUrl.GetFile());
if (strlen(fUrl.GetOptions()) > 0)
castorturl += Form("?%s", fUrl.GetOptions());
TString fname = castorturl;
if (::rfio_parse((char *)fname.Data(), &host, &name)>=0) {
castorturl = Form("%s",(!name || !strstr(name,"/castor"))?fname.Data():name);
fname = castorturl.Data();
} else {
Error("FindServerAndPath", "error parsing %s", fUrl.GetUrl());
return;
}
if (!UseCastor2API()) {
struct stgcat_entry *stcp_output = 0;
if (rfio_HsmIf_IsHsmFile(fUrl.GetFile()) == RFIO_HSM_CNS) {
int flags = O_RDONLY;
struct Cns_filestat st;
int rc;
char stageoutbuf[1025];
char stageerrbuf[1025];
if (strlen(fUrl.GetFile()) > STAGE_MAX_HSMLENGTH) {
serrno = ENAMETOOLONG;
Error("FindServerAndPath", "can't open %s, error %d (%s)", fUrl.GetFile(), serrno, sstrerror(serrno));
return;
}
if (fOption == "CREATE" || fOption == "RECREATE" || fOption == "UPDATE")
flags |= O_RDWR;
if (fOption == "CREATE" || fOption == "RECREATE")
flags |= O_CREAT | O_TRUNC;
memset(&st, 0, sizeof(st));
rc = Cns_stat(fUrl.GetFile(), &st);
if (rc == -1 || ((flags & O_TRUNC) != 0))
st.filesize = 0;
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));
strlcpy(stcp_input.u1.h.xfile, fUrl.GetFile(), sizeof(stcp_input.u1.h.xfile));
if (flags == O_RDONLY || st.filesize > 0) {
if (stage_in_hsm((u_signed64) 0,
(int) flags,
(char *) 0,
(char *) 0,
(int) 1,
(struct stgcat_entry *) &stcp_input,
(int *) &nstcp_output,
(struct stgcat_entry **) &stcp_output,
(int) 0,
(struct stgpath_entry *) 0
) != 0) {
Error("FindServerAndPath", "can't open %s, stage_in_hsm error %d (%s)",
fUrl.GetFile(), serrno, sstrerror(serrno));
return;
}
} else {
if (stage_out_hsm((u_signed64) 0,
(int) flags,
(mode_t) 0666,
(char *) 0,
(char *) 0,
(int) 1,
(struct stgcat_entry *) &stcp_input,
(int *) &nstcp_output,
(struct stgcat_entry **) &stcp_output,
(int) 0,
(struct stgpath_entry *) 0
) != 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')) {
serrno = SEINTERNAL;
if (stcp_output != 0) free(stcp_output);
Error("FindServerAndPath", "can't open %s, error %d (%s)",
fUrl.GetFile(), serrno, sstrerror(serrno));
return;
}
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;
}
fDiskServer = realhost;
if (filename[0] != '/') {
fInternalPath = "/";
fInternalPath += filename;
} else {
fInternalPath = filename;
}
if (st.filesize == 0) {
fWrittenTo = kTRUE;
}
}
TString r = fAuthProto;
if (fAuthProto == "root") {
TString fqdn;
TInetAddress addr = gSystem->GetHostByName(fDiskServer);
if (addr.IsValid()) {
fqdn = addr.GetHostName();
if (fqdn.EndsWith(".cern.ch") || fqdn.BeginsWith("137.138."))
r = "rootug://";
else
r = "root://";
} else
r = "root://";
} else {
r += "://";
}
r += fDiskServer + "/";
r += fInternalPath;
TUrl rurl(r);
fUrl = rurl;
if (gDebug > 0)
Info("FindServerAndPath"," fDiskServer: %s, r: %s", fDiskServer.Data(), r.Data());
fInternalPath = stcp_output==0?0:stcp_output->ipath;
if (stcp_output)
free(stcp_output);
} else {
#ifdef R__CASTOR2
int flags = O_RDONLY;
int rc;
struct stage_io_fileresp *response = 0;
char *requestId = 0, *url = 0;
char stageerrbuf[1025];
if (fOption == "CREATE" || fOption == "RECREATE" || fOption == "UPDATE")
flags |= O_RDWR;
if (fOption == "CREATE" || fOption == "RECREATE")
flags |= O_CREAT | O_TRUNC;
stage_seterrbuf(stageerrbuf, 1024);
int* auxVal;
char ** auxPoint;
struct stage_options opts;
opts.stage_host=0;
opts.stage_port=0;
opts.service_class=0;
opts.stage_version=0;
void *ptrPoint = &auxPoint;
void *ptrVal = &auxVal;
int ret=Cglobals_get(& tStageHostKey, (void**)ptrPoint,sizeof(void*));
if(ret==0){
opts.stage_host=*auxPoint;
}
ret=Cglobals_get(& tStagePortKey, (void**)ptrVal,sizeof(int));
if(ret==0){
opts.stage_port=*auxVal;
}
opts.stage_version=2;
ret=Cglobals_get(& tSvcClassKey, (void**)ptrPoint,sizeof(void*));
if (ret==0){
opts.service_class=*auxPoint;
}
rc = stage_open(0,
MOVER_PROTOCOL_ROOT,
(char *)fname.Data(),
flags,
(mode_t) 0666,
0,
&response,
&requestId,
&opts);
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",
fname.Data(), 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",
fname.Data(), 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",
fname.Data(), requestId,
serrno, sstrerror(serrno));
free(response);
if (requestId) free(requestId);
return;
}
TUrl rurl(url);
TString p = fAuthProto;
if (fAuthProto == "root") {
TString fqdn = rurl.GetHostFQDN();
if (fqdn.EndsWith(".cern.ch") || fqdn.BeginsWith("137.138."))
fAuthProto = "rootug";
}
rurl.SetProtocol(fAuthProto);
fUrl = rurl;
if (response) free(response);
if (url) free(url);
if (requestId) free(requestId);
#endif
}
fIsCastor = kTRUE;
}
Int_t TCastorFile::SysClose(Int_t fd)
{
Int_t r = TNetFile::SysClose(fd);
if (!UseCastor2API()) {
if (fIsCastor && fWrittenTo) {
#ifndef R__CASTOR2
rfio_HsmIf_reqtoput((char *)fInternalPath.Data());
#endif
fWrittenTo = kFALSE;
}
}
return r;
}
Bool_t TCastorFile::WriteBuffer(const char *buf, Int_t len)
{
if (TNetFile::WriteBuffer(buf, len))
return kTRUE;
if (!UseCastor2API()) {
if (fIsCastor && !fWrittenTo && len > 0) {
stage_hsm_t hsmfile;
memset(&hsmfile, 0, sizeof(hsmfile));
hsmfile.upath = StrDup(fInternalPath);
if (stage_updc_filchg(0, &hsmfile) < 0) {
Error("WriteBuffer", "error calling stage_updc_filchg");
delete [] hsmfile.upath;
return kTRUE;
}
delete [] hsmfile.upath;
fWrittenTo = kTRUE;
}
}
return kFALSE;
}
void TCastorFile::ConnectServer(Int_t *stat, EMessageTypes *kind, Int_t netopt,
Int_t tcpwindowsize, Bool_t forceOpen,
Bool_t forceRead)
{
FindServerAndPath();
if (fIsCastor) {
TNetFile::ConnectServer(stat, kind, netopt, tcpwindowsize, forceOpen, forceRead);
} else {
*stat = kErrFileOpen;
*kind = kROOTD_ERR;
}
}