/******************************************************************************/ /* */ /* X r d O s s R e l o c . c c */ /* */ /* (c) 2009 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 "XrdOss/XrdOssApi.hh" #include "XrdOss/XrdOssCache.hh" #include "XrdOss/XrdOssConfig.hh" #include "XrdOss/XrdOssCopy.hh" #include "XrdOss/XrdOssError.hh" #include "XrdOss/XrdOssPath.hh" #include "XrdOss/XrdOssSpace.hh" #include "XrdOss/XrdOssTrace.hh" #include "XrdOuc/XrdOucUtils.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; /******************************************************************************/ /* R e l o c */ /******************************************************************************/ /* Function: Relocate/Copy the file at `path' to a new location. Input: path - The fully qualified name of the file to relocate. cgName - Target space name[:path] anchor - The base path where a symlink to the copied file is to be created. If present, the original file is kept. If anchor is "." then path is taken as pfn (not lfn) and a pure relocation is performed. Output: Returns XrdOssOK upon success; (-errno) otherwise. */ int XrdOssSys::Reloc(const char *tident, const char *path, const char *cgName, const char *anchor) { EPNAME("Reloc") const int AMode = S_IRWXU|S_IRWXG|S_IROTH|S_IXOTH; // 775 class pendFiles {public: char *pbuff; char *tbuff; int datfd; pendFiles(char *pb, char *tb) : datfd(-1) {pbuff = pb; *pb = '\0'; tbuff = tb; *tb = '\0'; } ~pendFiles() {if (datfd >= 0) close(datfd); if (pbuff && *pbuff) unlink(pbuff); if (tbuff && *tbuff) unlink(tbuff); } }; char cgNow[XrdOssSpace::minSNbsz], cgbuff[XrdOssSpace::minSNbsz]; char lbuff[MAXPATHLEN+8]; char pbuff[MAXPATHLEN+8]; char tbuff[MAXPATHLEN+8]; char local_path[MAXPATHLEN+8]; pendFiles PF(pbuff, tbuff); XrdOssCache::allocInfo aInfo(path, pbuff, sizeof(pbuff)); int rc, lblen, datfd, Pure = (anchor && !strcmp(anchor, ".")); off_t rc_c; struct stat buf; // Generate the actual local path for this file. // if (Pure) {strcpy(local_path, path); anchor = 0;} else if ((rc = GenLocalPath(path, local_path))) return rc; // Determine the state of the file. // if (stat(local_path, &buf)) return -errno; if ((buf.st_mode & S_IFMT) == S_IFDIR) return -EISDIR; if ((buf.st_mode & S_IFMT) != S_IFREG) return -ENOTBLK; // Get the correct cache group and partition path // if ((aInfo.cgPath = XrdOssCache::Parse(cgName, cgbuff, sizeof(cgbuff)))) aInfo.cgPlen = strlen(aInfo.cgPath); // Verify that this file will go someplace other than where it is now // lblen = XrdOssPath::getCname(local_path, cgNow, lbuff, sizeof(lbuff)-7); lbuff[lblen] = '\0'; if (!Pure && !strcmp(cgbuff, cgNow) && (!aInfo.cgPath || !strncmp(aInfo.cgPath, lbuff, aInfo.cgPlen))) return -EEXIST; // Allocate space in the cache. Note that the target must be an xa cache // aInfo.aMode = buf.st_mode & S_IAMB; aInfo.cgSize = (Pure ? 0 : buf.st_size); aInfo.cgName = cgbuff; if ((PF.datfd = datfd = XrdOssCache::Alloc(aInfo)) < 0) return datfd; if (!aInfo.cgPsfx) return -ENOTSUP; // Copy the original file to the new location. Copy() always closes the fd. // PF.datfd = -1; if ((rc_c = XrdOssCopy::Copy(local_path, pbuff, datfd)) < 0) return (int)rc_c; // If the file is to be merely copied, substitute the desired destination // if (!anchor) {strcpy(tbuff, local_path); strcat(tbuff, ".anew");} else {struct stat sbuf; char *Slash; if (strlen(anchor)+strlen(path) >= sizeof(local_path)) return -ENAMETOOLONG; strcpy(local_path, anchor); strcat(local_path, path); if (!(Slash = rindex(local_path, '/'))) return -ENOTDIR; *Slash = '\0'; rc = stat(local_path, &sbuf); *Slash = '/'; if (rc && (rc = XrdOucUtils::makePath(local_path, AMode))) return rc; strcpy(tbuff, local_path); } // Now create a symbolic link to the target // if ((symlink(pbuff, tbuff) && errno != EEXIST) || unlink(tbuff) || symlink(pbuff, tbuff)) return -errno; // Rename the link atomically over the existing name // if (!anchor && rename(tbuff, local_path) < 0) return -errno; PF.tbuff = 0; PF.pbuff = 0; rc = 0; // Now create a symlink from the cache pfn to the actual path (xa runOld only) // if (runOld) {strcpy(aInfo.cgPsfx, ".pfn"); if ((symlink(local_path, pbuff) && errno != EEXIST) || unlink(pbuff) || symlink(local_path, pbuff)) rc = errno; } // Issue warning if the pfn file could not be created (very very rare). // At this point we can't do much about it. // if (rc) OssEroute.Emsg("Reloc", rc, "create symlink", pbuff); *(aInfo.cgPsfx) = '\0'; // If this was a copy operation, we are done // DEBUG(cgNow <<':' < " <