[BACK]Return to file.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / cvs

Diff for /src/usr.bin/cvs/file.c between version 1.99 and 1.100

version 1.99, 2005/07/22 16:27:29 version 1.100, 2005/07/23 11:19:46
Line 44 
Line 44 
 #include "log.h"  #include "log.h"
 #include "strtab.h"  #include "strtab.h"
   
   
 #define CVS_IGN_STATIC    0x01     /* pattern is static, no need to glob */  #define CVS_IGN_STATIC    0x01     /* pattern is static, no need to glob */
   
 #define CVS_CHAR_ISMETA(c)  ((c == '*') || (c == '?') || (c == '['))  #define CVS_CHAR_ISMETA(c)  ((c == '*') || (c == '?') || (c == '['))
Line 106 
Line 105 
   
 TAILQ_HEAD(, cvs_ignpat)  cvs_ign_pats;  TAILQ_HEAD(, cvs_ignpat)  cvs_ign_pats;
   
   static int cvs_file_getdir(CVSFILE *, int, int (*)(CVSFILE *, void *),
       void *, int);
   
 static int cvs_file_getdir(CVSFILE *, int, char *, int (*)(CVSFILE *, void *), void *);  
 static int      cvs_load_dirinfo  (CVSFILE *, int);  static int      cvs_load_dirinfo  (CVSFILE *, int);
 static int      cvs_file_sort    (struct cvs_flist *, u_int);  static int      cvs_file_sort    (struct cvs_flist *, u_int);
 static int      cvs_file_cmp     (const void *, const void *);  static int      cvs_file_cmp     (const void *, const void *);
