/******************************************************************************/ /* */ /* X r d F r m A d m i n A u d i t . 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 "XrdFrc/XrdFrcTrace.hh" #include "XrdFrc/XrdFrcUtils.hh" #include "XrdFrm/XrdFrmAdmin.hh" #include "XrdFrm/XrdFrmConfig.hh" #include "XrdFrm/XrdFrmFiles.hh" #include "XrdOss/XrdOssPath.hh" #include "XrdOss/XrdOssSpace.hh" #include "XrdOuc/XrdOucNSWalk.hh" #include "XrdOuc/XrdOucTList.hh" using namespace XrdFrc; using namespace XrdFrm; /******************************************************************************/ /* A u d i t N a m e N B */ /******************************************************************************/ int XrdFrmAdmin::AuditNameNB(XrdFrmFileset *sP) { char Resp, buff[80]; int num = 0, rem; // Report what is orphaned // if (sP->lockFile()) {num++; Msg("Orphaned lock file: ", sP->lockPath());} if (sP->pfnFile() ) {num++; Msg("Orphaned pfn file: ", sP->pfnPath()); Msg("PFN file refers to: ", sP->pfnFile()->Link); } if (sP->pinFile() ) {num++; Msg("Orphaned pin file: ", sP->pinPath());} // Return if no fix is needed, otherwise check if we should ask before removal // numProb += num; if (!Opt.Fix || !num) return 1; if (!Opt.Force) {Resp = XrdFrcUtils::Ask('n', "Remove orphaned files?"); if (Resp != 'y') return Resp != 'a'; } // Remove the orphaned files // rem = AuditRemove(sP); numFix += rem; // Indicate final resolution // sprintf(buff, "%d of %d orphaned files removed.", rem, num); Msg(buff); return 1; } /******************************************************************************/ /* A u d i t N a m e N F */ /******************************************************************************/ int XrdFrmAdmin::AuditNameNF(XrdFrmFileset *sP) { char Resp; // Indicate what is wrong // Msg("Dangling link: ", sP->basePath()); Msg("Missing target: ", sP->baseFile()->Link); numProb++; // Return if no fix is needed, otherwise check if we should ask before removal // if (!Opt.Fix) return 1; if (!Opt.Force) {Resp = XrdFrcUtils::Ask('n', "Remove symlink?"); if (Resp != 'y') return Resp != 'a'; } // Remove the symlink and associated files // if (unlink(sP->basePath())) Emsg(errno,"remove symlink", sP->basePath()); else if (AuditRemove(sP)) {Msg("Symlink removed."); numFix++; return 1; } return 1; } /******************************************************************************/ /* A u d i t N a m e N L */ /******************************************************************************/ int XrdFrmAdmin::AuditNameNL(XrdFrmFileset *sP) { static const char *noCPT = (Config.runNew ? "No copy time for: " : "Missing lock file: "); static const char *mkCPT = (Config.runNew ? "Set copy time?" : "Create lock file?"); char Resp; // Indicate what is wrong // Msg(noCPT, sP->basePath()); numProb++; // Return if no fix is needed, otherwise check if we should ask before removal // if (!Opt.Fix) return -1; if (!Opt.Force) {Resp = XrdFrcUtils::Ask('y', mkCPT); if (Resp != 'y') return Resp != 'a'; } // Set copy time or create a lock file // if (Config.runNew) {if (XrdFrcUtils::updtCpy(sP->basePath(),(Opt.MPType == 'p' ? 0 : -113))) {numFix++; Msg("Copy time set."); } } else { if (mkFile(mkLF|isPFN, sP->basePath())) {numFix++; Msg("Lock file created."); } } return 1; } /******************************************************************************/ /* A u d i t N a m e s */ /******************************************************************************/ int XrdFrmAdmin::AuditNames() { static const int fsetOpts = XrdFrmFiles::GetCpyTim | XrdFrmFiles::NoAutoDel; XrdFrmFileset *sP; XrdFrmFiles *fP; char pDir[MAXPATHLEN], *lDir = Opt.Args[1]; int opts = (Opt.Recurse ? XrdFrmFiles::Recursive : 0) | fsetOpts; int ec = 0, Act = 1; // Initialization // numProb = 0; numFix = 0; if (VerifyMP("audit", lDir) != 'y') return 0; // Process the directory // if (!Config.LocalPath(lDir, pDir, sizeof(pDir))) {finalRC = 4; return 1;} fP = new XrdFrmFiles(pDir, opts); while(Act && (sP = fP->Get(ec,1))) {if (!(sP->baseFile())) Act = AuditNameNB(sP); else {if (sP->baseFile()->Type == XrdOucNSWalk::NSEnt::isLink) Act = AuditNameNF(sP); if (Act && Opt.MPType && !(sP->cpyInfo.Attr.cpyTime)) Act = AuditNameNL(sP); if (Act && sP->baseFile()->Link && isXA(sP->baseFile())) Act = Config.runNew ? AuditNameXA(sP) : AuditNameXB(sP); } delete sP; } if (ec) finalRC = 4; delete fP; // All done // if (!Act) Msg("Audit names aborted!"); sprintf(pDir,"%d problem%s found; %d fixed.", numProb, (numProb == 1 ? "" : "s"), numFix); Msg(pDir); return !Act; } /******************************************************************************/ /* A u d i t N a m e X A */ /******************************************************************************/ int XrdFrmAdmin::AuditNameXA(XrdFrmFileset *sP) { XrdOucXAttr pfnInfo; const char *doWhat = "Recreate pfn xref?"; char Resp, dfltAns = 'n'; int rc; // Make sure there is a PFN attribute is here and references the file // if ((rc = pfnInfo.Get(sP->baseFile()->Link)) > 0) {if (!strcmp(pfnInfo.Attr.Pfn,sP->basePath())) return 1; Msg("Incorrect pfn xref to ", sP->basePath()); Msg("Data file refers to ", pfnInfo.Attr.Pfn); } else { if (rc) Emsg(-rc, "get pfn xattr for ",sP->basePath()); else {Msg("Missing pfn xref to ", sP->basePath()); doWhat = "Create pfn xref?"; dfltAns = 'y'; } } // Check if we can fix this problem // if (!Opt.Fix || rc < 0) return 1; if (!Opt.Force) {Resp = XrdFrcUtils::Ask(dfltAns, doWhat); if (Resp != 'y') return Resp != 'a'; } // Reset the pfn xattr // strcpy(pfnInfo.Attr.Pfn, sP->basePath()); if (!(rc = pfnInfo.Set(sP->baseFile()->Link))) {Msg("pfn xref set."); numFix++;} else Emsg(-rc, "set pfn xref to ", sP->basePath()); // All done. // return 1; } /******************************************************************************/ /* A u d i t N a m e X B */ /******************************************************************************/ int XrdFrmAdmin::AuditNameXB(XrdFrmFileset *sP) { struct stat buf; char Path[1032], lkbuff[1032]; int n; // Make sure there is a PFN file here // strcpy(Path, sP->baseFile()->Link); strcat(Path, ".pfn"); if (lstat(Path,&buf)) {if (errno != ENOENT) {Emsg(errno, "stat ", Path); return AuditNameXL(sP,-1);} Msg("Missing pfn link to ", sP->basePath()); return AuditNameXL(sP,0); } // Make sure the PFN file is a link // if ((buf.st_mode & S_IFMT) != S_IFLNK) {Msg("Invalid pfn file for ", sP->basePath()); return AuditNameXL(sP,1); } // Make sure the link points to the right file // if ((n = readlink(Path, lkbuff, sizeof(lkbuff)-1)) < 0) {Emsg(errno, "read link from ", Path); return AuditNameXL(sP,-1);} lkbuff[n] = '\0'; if (strcmp(sP->basePath(), lkbuff)) {Msg("Incorrect pfn link to ", sP->basePath()); return AuditNameXL(sP,1); } // All is well // return 1; } /******************************************************************************/ /* A u d i t N a m e X L */ /******************************************************************************/ int XrdFrmAdmin::AuditNameXL(XrdFrmFileset *sP, int dorm) { char Resp, Path[1032]; // Return if no fix is needed, otherwise check if we should ask before doing it // numProb++; if (!Opt.Fix || dorm < 0) return 1; if (!Opt.Force) {if (dorm) Resp = XrdFrcUtils::Ask('n', "Recreate pfn symlink?"); else Resp = XrdFrcUtils::Ask('y', "Create pfn symlink?"); if (Resp != 'y') return Resp != 'a'; } // Create the pfn symlink // strcpy(Path, sP->baseFile()->Link); strcat(Path, ".pfn"); if (dorm) unlink(Path); if (symlink(sP->basePath(), Path)) {Emsg(errno, "create symlink ", Path); return 1;} Msg("pfn symlink created."); numFix++; return 1; } /******************************************************************************/ /* A u d i t R e m o v e */ /******************************************************************************/ int XrdFrmAdmin::AuditRemove(XrdFrmFileset *sP) { int rem = 0; // Remove the orphaned files // if (sP->lockFile()) {if (unlink(sP->lockPath())) Emsg(errno,"remove lock file."); else rem++; } if (sP-> pinFile()) {if (unlink(sP-> pinPath())) Emsg(errno,"remove pin file."); else rem++; } if (sP-> pfnFile()) {if (unlink(sP-> pfnPath())) Emsg(errno,"remove pfn file."); else rem++; } return rem; } /******************************************************************************/ /* A u d i t S p a c e */ /******************************************************************************/ int XrdFrmAdmin::AuditSpace() { XrdOucTList *pP; char buff[256], *Path = 0, *Space = Opt.Args[1]; int Act; // Parse the space specification // if (!(pP = ParseSpace(Space, &Path))) return 4; // Initialize // numBytes = 0; numFiles = 0; numProb = 0; numFix = 0; // Index the space via filesets // do {Act = (pP->val ? AuditSpaceXA(Space, pP->text) : AuditSpaceAX(pP->text)); pP = pP->next; } while(pP && !Path && Act); // All done // sprintf(buff,"%d problem%s found; %d fixed.", numProb, (numProb == 1 ? "" : "s"), numFix); Msg(buff); if (!Act) Msg("Audit space aborted!"); else {if (Path) *(--Path) = ':'; sprintf(buff, "Space %s has %d file%s with %lld byte%s in use " "(%lld unreachable).", Space, numFiles, (numFiles == 1 ? "" : "s"), numBytes, (numBytes == 1 ? "" : "s"), numBLost); Msg(buff); } return (Act ? 0 : 4); } /******************************************************************************/ /* A u d i t S p a c e A X */ /******************************************************************************/ int XrdFrmAdmin::AuditSpaceAX(const char *Path) { XrdOucNSWalk nsWalk(&Say, Path, 0, XrdOucNSWalk::retFile | XrdOucNSWalk::retStat | XrdOucNSWalk::skpErrs); XrdOucNSWalk::NSEnt *nP, *pP; char buff[1032]; int ec, Act = 1; // Get the files in this directory // if (!(nP = nsWalk.Index(ec))) {if (ec) finalRC = 4; return 1;} pP = nP; // Now traverse through all of the files // while(nP && Act) {Act = (XrdOssPath::genPFN(buff, sizeof(buff), nP->Path) ? AuditSpaceAXDC(buff, nP) : AuditSpaceAXDB(nP->Path)); nP = nP->Next; } // Delete the entries and return // while(pP) {nP = pP; pP = pP->Next; delete nP;} return Act; } /******************************************************************************/ /* A u d i t S p a c e A X D B */ /******************************************************************************/ int XrdFrmAdmin::AuditSpaceAXDB(const char *Path) { char Resp; // Indicate the problem // Msg("Invalid name for data file ", Path); numProb++; // Return if no fix is needed, otherwise check if we should ask before doing it // if (Opt.Fix) {if (!Opt.Force) {Resp = XrdFrcUtils::Ask('n', "Delete file?"); if (Resp != 'y') return Resp != 'a'; } if (unlink(Path)) Emsg(errno, "remove ", Path); else numFix++; } return 1; } /******************************************************************************/ /* A u d i t S p a c e A X D C */ /******************************************************************************/ int XrdFrmAdmin::AuditSpaceAXDC(const char *Path, XrdOucNSWalk::NSEnt *nP) { struct stat buf; char lkbuff[1032], *Dest = nP->Path; int n; // Assume we have a problem // numProb++; // Verify that the link to the file exists // if (lstat(Path,&buf)) {if (errno != ENOENT) {Emsg(errno, "stat ", Path); return -1;} Msg("Missing pfn data link ", Path); return AuditSpaceAXDL(0, Path, Dest); } // Make sure the PFN file is a link // if ((buf.st_mode & S_IFMT) != S_IFLNK) {Msg("Invalid pfn data link ", Path); return AuditSpaceAXDL(1, Path, Dest); } // Make sure tyhe link points to the right file // if ((n = readlink(Path, lkbuff, sizeof(lkbuff)-1)) < 0) {Emsg(errno, "read link from ", Path); return -1;} lkbuff[n] = '\0'; if (strcmp(Dest, lkbuff)) {Msg("Incorrect pfn data link ", Path); return AuditSpaceAXDL(1, Path, Dest); } // All went well // numProb--; numFiles++; numBytes += nP->Stat.st_size; return 1; } /******************************************************************************/ /* A u d i t S p a c e A X D L */ /******************************************************************************/ int XrdFrmAdmin::AuditSpaceAXDL(int dorm, const char *Path, const char *Dest) { char Resp; // Return if no fix is needed, otherwise check if we should ask before doing it // if (!Opt.Fix) return -1; if (!Opt.Force) {if (dorm) Resp = XrdFrcUtils::Ask('n', "Recreate pfn symlink?"); else Resp = XrdFrcUtils::Ask('y', "Create pfn symlink?"); if (Resp != 'y') return Resp != 'a'; } // Create the pfn symlink // if (dorm) unlink(Path); if (symlink(Dest, Path)) {Emsg(errno, "create symlink ", Path); return -1;} Msg("pfn symlink created."); numFix++; return 1; } /******************************************************************************/ /* A u d i t S p a c e X A */ /******************************************************************************/ int XrdFrmAdmin::AuditSpaceXA(const char *Space, const char *Path) { XrdFrmFileset *sP; XrdFrmFiles *fP; char tmpv[8], *buff; int ec = 0, Act = 1; // Construct the right space path and get a files object // buff = XrdOssPath::genPath(Path, Space, tmpv); fP = new XrdFrmFiles(buff, XrdFrmFiles::Recursive | XrdFrmFiles::NoAutoDel); // Go and check out the files // while(Act && (sP = fP->Get(ec,1))) {if (sP->baseFile()) Act = AuditNameNB(sP); else {numFiles++; if ((Act = AuditSpaceXA(sP))) {if (Act < 0) numFiles--; else numBytes += sP->baseFile()->Stat.st_size; } } delete sP; } // All done // if (ec) finalRC = 4; free(buff); delete fP; return Act; } /******************************************************************************/ int XrdFrmAdmin::AuditSpaceXA(XrdFrmFileset *sP) { XrdOucXAttr pfnInfo; struct stat buf; const char *Plug; char Resp = 0, tempPath[1032], lkbuff[1032], *Pfn = pfnInfo.Attr.Pfn; int n; // First step is to get the pfn extended attribute (Get will issue a msg) // if ((n = pfnInfo.Get(sP->basePath()) <= 0)) {if (!n) Msg("Missing pfn xref for data file ", sP->basePath()); numProb++; return 1; } // If there is no PFN file then recreate symlink if possible // if (lstat(Pfn,&buf)) {numProb++; if (errno != ENOENT) {Emsg(errno, "stat ", Pfn); return 1;} Msg("Data file xrefs missing pfn ", Pfn); if (Opt.Fix) {if (Opt.Force) Resp = 'y'; else Resp = XrdFrcUtils::Ask('y',"Create pfn symlink?"); if (Resp == 'y') {if (!symlink(sP->basePath(), Pfn)) {Msg("pfn symlink created."); numFix++; return 1;} Emsg(errno, "create symlink ", Pfn); } } numBLost += sP->baseFile()->Stat.st_size; return Resp != 'a'; } // If the PFN file is not a link, the see if we should remove the data file // if ((buf.st_mode & S_IFMT) != S_IFLNK) {numProb++; Msg("Data file xrefs non-symlink pfn ", Pfn); if (Opt.Fix) {if (Opt.Force) Resp = 'n'; else Resp = XrdFrcUtils::Ask('n',"Remove data file?"); if (Resp == 'y') {if (unlink(sP->basePath())) Emsg(errno,"remove ",sP->basePath()); else {Msg("Data file removed."); numFix++; return -1;} } } numBLost += sP->baseFile()->Stat.st_size; return Resp != 'a'; } // Check if xrefs are consistent. // if ((n = readlink(Pfn, lkbuff, sizeof(lkbuff)-1)) < 0) {Emsg(errno, "read link from ", Pfn); numProb++; return 1;} lkbuff[n] = '\0'; if (!strcmp(sP->basePath(), lkbuff)) return 1; // Issue first message (there is value in seeing the data file path) // Msg("Inconsistent data file: ", sP->basePath()); numProb++; // Diagnose the problem and check if fix is possible // if (!stat(lkbuff, &buf)) Plug = "exists."; else if (errno == ENOENT) Plug = "is missing."; else {Emsg(errno, "stat ", lkbuff); return 1;} Msg("Data file xrefs pfn ", Pfn); Msg("Pfn points to a different data file that ", Plug); if (!Opt.Fix) return 1; // If the data file is orphaned then check if we can remove it otherwise // see if we can simply change the symlink to point to this file // if (*Plug == 'e') {if (Opt.Force) Resp = 'n'; else Resp = XrdFrcUtils::Ask('n',"Remove unreferenced data file?"); if (Resp == 'y') {if (unlink(sP->basePath())) Emsg(errno,"remove ",sP->basePath()); else {Msg("Data file removed."); numFix++; return -1;} } } else { if (Opt.Force) Resp = 'n'; else Resp = XrdFrcUtils::Ask('n',"Change pfn symlink?"); if (Resp == 'y') {*tempPath = ' '; strcpy(tempPath+1, Pfn); unlink(tempPath); if (symlink(sP->basePath(), tempPath) || rename(tempPath, Pfn)) {Emsg(errno, "create symlink ", Pfn); unlink(tempPath);} else {Msg("pfn symlink changed."); numFix++; return 1;} } } // Space for this file is definitely lost // numBLost += sP->baseFile()->Stat.st_size; return Resp != 'a'; } /******************************************************************************/ /* A u d i t S p a c e X B */ /******************************************************************************/ int XrdFrmAdmin::AuditSpaceXB(const char *Space, const char *Path) { XrdFrmFileset *sP; XrdFrmFiles *fP; char tmpv[8], *buff; int ec = 0, Act = 1; // Construct the right space path and get a files object // buff = XrdOssPath::genPath(Path, Space, tmpv); fP = new XrdFrmFiles(buff, XrdFrmFiles::Recursive | XrdFrmFiles::NoAutoDel); // Go and check out the files // while(Act && (sP = fP->Get(ec,1))) { if (!(sP->baseFile())) Act = AuditNameNB(sP); else if (!(sP-> pfnFile())) Act = AuditSpaceXANB(sP); else {numFiles++; numBytes += sP->baseFile()->Stat.st_size;} delete sP; } // All done // if (ec) finalRC = 4; free(buff); delete fP; return Act; } /******************************************************************************/ /* A u d i t S p a c e X A N B */ /******************************************************************************/ int XrdFrmAdmin::AuditSpaceXANB(XrdFrmFileset *sP) { char Resp; // Update statistics which we may have to correct later // numProb++; numFiles++; numBytes += sP->baseFile()->Stat.st_size; // Report what is orphaned // Msg("Missing pfn file for data file ", sP->basePath()); // Return if no fix is needed, otherwise check if we should ask before removal // if (!Opt.Fix) return -1; if (!Opt.Force) {Resp = XrdFrcUtils::Ask('n', "Remove data file?"); if (Resp != 'y') return Resp != 'a'; } // Remove the file // if (unlink(sP->basePath())) Emsg(errno,"remove data file ", sP->basePath()); else {numFix++; numFiles--; numBytes -= sP->baseFile()->Stat.st_size;} return 1; } /******************************************************************************/ /* A u d i t U s a g e */ /******************************************************************************/ int XrdFrmAdmin::AuditUsage() { XrdFrmConfig::VPInfo *vP = Config.VPList; char Sbuff[1024]; int retval, rc; // Check if we have a space or we should do all spaces // if (Opt.Args[1]) return AuditUsage(Opt.Args[1]); // If no cache configured say so // if (!vP) {Emsg("No outplace space has been configured."); return -1;} // Audit usage for each space // retval = 1; while(vP) {strcpy(Sbuff, vP->Name); if (!(rc = AuditUsage(Sbuff))) return 0; if (rc < 0) retval = rc; vP = vP->Next; } return retval; } /******************************************************************************/ int XrdFrmAdmin::AuditUsage(char *Space) { XrdOucTList *pP; const char *Sfx; char Resp, buff[256], *Path = 0; long long theClaim, theDiff; int haveUsage, Probs = 0; // Parse the space specification // if (!(pP = ParseSpace(Space, &Path))) return -1; if (Path) {Emsg("Path not allowed for audit usage."); return -1;} // Initialize // numBytes = 0; numFiles = 0; numProb = 0; haveUsage = XrdOssSpace::Init(); // Index the space via filesets // do {Probs |= (pP->val ? AuditUsageXA(pP->text, Space) : AuditUsageAX(pP->text)); pP = pP->next; } while(pP); // Print ending condition // sprintf(buff, "Audit of %d file%s in %s space completed with %serrors.", numFiles, (numFiles == 1 ? "" : "s"), Space, (Probs ? "" : "no ")); Msg(buff); // Print what is in the usage file // if (haveUsage) {XrdOssSpace::uEnt myEnt; XrdOssSpace::Usage(Space, myEnt); theClaim = myEnt.Bytes[XrdOssSpace::Serv] + myEnt.Bytes[XrdOssSpace::Pstg] - myEnt.Bytes[XrdOssSpace::Purg] + myEnt.Bytes[XrdOssSpace::Admin]; sprintf(buff, "%12lld", theClaim); Msg("Claimed: ", buff); } else theClaim = numBytes; // Print what we came up with // sprintf(buff, "%12lld", numBytes); Msg("Actual: ", buff); // Check if fix is required and wanted // if (numBytes == theClaim || !Opt.Fix) return 1; if (!haveUsage) {Emsg(0, "No usage file present to fix!"); return -1;} // Compute difference // if (theClaim < numBytes) theDiff = numBytes - theClaim; else theDiff = theClaim - numBytes; // See if we should fix this // if (!Opt.Force) {if (theDiff < 500000) Sfx = "byte"; {theDiff = (theDiff+512)/1024; Sfx = "KB";} sprintf(buff, "Fix %lld %s difference?", theDiff, Sfx); Resp = XrdFrcUtils::Ask('n', "Fix usage information?"); if (Resp != 'y') return Resp != 'a'; } // Fix the problem // XrdOssSpace::Adjust(Space, numBytes-theClaim, XrdOssSpace::Admin); return 1; } /******************************************************************************/ /* A u d i t U s a g e A X */ /******************************************************************************/ int XrdFrmAdmin::AuditUsageAX(const char *Path) { XrdOucNSWalk nsWalk(&Say, Path, 0, XrdOucNSWalk::retFile | XrdOucNSWalk::retStat | XrdOucNSWalk::skpErrs); XrdOucNSWalk::NSEnt *nP, *pP; int ec; // Get the files in this directory // if (!(nP = nsWalk.Index(ec))) {if (ec) finalRC = 4; return 1;} // Now traverse through all of the files // while(nP) {numBytes += nP->Stat.st_size; numFiles++; pP = nP; nP = nP->Next; delete pP; } // All done // return 0; } /******************************************************************************/ /* A u d i t U s a g e X A */ /******************************************************************************/ int XrdFrmAdmin::AuditUsageXA(const char *Path, const char *Space) { XrdFrmFileset *sP; XrdFrmFiles *fP; char tmpv[8], *buff; int ec = 0; // Construct the right space path and get a files object // buff = XrdOssPath::genPath(Path, Space, tmpv); fP = new XrdFrmFiles(buff, XrdFrmFiles::Recursive | XrdFrmFiles::NoAutoDel); // Go and check out the files // while((sP = fP->Get(ec))) {if ((sP->baseFile())) {numFiles++; numBytes += sP->baseFile()->Stat.st_size;} delete sP; } // All done // free(buff); delete fP; return ec; } /******************************************************************************/ /* i s X A */ /******************************************************************************/ int XrdFrmAdmin::isXA(XrdOucNSWalk::NSEnt *nP) { char *lP; if (!(nP->Link)) return 0; lP = nP->Link + nP->Lksz -1; return (*lP == XrdOssPath::xChar); }