/******************************************************************************/
/* */
/* X r d F r m A d m i n F i l e s . c c */
/* */
/* (c) 2010 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. */
/******************************************************************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "XrdFrc/XrdFrcUtils.hh"
#include "XrdFrc/XrdFrcXAttr.hh"
#include "XrdFrm/XrdFrmAdmin.hh"
#include "XrdFrm/XrdFrmConfig.hh"
#include "XrdFrm/XrdFrmFiles.hh"
#include "XrdOuc/XrdOucXAttr.hh"
using namespace XrdFrm;
/******************************************************************************/
/* c k A t t r */
/******************************************************************************/
char XrdFrmAdmin::ckAttr(int What, const char *Lfn, char *Pfn, int Pfnsz)
{
struct stat Stat;
const char *Msg = (What & mkLF ? "mark " : (What & mkMF ? "mmap " : "pin "));
char Buff[80], Resp;
// Get the actual pfn for the base file
//
if (!Config.LocalPath(Lfn, Pfn, Pfnsz)) {finalRC = 4; return 0;}
// Get file state
//
if (stat(Pfn, &Stat))
{Emsg(errno, "ckAttr ", Msg, Lfn); return 0;}
// If this is not a directory, then all is well
//
if ((Stat.st_mode & S_IFMT) != S_IFDIR)
{if (!Opt.All) return 'f';
Emsg(ENOTDIR, "ckAttr ", Msg, "files in ", Lfn);
return 0;
}
// Make sure the whole directory is being considered
//
if (Opt.All || Opt.Recurse) return 'd';
// Ask what we should do
//
sprintf(Buff, "%s ALL files in directory ", Msg);
Buff[0] = toupper(*Buff);
if ((Resp = XrdFrcUtils::Ask('n', Buff, Lfn)) == 'y') return 'd';
return (Resp == 'a' ? 'a' : 0);
}
/******************************************************************************/
/* m k M a r k */
/******************************************************************************/
int XrdFrmAdmin::mkMark(const char *Lfn)
{
XrdFrmFileset *sP;
XrdFrmFiles *fP;
char Pfn[MAXPATHLEN+8], Resp;
int opts = (Opt.Recurse ? XrdFrmFiles::Recursive : 0);
int ec = 0, Adj = (Opt.MPType == 'p' ? 0 : -113);
// Check what we are dealing with
//
if (!(Resp = ckAttr(mkLF, Lfn, Pfn, sizeof(Pfn)-8))) return 1;
if (Resp == 'a') return 0;
// If this is a file then do one file
//
if (Resp == 'f')
{if (XrdFrcUtils::updtCpy(Pfn, Adj)) numFiles++;
return 1;
}
// Process the directory
//
fP = new XrdFrmFiles(Pfn, opts | XrdFrmFiles::NoAutoDel);
while((sP = fP->Get(ec,1)))
{if (sP->baseFile()
&& XrdFrcUtils::updtCpy(sP->basePath(), Adj)) numFiles++;
delete sP;
}
// All done
//
if (ec) finalRC = 4;
delete fP;
return 1;
}
/******************************************************************************/
/* m k M m a p */
/******************************************************************************/
int XrdFrmAdmin::mkMmap(const char *Lfn)
{
XrdOucXAttr memInfo;
XrdFrmFileset *sP;
XrdFrmFiles *fP;
const char *bFn;
char Pfn[MAXPATHLEN+8], Resp;
int opts = (Opt.Recurse ? XrdFrmFiles::Recursive : 0);
int ec, doSet = 0;
// Check what we are dealing with
//
if (!(Resp = ckAttr(mkMF, Lfn, Pfn, sizeof(Pfn)-8))) return 1;
if (Resp == 'a') return 0;
// Construct the proper mmap attribute
//
if (!Opt.Local)
{ doSet = memInfo.Attr.Flags = XrdFrcXAttrMem::memMap;
if (Opt.Fix) memInfo.Attr.Flags |= XrdFrcXAttrMem::memLock;
if (Opt.Keep) memInfo.Attr.Flags |= XrdFrcXAttrMem::memKeep;
}
// If this is a file then do one file
//
if (Resp == 'f')
{if ((doSet ? !memInfo.Set(Pfn) : !memInfo.Del(Pfn))) numFiles++;
return 1;
}
// Process the directory
//
fP = new XrdFrmFiles(Pfn, opts | XrdFrmFiles::NoAutoDel);
while((sP = fP->Get(ec,1)))
{if (sP->baseFile() && (bFn = sP->basePath())
&& (doSet ? !memInfo.Set(bFn) : !memInfo.Del(bFn))) numFiles++;
delete sP;
}
// All done
//
if (ec) finalRC = 4;
delete fP;
return 1;
}
/******************************************************************************/
/* m k P i n */
/******************************************************************************/
int XrdFrmAdmin::mkPin(const char *Lfn)
{
XrdOucXAttr pinInfo;
XrdFrmFileset *sP;
XrdFrmFiles *fP;
const char *bFn;
char Pfn[MAXPATHLEN+8], Resp;
int opts = (Opt.Recurse ? XrdFrmFiles::Recursive : 0);
int ec, doSet;
// Check what we are dealing with
//
if (!(Resp = ckAttr(mkPF, Lfn, Pfn, sizeof(Pfn)-8))) return 1;
if (Resp == 'a') return 0;
// Construct the proper pin attribute
//
if (Opt.ktAlways) pinInfo.Attr.Flags = XrdFrcXAttrPin::pinPerm;
else if (Opt.KeepTime)
{pinInfo.Attr.pinTime = static_cast(Opt.KeepTime);
if (Opt.ktIdle) pinInfo.Attr.Flags = XrdFrcXAttrPin::pinIdle;
else pinInfo.Attr.Flags = XrdFrcXAttrPin::pinKeep;
}
doSet = (Opt.ktAlways || Opt.KeepTime ? 1 : 0);
// If this is a file then do one file
//
if (Resp == 'f')
{if ((doSet ? !pinInfo.Set(Pfn) : !pinInfo.Del(Pfn))) numFiles++;
return 1;
}
// Process the directory
//
fP = new XrdFrmFiles(Pfn, opts | XrdFrmFiles::NoAutoDel);
while((sP = fP->Get(ec,1)))
{if (sP->baseFile() && (bFn = sP->basePath())
&& (doSet ? !pinInfo.Set(bFn) : !pinInfo.Del(bFn))) numFiles++;
delete sP;
}
// All done
//
if (ec) finalRC = 4;
delete fP;
return 1;
}
/******************************************************************************/
/* O b s o l e t e M e t h o d s */
/******************************************************************************/
/******************************************************************************/
/* m k F i l e */
/******************************************************************************/
int XrdFrmAdmin::mkFile(int What, const char *Path, const char *Data, int DLen)
{
static const mode_t Mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH;
struct stat Stat;
time_t Tid;
uid_t Uid;
gid_t Gid;
char *pfn, baseFN[1038], tempFN[1038];
int rc, theFD;
// Check if we are handling hidden files
//
if (!Config.lockFN || *Config.lockFN != '.') pfn = baseFN;
else {*baseFN = '.'; pfn = baseFN+1;}
// Get the actual pfn for the base file
//
if (What & isPFN) strcpy(pfn, Path);
else if (!Config.LocalPath(Path, pfn, sizeof(baseFN)-6)) return 0;
// Make sure the base file exists
//
if (stat(pfn, &Stat)) {Emsg(errno,"stat pfn ",pfn); return 0;}
// Add the appropriate suffix
//
strcat(baseFN, (What & mkLF ? ".lock" : ".pin"));
strcpy(tempFN, baseFN);
strcat(tempFN, ".TEMP");
// Check if we need to merely delete the pin file
//
if ((What & mkPF) && !Opt.ktAlways && !Opt.KeepTime)
{if (unlink(baseFN)) {Emsg(errno, "remove pfn ", tempFN); return 0;}
return 1;
}
// Open the file, possibly creating it
//
if ((theFD = open(tempFN, O_RDWR | O_CREAT | O_TRUNC, Mode)) < 0)
{Emsg(errno, "open pfn ", tempFN); return 0;}
// If we need to write some data into the file
//
if (Data && DLen)
{do {rc = write(theFD, Data, DLen);
if (rc < 0) {if (errno != EINTR) break;}
else {Data += rc; DLen -= rc;}
} while(DLen > 0);
if (rc< 0) {Emsg(errno, "write pfn ", tempFN);
close(theFD); unlink(tempFN); return 0;
}
}
// Set correct ownership
//
Uid = (int(Opt.Uid) < 0 ? Stat.st_uid : Opt.Uid);
Gid = (int(Opt.Gid) < 0 ? Stat.st_gid : Opt.Gid);
if (Stat.st_uid != Uid || Stat.st_gid != Gid)
{do {rc = fchown(theFD, Uid, Gid);} while(rc && errno == EINTR);
if (rc) {Emsg(errno, "set uid/gid for pfn ", tempFN);
close(theFD); unlink(tempFN); return 0;
}
}
// Set the file time (mig -> lock < file; prg -> lock > file)
//
if (What & mkLF) {Tid = Stat.st_mtime + (Opt.MPType == 'p' ? +113 : -113);}
else {Tid = (DLen || Opt.ktAlways ? time(0) : Opt.KeepTime);
if (Opt.ktAlways)
{do {rc = fchmod(theFD, Mode);} while(rc && errno == EINTR);
if (rc) {Emsg(errno, "set mode for pfn ", tempFN);
close(theFD); unlink(tempFN); return 0;
}
}
}
close(theFD);
if (!XrdFrcUtils::Utime(tempFN,Tid)) {unlink(tempFN); return 0;}
// Finish up
//
if (rename(tempFN, baseFN))
{Emsg(errno, "rename pfn ", tempFN);
unlink(tempFN);
return 0;
}
return 1;
}
/******************************************************************************/
/* m k L o c k */
/******************************************************************************/
int XrdFrmAdmin::mkLock(const char *Lfn)
{
XrdFrmFileset *sP;
XrdFrmFiles *fP;
char Pfn[MAXPATHLEN+8], Resp;
int opts = (Opt.Recurse ? XrdFrmFiles::Recursive : 0);
int ec = 0;
// Check what we are dealing with
//
if (!(Resp = mkStat(mkLF, Lfn, Pfn, sizeof(Pfn)-8))) return 1;
if (Resp == 'a') return 0;
// If this is a file then do one file
//
if (Resp == 'f')
{if (mkFile(mkLF|isPFN, Pfn)) numFiles++;
return 1;
}
// Process the directory
//
fP = new XrdFrmFiles(Pfn, opts | XrdFrmFiles::NoAutoDel);
while((sP = fP->Get(ec,1)))
{if (sP->baseFile() && mkFile(mkLF|isPFN, sP->basePath())) numFiles++;
delete sP;
}
// All done
//
if (ec) finalRC = 4;
delete fP;
return 1;
}
/******************************************************************************/
/* m k S t a t */
/******************************************************************************/
char XrdFrmAdmin::mkStat(int What, const char *Lfn, char *Pfn, int Pfnsz)
{
struct stat Stat;
const char *Msg = (What & mkLF ? "create lock file for "
: "create pin file for ");
const char *Msh = (What & mkLF ? "create lock files in "
: "create pin files in ");
char Resp;
// Get the actual pfn for the base file
//
if (!Config.LocalPath(Lfn, Pfn, Pfnsz)) {finalRC = 4; return 0;}
// Get file state
//
if (stat(Pfn, &Stat))
{Emsg(errno, "create ", Msg, Lfn); return 0;}
// If this is not a directory, then all is well
//
if ((Stat.st_mode & S_IFMT) != S_IFDIR)
{if (!Opt.All) return 'f';
Emsg(ENOTDIR, "create ", Msh, Lfn);
return 0;
}
// Make sure the whole directory is being considered
//
if (Opt.All || Opt.Recurse) return 'd';
// Ask what we should do
//
Msg = (What & mkLF ? "Apply makelf to ALL files in directory "
: "Apply pin to ALL files in directory ");
if ((Resp = XrdFrcUtils::Ask('n', Msg, Lfn)) == 'y') return 'd';
return (Resp == 'a' ? 'a' : 0);
}