Line 248 
Line 248 
 cvs_file_create(CVSFILE *parent, const char *path, u_int type, mode_t mode)  cvs_file_create(CVSFILE *parent, const char *path, u_int type, mode_t mode)
 {  {
         int fd, l;          int fd, l;
         int bail;  
         char fp[MAXPATHLEN], repo[MAXPATHLEN];          char fp[MAXPATHLEN], repo[MAXPATHLEN];
         CVSFILE *cfp;          CVSFILE *cfp;
         CVSENTRIES *ent;          CVSENTRIES *ent;
Line 257 
Line 256 
         if (cfp == NULL)          if (cfp == NULL)
                 return (NULL);                  return (NULL);
   
         bail = l = 0;          l = 0;
         cfp->cf_mode = mode;          cfp->cf_mode = mode;
         cfp->cf_parent = parent;          cfp->cf_parent = parent;
   
         if (type == DT_DIR) {          if (type == DT_DIR) {
                 cfp->cf_root = cvsroot_get(path);                  cfp->cf_root = cvsroot_get(path);
   
                 /*  
                  * If we do not have a valid root for this, try looking at  
                  * the parent its root.  
                  */  
                 if (cfp->cf_root == NULL) {                  if (cfp->cf_root == NULL) {
                         if (parent != NULL && parent->cf_root != NULL) {                          cvs_file_free(cfp);
                                 cfp->cf_root =  
                                     cvsroot_parse(parent->cf_root->cr_str);  
                                 if (cfp->cf_root == NULL)  
                                         bail = 1;  
                         } else {  
                                 bail = 1;  
                         }  
                 }  
   
                 /* we tried, too bad */  
                 if (bail) {  
                         cvs_log(LP_ERR, "failed to obtain root info for `%s'",  
                             path);  
                         return (NULL);                          return (NULL);
                 }                  }
   
Line 385 
Line 366 
  * with cvs_file_free().   * with cvs_file_free().
  */   */
   
 CVSFILE*  int
 cvs_file_get(const char *path, int flags, int (*cb)(CVSFILE *, void *),  cvs_file_get(const char *path, int flags, int (*cb)(CVSFILE *, void *),
     void *arg)      void *arg, struct cvs_flist *list)
 {  {
         char *files[1];          char *files[1];
   
         files[0] = path;          files[0] = path;
         return cvs_file_getspec(files, 1, flags, cb, arg);          return cvs_file_getspec(files, 1, flags, cb, arg, list);
 }  }
   
   
 /*  /*
  * cvs_file_getspec()   * cvs_file_getspec()
  *   *
  * Load a specific set of files whose paths are given in the vector <fspec>,   * Obtain the info about the supplied files or directories.
  * whose size is given in <fsn>.  
  * Returns a pointer to the lowest common subdirectory to all specified  
  * files.  
  */   */
 CVSFILE*  int
 cvs_file_getspec(char **fspec, int fsn, int flags, int (*cb)(CVSFILE *, void *),  cvs_file_getspec(char **fspec, int fsn, int flags, int (*cb)(CVSFILE *, void *),
     void *arg)      void *arg, struct cvs_flist *list)
 {  {
         int i;          int i, freecf;
         int pwd;          char pcopy[MAXPATHLEN];
         char *sp, *np, pcopy[MAXPATHLEN];          CVSFILE *cf;
         CVSFILE *base, *nf;          extern char *cvs_rootstr;
         CVSENTRIES *entfile;  
         struct cvs_ent *ent;  
   
         base = cvs_file_lget(".", 0, NULL, NULL);          freecf = (list == NULL);
         if (base == NULL)          cvs_error = CVS_EX_DATA;
                 return (NULL);  
   
         entfile = cvs_ent_open(".", O_RDONLY);          /* init the list */
           if (list != NULL)
                   SIMPLEQ_INIT(list);
   
         /*          /*
          * fill in the repository base (needed to construct repo's in           * Fetch the needed information about ".", so we can setup a few
          * cvs_file_create).           * things to get ourselfs going.
          */           */
         if (base->cf_repo != NULL) {          cf = cvs_file_lget(".", 0, NULL, NULL);
                 cvs_repo_base = strdup(base->cf_repo);          if (cf == NULL) {
                   cvs_log(LP_ERR, "arrrr i failed captain!");
                   return (-1);
           }
   
           /*
            * save the base repository path so we can use it to create
            * the correct full repopath later on.
            */
           if (cf->cf_repo != NULL) {
                   if (cvs_repo_base != NULL)
                           free(cvs_repo_base);
                   cvs_repo_base = strdup(cf->cf_repo);
                 if (cvs_repo_base == NULL) {                  if (cvs_repo_base == NULL) {
                         cvs_log(LP_ERR, "failed to duplicate repository base");                          cvs_log(LP_ERRNO, "strdup failed");
                         cvs_file_free(base);                          cvs_file_free(cf);
                         if (entfile)                          return (-1);
                                 cvs_ent_close(entfile);  
                         return (NULL);  
                 }                  }
         }          }
   
         /*          /*
          * XXX - needed for some commands           * This will go away when we have support for multiple Roots.
          */           */
         if (cb != NULL) {          if (cvs_rootstr == NULL && cf->cf_root != NULL) {
                 if (cb(base, arg) != CVS_EX_OK) {                  cvs_rootstr = strdup(cf->cf_root->cr_str);
                         cvs_file_free(base);                  if (cvs_rootstr == NULL) {
                         if (entfile)                          cvs_log(LP_ERRNO, "strdup failed");
                                 cvs_ent_close(entfile);                          cvs_file_free(cf);
                         return (NULL);                          return (-1);
                 }                  }
         }          }
   
           cvs_error = CVS_EX_OK;
           cvs_file_free(cf);
   
           /*
            * Since some commands don't require any files to operate
            * we can stop right here for those.
            */
           if (cvs_cmdop == CVS_OP_CHECKOUT || cvs_cmdop == CVS_OP_VERSION)
                   return (0);
   
         for (i = 0; i < fsn; i++) {          for (i = 0; i < fsn; i++) {
                 strlcpy(pcopy, fspec[i], sizeof(pcopy));                  strlcpy(pcopy, fspec[i], sizeof(pcopy));
                 sp = pcopy;  
                 pwd = (!strcmp(pcopy, "."));  
   
                 np = strchr(sp, '/');                  /*
                 if (np != NULL)                   * Load the information.
                         *np = '\0';                   */
                   cf = cvs_file_loadinfo(pcopy, flags, cb, arg, freecf);
                   if (cf == NULL)
                           continue;
   
                 if (pwd) {                  /*
                         nf = base;                   * If extra actions are needed, do them now.
                    */
                   if (cf->cf_type == DT_DIR) {
                           /* do possible extra actions .. */
                 } else {                  } else {
                         nf = cvs_file_find(base, pcopy);                          /* do possible extra actions .. */
                         if (nf == NULL) {  
                                 if (entfile != NULL)  
                                         ent = cvs_ent_get(entfile, pcopy);  
                                 else  
                                         ent = NULL;  
                                 nf = cvs_file_lget(pcopy, 0, base, ent);  
                                 if (nf == NULL) {  
                                         cvs_file_free(base);  
                                         if (entfile)  
                                                 cvs_ent_close(entfile);  
                                         return (NULL);  
                                 }  
   
                                 if (cvs_file_attach(base, nf) < 0) {  
                                         cvs_file_free(base);  
                                         if (entfile)  
                                                 cvs_ent_close(entfile);  
                                         return (NULL);  
                                 }  
                         }  
                 }                  }
   
                 if (nf->cf_type == DT_DIR) {                  /*
                         if (np != NULL)                   * Attach it to a list if requested, otherwise
                                 *np++;                   * just free it again.
                    */
                   if (list != NULL)
                           SIMPLEQ_INSERT_TAIL(list, cf, cf_list);
                   else
                           cvs_file_free(cf);
           }
   
                         if (cvs_file_getdir(nf, flags, np, cb, arg) < 0) {          return (0);
                                 cvs_file_free(base);  }
                                 if (entfile)  
                                         cvs_ent_close(entfile);  /*
                                 return (NULL);   * Load the neccesary information about file or directory <path>.
                         }   * Returns a pointer to the loaded information on success, or NULL
                 } else {   * on failure.
                         if (cb != NULL) {   *
                                 if (cb(nf, arg) != CVS_EX_OK) {   * If cb is not NULL, the requested path will be passed to that callback
                                         cvs_file_free(base);   * with <arg> as an argument.
                                         if (entfile)   *
                                                 cvs_ent_close(entfile);   * the <freecf> argument is passed to cvs_file_getdir, if this is 1
                                         return (NULL);   * CVSFILE * structs will be free'd once we are done with them.
                                 }   */
                         }  CVSFILE *
   cvs_file_loadinfo(char *path, int flags, int (*cb)(CVSFILE *, void *),
       void *arg, int freecf)
   {
           CVSFILE *cf, *base;
           CVSENTRIES *entf;
           struct cvs_ent *ent;
           char *p;
           char parent[MAXPATHLEN], item[MAXPATHLEN];
           int type;
           struct stat st;
           struct cvsroot *root;
   
           type = 0;
           base = cf = NULL;
           entf = NULL;
           ent = NULL;
   
           /*
            * We first have to find out what type of item we are
            * dealing with. A file or a directory.
            *
            * We can do this by stat(2)'ing the item, but since it
            * might be gone we also check the Entries file in the
            * parent directory.
            */
   
           /* get parent directory */
           if ((p = strrchr(path, '/')) != NULL) {
                   *p++ = '\0';
                   strlcpy(parent, path, sizeof(parent));
                   strlcpy(item, p, sizeof(item));
                   *--p = '/';
           } else {
                   strlcpy(parent, ".", sizeof(parent));
                   strlcpy(item, path, sizeof(item));
           }
   
           /*
            * There might not be an Entries file, so do not fail if there
            * is none available to get the info from.
            */
           entf = cvs_ent_open(parent, O_RDONLY);
   
           /*
            * Load the Entry if we successfully opened the Entries file.
            */
           if (entf != NULL)
                   ent = cvs_ent_get(entf, item);
   
           /*
            * No Entry available? fall back to stat(2)'ing the item, if
            * that fails, bail out in client mode, or assume a file in
            * server mode (it will show up as CVS_FST_UNKNOWN).
            */
           if (ent == NULL) {
                   if (stat(path, &st) == -1) {
                           if (cvs_cmdop != CVS_OP_SERVER)
                                   goto fail;
                           type = DT_REG;
                   } else
                           type = IFTODT(st.st_mode);
           } else {
                   if (ent->ce_type == CVS_ENT_DIR)
                           type = DT_DIR;
                   else
                           type = DT_REG;
           }
   
           /*
            * Get the base, which is <parent> for a normal file or
            * <path> for a directory.
            */
           if (type == DT_DIR)
                   base = cvs_file_lget(path, flags, NULL, ent);
           else
                   base = cvs_file_lget(parent, flags, NULL, NULL);
   
           if (base == NULL) {
                   cvs_log(LP_ERR, "failed to obtain directory info for '%s'",
                       parent);
                   goto fail;
           }
   
           /*
            * Sanity.
            */
           if (base->cf_type != DT_DIR) {
                   cvs_log(LP_ERR, "base directory isn't a directory at all");
                   goto fail;
           }
   
           root = CVS_DIR_ROOT(base);
           if (root == NULL) {
                   cvs_log(LP_ERR, "no Root in base directory found");
                   goto fail;
           }
   
           /*
            * If we have a normal file, get the info and link it
            * to the base.
            */
           if (type != DT_DIR) {
                   cf = cvs_file_lget(path, flags, base, ent);
                   if (cf == NULL) {
                           cvs_log(LP_ERR, "failed to fetch '%s'", path);
                           goto fail;
                 }                  }
   
                   cvs_file_attach(base, cf);
         }          }
   
         if (entfile)          if (entf != NULL) {
                 cvs_ent_close(entfile);                  cvs_ent_close(entf);
                   entf = NULL;
           }
   
           /*
            * Always pass the base directory, unless:
            * - we are running in server or local mode and the path is not "."
            * - the directory does not exist on disk.
            * - the callback is NULL.
            */
           if (!(((cvs_cmdop == CVS_OP_SERVER) ||
               (root->cr_method == CVS_METHOD_LOCAL)) && (strcmp(path, "."))) &&
               (base->cf_flags & CVS_FILE_ONDISK) && (cb != NULL) &&
               ((cvs_error = cb(base, arg)) != CVS_EX_OK))
                   goto fail;
   
           /*
            * If we have a normal file, pass it as well.
            */
           if (type != DT_DIR) {
                   if ((cb != NULL) && ((cvs_error = cb(cf, arg)) != CVS_EX_OK))
                           goto fail;
           } else {
                   /*
                    * If the directory exists, recurse through it.
                    */
                   if ((base->cf_flags & CVS_FILE_ONDISK) &&
                       cvs_file_getdir(base, flags, cb, arg, freecf) < 0) {
                           cvs_log(LP_ERR, "cvs_file_getdir failed");
                           goto fail;
                   }
           }
   
         return (base);          return (base);
   
   fail:
           if (entf != NULL)
                   cvs_ent_close(entf);
           if (base != NULL)
                   cvs_file_free(base);
           return (NULL);
 }  }
   
   
 /*  /*
  * cvs_file_find()   * cvs_file_find()
  *   *
Line 569 
Line 701 
  * Get the full path of the file <file> and store it in <buf>, which is of   * Get the full path of the file <file> and store it in <buf>, which is of
  * size <len>.  For portability, it is recommended that <buf> always be   * size <len>.  For portability, it is recommended that <buf> always be
  * at least MAXPATHLEN bytes long.   * at least MAXPATHLEN bytes long.
  * Returns a pointer to the start of the path on success, or NULL on failure.   * Returns a pointer to the start of the path.
  */   */
 char*  char*
 cvs_file_getpath(CVSFILE *file, char *buf, size_t len)  cvs_file_getpath(CVSFILE *file, char *buf, size_t len)
 {  {
         u_int i;          memset(buf, '\0', len);
         const char *fp, *namevec[CVS_FILE_MAXDEPTH];          if (file->cf_dir != NULL) {
         CVSFILE *top;                  strlcat(buf, file->cf_dir, len);
   
         buf[0] = '\0';  
         i = CVS_FILE_MAXDEPTH;  
         memset(namevec, 0, sizeof(namevec));  
   
         /* find the top node */  
         for (top = file; (top != NULL) && (i > 0); top = top->cf_parent) {  
                 fp = top->cf_name;  
   
                 /* skip self-references */  
                 if ((fp[0] == '.') && (fp[1] == '\0'))  
                         continue;  
                 namevec[--i] = fp;  
         }  
   
         if (i == 0)  
                 return (NULL);  
         else if (i == CVS_FILE_MAXDEPTH) {  
                 strlcpy(buf, ".", len);  
                 return (buf);  
         }  
   
         while (i < CVS_FILE_MAXDEPTH - 1) {  
                 strlcat(buf, namevec[i++], len);  
                 strlcat(buf, "/", len);                  strlcat(buf, "/", len);
         }          }
         strlcat(buf, namevec[i], len);  
   
           strlcat(buf, file->cf_name, len);
         return (buf);          return (buf);
 }  }
   
   
 /*  /*
  * cvs_file_attach()   * cvs_file_attach()
  *   *
Line 641 
Line 748 
         int l;          int l;
   
         cvs_file_getpath(cf, fpath, sizeof(fpath));          cvs_file_getpath(cf, fpath, sizeof(fpath));
   
           /*
            * Try to obtain the Root for this given directory, if we cannot
            * get it, fail, unless we are dealing with a directory that is
            * unknown or not on disk.
            */
         cf->cf_root = cvsroot_get(fpath);          cf->cf_root = cvsroot_get(fpath);
         if (cf->cf_root == NULL) {          if (cf->cf_root == NULL) {
                 /*                  if (cf->cf_cvstat == CVS_FST_UNKNOWN ||
                  * Do not fail here for an unknown directory.                      !(cf->cf_flags & CVS_FILE_ONDISK))
                  */  
                 if (cf->cf_cvstat == CVS_FST_UNKNOWN)  
                         return (0);                          return (0);
                 return (-1);                  return (-1);
         }          }
   
         if (flags & CF_MKADMIN)  
                 cvs_mkadmin(fpath, cf->cf_root->cr_str, NULL);  
   
         /* if the CVS administrative directory exists, load the info */          /* if the CVS administrative directory exists, load the info */
         l = snprintf(pbuf, sizeof(pbuf), "%s/" CVS_PATH_CVSDIR, fpath);          l = snprintf(pbuf, sizeof(pbuf), "%s/" CVS_PATH_CVSDIR, fpath);
         if (l == -1 || l >= (int)sizeof(pbuf)) {          if (l == -1 || l >= (int)sizeof(pbuf)) {
Line 671 
Line 779 
                                 return (-1);                                  return (-1);
                         }                          }
                 }                  }
           } else {
                   /*
                    * Fill in the repo path ourselfs.
                    */
                   l = snprintf(pbuf, sizeof(pbuf), "%s/%s",
                       cvs_repo_base, fpath);
                   if (l == -1 || l >= (int)sizeof(pbuf))
                           return (-1);
   
                   cf->cf_repo = strdup(pbuf);
                   if (cf->cf_repo == NULL) {
                           cvs_log(LP_ERRNO, "failed to dup repo string");
                           return (-1);
                   }
         }          }
   
           if (flags & CF_MKADMIN)
                   cvs_mkadmin(fpath, cf->cf_root->cr_str, NULL);
   
         return (0);          return (0);
 }  }
   
