XrdOucNSWalk.cc

Go to the documentation of this file.
00001 /******************************************************************************/
00002 /*                                                                            */
00003 /*                       X r d O u c N S W a l k . c c                        */
00004 /*                                                                            */
00005 /* (c) 2009 by the Board of Trustees of the Leland Stanford, Jr., University  */
00006 /*                            All Rights Reserved                             */
00007 /*   Produced by Andrew Hanushevsky for Stanford University under contract    */
00008 /*              DE-AC02-76-SFO0515 with the Department of Energy              */
00009 /******************************************************************************/
00010   
00011 //         $Id: XrdOucNSWalk.cc 34000 2010-06-21 06:49:56Z ganis $
00012 
00013 const char *XrdOucNSWalkCVSID = "$Id: XrdOucNSWalk.cc 34000 2010-06-21 06:49:56Z ganis $";
00014 
00015 #include <string.h>
00016 #include <errno.h>
00017 #include <dirent.h>
00018 #include <unistd.h>
00019 
00020 #include "XrdOuc/XrdOucNSWalk.hh"
00021 #include "XrdOuc/XrdOucTList.hh"
00022 #include "XrdSys/XrdSysError.hh"
00023 #include "XrdSys/XrdSysPlatform.hh"
00024 
00025 /******************************************************************************/
00026 /*                           C o n s t r u c t o r                            */
00027 /******************************************************************************/
00028   
00029 XrdOucNSWalk::XrdOucNSWalk(XrdSysError *erp, const char *dpath,
00030                                              const char *lkfn, int opts,
00031                                              XrdOucTList *xlist)
00032 {
00033 // Set the required fields
00034 //
00035    eDest = erp;
00036    DList = new XrdOucTList(dpath);
00037    if (lkfn) LKFn = strdup(lkfn);
00038       else   LKFn = 0;
00039    Opts = opts;
00040    DPfd = LKfd = -1;
00041    errOK= opts & skpErrs;
00042    DEnts= 0;
00043    edCB = 0;
00044 
00045 // Copy the exclude list if one exists
00046 //
00047    if (!xlist) XList = 0;
00048       else while(xlist)
00049                 {XList = new XrdOucTList(xlist->text,xlist->ival,XList);
00050                  xlist = xlist->next;
00051                 }
00052 }
00053 
00054 /******************************************************************************/
00055 /*                            D e s t r u c t o r                             */
00056 /******************************************************************************/
00057   
00058 XrdOucNSWalk::~XrdOucNSWalk()
00059 {
00060    XrdOucTList *tP;
00061 
00062    if (LKFn) free(LKFn);
00063 
00064    while((tP = DList)) {DList = tP->next; delete tP;}
00065 
00066    while((tP = XList)) {XList = tP->next; delete tP;}
00067 }
00068 
00069 /******************************************************************************/
00070 /*                                 I n d e x                                  */
00071 /******************************************************************************/
00072   
00073 XrdOucNSWalk::NSEnt *XrdOucNSWalk::Index(int &rc, const char **dPath)
00074 {
00075    XrdOucTList *tP;
00076    NSEnt *eP;
00077 
00078 // Sequence the directory
00079 //
00080    rc = 0; *DPath = '\0';
00081    while((tP = DList))
00082         {setPath(tP->text);
00083          DList = tP->next; delete tP;
00084          if (LKFn && (rc = LockFile())) break;
00085          rc = Build();
00086          if (LKfd >= 0) close(LKfd);
00087          if (DEnts || (rc && !errOK)) break;
00088          if (edCB && isEmpty) edCB->isEmpty(&dStat, DPath, LKFn);
00089         }
00090 
00091 // Return the result
00092 //
00093    eP = DEnts; DEnts = 0;
00094    if (dPath) *dPath = DPath;
00095    return eP;
00096 }
00097 
00098 /******************************************************************************/
00099 /*                       P r i v a t e   M e t h o d s                        */
00100 /******************************************************************************/
00101 /******************************************************************************/
00102 /*                                a d d E n t                                 */
00103 /******************************************************************************/
00104   
00105 void XrdOucNSWalk::addEnt(XrdOucNSWalk::NSEnt *eP)
00106 {
00107    static const int retIxLO = retIDLO | retIILO;
00108 
00109 // Complete the entry
00110 //
00111    if (Opts & noPath) {eP->Path = strdup(File); eP->File = eP->Path;}
00112       else {eP->Path = strdup(DPath);
00113             eP->File = eP->Path + (File - DPath);
00114            }
00115     eP->Plen = (eP->File - eP->Path) + strlen(eP->File);
00116 
00117 // Chain the entry into the list
00118 //
00119    if (!(Opts & retIxLO)) {eP->Next = DEnts; DEnts = eP;}
00120       else {NSEnt *pP = 0, *nP = DEnts;
00121             if (Opts & retIDLO)
00122                while(nP && eP->Plen < nP->Plen) {pP = nP; nP = nP->Next;}
00123                else
00124                while(nP && eP->Plen > nP->Plen) {pP = nP; nP = nP->Next;}
00125             if (pP) {eP->Next = nP; pP->Next = eP;}
00126                else {eP->Next = nP; DEnts    = eP;}
00127            }
00128 }
00129 
00130 /******************************************************************************/
00131 /*                                 B u i l d                                  */
00132 /******************************************************************************/
00133   
00134 int XrdOucNSWalk::Build()
00135 {
00136    struct Helper {XrdOucNSWalk::NSEnt *P;
00137                   DIR                 *D;
00138                   int                  F;
00139                                        Helper() : P(0), D(0), F(-1) {}
00140                                       ~Helper() {if (P)   delete P;
00141                                                  if (D)   closedir(D);
00142                                                  if (F>0) close(F);
00143                                                 }
00144                  } theEnt;
00145    struct dirent  *dp;
00146    int             rc = 0, getLI = Opts & retLink;
00147    int             nEnt = 0, xLKF = 0, chkED = (edCB != 0) && (LKFn != 0);
00148 
00149 // Initialize the empty flag prior to doing anything else
00150 //
00151    isEmpty = 0;
00152 
00153 // If we can optimize with a directory file descriptor, get one
00154 //
00155 #ifdef HAVE_FSTATAT
00156    if ((DPfd = open(DPath, O_RDONLY)) < 0) rc = errno;
00157       else theEnt.F = DPfd;
00158 #else
00159    DPfd = -1;
00160 #endif
00161 
00162 // Open the directory
00163 //
00164    if (!(theEnt.D = opendir(DPath)))
00165       {rc = errno;
00166        if (eDest) eDest->Emsg("Build", rc, "open directory", DPath);
00167        return rc;
00168       }
00169 
00170 // Process the entries
00171 //
00172    errno = 0;
00173    while((dp = readdir(theEnt.D)))
00174         {if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) continue;
00175          strcpy(File, dp->d_name); nEnt++;
00176          if (!theEnt.P) theEnt.P = new NSEnt();
00177          rc = getStat(theEnt.P, getLI);
00178          switch(theEnt.P->Type)
00179                {case NSEnt::isDir:
00180                      if (Opts & Recurse && (!getLI || !isSymlink())
00181                      &&  (!XList || !inXList(File)))
00182                         DList = new XrdOucTList(DPath, 0, DList);
00183                      if (!(Opts & retDir)) continue;
00184                      break;
00185                 case NSEnt::isFile:
00186                      if ((chkED && !xLKF && (xLKF = !strcmp(File, LKFn)))
00187                      ||  !(Opts & retFile)) continue;
00188                      break;
00189                 case NSEnt::isLink:
00190                      if ((rc = getLink(theEnt.P)))
00191                         memset(&theEnt.P->Stat, 0, sizeof(struct stat));
00192                         else if ((Opts & retStat) && (rc = getStat(theEnt.P)))
00193                                 {theEnt.P->Type = NSEnt::isLink; rc = 0;}
00194                      break;
00195                 case NSEnt::isMisc:
00196                      if (!(Opts & retMisc)) continue;
00197                      break;
00198                 default:
00199                      if (!rc) rc = EINVAL;
00200                      break;
00201                }
00202          errno = 0;
00203          if (rc) {if (errOK) continue; return rc;}
00204          addEnt(theEnt.P); theEnt.P = 0; 
00205         }
00206 
00207 // All done, check if we reached EOF or there is an error
00208 //
00209    *File = '\0';
00210    if ((rc = errno) && !errOK)
00211       {eDest->Emsg("Build", rc, "reading directory", DPath); return rc;}
00212 
00213 // Check if we need to do a callback for an empty directory
00214 //
00215    if (edCB && xLKF == nEnt && !DEnts)
00216       {if ((DPfd < 0 ? !stat(DPath, &dStat) : !fstat(DPfd, &dStat))) isEmpty=1;
00217           else eDest->Emsg("Build", errno, "stating directory", DPath);
00218       }
00219    return 0;
00220 }
00221 
00222 /******************************************************************************/
00223 /*                               g e t L i n k                                */
00224 /******************************************************************************/
00225 
00226 int XrdOucNSWalk::getLink(XrdOucNSWalk::NSEnt *eP)
00227 {
00228    char lnkbuff[2048];
00229    int rc;
00230 
00231    if ((rc = readlink(DPath, lnkbuff, sizeof(lnkbuff))) < 0)
00232       {rc = errno;
00233        if (eDest) eDest->Emsg("getLink", rc, "read link of", DPath);
00234        return rc;
00235       }
00236 
00237    eP->Lksz = rc;
00238    eP->Link = (char *)malloc(rc+1);
00239    memcpy(eP->Link, lnkbuff, rc);
00240    *(eP->Link+rc) = '\0';
00241    return 0;
00242 }
00243   
00244 /******************************************************************************/
00245 /*                               g e t S t a t                                */
00246 /******************************************************************************/
00247   
00248 int XrdOucNSWalk::getStat(XrdOucNSWalk::NSEnt *eP, int doLstat)
00249 {
00250    int rc;
00251 
00252 // The following code either uses fstatat() or regular stat()
00253 //
00254 #ifdef HAVE_FSTATAT
00255 do{rc = fstatat(DPfd, File, &(eP->Stat), (doLstat ? AT_SYMLINK_NOFOLLOW : 0));
00256 #else
00257 do{rc = doLstat ? lstat(DPath, &(eP->Stat)) : stat(DPath, &(eP->Stat));
00258 #endif
00259   } while(rc && errno == EINTR);
00260 
00261 // Check for errors
00262 //
00263    if (rc)
00264       {rc = errno;
00265        if (eDest && rc != ENOENT && rc != ELOOP)
00266           eDest->Emsg("getStat", rc, "stat", DPath);
00267        memset(&eP->Stat, 0, sizeof(struct stat));
00268        eP->Type = NSEnt::isBad;
00269        return rc;
00270       }
00271 
00272 // Set appropraite type
00273 //
00274         if ((eP->Stat.st_mode & S_IFMT) == S_IFDIR) eP->Type = NSEnt::isDir;
00275    else if ((eP->Stat.st_mode & S_IFMT) == S_IFREG) eP->Type = NSEnt::isFile;
00276    else if ((eP->Stat.st_mode & S_IFMT) == S_IFLNK) eP->Type = NSEnt::isLink;
00277    else                                             eP->Type = NSEnt::isMisc;
00278 
00279    return 0;
00280 }
00281   
00282 /******************************************************************************/
00283 /*                               i n X L i s t                                */
00284 /******************************************************************************/
00285   
00286 int XrdOucNSWalk::inXList(const char *dName)
00287 {
00288     XrdOucTList *xTP = XList, *pTP = 0;
00289 
00290 // Search for the directory entry
00291 //
00292     while(xTP && strcmp(DPath, xTP->text)) {pTP = xTP; xTP = xTP->next;}
00293 
00294 // If not found return false. Otherwise, delete the entry and return true.
00295 //
00296    if (!xTP) return 0;
00297    if (pTP) pTP->next = xTP->next;
00298       else      XList = xTP->next;
00299    delete xTP;
00300    return 1;
00301 }
00302   
00303 /******************************************************************************/
00304 /*                             i s S y m l i n k                              */
00305 /******************************************************************************/
00306   
00307 int XrdOucNSWalk::isSymlink()
00308 {
00309    struct stat buf;
00310    int rc;
00311 
00312 
00313 // The following code either uses fstatat() or regular stat()
00314 //
00315 #ifdef HAVE_FSTATAT
00316 do{rc = fstatat(DPfd, File, &buf, AT_SYMLINK_NOFOLLOW);
00317 #else
00318 do{rc = lstat(DPath, &buf);
00319 #endif
00320   } while(rc && errno == EINTR);
00321 
00322 // Check for errors
00323 //
00324    if (rc) return 0;
00325    return (buf.st_mode & S_IFMT) == S_IFLNK;
00326 }
00327 
00328 /******************************************************************************/
00329 /*                              L o c k F i l e                               */
00330 /******************************************************************************/
00331   
00332 int XrdOucNSWalk::LockFile()
00333 {
00334    FLOCK_t lock_args;
00335    int rc;
00336 
00337 // Construct the path and open the file
00338 //
00339    strcpy(File, LKFn);
00340    do {LKfd = open(DPath, O_RDWR);} while(LKfd < 0 && errno == EINTR);
00341    if (LKfd < 0)
00342       {if (errno == ENOENT) {*File = '\0'; return 0;}
00343           {rc = errno;
00344            if (eDest) eDest->Emsg("LockFile", rc, "open", DPath);
00345            *File = '\0'; return rc;
00346           }
00347       }
00348 
00349 // Establish locking options
00350 //
00351    bzero(&lock_args, sizeof(lock_args));
00352    lock_args.l_type = F_WRLCK;
00353 
00354 // Perform action.
00355 //
00356    do {rc = fcntl(LKfd,F_SETLKW,&lock_args);}
00357        while(rc < 0 && errno == EINTR);
00358    if (rc < 0)
00359        {rc = -errno;
00360         if (eDest) eDest->Emsg("LockFile", errno, "lock", DPath);
00361        }
00362 
00363 // All done
00364 //
00365    *File = '\0';
00366    return rc;
00367 }
00368 
00369 /******************************************************************************/
00370 /*                               s e t P a t h                                */
00371 /******************************************************************************/
00372   
00373 void XrdOucNSWalk::setPath(char *newpath)
00374 {
00375    int n;
00376 
00377    strcpy(DPath, newpath);
00378    n = strlen(newpath);
00379    if (DPath[n-1] != '/')
00380       {DPath[n++] = '/'; DPath[n] = '\0';}
00381    File = DPath+n;
00382 }

Generated on Tue Jul 5 14:46:50 2011 for ROOT_528-00b_version by  doxygen 1.5.1