/******************************************************************************/
/* */
/* X r d O s s C r e a t e . c c */
/* */
/* (c) 2003 by the Board of Trustees of the Leland Stanford, Jr., University */
/* All Rights Reserved */
/* 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. */
/******************************************************************************/
/******************************************************************************/
/* i n c l u d e s */
/******************************************************************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#if defined(__solaris__) || defined(AIX)
#include
#endif
#include "XrdFrc/XrdFrcXAttr.hh"
#include "XrdOss/XrdOssApi.hh"
#include "XrdOss/XrdOssCache.hh"
#include "XrdOss/XrdOssConfig.hh"
#include "XrdOss/XrdOssCopy.hh"
#include "XrdOss/XrdOssError.hh"
#include "XrdOss/XrdOssOpaque.hh"
#include "XrdOss/XrdOssPath.hh"
#include "XrdOss/XrdOssSpace.hh"
#include "XrdOss/XrdOssTrace.hh"
#include "XrdOuc/XrdOuca2x.hh"
#include "XrdOuc/XrdOucEnv.hh"
#include "XrdOuc/XrdOucExport.hh"
#include "XrdOuc/XrdOucUtils.hh"
#include "XrdOuc/XrdOucXAttr.hh"
#include "XrdSys/XrdSysError.hh"
#include "XrdSys/XrdSysHeaders.hh"
#include "XrdSys/XrdSysPlatform.hh"
/******************************************************************************/
/* E r r o r R o u t i n g O b j e c t */
/******************************************************************************/
extern XrdSysError OssEroute;
extern XrdOucTrace OssTrace;
extern XrdOssSys *XrdOssSS;
/******************************************************************************/
/* L o c a l C l a s s e s */
/******************************************************************************/
class XrdOssCreateInfo
{public:
unsigned long long pOpts;
const char *Path;
const char *LFN;
mode_t Amode;
int cOpts;
XrdOssCreateInfo(const char *path, const char *lfn, mode_t amode, int opts)
: Path(path), LFN(lfn), Amode(amode), cOpts(opts) {}
~XrdOssCreateInfo() {}
};
/******************************************************************************/
/* c r e a t e */
/******************************************************************************/
/*
Function: Create a file named `path' with 'file_mode' access mode bits set.
Input: path - The fully qualified name of the file to create.
access_mode - The Posix access mode bits to be assigned to the file.
These bits correspond to the standard Unix permission
bits (e.g., 744 == "rwxr--r--").
env - Environmental information.
opts - Set as follows:
XRDOSS_mkpath - create dir path if it does not exist.
XRDOSS_new - the file must not already exist.
x00000000 - x are standard open flags (<<8)
Output: Returns XRDOSS_OK upon success; (-errno) otherwise.
*/
int XrdOssSys::Create(const char *tident, const char *path, mode_t access_mode,
XrdOucEnv &env, int Opts)
{
EPNAME("Create")
const int AMode = S_IRWXU|S_IRWXG|S_IROTH|S_IXOTH; // 775
char local_path[MAXPATHLEN+1], *p, pc;
unsigned long long remotefs;
int isLink = 0, Missing = 1, retc = 0, datfd;
XrdOssCreateInfo crInfo(local_path, path, access_mode, Opts);
struct stat buf;
// Get options associated with this path and check if it's r/w
//
remotefs = Check_RO(Create, crInfo.pOpts, path, "create");
// Generate the actual local path for this file.
//
if ((retc = GenLocalPath(path, local_path))) return retc;
// Determine the state of the file. We will need this information as we go on.
//
if ((Missing = lstat(local_path, &buf))) retc = errno;
else {if ((isLink = ((buf.st_mode & S_IFMT) == S_IFLNK)))
{if (stat(local_path, &buf))
{if (errno != ENOENT) return -errno;
OssEroute.Emsg("Create","removing dangling link",local_path);
if (unlink(local_path)) retc = errno;
Missing = 1; isLink = 0;
}
}
}
if (retc && retc != ENOENT) return -retc;
// At this point, creation requests may need to be routed via the stagecmd.
// This is done if the file/link do not exist. Otherwise, we drop through.
//
if (StageCreate && Missing)
return XrdOssSS->Stage(tident, path, env, Opts>>8,
access_mode, crInfo.pOpts);
// The file must not exist if it's declared "new". Otherwise, reuse the space.
// SetFattr() alaways closes the provided file descriptor!
//
if (!Missing)
{if (Opts & XRDOSS_new) return -EEXIST;
if ((buf.st_mode & S_IFMT) == S_IFDIR) return -EISDIR;
do {datfd = open(local_path, Opts>>8, access_mode);}
while(datfd < 0 && errno == EINTR);
if (datfd < 0) return -errno;
if ((retc = SetFattr(crInfo, datfd, buf.st_mtime))) return retc;
if (Opts>>8 & O_TRUNC && buf.st_size)
{off_t theSize = buf.st_size;
if (isLink) {buf.st_mode = (buf.st_mode & ~S_IFMT) | S_IFLNK;
XrdOssCache::Adjust(local_path, -theSize, &buf);
}
}
return 0;
}
// If the path is to be created, make sure the path exists at this point
//
if ((Opts & XRDOSS_mkpath) && (p = rindex(local_path, '/')))
{p++; pc = *p; *p = '\0';
XrdOucUtils::makePath(local_path, AMode);
*p = pc;
}
// If this is a staging filesystem then we have lots more work to do.
//
if (remotefs)
{char remote_path[MAXPATHLEN+1];
// Generate the remote path for this file
//
if ((retc = GenRemotePath(path,remote_path))) return retc;
// Create the file in remote system unless not wanted so
//
if (crInfo.pOpts & XRDEXP_RCREATE)
{if ((retc = MSS_Create(remote_path, access_mode, env)) < 0)
{DEBUG("rc" <Attr() == spAssign)) spName = pl->Name();
}
// Get the correct cache group and partition path
//
if ((aInfo.cgPath=XrdOssCache::Parse(spName,cgbuff,sizeof(cgbuff))))
aInfo.cgPlen = strlen(aInfo.cgPath);
// Allocate space in the cache.
//
aInfo.cgName = cgbuff;
aInfo.aMode = crInfo.Amode;
if ((datfd = XrdOssCache::Alloc(aInfo)) < 0) return datfd;
// Set the pfn as the extended attribute if we are in new mode
//
if (!runOld && !(crInfo.pOpts & XRDEXP_NOXATTR)
&& (rc = XrdSysFAttr::Xat->Set(XrdFrcXAttrPfn::Name(), crInfo.Path,
strlen(crInfo.Path)+1, pbuff, datfd)))
{close(datfd); return rc;}
// Set extended attributes for this newly created file if allowed to do so.
// SetFattr() alaways closes the provided file descriptor!
//
if ((rc = SetFattr(crInfo, datfd, 1))) return rc;
// Now create a symbolic link to the target
//
if ((symlink(pbuff, crInfo.Path) && errno != EEXIST)
|| unlink(crInfo.Path) || symlink(pbuff, crInfo.Path))
{rc = -errno; unlink(pbuff);}
// Now create a symlink from the cache pfn to the actual path (xa runOld only)
//
if (runOld && aInfo.cgPsfx)
{strcpy(aInfo.cgPsfx, ".pfn");
if ((symlink(crInfo.Path, pbuff) && errno != EEXIST)
|| unlink(pbuff) || symlink(crInfo.Path, pbuff)) rc = -errno;
*(aInfo.cgPsfx) = '\0';
if (rc) {unlink(pbuff); unlink(crInfo.Path);}
}
// All done
//
DEBUG(aInfo.cgName <<" cache for " < crX;
int rc;
// Skip all of this if we do not need to create a lock file
//
if (!(XRDEXP_MAKELF & crInfo.pOpts)) return Act.Done(0);
// If we are running in backward compatability mode, then we need to create
// an old-style lock file.
//
if (runOld)
{struct utimbuf times;
char lkBuff[MAXPATHLEN+lkSuffsz+1];
int lkfd, n = strlen(crInfo.Path);
if (n+lkSuffsz >= (int)sizeof(lkBuff))
return Act.Done(OssEroute.Emsg("Create", -ENAMETOOLONG,
"generate lkfname for", crInfo.Path));
strcpy(lkBuff, crInfo.Path); strcpy(lkBuff+n, lkSuffix);
do {lkfd = open(lkBuff, O_RDWR|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR);}
while( lkfd < 0 && errno == EINTR);
if ( lkfd < 0)
return Act.Done(OssEroute.Emsg("Create", -errno, "create", lkBuff));
close(lkfd); times.actime = time(0); times.modtime = mtime;
if (utime(lkBuff, (const struct utimbuf *)×))
return Act.Done(OssEroute.Emsg("Create",-errno,"set mtime for",lkBuff));
return Act.Done(0);
}
// Check if we should really create any extended attribute
//
if ((crInfo.pOpts & XRDEXP_NOXATTR)) return Act.Done(0);
// Set copy time
//
crX.Attr.cpyTime = static_cast(mtime);
rc = crX.Set(crInfo.Path, fd);
// Check if extended attribute were set and indicate whether it is supported
//
if (rc == -ENOTSUP) {rc = 0; crInfo.cOpts |= XRDOSS_setnoxa;}
return Act.Done(rc);
}