Line 684 
Line 809 
  * is performed by cvs_file_free().   * is performed by cvs_file_free().
  */   */
 static int  static int
 cvs_file_getdir(CVSFILE *cf, int flags, char *path, int (*cb)(CVSFILE *, void *), void *arg)  cvs_file_getdir(CVSFILE *cf, int flags, int (*cb)(CVSFILE *, void *),
       void *arg, int freecf)
 {  {
         int l, ret;          int ret;
         int check_entry;          size_t len;
         u_int ndirs, nfiles;          DIR *dp;
         char *cur, *np;          struct dirent *de;
         char pbuf[MAXPATHLEN], fpath[MAXPATHLEN];          char fpath[MAXPATHLEN], pbuf[MAXPATHLEN];
         struct dirent *ent;          CVSENTRIES *entf;
         CVSFILE *cfp;          CVSFILE *cfp;
         struct cvs_ent *cvsent;          struct cvs_ent *ent;
         struct cvs_flist dirs;          struct cvs_flist dirs;
         DIR *dirp;          int nfiles, ndirs;
         CVSENTRIES *entfile;  
   
         ret = -1;  
         check_entry = 1;  
         ndirs = nfiles = 0;  
         SIMPLEQ_INIT(&dirs);  
   
         cvs_file_getpath(cf, fpath, sizeof(fpath));  
   
         cur = np = NULL;  
         if (path != NULL) {  
                 cur = strchr(path, '/');  
                 if (cur != NULL) {  
                         *cur = '\0';  
                         np = cur + 1;  
                         if (np != NULL && *np == '\0')  
                                 np = NULL;  
                 }  
         }  
   
         if ((flags & CF_KNOWN) && (cf->cf_cvstat == CVS_FST_UNKNOWN))          if ((flags & CF_KNOWN) && (cf->cf_cvstat == CVS_FST_UNKNOWN))
                 return (0);                  return (0);
   
         /*          nfiles = ndirs = 0;
          * XXX - Do not call the callback for ".", this has          SIMPLEQ_INIT(&dirs);
          * already been done in cvs_file_getspec().          cvs_file_getpath(cf, fpath, sizeof(fpath));
          */  
         if (cb != NULL && strcmp(cf->cf_name, ".")) {  
                 if (cb(cf, arg) != CVS_EX_OK)  
                         return (-1);  
         }  
   
         cf->cf_root = cvsroot_get(fpath);          if ((dp = opendir(fpath)) == NULL) {
         if (cf->cf_root == NULL) {                  cvs_log(LP_ERRNO, "failed to open directory '%s'", fpath);
                 /*  
                  * Do not fail here for an unknown directory.  
                  */  
                 if (cf->cf_cvstat == CVS_FST_UNKNOWN)  
                         return (0);  
                 return (-1);                  return (-1);
         }          }
   
         dirp = opendir(fpath);          ret = -1;
         if (dirp == NULL) {          entf = cvs_ent_open(fpath, O_RDONLY);
                 cvs_log(LP_ERRNO, "failed to open directory %s", fpath);          while ((de = readdir(dp)) != NULL) {
                 return (-1);                  if (!strcmp(de->d_name, ".") ||
         }                      !strcmp(de->d_name, ".."))
   
         entfile = cvs_ent_open(fpath, O_RDONLY);  
         while ((ent = readdir(dirp)) != NULL) {  
                 if ((flags & CF_IGNORE) && cvs_file_chkign(ent->d_name))  
                         continue;                          continue;
   
                 if ((flags & CF_NOSYMS) && (ent->d_type == DT_LNK))                  /*
                    * Do some filtering on the current directory item.
                    */
                   if ((flags & CF_IGNORE) && cvs_file_chkign(de->d_name))
                         continue;                          continue;
   
                 if (!(flags & CF_RECURSE) && (ent->d_type == DT_DIR)) {                  if (!(flags & CF_RECURSE) && (de->d_type == DT_DIR)) {
                         if (entfile != NULL)                          if (entf != NULL)
                                 (void)cvs_ent_remove(entfile,                                  (void)cvs_ent_remove(entf, de->d_name);
                                     ent->d_name);  
                         continue;                          continue;
                 }                  }
   
                 if ((ent->d_type != DT_DIR) && (flags & CF_NOFILES))                  if ((de->d_type != DT_DIR) && (flags & CF_NOFILES))
                         continue;                          continue;
   
                 if (path != NULL) {                  /*
                         if (strcmp(path, ent->d_name))                   * Obtain info about the item.
                                 continue;                   */
                 }                  len = cvs_path_cat(fpath, de->d_name, pbuf, sizeof(pbuf));
                   if (len >= sizeof(pbuf))
                 l = snprintf(pbuf, sizeof(pbuf), "%s/%s", fpath,  
                     ent->d_name);  
                 if (l == -1 || l >= (int)sizeof(pbuf)) {  
                         errno = ENAMETOOLONG;  
                         cvs_log(LP_ERRNO, "%s", pbuf);  
                         closedir(dirp);  
                         goto done;                          goto done;
                 }  
   
                 cfp = cvs_file_find(cf, ent->d_name);                  if (entf != NULL)
                 if (cfp == NULL) {                          ent = cvs_ent_get(entf, de->d_name);
                         if (entfile != NULL)                  else
                                 cvsent = cvs_ent_get(entfile, ent->d_name);                          ent = NULL;
                         else  
                                 cvsent = NULL;  
   
                         cfp = cvs_file_lget(pbuf, flags, cf, cvsent);                  cfp = cvs_file_lget(pbuf, flags, cf, ent);
                   if (cfp == NULL) {
                         if (cfp == NULL) {                          cvs_log(LP_ERR, "failed to get '%s'", pbuf);
                                 closedir(dirp);                          goto done;
                                 goto done;  
                         }  
                         if (entfile != NULL)  
                                 cvs_ent_remove(entfile, cfp->cf_name);  
   
                         if (cfp->cf_type != DT_DIR) {  
                                 SIMPLEQ_INSERT_TAIL(&(cf->cf_files), cfp,  
                                     cf_list);  
                                 nfiles++;  
                         }  
                 } else {  
                         cfp->cf_flags |= CVS_GDIR_IGNORE;  
                 }                  }
   
                 if (cfp->cf_type == DT_DIR) {                  /*
                         ndirs++;                   * A file is linked to the parent <cf>, a directory
                    * is added to the dirs SIMPLEQ list for later use.
                    */
                   if ((cfp->cf_type != DT_DIR) && !freecf) {
                           SIMPLEQ_INSERT_TAIL(&(cf->cf_files), cfp, cf_list);
                           nfiles++;
                   } else if (cfp->cf_type == DT_DIR) {
                         SIMPLEQ_INSERT_TAIL(&dirs, cfp, cf_list);                          SIMPLEQ_INSERT_TAIL(&dirs, cfp, cf_list);
                 } else {                          ndirs++;
                         /* callback for the file */  
                         if (cb != NULL) {  
                                 if (cb(cfp, arg) != CVS_EX_OK) {  
                                         closedir(dirp);  
                                         goto done;  
                                 }  
                         }  
                 }                  }
   
                 if (path != NULL) {                  /*
                         check_entry = 0;                   * Now, for a file, pass it to the callback if it was
                         break;                   * supplied to us.
                    */
                   if (cfp->cf_type != DT_DIR && cb != NULL) {
                           if ((cvs_error = cb(cfp, arg)) != CVS_EX_OK)
                                   goto done;
                 }                  }
         }  
   
         closedir(dirp);                  /*
                    * Remove it from the Entries list to make sure it won't
                    * be picked up again when we look at the Entries.
                    */
                   if (entf != NULL)
                           (void)cvs_ent_remove(entf, de->d_name);
   
         if (entfile != NULL && check_entry) {                  /*
                 while ((cvsent = cvs_ent_next(entfile)) != NULL) {                   * If we don't want to keep it, free it
                         if (path != NULL) {                   */
                                 if (strcmp(cvsent->ce_name, path))                  if ((cfp->cf_type != DT_DIR) && freecf)
                                         continue;                          cvs_file_free(cfp);
                         }          }
   
                         l = snprintf(pbuf, sizeof(pbuf), "%s/%s", fpath,          closedir(dp);
                             cvsent->ce_name);          dp = NULL;
                         if (l == -1 || l >= (int)sizeof(pbuf)) {  
                                 errno = ENAMETOOLONG;  
                                 cvs_log(LP_ERRNO, "%s", pbuf);  
                                 goto done;  
                         }  
   
                         cfp = cvs_file_find(cf, cvsent->ce_name);          /*
                         if (cfp == NULL) {           * Pass over all of the entries now, so we pickup any files
                                 cfp = cvs_file_lget(pbuf, flags, cf, cvsent);           * that might have been lost, or are for some reason not on disk.
                                 if (cfp == NULL)           *
                                         continue;           * (Follows the same procedure as above ... can we merge them?)
            */
           while ((entf != NULL) && ((ent = cvs_ent_next(entf)) != NULL)) {
                   if (!(flags & CF_RECURSE) && (ent->ce_type == CVS_ENT_DIR))
                           continue;
                   if ((flags & CF_NOFILES) && (ent->ce_type != CVS_ENT_DIR))
                           continue;
   
                                 if (cfp->cf_type != DT_DIR) {                  len = cvs_path_cat(fpath, ent->ce_name, pbuf, sizeof(pbuf));
                                         SIMPLEQ_INSERT_TAIL(&(cf->cf_files),                  if (len >= sizeof(pbuf))
                                             cfp, cf_list);                          goto done;
                                         nfiles++;  
                                 }  
                         } else {  
                                 cfp->cf_flags |= CVS_GDIR_IGNORE;  
                         }  
   
                         if (cfp->cf_type == DT_DIR) {                  cfp = cvs_file_lget(pbuf, flags, cf, ent);
                                 ndirs++;                  if (cfp == NULL) {
                                 SIMPLEQ_INSERT_TAIL(&dirs, cfp,                          cvs_log(LP_ERR, "failed to fetch '%s'", pbuf);
                                     cf_list);                          goto done;
                         } else {                  }
                                 /* callback for the file */  
                                 if (cb != NULL) {  
                                         if (cb(cfp, arg) != CVS_EX_OK)  
                                                 goto done;  
                                 }  
                         }  
   
                         if (path != NULL)                  if ((cfp->cf_type != DT_DIR) && !freecf) {
                                 break;                          SIMPLEQ_INSERT_TAIL(&(cf->cf_files), cfp, cf_list);
                           nfiles++;
                   } else if (cfp->cf_type == DT_DIR) {
                           SIMPLEQ_INSERT_TAIL(&dirs, cfp, cf_list);
                           ndirs++;
                 }                  }
   
                   if (cfp->cf_type != DT_DIR && cb != NULL) {
                           if ((cvs_error = cb(cfp, arg)) != CVS_EX_OK)
                                   goto done;
                   }
   
                   if ((cfp->cf_type != DT_DIR) && freecf)
                           cvs_file_free(cfp);
         }          }
   
           /*
            * Sort files and dirs if requested.
            */
         if (flags & CF_SORT) {          if (flags & CF_SORT) {
                 if (nfiles > 0)                  if (nfiles > 0)
                         cvs_file_sort(&(cf->cf_files), nfiles);                          cvs_file_sort(&(cf->cf_files), nfiles);
Line 876 
Line 962 
                         cvs_file_sort(&dirs, ndirs);                          cvs_file_sort(&dirs, ndirs);
         }          }
   
           /*
            * Finally, run over the directories we have encountered.
            * Before calling cvs_file_getdir() on them, we pass them
            * to the callback first.
            */
         while (!SIMPLEQ_EMPTY(&dirs)) {          while (!SIMPLEQ_EMPTY(&dirs)) {
                 cfp = SIMPLEQ_FIRST(&dirs);                  cfp = SIMPLEQ_FIRST(&dirs);
                 SIMPLEQ_REMOVE_HEAD(&dirs, cf_list);                  SIMPLEQ_REMOVE_HEAD(&dirs, cf_list);
   
                 if (!(cfp->cf_flags & CVS_GDIR_IGNORE))                  if (!freecf)
                         SIMPLEQ_INSERT_TAIL(&(cf->cf_files), cfp, cf_list);                          SIMPLEQ_INSERT_TAIL(&(cf->cf_files), cfp, cf_list);
                 else  
                         cfp->cf_flags &= ~CVS_GDIR_IGNORE;  
   
                 if (cvs_file_getdir(cfp, flags, np, cb, arg) < 0) {                  if (cb != NULL) {
                         cvs_log(LP_ERR, "failed to get %s", cfp->cf_name);                          if ((cvs_error = cb(cfp, arg)) != CVS_EX_OK)
                         continue;                                  goto done;
                 }                  }
   
                   if ((cfp->cf_flags & CVS_FILE_ONDISK) &&
                       (cvs_file_getdir(cfp, flags, cb, arg, freecf) < 0))
                           goto done;
   
                   if (freecf)
                           cvs_file_free(cfp);
         }          }
   
         ret = 0;          ret = 0;
           cfp = NULL;
 done:  done:
         if (entfile != NULL)          if ((cfp != NULL) && freecf)
                 cvs_ent_close(entfile);                  cvs_file_free(cfp);
   
           while (!SIMPLEQ_EMPTY(&dirs)) {
                   cfp = SIMPLEQ_FIRST(&dirs);
                   SIMPLEQ_REMOVE_HEAD(&dirs, cf_list);
   
                   cvs_file_free(cfp);
           }
   
           if (entf != NULL)
                   cvs_ent_close(entf);
           if (dp != NULL)
                   closedir(dp);
   
         return (ret);          return (ret);
 }  }
   
