/******************************************************************************/
/* */
/* X r d F r m A d m i n U n l i n k . 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. */
/******************************************************************************/
#include
#include
#include
#include
#include
#include "XrdFrc/XrdFrcTrace.hh"
#include "XrdFrc/XrdFrcUtils.hh"
#include "XrdFrm/XrdFrmAdmin.hh"
#include "XrdFrm/XrdFrmCns.hh"
#include "XrdFrm/XrdFrmConfig.hh"
#include "XrdNet/XrdNetCmsNotify.hh"
#include "XrdOss/XrdOss.hh"
#include "XrdOss/XrdOssPath.hh"
#include "XrdOuc/XrdOucNSWalk.hh"
using namespace XrdFrc;
using namespace XrdFrm;
/******************************************************************************/
/* L o c a l C l a s s e s */
/******************************************************************************/
class XrdFrmAdminNSE
{public:
XrdOucNSWalk::NSEnt *nP, *dP;
XrdOucNSWalk *nsP;
XrdFrmAdminNSE() : nP(0), dP(0), nsP(0) {}
~XrdFrmAdminNSE() {XrdOucNSWalk::NSEnt *fP;
while((fP = dP)) {dP = dP->Next; delete fP;}
while((fP = nP)) {nP = nP->Next; delete fP;}
if (nsP) delete nsP;
}
};
/******************************************************************************/
/* U n l i n k */
/******************************************************************************/
int XrdFrmAdmin::Unlink(const char *Path)
{
static const int ulOpts = XRDOSS_Online | XRDOSS_isPFN;
XrdOucNSWalk::NSEnt *fP;
XrdFrmAdminNSE NSE;
struct stat Stat;
char Resp, lclPath[MAXPATHLEN+8];
int aOK = 1, rc;
// Get the actual pfn for the base file
//
if (!Config.LocalPath(Path, lclPath, sizeof(lclPath)-8))
{numProb++; return -1;}
// Make sure the base file exists
//
if (stat(lclPath, &Stat))
{Emsg(errno,"remove ",lclPath); numProb++; return -1;}
// Check if the file is actually a directory or a plain file
//
if ((Stat.st_mode & S_IFMT) != S_IFDIR)
{if (Opt.All) {Emsg(ENOTDIR, "remove ", Path); numProb++; return -1;}
return UnlinkFile(lclPath);
}
// This is a directory, see if a non-recursive delete wanted
//
if (!Opt.Recurse) return UnlinkDir(Path, lclPath);
// Get confirmation unless not wanted
//
if (!Opt.Force)
{Resp = XrdFrcUtils::Ask('n', "Remove EVERYTHING starting at ",Path,"?");
if (Resp != 'y') return Resp != 'a';
}
// Create the name space object to return the contents of each directory
//
NSE.nsP = new XrdOucNSWalk(&Say, lclPath, 0, XrdOucNSWalk::Recurse
|XrdOucNSWalk::retAll | XrdOucNSWalk::retStat);
// Process each directory
//
while((NSE.nP = NSE.nsP->Index(rc)) && !rc)
{if ((rc = UnlinkDir(NSE.nP, NSE.dP)) < 0) break;
rc = 0;
}
aOK = !rc;
// Check if we can now delete the directories
//
while((fP = NSE.dP))
{if (aOK)
{if ((rc = Config.ossFS->Remdir(fP->Path, ulOpts)))
{Emsg(-rc, "remove directory ", fP->Path); aOK = 0; numProb++;}
else {if (Opt.Echo) Msg("Local directory ",fP->Path," removed.");
numDirs++; XrdFrmCns::Rmd(fP->Path);
}
}
NSE.dP = NSE.dP->Next; delete fP;
}
// Now remove the base directory
//
if (aOK)
{if ((rc = Config.ossFS->Remdir(lclPath, ulOpts)))
{Emsg(-rc, "remove directory ", lclPath); aOK = 0;}
else {numDirs++; XrdFrmCns::Rmd(Path, 1);
if (Opt.Echo) Msg("Local directory ", lclPath, " removed.");
}
}
// All done
//
return aOK ? 1 : -1;
}
/******************************************************************************/
/* U n l i n k D i r */
/******************************************************************************/
int XrdFrmAdmin::UnlinkDir(const char *Path, const char *lclPath)
{
static const int ulOpts = XRDOSS_Online | XRDOSS_isPFN;
XrdFrmAdminNSE NSE;
XrdOucNSWalk::NSEnt *fP;
char Resp;
int rc;
// Create the name space object to return the contents of each directory
//
NSE.nsP = new XrdOucNSWalk(&Say, lclPath, 0, XrdOucNSWalk::retAll
| XrdOucNSWalk::retStat);
// Get the entries in this directory
//
NSE.nP = NSE.nsP->Index(rc);
if (rc) {numProb++; return -1;}
// If the only entry is the DIR_LOCK file then we can remove it and the
// directory without asking
//
if (!Opt.All)
{if (NSE.nP && !NSE.nP->Next && !strcmp(Config.lockFN, NSE.nP->Path))
if (unlink(NSE.nP->Path)) {Emsg(-rc, "remove ", lclPath); return -1;}
if ((rc = Config.ossFS->Remdir(lclPath, ulOpts)))
{Emsg(-rc, "remove directory ", lclPath); numProb++; return -1;}
if (Opt.Echo) Msg("Local directory ", Path, " removed.");
numDirs++; XrdFrmCns::Rmd(lclPath);
return 1;
}
// Run through the list looking to see if we have any directories
//
fP = NSE.nP;
while(fP)
{if (fP->Type != XrdOucNSWalk::NSEnt::isDir) fP = fP->Next;
else {Emsg(EISDIR, "remove ", fP->Path); numProb++; return -1;}
}
// If neither 'all' nor 'force' not specified, then we must ask for permission
//
if (!Opt.Force)
{Resp = XrdFrcUtils::Ask('n', "Remove EVERYTHING in ",Path,"?");
if (Resp != 'y') return Resp != 'a';
}
// Remove all items in this directory
//
if ((rc = UnlinkDir(NSE.nP, NSE.dP)) < 0) return -1;
return 1;
}
/******************************************************************************/
int XrdFrmAdmin::UnlinkDir(XrdOucNSWalk::NSEnt *&nP, XrdOucNSWalk::NSEnt *&dP)
{
XrdOucNSWalk::NSEnt *fP;
int retval = 1;
// Remove each entry but remember any directories
//
while((fP = nP))
{nP = fP->Next;
if (fP->Type == XrdOucNSWalk::NSEnt::isDir)
{fP->Next = dP; dP = fP;}
else {if (UnlinkFile(fP->Path) < 0) retval = -1;
delete fP;
}
}
// All done
//
return retval;
}
/******************************************************************************/
/* U n l i n k F i l e */
/******************************************************************************/
int XrdFrmAdmin::UnlinkFile(const char *lclPath)
{
static const int ulOpts = XRDOSS_Online | XRDOSS_isMIG | XRDOSS_isPFN;
int rc;
// Remove this file as needed
//
if (XrdOssPath::pathType(lclPath))
{if (!unlink(lclPath) || errno == ENOENT) return 1;
rc = -errno;
} else {
if (!(rc = Config.ossFS->Unlink(lclPath, ulOpts)))
{if (Opt.Echo) Msg("Local file ", lclPath, " removed.");
if (Config.cmsPath) Config.cmsPath->Gone(lclPath);
numFiles++; XrdFrmCns::Rm(lclPath);
return 1;
}
}
// Unlink failed
//
Emsg(-rc, "remove ", lclPath);
numProb++;
return -1;
}