/******************************************************************************/ /* */ /* 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); }