Line 913 
Line 1022 
         if (cf->cf_name != NULL)          if (cf->cf_name != NULL)
                 cvs_strfree(cf->cf_name);                  cvs_strfree(cf->cf_name);
   
           if (cf->cf_dir != NULL)
                   cvs_strfree(cf->cf_dir);
   
         if (cf->cf_type == DT_DIR) {          if (cf->cf_type == DT_DIR) {
                 if (cf->cf_root != NULL)                  if (cf->cf_root != NULL)
                         cvsroot_free(cf->cf_root);                          cvsroot_free(cf->cf_root);
Line 937 
Line 1049 
 /*  /*
  * cvs_file_examine()   * cvs_file_examine()
  *   *
  * Examine the contents of the CVS file structure <cf> with the function   * Walk through the files, calling the callback as we go.
  * <exam>.  The function is called for all subdirectories and files of the  
  * root file.  
  */   */
 int  int
 cvs_file_examine(CVSFILE *cf, int (*exam)(CVSFILE *, void *), void *arg)  cvs_file_examine(CVSFILE *cf, int (*exam)(CVSFILE *, void *), void *arg)
Line 947 
Line 1057 
         int ret;          int ret;
         CVSFILE *fp;          CVSFILE *fp;
   
         if (cf->cf_type == DT_DIR) {          fp = NULL;
                 ret = (*exam)(cf, arg);          ret = 0;
                 SIMPLEQ_FOREACH(fp, &(cf->cf_files), cf_list) {  
                         ret = cvs_file_examine(fp, exam, arg);  
                         if (ret != 0)  
                                 break;  
                 }  
         } else  
                 ret = (*exam)(cf, arg);  
   
         return (ret);          return (ret);
 }  }
   
