/******************************************************************************/
/* */
/* X r d S s i F i l e . c c */
/* */
/* (c) 2013 by the Board of Trustees of the Leland Stanford, Jr., University */
/* Produced by Andrew Hanushevsky for Stanford University under contract */
/* DE-AC02-76-SFO0515 with the Department of Energy */
/* */
/* This file is part of the XRootD software suite. */
/* */
/* XRootD is free software: you can redistribute it and/or modify it under */
/* the terms of the GNU Lesser General Public License as published by the */
/* Free Software Foundation, either version 3 of the License, or (at your */
/* option) any later version. */
/* */
/* XRootD is distributed in the hope that it will be useful, but WITHOUT */
/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
/* License for more details. */
/* */
/* You should have received a copy of the GNU Lesser General Public License */
/* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
/* COPYING (GPL license). If not, see . */
/* */
/* The copyright holder's institutional names and contributor's names may not */
/* be used to endorse or promote products derived from this software without */
/* specific prior written permission of the institution or contributor. */
/******************************************************************************/
#include
#include
#include
#include
#include
#include "XrdOuc/XrdOucBuffer.hh"
#include "XrdOuc/XrdOucEnv.hh"
#include "XrdOuc/XrdOucPList.hh"
#include "XrdSfs/XrdSfsAio.hh"
#include "XrdSfs/XrdSfsXio.hh"
#include "XrdSsi/XrdSsiFile.hh"
#include "XrdSsi/XrdSsiFileSess.hh"
#include "XrdSsi/XrdSsiSfs.hh"
#include "XrdSsi/XrdSsiUtils.hh"
/******************************************************************************/
/* G l o b a l s */
/******************************************************************************/
namespace XrdSsi
{
XrdOucBuffPool EmsgPool;
extern XrdSfsFileSystem *theFS;
extern XrdOucPListAnchor FSPath;
extern bool fsChk;
};
using namespace XrdSsi;
/******************************************************************************/
/* X r d S s i F i l e C o n s t r u c t o r */
/******************************************************************************/
XrdSsiFile::XrdSsiFile(const char *user, int monid)
: XrdSfsFile(user, monid), fsFile(0), fSessP(0), xioP(0) {}
/******************************************************************************/
/* X r d S s i F i l e D e s t r u c t o r */
/******************************************************************************/
XrdSsiFile::~XrdSsiFile()
{
// If we have a file object then delete it -- it needs to close. Else do it.
//
if (fsFile) delete fsFile;
if (fSessP) fSessP->Recycle();
}
/******************************************************************************/
/* c l o s e */
/******************************************************************************/
int XrdSsiFile::close()
/*
Function: Close the file object.
Input: None
Output: Always returns SFS_OK
*/
{
// Route this request as needed (no callback possible)
//
if (fsFile)
{int rc = fsFile->close();
return (rc ? CopyErr("close", rc) : rc);
}
// Forward this to the file session object
//
return fSessP->close();
}
/******************************************************************************/
/* Private: C o p y E C B */
/******************************************************************************/
void XrdSsiFile::CopyECB(bool forOpen)
{
unsigned long long cbArg;
XrdOucEICB *cbVal = error.getErrCB(cbArg);
// We only need to copy some information
//
if (forOpen) fsFile->error.setUCap(error.getUCap());
fsFile->error.setErrCB(cbVal, cbArg);
}
/******************************************************************************/
/* Private: C o p y E r r */
/******************************************************************************/
int XrdSsiFile::CopyErr(const char *op, int rc)
{
XrdOucBuffer *buffP;
const char *eText;
int eTLen, eCode;
// Get the error information
//
eText = fsFile->error.getErrText(eCode);
// Handle callbacks
//
if (rc == SFS_STARTED || rc == SFS_DATAVEC)
{unsigned long long cbArg;
XrdOucEICB *cbVal = fsFile->error.getErrCB(cbArg);
error.setErrCB(cbVal, cbArg);
if (rc == SFS_DATAVEC)
{struct iovec *iovP = (struct iovec *)eText;
char *mBuff = error.getMsgBuff(eTLen);
eTLen = iovP->iov_len;
memcpy(mBuff, eText, eTLen);
error.setErrCode(eCode);
return SFS_DATAVEC;
}
}
// Check if we need to copy an external buffer. If this fails then if there is
// an ofs callback pending, we must tell the ofs plugin we failed.
//
if (!(fsFile->error.extData())) error.setErrInfo(eCode, eText);
else {eTLen = fsFile->error.getErrTextLen();
buffP = EmsgPool.Alloc(eTLen);
if (buffP)
{memcpy(buffP->Buffer(), eText, eTLen);
error.setErrInfo(eCode, buffP);
} else {
XrdSsiUtils::Emsg("CopyErr",ENOMEM,op,fsFile->FName(),error);
if (rc == SFS_STARTED && fsFile->error.getErrCB())
{rc = eCode = SFS_ERROR;
fsFile->error.getErrCB()->Done(eCode, &error);
}
}
}
// All done
//
return rc;
}
/******************************************************************************/
/* f c t l */
/******************************************************************************/
int XrdSsiFile::fctl(const int cmd,
const char *args,
XrdOucErrInfo &out_error)
{
// Route this request as needed
//
if (fsFile) return fsFile->fctl(cmd, args, out_error);
// Indicate we would like to use SendData()
//
if (cmd == SFS_FCTL_GETFD)
{out_error.setErrCode(SFS_SFIO_FDVAL);
return SFS_OK;
}
// We don't support any other kind of command
//
return XrdSsiUtils::Emsg("fctl",ENOTSUP,"fctl",fSessP->FName(),out_error);
}
/******************************************************************************/
int XrdSsiFile::fctl(const int cmd,
int alen,
const char *args,
const XrdSecEntity *client)
{
// Route this request as needed (callback possible)
//
if (fsFile)
{CopyECB();
int rc = fsFile->fctl(cmd, alen, args, client);
return (rc ? CopyErr("fctl", rc) : rc);
}
// Forward this to the session object
//
return fSessP->fctl(cmd, alen, args, client);
}
/******************************************************************************/
/* F N a m e */
/******************************************************************************/
const char *XrdSsiFile::FName()
{
// Route to filesystem if need be
//
if (fsFile) return fsFile->FName();
// Return our name
//
return fSessP->FName();
}
/******************************************************************************/
/* g e t C X i n f o */
/******************************************************************************/
int XrdSsiFile::getCXinfo(char cxtype[4], int &cxrsz)
/*
Function: Set the length of the file object to 'flen' bytes.
Input: n/a
Output: cxtype - Compression algorithm code
cxrsz - Compression region size
Returns SFS_OK upon success and SFS_ERROR upon failure.
*/
{
// Route this request as needed (no callback possible)
//
if (fsFile)
{int rc = fsFile->getCXinfo(cxtype, cxrsz);
return (rc ? CopyErr("getcx", rc) : rc);
}
// Indicate we don't support compression
//
cxrsz = 0;
return SFS_OK;
}
/******************************************************************************/
/* g e t M m a p */
/******************************************************************************/
int XrdSsiFile::getMmap(void **Addr, off_t &Size) // Out
/*
Function: Return memory mapping for file, if any.
Output: Addr - Address of memory location
Size - Size of the file or zero if not memory mapped.
Returns SFS_OK upon success and SFS_ERROR upon failure.
*/
{
// Route this request as needed (no callback possible)
//
if (fsFile)
{int rc = fsFile->getMmap(Addr, Size);
return (rc ? CopyErr("getmmap", rc) : rc);
}
// Indicate we don't support memory mapping
//
if (Addr) *Addr = 0;
Size = 0;
return SFS_OK;
}
/******************************************************************************/
/* o p e n */
/******************************************************************************/
int XrdSsiFile::open(const char *path, // In
XrdSfsFileOpenMode open_mode, // In
mode_t Mode, // In
const XrdSecEntity *client, // In
const char *info) // In
/*
Function: Open the file `path' in the mode indicated by `open_mode'.
Input: path - The fully qualified name of the resource.
open_mode - It must contain only SFS_O_RDWR.
Mode - Ignored.
client - Authentication credentials, if any.
info - Opaque information to be used as seen fit.
Output: Returns OOSS_OK upon success, otherwise SFS_ERROR is returned.
*/
{
static const char *epname = "open";
int eNum;
// Verify that this object is not already associated with an open file
//
if (fsFile || fSessP)
return XrdSsiUtils::Emsg(epname, EADDRINUSE, "open session", path, error);
// Open a regular file if this is wanted
//
if (fsChk && FSPath.Find(path))
{if (!(fsFile = theFS->newFile((char *)error.getErrUser(),
error.getErrMid())))
return XrdSsiUtils::Emsg(epname, ENOMEM, "open file", path, error);
CopyECB(true);
if ((eNum = fsFile->open(path, open_mode, Mode, client, info)))
{eNum = CopyErr(epname, eNum);
delete fsFile; fsFile = 0;
}
return eNum;
}
// Convert opaque and security into an environment
//
XrdOucEnv Open_Env(info, 0, client);
// Allocate file session and issue open
//
fSessP = XrdSsiFileSess::Alloc(error, error.getErrUser());
eNum = fSessP->open(path, Open_Env, open_mode);
if (eNum) {fSessP->Recycle(); fSessP = 0;}
return eNum;
}
/******************************************************************************/
/* r e a d */
/******************************************************************************/
int XrdSsiFile::read(XrdSfsFileOffset offset, // In
XrdSfsXferSize blen) // In
/*
Function: Preread `blen' bytes at `offset'
Input: offset - The absolute byte offset at which to start the read.
blen - The amount to preread.
Output: Returns SFS_OK upon success and SFS_ERROR o/w.
*/
{
// Route to file system if need be (no callback possible)
//
if (fsFile)
{int rc = fsFile->read(offset, blen);
return (rc ? CopyErr("read", rc) : rc);
}
// We ignore these
//
return SFS_OK;
}
/******************************************************************************/
/* r e a d */
/******************************************************************************/
XrdSfsXferSize XrdSsiFile::read(XrdSfsFileOffset offset, // In
char *buff, // Out
XrdSfsXferSize blen) // In
/*
Function: Read `blen' bytes at `offset' into 'buff' and return the actual
number of bytes read.
Input: offset - Contains request information.
buff - Address of the buffer in which to place the data.
blen - The size of the buffer. This is the maximum number
of bytes that will be returned.
Output: Returns the number of bytes read upon success and SFS_ERROR o/w.
*/
{
// Route to file system if need be (no callback possible)
//
if (fsFile)
{int rc = fsFile->read(offset, buff, blen);
return (rc ? CopyErr("read", rc) : rc);
}
// Forward this to the file session
//
return fSessP->read(offset, buff, blen);
}
/******************************************************************************/
/* r e a d A I O */
/******************************************************************************/
int XrdSsiFile::read(XrdSfsAio *aiop)
{
// Route to file system if need be (no callback possible)
//
if (fsFile)
{int rc = fsFile->read(aiop);
return (rc ? CopyErr("readaio", rc) : rc);
}
// Execute this request in a synchronous fashion
//
aiop->Result = fSessP->read((XrdSfsFileOffset)aiop->sfsAio.aio_offset,
(char *)aiop->sfsAio.aio_buf,
(XrdSfsXferSize)aiop->sfsAio.aio_nbytes);
aiop->doneRead();
return 0;
}
/******************************************************************************/
/* r e a d v */
/******************************************************************************/
XrdSfsXferSize XrdSsiFile::readv(XrdOucIOVec *readV, // In
int readCount) // In
/*
Function: Perform all the reads specified in the readV vector.
Input: readV - A description of the reads to perform; includes the
absolute offset, the size of the read, and the buffer
to place the data into.
readCount - The size of the readV vector.
Output: Returns an error as this is not supported.
*/
{
// Route this request to file system if need be (no callback possible)
//
if (fsFile)
{int rc = fsFile->readv(readV, readCount);
return (rc ? CopyErr("readv", rc) : rc);
}
return XrdSsiUtils::Emsg("readv", ENOSYS, "readv", fSessP->FName(), error);
}
/******************************************************************************/
/* S e n d D a t a */
/******************************************************************************/
int XrdSsiFile::SendData(XrdSfsDio *sfDio,
XrdSfsFileOffset offset,
XrdSfsXferSize size)
{
// Route this request to file system if need be (no callback possible)
//
if (fsFile)
{int rc = fsFile->SendData(sfDio, offset, size);
return (rc ? CopyErr("SendData", rc) : rc);
}
// Forward this to the file session object
//
return fSessP->SendData(sfDio, offset, size);
}
/******************************************************************************/
/* s t a t */
/******************************************************************************/
int XrdSsiFile::stat(struct stat *buf) // Out
/*
Function: Return file status information
Input: buf - The stat structure to hold the results
Output: Returns SFS_OK upon success and SFS_ERROR upon failure.
*/
{
// Route this request to file system if need be (no callback possible)
//
if (fsFile)
{int rc = fsFile->stat(buf);
return (rc ? CopyErr("stat", rc) : rc);
}
// Otherwise there is no stat information
//
memset(buf, 0 , sizeof(struct stat));
return SFS_OK;
}
/******************************************************************************/
/* s y n c */
/******************************************************************************/
int XrdSsiFile::sync()
/*
Function: Commit all unwritten bytes to physical media.
Input: None
Output: Returns SFS_OK if a response is ready or SFS_STARTED otherwise.
*/
{
// Route this request to file system if need be (callback possible)
//
if (fsFile)
{CopyECB();
int rc = fsFile->sync();
return (rc ? CopyErr("sync", rc) : rc);
}
// We don't support this
//
return XrdSsiUtils::Emsg("sync", ENOSYS, "sync", fSessP->FName(), error);
}
/******************************************************************************/
/* s y n c A I O */
/******************************************************************************/
int XrdSsiFile::sync(XrdSfsAio *aiop)
{
// Route this request to file system if need be (callback possible)
//
if (fsFile)
{CopyECB();
int rc = fsFile->sync(aiop);
return (rc ? CopyErr("syncaio", rc) : rc);
}
// We don't support this
//
return XrdSsiUtils::Emsg("syncaio", ENOSYS, "sync", fSessP->FName(), error);
}
/******************************************************************************/
/* t r u n c a t e */
/******************************************************************************/
int XrdSsiFile::truncate(XrdSfsFileOffset flen) // In
/*
Function: Set the length of the file object to 'flen' bytes.
Input: flen - The new size of the file.
Output: Returns SFS_ERROR a this function is not supported.
*/
{
// Route this request to file system if need be (callback possible)
//
if (fsFile)
{CopyECB();
int rc = fsFile->truncate(flen);
return (rc ? CopyErr("trunc", rc) : rc);
}
// Route this to the file session object
//
return fSessP->truncate(flen);
}
/******************************************************************************/
/* w r i t e */
/******************************************************************************/
XrdSfsXferSize XrdSsiFile::write(XrdSfsFileOffset offset, // In
const char *buff, // In
XrdSfsXferSize blen) // In
/*
Function: Write `blen' bytes at `offset' from 'buff' and return the actual
number of bytes written.
Input: offset - The absolute byte offset at which to start the write.
buff - Address of the buffer from which to get the data.
blen - The size of the buffer. This is the maximum number
of bytes that will be written to 'fd'.
Output: Returns the number of bytes written upon success and SFS_ERROR o/w.
Notes: An error return may be delayed until the next write(), close(), or
sync() call.
*/
{
// Route this request to file system if need be (no callback possible)
//
if (fsFile)
{int rc = fsFile->write(offset, buff, blen);
return (rc ? CopyErr("write", rc) : rc);
}
// Route this to the file session object
//
return fSessP->write(offset, buff, blen);
}
/******************************************************************************/
/* w r i t e A I O */
/******************************************************************************/
int XrdSsiFile::write(XrdSfsAio *aiop)
{
// Route to file system if need be (no callback possible)
//
if (fsFile)
{int rc = fsFile->write(aiop);
return (rc ? CopyErr("writeaio", rc) : rc);
}
// Execute this request in a synchronous fashion
//
aiop->Result = fSessP->write((XrdSfsFileOffset)aiop->sfsAio.aio_offset,
(char *)aiop->sfsAio.aio_buf,
(XrdSfsXferSize)aiop->sfsAio.aio_nbytes);
aiop->doneWrite();
return 0;
}