Line 1033 
Line 1135 
 cvs_file_alloc(const char *path, u_int type)  cvs_file_alloc(const char *path, u_int type)
 {  {
         CVSFILE *cfp;          CVSFILE *cfp;
           char *p;
   
         cfp = (CVSFILE *)malloc(sizeof(*cfp));          cfp = (CVSFILE *)malloc(sizeof(*cfp));
         if (cfp == NULL) {          if (cfp == NULL) {
Line 1055 
Line 1158 
                 return (NULL);                  return (NULL);
         }          }
   
           if ((p = strrchr(path, '/')) != NULL) {
                   *p = '\0';
                   if (strcmp(path, ".")) {
                           cfp->cf_dir = cvs_strdup(path);
                           if (cfp->cf_dir == NULL) {
                                   cvs_log(LP_ERR,
                                       "failed to copy directory");
                                   cvs_file_free(cfp);
                                   return (NULL);
                           }
                   } else
                           cfp->cf_dir = NULL;
                   *p = '/';
           } else
                   cfp->cf_dir = NULL;
   
         return (cfp);          return (cfp);
 }  }
   
Line 1069 
Line 1188 
 static CVSFILE*  static CVSFILE*
 cvs_file_lget(const char *path, int flags, CVSFILE *parent, struct cvs_ent *ent)  cvs_file_lget(const char *path, int flags, CVSFILE *parent, struct cvs_ent *ent)
 {  {
         int ret, cwd;          int ret;
         u_int type;          u_int type;
         struct stat st;          struct stat st;
         CVSFILE *cfp;          CVSFILE *cfp;
   
         type = DT_UNKNOWN;          type = DT_UNKNOWN;
         cwd = (strcmp(path, ".") == 0) ? 1 : 0;  
   
         ret = stat(path, &st);          ret = stat(path, &st);
         if (ret == 0)          if (ret == 0)
                 type = IFTODT(st.st_mode);                  type = IFTODT(st.st_mode);
Line 1092 
Line 1209 
                 cfp->cf_mode = st.st_mode & ACCESSPERMS;                  cfp->cf_mode = st.st_mode & ACCESSPERMS;
                 if (cfp->cf_type == DT_REG)                  if (cfp->cf_type == DT_REG)
                         cfp->cf_mtime = st.st_mtime;                          cfp->cf_mtime = st.st_mtime;
                   cfp->cf_flags |= CVS_FILE_ONDISK;
   
                 if (ent == NULL)                  if (ent == NULL)
                         cfp->cf_cvstat = (cwd == 1) ?                          if (cfp->cf_flags & CVS_DIRF_BASE)
                             CVS_FST_UPTODATE : CVS_FST_UNKNOWN;                                  cfp->cf_cvstat = CVS_FST_UPTODATE;
                           else
                                   cfp->cf_cvstat = CVS_FST_UNKNOWN;
                 else {                  else {
                         /* always show directories as up-to-date */                          /* always show directories as up-to-date */
                         if (ent->ce_type == CVS_ENT_DIR)                          if (ent->ce_type == CVS_ENT_DIR)
Line 1171 
Line 1291 
             !strcmp(cfp->cf_repo, path))              !strcmp(cfp->cf_repo, path))
                 cfp->cf_cvstat = CVS_FST_UPTODATE;                  cfp->cf_cvstat = CVS_FST_UPTODATE;
   
           /*
            * In server mode, we do a few extra checks.
            */
           if (cvs_cmdop == CVS_OP_SERVER) {
                   /*
                    * If for some reason a file was added,
                    * but does not exist anymore, start complaining.
                    */
                   if (!(cfp->cf_flags & CVS_FILE_ONDISK) &&
                       (cfp->cf_cvstat == CVS_FST_ADDED) &&
                       (cfp->cf_type != DT_DIR))
                           cvs_log(LP_WARN, "new-born %s has disappeared", path);
   
                   /*
                    * Any other needed checks?
                    */
           }
   
         return (cfp);          return (cfp);
 }  }
   
Line 1183 
Line 1321 
 }  }
   
 /*  /*
  * remove a directory if it does not contain   * remove any empty directories.
  * any files other than the CVS/ administrative files.  
  */   */
 int  int
 cvs_file_prune(char *path)  cvs_file_prune(char *path)

Legend:
Removed from v.1.99  
changed lines
  Added in v.1.100