示例#1
0
文件: find_names.cpp 项目: acml/cvsnt
/*
 * Finds all the ,v files in the argument directory, and adds them to the
 * files list.  Returns 0 for success and non-zero if the argument directory
 * cannot be opened, in which case errno is set to indicate the error.
 * In the error case LIST is left in some reasonable state (unchanged, or
 * containing the files which were found before the error occurred).
 */
static int find_rcs (const char *dir, List *list, const char *regex)
{
    Node *p;
    struct dirent *dp;
    DIR *dirp;

	/* set up to read the dir */
    if ((dirp = opendir (dir)) == NULL)
	return (1);

	/* read the dir, grabbing the ,v files */
    errno = 0;
    while ((dp = readdir (dirp)) != NULL)
    {
		if (CVS_FNMATCH (RCSPAT, dp->d_name, CVS_CASEFOLD) == 0) 
		{
			char *comma, *q;

			comma = strrchr (dp->d_name, ',');	/* strip the ,v */
			*comma = '\0';

			if(!fncmp(dp->d_name,RCSREPOVERSION))
				continue;

			q = map_fixed_rename(dir,dp->d_name);

			if(q && *q && (!regex || regex_filename_match(regex, q)))
			{
				p = getnode ();
				p->type = FILES;
				p->key = xstrdup (q);
				if(!findnode_fn(list,p->key))
				{
					if(addnode (list, p) != 0)
						freenode (p);
				}
			}
		}
		errno = 0;
    }
    if (errno != 0)
    {
	int save_errno = errno;
	(void) closedir (dirp);
	errno = save_errno;
	return 1;
    }
    (void) closedir (dirp);
    return (0);
}
示例#2
0
static void selectAddCb(Widget w, FileWindowRec *fw, XtPointer call_data)
{
  register int i;
  
  XtPopdown(popups.select);
  for(i=0; i<popups.fw->n_files; i++)
    if (popups.fw->files[i]->icon.toggle) {
      if (!popups.fw->files[i]->selected && 
	  (fncmp(popups.select_s, popups.fw->files[i]->name))) {
	popups.fw->files[i]->selected = True;
	popups.fw->n_selections++;
	XtVaSetValues(popups.fw->files[i]->icon.toggle, XtNstate, True, NULL);
      }
    }
  updateMenus(popups.fw);
}
示例#3
0
static void selectReplaceCb(Widget w, FileWindowRec *fw, 
			    XtPointer call_data)
{
  register int i;

  XtPopdown(popups.select);
  popups.fw->n_selections = 0;
  for (i=0; i<popups.fw->n_files; i++) {
    if (popups.fw->files[i]->icon.toggle) {
      if (fncmp(popups.select_s, popups.fw->files[i]->name)) {
	popups.fw->files[i]->selected = True;
	popups.fw->n_selections++;
      }
      else
	popups.fw->files[i]->selected = False;
      XtVaSetValues(popups.fw->files[i]->icon.toggle, XtNstate,
		    (XtArgVal) popups.fw->files[i]->selected, NULL);
    }
  }
  updateMenus(popups.fw);
}
示例#4
0
const T * BinaryLookupFromIndex (const int aIndex[], const T aTable[], int cElms, const char * name, int (*fncmp)(const char *, const char *))
{
	if (cElms <= 0)
		return NULL;

	int ixLower = 0;
	int ixUpper = cElms-1;
	for (;;) {
		if (ixLower > ixUpper)
			return NULL; // return null for "not found"

		int ix = (ixLower + ixUpper) / 2;
		int iMatch = fncmp(aTable[aIndex[ix]].name, name);
		if (iMatch < 0)
			ixLower = ix+1;
		else if (iMatch > 0)
			ixUpper = ix-1;
		else
			return &aTable[aIndex[ix]];
	}
}
示例#5
0
const T * BinaryLookup (const T aTable[], int cElms, const char * key, int (*fncmp)(const char *, const char *))
{
	if (cElms <= 0)
		return NULL;

	int ixLower = 0;
	int ixUpper = cElms-1;
	for (;;) {
		if (ixLower > ixUpper)
			return NULL; // return null for "not found"

		int ix = (ixLower + ixUpper) / 2;
		int iMatch = fncmp(aTable[ix].key, key);
		if (iMatch < 0)
			ixLower = ix+1;
		else if (iMatch > 0)
			ixUpper = ix-1;
		else
			return &aTable[ix];
	}
}
示例#6
0
/* match a pattern with a filename, returning True if the match was correct */
static int fncmp(char *pattern, char *fn)
{
  
  for (;; fn++, pattern++) {
    
    switch (*pattern) {
      
    case '?':
      if (!*fn)
	return False;
      break;
      
    case '*':
      pattern++;
      do
	if (fncmp(pattern,fn))
	  return True;
      while (*fn++);
      return False;
      
    case '[':
      do {
	pattern++;
	if (*pattern == ']')
	  return False;
      } while (*fn != *pattern);
      while (*pattern != ']')
	if (!*pattern++)
	  return False;
      break;
      
    default:
      if (*fn != *pattern)
	return False;
    }
    
    if (!*fn)
      return True;
  };
}
示例#7
0
文件: rename.cpp 项目: acml/cvsnt
int cvsrename(int argc, char **argv)
{
    int c;
    int err = 0;
	char *repos_file1, *repos_file2;
	char *root1, *root2;
	const char *filename1, *filename2, *dir1, *dir2;
	int rootlen;
	List *ent,*ent2;
	Node *node;
	Entnode *entnode;
	const char *cwd;

	if (argc == -1)
		usage (rename_usage);

	quiet = 0;

    optind = 0;
    while ((c = getopt (argc, argv, "+q")) != -1)
    {
	switch (c)
	{
	case 'q':
		quiet = 1;
		break;
    case '?':
    default:
		usage (rename_usage);
		break;
	}
    }
    argc -= optind;
    argv += optind;

	if(argc!=2)
	{
		usage(rename_usage);
	};

	error(0,0,"Warning: rename is still experimental and may not behave as you would expect");

	if(current_parsed_root->isremote)
	{
		if(!supported_request("Rename"))
			error(1,0,"Remote server does not support rename");
		if(!supported_request("Can-Rename"))
			error(1,0,"Renames are currently disabled");
	}

	if(!strcmp(argv[0],argv[1]))
		return 0;

	rootlen = strlen(current_parsed_root->directory);

	if(!isfile(argv[0]))
		error(1,0,"%s does not exist",argv[0]);

	if(isfile(argv[1]) && fncmp(argv[0],argv[1])) /* We allow case renames (on Unix this is redundant) */
		error(1,0,"%s already exists",argv[1]);

	if(isdir(argv[0]))
		error(1,0,"Directory renames are not currently supported");

	validate_file(argv[0],&root1, &repos_file1, &filename1, &dir1, 1);
	validate_file(argv[1],&root2, &repos_file2, &filename2, &dir2, 0);

	if(strcmp(root1,root2) || strcmp(root1,current_parsed_root->original))
		error(1,0,"%s and %s are in different repositories",argv[0],argv[1]);

	xfree(root1);
	xfree(root2);

	repos_file1 = (char*)xrealloc(repos_file1, strlen(filename1)+strlen(repos_file1)+rootlen+10);
	repos_file2 = (char*)xrealloc(repos_file2, strlen(filename2)+strlen(repos_file2)+rootlen+10);
	memmove(repos_file1+rootlen+1,repos_file1,strlen(repos_file1)+1);
	memmove(repos_file2+rootlen+1,repos_file2,strlen(repos_file2)+1);
	strcpy(repos_file1,current_parsed_root->directory);
	strcpy(repos_file2,current_parsed_root->directory);
	repos_file1[rootlen]='/';
	repos_file2[rootlen]='/';
	strcat(repos_file1,"/");
	strcat(repos_file2,"/");
	strcat(repos_file1,filename1);
	strcat(repos_file2,filename2);

	if(fncmp(argv[0],argv[1]))
		set_mapping(dir2,repos_file2+rootlen+1,""); /* Delete old file */
	if(fncmp(dir1,dir2))
		set_mapping(dir1,repos_file1+rootlen+1,""); 
	set_mapping(dir2,repos_file1+rootlen+1,repos_file2+rootlen+1); /* Rename to new file */

	cwd = xgetwd();
	if(CVS_CHDIR(dir1))
		error(1,errno,"Couldn't chdir to %s",dir1);
	ent = Entries_Open(0, NULL);
	node = findnode_fn(ent, filename1);
	entnode=(Entnode*)node->data;

	if(!node)
	{
		error(1,0,"%s is not listed in CVS/Entries",filename1);
		CVS_CHDIR(cwd);
		xfree(cwd);
		return 1;
	}

	if(!fncmp(dir1,dir2))
		Rename_Entry(ent,filename1,filename2);
	else
	{
		if(CVS_CHDIR(cwd))
			error(1,errno,"Couldn't chdir to %s",cwd);
		if(CVS_CHDIR(dir2))
			error(1,errno,"Couldn't chdir to %s",dir2);
		ent2 = Entries_Open(0, NULL);
		if(entnode->type==ENT_FILE)
			Register(ent2,(char*)filename2,entnode->version,entnode->timestamp,entnode->options,entnode->tag,entnode->date,entnode->conflict,entnode->merge_from_tag_1,entnode->merge_from_tag_2,entnode->rcs_timestamp,entnode->edit_revision,entnode->edit_tag,entnode->edit_bugid,entnode->md5);
		else if(entnode->type==ENT_SUBDIR)
			Subdir_Register(ent2,NULL,filename2);
		else
			error(1,0,"Unknown entry type %d in entries file",node->type);

		Entries_Close(ent2);
		if(CVS_CHDIR(cwd))
			error(1,errno,"Couldn't chdir to %s",cwd);
		if(CVS_CHDIR(dir1))
			error(1,errno,"Couldn't chdir to %s",dir1);

		if(entnode->type==ENT_SUBDIR)
			Subdir_Deregister(ent,NULL,filename1);
		else if(entnode->type==ENT_FILE)
			Scratch_Entry(ent,filename1);
		else
			error(1,0,"Unknown entry type %d in entries file",node->type);
	}
	Entries_Close(ent);

	CVS_RENAME(argv[0],argv[1]);

	if(isdir(argv[1]))
	{
		char *tmp=(char*)xmalloc(strlen(argv[1])+strlen(CVSADM_VIRTREPOS)+10);
		FILE *fp;
		sprintf(tmp,"%s/%s",argv[1],CVSADM_VIRTREPOS);
		fp = fopen(tmp,"w");
		if(!fp)
			error(0,errno,"Couldn't write %s",tmp);
		fprintf(fp,"%s\n",repos_file2+rootlen+1);
		fclose(fp);
	}

	xfree(repos_file1);
	xfree(repos_file2);
	xfree(dir1);
	xfree(dir2);
	CVS_CHDIR(cwd);
	xfree(cwd);

    return (err);
}
示例#8
0
文件: find_names.cpp 项目: acml/cvsnt
/*
 * Finds all the subdirectories of the argument dir and adds them to
 * the specified list.  Sub-directories without a CVS administration
 * directory are optionally ignored.  If ENTRIES is not NULL, all
 * files on the list are ignored.  Returns 0 for success or 1 on
 * error, in which case errno is set to indicate the error.
 */
static int find_dirs (const char *dir, List *list, int checkadm, List *entries, const char *regex)
{
    Node *p;
    char *tmp = NULL;
    size_t tmp_size = 0;
    struct dirent *dp;
    DIR *dirp;
    int skip_emptydir = 0;

    /* First figure out whether we need to skip directories named
       Emptydir.  Except in the CVSNULLREPOS case, Emptydir is just
       a normal directory name.  */
    if (isabsolute (dir)
	&& fnncmp (dir, current_parsed_root->directory, strlen (current_parsed_root->directory)) == 0
	&& ISDIRSEP (dir[strlen (current_parsed_root->directory)])
	&& fncmp (dir + strlen (current_parsed_root->directory) + 1, CVSROOTADM) == 0)
	skip_emptydir = 1;

    /* set up to read the dir */
    if ((dirp = opendir (dir)) == NULL)
	return (1);

    /* read the dir, grabbing sub-dirs */
    errno = 0;
    while ((dp = readdir (dirp)) != NULL)
    {
	if (fncmp (dp->d_name, ".") == 0 ||
	    fncmp (dp->d_name, "..") == 0 ||
	    fncmp (dp->d_name, CVSATTIC) == 0 ||
	    fncmp (dp->d_name, CVSLCK) == 0 ||
	    fncmp (dp->d_name, CVSREP) == 0 ||
		fncmp (dp->d_name, CVSDUMMY) == 0)
	    goto do_it_again;

	/* findnode() is going to be significantly faster than stat()
	   because it involves no system calls.  That is why we bother
	   with the entries argument, and why we check this first.  */
	if (entries != NULL && findnode_fn (entries, dp->d_name) != NULL)
	    goto do_it_again;

	if (skip_emptydir
	    && fncmp (dp->d_name, CVSNULLREPOS) == 0)
	    goto do_it_again;

	    /* don't bother stating ,v files */
	    if (CVS_FNMATCH (RCSPAT, dp->d_name, CVS_CASEFOLD) == 0)
		goto do_it_again;

	    expand_string (&tmp,
			   &tmp_size,
			   strlen (dir) + strlen (dp->d_name) + 10);
	    sprintf (tmp, "%s/%s", dir, dp->d_name);
	    if (!isdir (tmp))
		goto do_it_again;

	/* check for administration directories (if needed) */
	if (checkadm)
	{
	    /* blow off symbolic links to dirs in local dir */
		/* Note that we only get here if we already set tmp
		   above.  */
		if (islink (tmp))
		    goto do_it_again;

	    /* check for new style */
	    expand_string (&tmp,
			   &tmp_size,
			   (strlen (dir) + strlen (dp->d_name)
			    + sizeof (CVSADM) + 10));
	    (void) sprintf (tmp, "%s/%s/%s", dir, dp->d_name, CVSADM);
	    if (!isdir (tmp))
		goto do_it_again;
	}

	/* If there's a regex, test against the name with '/' on the end to signify a directory */
	if(regex)
	{
		strcpy(tmp,dp->d_name);
		strcat(tmp,"/");
		if(!regex_filename_match(regex,tmp))
			goto do_it_again;
	}

	/* put it in the list */
	p = getnode ();
	p->type = DIRS;
	p->key = xstrdup (dp->d_name);
	if (addnode (list, p) != 0)
	    freenode (p);

    do_it_again:
	errno = 0;
    }
    if (errno != 0)
    {
	int save_errno = errno;
	(void) closedir (dirp);
	errno = save_errno;
	return 1;
    }
    (void) closedir (dirp);
    if (tmp != NULL)
	xfree (tmp);
    return (0);
}
示例#9
0
文件: utils.c 项目: foxbow/fbfstools
/**
 * mix a list of titles into a new order
 */
 struct entry_t *shuffleTitles( struct entry_t *base ) {
	struct entry_t *list=NULL;
	struct entry_t *end=NULL;
	struct entry_t *runner=NULL;
	struct entry_t *guard=NULL;
	char *lastname=NULL;

	int i, num=0, artguard=-1;
	struct timeval tv;

	// improve 'randomization'
	gettimeofday(&tv,NULL);
	srand(getpid()*tv.tv_sec);

	base = rewindTitles( base );
	num  = countTitles(base)+1;

	// Stepping through every item
	while( base != NULL ) {
		int j, pos;
		runner=base;
		pos=RANDOM(num--);
		for(j=1; j<=pos; j++){
			runner=runner->next;
			if( runner == NULL ) {
				runner=base;
			}
		}

		if( artguard && lastname ) {
			guard=runner;
			while( 75 < fncmp( runner->artist, lastname ) ) {
				runner=runner->next;
				if( runner == NULL ) {
					runner=base;
				}
				if( guard == runner ) {
					artguard=0;
					break;
				}
			}
		}

		lastname=runner->artist;

		// Remove entry from base
		if(runner==base) base=runner->next;

		if(runner->prev != NULL){
			runner->prev->next=runner->next;
		}
		if(runner->next != NULL){
			runner->next->prev=runner->prev;
		}

		// add entry to list
		runner->next=NULL;
		runner->prev=end;
		if( NULL != end ) {
			end->next=runner;
		}
		end=runner;

		activity("Shuffling ");
	}
	return rewindTitles( end );
}
示例#10
0
文件: recurse.cpp 项目: acml/cvsnt
/*
 * Process each of the directories in the list (recursing as we go)
 */
static int do_dir_proc (Node *p, void *closure)
{
    struct frame_and_entries *frent = (struct frame_and_entries *) closure;
    struct recursion_frame *frame = frent->frame;
    struct recursion_frame xframe;
    char *dir = p->key;
    char *newrepos, *virtrepos;
    List *sdirlist;
    char *srepository;
	char *smapped_repository;
    Dtype dir_return = R_PROCESS;
	Dtype hint;
    int stripped_dot = 0;
    int err = 0;
    struct saved_cwd cwd;
    char *saved_update_dir;
    int process_this_directory = 1;
	int directory_opened = 0;
	char *old_update_repos = NULL;
	int directory_not_valid = 0;

    if (fncmp (dir, CVSADM) == 0
		|| fncmp (dir, CVSDUMMY) == 0)
    {
	/* This seems to most often happen when users (beginning users,
	   generally), try "cvs ci *" or something similar.  On that
	   theory, it is possible that we should just silently skip the
	   CVSADM directories, but on the other hand, using a wildcard
	   like this isn't necessarily a practice to encourage (it operates
	   only on files which exist in the working directory, unlike
	   regular CVS recursion).  */

	/* FIXME-reentrancy: printed_cvs_msg should be in a "command
	   struct" or some such, so that it gets cleared for each new
	   command (this is possible using the remote protocol and a
	   custom-written client).  The struct recursion_frame is not
	   far back enough though, some commands (commit at least)
	   will call start_recursion several times.  An alternate solution
	   would be to take this whole check and move it to a new function
	   validate_arguments or some such that all the commands call
	   and which snips the offending directory from the argc,argv
	   vector.  */
	static int printed_cvs_msg = 0;
	if (!printed_cvs_msg)
	{
	    error (0, 0, "warning: directory %s specified in argument",
		   dir);
	    error (0, 0, "but CVS uses %s for its own purposes; skipping %s directory", dir, dir);
	    printed_cvs_msg = 1;
	}
	return 0;
    }

    saved_update_dir = update_dir;
    update_dir = (char*)xmalloc (strlen (saved_update_dir)
			  + strlen (dir)
			  + 5);
    strcpy (update_dir, saved_update_dir);

    /* set up update_dir - skip dots if not at start */
    if (strcmp (dir, ".") != 0)
    {
	if (update_dir[0] != '\0')
	{
	    (void) strcat (update_dir, "/");
	    (void) strcat (update_dir, dir);
	}
	else
	    (void) strcpy (update_dir, dir);

	/*
	 * Here we need a plausible repository name for the sub-directory. We
	 * create one by concatenating the new directory name onto the
	 * previous repository name.  The only case where the name should be
	 * used is in the case where we are creating a new sub-directory for
	 * update -d and in that case the generated name will be correct.
	 */
	if (repository == NULL)
	{
	    newrepos = xstrdup ("");
		virtrepos = xstrdup ("");
	}
	else
	{
		if(frame->which&W_LOCAL)
		{
			char *d=(char*)xmalloc(strlen(dir)+strlen(CVSADM_REP)+32);
			sprintf(d,"%s/%s",dir,CVSADM_REP);
			if(isfile(d))
				virtrepos = Name_Repository(dir,update_dir);
			else
			{
				virtrepos = (char*)xmalloc (strlen (repository) + strlen (dir) + 5);
				sprintf (virtrepos, "%s/%s", repository, dir);
			}
			xfree(d);

		}
		else
		{
			virtrepos = (char*)xmalloc (strlen (repository) + strlen (dir) + 5);
			sprintf (virtrepos, "%s/%s", repository, dir);
		}
		if(!current_parsed_root->isremote)
		{
			newrepos = map_repository(virtrepos);
			if(!newrepos)
				error(1,0,"Internal error - couldn't map %s to anything",virtrepos);
		}
		else
			newrepos = xstrdup(virtrepos);
	}
    }
    else
    {
	if (update_dir[0] == '\0')
	    (void) strcpy (update_dir, dir);

	if (repository == NULL)
	{
	    newrepos = xstrdup ("");
		virtrepos = xstrdup ("");
	}
	else
	{
	    newrepos = xstrdup (mapped_repository);
		virtrepos = xstrdup (repository);
	}
    }

	/* Check to see that the CVSADM directory, if it exists, seems to be
       well-formed.  It can be missing files if the user hit ^C in the
       middle of a previous run.  We want to (a) make this a nonfatal
       error, and (b) make sure we print which directory has the
       problem.

       Do this before the direntproc, so that (1) the direntproc
       doesn't have to guess/deduce whether we will skip the directory
       (e.g. send_dirent_proc and whether to send the directory), and
       (2) so that the warm fuzzy doesn't get printed if we skip the
       directory.  */
    if (frame->which & W_LOCAL)
    {
	char *cvsadmdir;

	cvsadmdir = (char*)xmalloc (strlen (dir)
			     + sizeof (CVSADM_REP)
			     + sizeof (CVSADM_ENT)
			     + 80);

	strcpy (cvsadmdir, dir);
	strcat (cvsadmdir, "/");
	strcat (cvsadmdir, CVSADM);
	if (isdir (cvsadmdir))
	{
	    strcpy (cvsadmdir, dir);
	    strcat (cvsadmdir, "/");
	    strcat (cvsadmdir, CVSADM_REP);
	    if (!isfile (cvsadmdir))
	    {
		/* Some commands like update may have printed "? foo" but
		   if we were planning to recurse, and don't on account of
		   CVS/Repository, we want to say why.  */
		error (0, 0, "ignoring %s (%s missing)", update_dir,
		       CVSADM_REP);
		dir_return = R_SKIP_ALL;
	    }

	    /* Likewise for CVS/Entries.  */
	    if (dir_return != R_SKIP_ALL)
	    {
		strcpy (cvsadmdir, dir);
		strcat (cvsadmdir, "/");
		strcat (cvsadmdir, CVSADM_ENT);
		if (!isfile (cvsadmdir))
		{
		    /* Some commands like update may have printed "? foo" but
		       if we were planning to recurse, and don't on account of
		       CVS/Repository, we want to say why.  */
		    error (0, 0, "ignoring %s (%s missing)", update_dir,
			   CVSADM_ENT);
		    dir_return = R_SKIP_ALL;
		}
	    }
	}
	xfree (cvsadmdir);
    }

    /* Only process this directory if the root matches.  This nearly
       duplicates code in do_recursion. */

	/* If -d was specified, it should override CVS/Root.

	   In the single-repository case, it is long-standing CVS behavior
	   and makes sense - the user might want another access method,
	   another server (which mounts the same repository), &c.

	   In the multiple-repository case, -d overrides all CVS/Root
	   files.  That is the only plausible generalization I can
	   think of.  */
    if (!(frame->which&W_FAKE) && CVSroot_cmdline == NULL && !server_active)
    {
	char *this_root = Name_Root (dir, update_dir);
	if (this_root != NULL)
	{
	    if (findnode_fn (root_directories, this_root) == NULL)
	    {
		/* Add it to our list. */

		Node *n = getnode ();
		n->type = NT_UNKNOWN;
		n->key = xstrdup (this_root);

		if (addnode (root_directories, n))
		    error (1, 0, "cannot add new CVSROOT %s", this_root);

	    }

	    process_this_directory = (fncmp (current_parsed_root->original, this_root) == 0);

	    xfree (this_root);
	}
    }
    /*
     * Do we have access to this directory?
     */
	if(!current_parsed_root->isremote)
	{
		const char *tag=NULL;
		const char *date=NULL;
		int nonbranch=0;
		const char *message;
		const char *v_msg;

		/* before we do anything else, see if we have any
		   per-directory tags */
		ParseTag (&tag, &date, &nonbranch, NULL);
		if (! verify_access (frame->permproc, newrepos, NULL, update_dir, frame->tag?frame->tag:tag,&message, &v_msg))
		{
			if(frame->permproc!=verify_read)
			{
			  if(tag)
			    error (0, 0, "User '%s' cannot %s %s on tag/branch %s", CVS_Username, v_msg, fn_root(virtrepos), tag);
			  else
			    error (0, 0, "User '%s' cannot %s %s", CVS_Username, v_msg, fn_root(virtrepos));
			  if(message)
				error(0,0,"%s",message);	
			}
			dir_return = R_SKIP_ALL;
		}
		xfree(tag);
		xfree(date);
	}

	if(dir_return!=R_SKIP_ALL)
	{
		/* Generic behavior.  I don't see a reason to make the caller specify
		a direntproc just to get this.  */
		if ((frame->which & (W_LOCAL|W_FAKE)))
		{
			if(!isdir (dir))
				hint = R_SKIP_ALL;
			else
				hint = R_PROCESS;
		}
		else if(!isdir(newrepos))
			hint = R_SKIP_ALL;
		else
			hint = R_PROCESS;
	}

    if (dir_return == R_SKIP_ALL || dir_return == R_ERROR)
	;
    else if(process_this_directory)
	{
		int directory_opened_status=-1;
		const char *dirversion=NULL;
		const char *dirtag=NULL;
		const char *dirdate=NULL;
		int dirnonbranch=0;

		if(frame->predirentproc != NULL)
		{
			frame->predirentproc (frame->callerdat, dir, newrepos,
							update_dir, frent->entries, virtrepos, hint);
		}

		/* before we do anything else, see if we have any
			per-directory tags */
		ParseTag_Dir (dir, &dirtag, &dirdate, &dirnonbranch, &dirversion);
		directory_opened_status=open_directory(newrepos,dir,dirtag,dirdate,dirnonbranch,dirversion,current_parsed_root->isremote);
		if (directory_opened_status!=-1)
			directory_opened = 1;
		xfree(dirversion);
		xfree(dirtag);
		xfree(dirdate);
		if(!current_parsed_root->isremote)
			fileattr_startdir(newrepos);
	}

	/* call-back dir entry proc (if any) */
    if (dir_return == R_SKIP_ALL || dir_return == R_ERROR)
		;
    else if (frame->direntproc != NULL)
    {
	/* If we're doing the actual processing, call direntproc.
           Otherwise, assume that we need to process this directory
           and recurse. FIXME. */

	if (process_this_directory)
	    dir_return = frame->direntproc (frame->callerdat, dir, newrepos,
					    update_dir, frent->entries, virtrepos, hint);
	else
	    dir_return = R_PROCESS;
    }
    else
    {
	/* Generic behavior.  I don't see a reason to make the caller specify
	   a direntproc just to get this.  */
		dir_return = hint;
    }

    /* only process the dir if the return code was 0 */
    if (dir_return != R_SKIP_ALL && dir_return !=R_ERROR)
    {
		/* save our current directory and static vars */
        if (save_cwd (&cwd))
			error_exit ();

		sdirlist = dirlist;
		srepository = repository;
		smapped_repository = mapped_repository;
		dirlist = NULL;

		/* cd to the sub-directory */
		if (!(frame->which&(W_LOCAL|W_FAKE)))
		{
			if ( CVS_CHDIR (newrepos) < 0)
			{
				error (1, errno, "could not chdir to %s", fn_root(newrepos));
			}
		}
		else
		{
			if ( !(frame->which&W_FAKE) && CVS_CHDIR (dir) < 0)
			{
				if(!noexec)
					error (1, errno, "could not chdir to %s", fn_root(update_dir));
				else
					directory_not_valid=1;
			}

		}
		old_update_repos = update_repos;
		update_repos = xstrdup(newrepos);

		/* honor the global SKIP_DIRS (a.k.a. local) */
		if (frame->flags == R_SKIP_DIRS)
			dir_return = R_SKIP_DIRS;

		/* remember if the `.' will be stripped for subsequent dirs */
		if (strcmp (update_dir, ".") == 0)
		{
			update_dir[0] = '\0';
			stripped_dot = 1;
		}

		/* make the recursive call */
		xframe = *frame;
		xframe.flags = dir_return;
		if(directory_not_valid)
		{
			xframe.which &= ~W_LOCAL;
			xframe.which |= W_FAKE;
		}
		err += do_recursion (&xframe, 0);

		/* put the `.' back if necessary */
		if (stripped_dot)
			(void) strcpy (update_dir, ".");

		/* call-back dir leave proc (if any) */
		if (process_this_directory && frame->dirleaveproc != NULL)
			err = frame->dirleaveproc (frame->callerdat, dir, err, update_dir,
						frent->entries);

		if(directory_opened)
			close_directory();

		/* get back to where we started and restore state vars */
		if (restore_cwd (&cwd, NULL))
			error_exit ();

		xfree(update_repos);
		update_repos = old_update_repos;

		free_cwd (&cwd);
		dirlist = sdirlist;
		repository = srepository;
		mapped_repository = smapped_repository;
    }
	else
	{
		if(directory_opened)
			close_directory();
		fileattr_write();
		fileattr_free();
	}

    xfree (newrepos);
	xfree (virtrepos);
    xfree (update_dir);
    update_dir = saved_update_dir;

	if(dir_return == R_ERROR)
		err++;

    return (err);
}
示例#11
0
文件: recurse.cpp 项目: acml/cvsnt
/*
 * Implement the recursive policies on the local directory.  This may be
 * called directly, or may be called by start_recursion
 */
static int do_recursion (struct recursion_frame *frame, int top_level)
{
    int err = 0;
    int dodoneproc = 1;
    char *srepository;
    List *entries = NULL;
    int should_readlock;
    int process_this_directory = 1;

    /* do nothing if told */
    if (frame->flags == R_SKIP_ALL)
	return (0);

    should_readlock = noexec ? 0 : frame->readlock;

    /* Check the value in CVSADM_ROOT and see if it's in the list.  If
       not, add it to our lists of CVS/Root directories and do not
       process the files in this directory.  Otherwise, continue as
       usual.  THIS_ROOT might be NULL if we're doing an initial
       checkout -- check before using it.  The default should be that
       we process a directory's contents and only skip those contents
       if a CVS/Root file exists. 

       If we're running the server, we want to process all
       directories, since we're guaranteed to have only one CVSROOT --
       our own.  */

	/* If -d was specified, it should override CVS/Root.

	   In the single-repository case, it is long-standing CVS behavior
	   and makes sense - the user might want another access method,
	   another server (which mounts the same repository), &c.

	   In the multiple-repository case, -d overrides all CVS/Root
	   files.  That is the only plausible generalization I can
	   think of.  */
	if(!(frame->which&W_FAKE) && CVSroot_cmdline == NULL && ! server_active)
    {
	char *this_root = Name_Root ((char *) NULL, update_dir);
	if (this_root != NULL)
	{
	    if (findnode_fn (root_directories, this_root) == NULL)
	    {
		/* Add it to our list. */

		Node *n = getnode ();
		n->type = NT_UNKNOWN;
		n->key = xstrdup (this_root);

		if (addnode (root_directories, n))
		    error (1, 0, "cannot add new CVSROOT %s", this_root);
	
	    }
	
	    process_this_directory =
		    (fncmp (current_parsed_root->original, this_root) == 0);

	    xfree (this_root);
	}
    }

    /*
     * Fill in repository with the current repository
     */
    if (frame->which & W_LOCAL)
    {
		if (isdir (CVSADM))
			repository = Name_Repository ((char *) NULL, update_dir);
		else
			repository = NULL;
    }
    else
	{
		if(update_repos) /* May have been preloaded by checkout */
			repository = xstrdup(update_repos);
		else
		{
			repository = (char*)xmalloc(strlen(current_parsed_root->directory)+strlen(update_dir)+10);
			sprintf(repository,"%s/%s",current_parsed_root->directory,update_dir);
		}
    }

	if(repository && ISDIRSEP(repository[strlen(repository)-1]))
		repository[strlen(repository)-1]='\0';
    srepository = repository;		/* remember what to free */

	if(repository && !current_parsed_root->isremote)
	{
		mapped_repository = map_repository(repository);
	}
	else
	{
		mapped_repository=xstrdup(repository);
	}

	xfree(last_repository);
	last_repository = xstrdup(mapped_repository);

    /*
     * Do we have access to this directory?
     */
	/* Note that for a recursion this is done already in do_dir_proc... */
	if(top_level)
	{
		if(repository && !current_parsed_root->isremote)
		{
			const char *tag;
			const char *message;
			const char *v_msg;

			ParseTag(&tag, NULL, NULL, NULL);

			if (! verify_access(frame->permproc, mapped_repository, NULL, update_dir,frame->tag?frame->tag:tag,&message, &v_msg))
			{
				if(tag)
					error (0, 0, "User '%s' cannot %s %s on tag/branch %s", CVS_Username, v_msg, fn_root(repository), tag);
				else
					error (0, 0, "User '%s' cannot %s %s", CVS_Username, v_msg, fn_root(repository));
				if(message)
					error (0, 0, "%s", message);
				return (1);
			}
			xfree(tag);
			fileattr_startdir (mapped_repository);
		}
	}

    /*
     * The filesdoneproc needs to be called for each directory where files
     * processed, or each directory that is processed by a call where no
     * directories were passed in.  In fact, the only time we don't want to
     * call back the filesdoneproc is when we are processing directories that
     * were passed in on the command line (or in the special case of `.' when
     * we were called with no args
     */
    if (dirlist != NULL && filelist == NULL)
		dodoneproc = 0;

    /*
     * If filelist or dirlist is already set, we don't look again. Otherwise,
     * find the files and directories
     */
    if (filelist == NULL && dirlist == NULL)
    {
	/* both lists were NULL, so start from scratch */
	if (frame->fileproc != NULL && frame->flags != R_SKIP_FILES)
	{
	    int lwhich = frame->which;

	    /* In the !(which & W_LOCAL) case, we filled in repository
	       earlier in the function.  In the (which & W_LOCAL) case,
	       the Find_Names function is going to look through the
	       Entries file.  If we do not have a repository, that
	       does not make sense, so we insist upon having a
	       repository at this point.  Name_Repository will give a
	       reasonable error message.  */
	    if (repository == NULL)
			repository = Name_Repository ((char *) NULL, update_dir);
		else
		if(mapped_repository == NULL)
			mapped_repository = map_repository(repository);

	    /* find the files and fill in entries if appropriate */
	    if (process_this_directory)
	    {
			filelist = Find_Names (mapped_repository, lwhich, frame->aflag,
						&entries, repository);
			if (filelist == NULL)
			{
				error (0, 0, "skipping directory %s", update_dir);
				/* Note that Find_Directories and the filesdoneproc
				in particular would do bad things ("? foo.c" in
				the case of some filesdoneproc's).  */
				goto skip_directory;
			}
	    }
	}

	if (frame->flags == R_SKIP_DIRS && !(frame->which&W_LOCAL) && nonrecursive_module(repository))
		frame->flags = R_SKIP_DIRS;

	/* find sub-directories if we will recurse */
	if (frame->flags != R_SKIP_DIRS)
	    dirlist = Find_Directories (
		process_this_directory ? mapped_repository : NULL,
		frame->which, entries, repository);
    }
    else
    {
		/* something was passed on the command line */
		if (filelist != NULL && frame->fileproc != NULL)
		{
			/* we will process files, so pre-parse entries */
			if (frame->which & W_LOCAL)
				entries = Entries_Open (frame->aflag, NULL);
		}
    }

    /* process the files (if any) */
    if (process_this_directory && filelist != NULL && frame->fileproc)
    {
	struct file_info finfo_struct;
	struct frame_and_file frfile;

	/* read lock it if necessary */
	if (should_readlock && mapped_repository && Reader_Lock (mapped_repository) != 0)
	    error (1, 0, "read lock failed - giving up");

	/* For the server, we handle notifications in a completely different
	   place (server_notify).  For local, we can't do them here--we don't
	   have writelocks in place, and there is no way to get writelocks
	   here.  */
	if (current_parsed_root->isremote)
	    client_notify_check (repository, update_dir);

	finfo_struct.repository = mapped_repository;
	finfo_struct.update_dir = update_dir;
	finfo_struct.entries = entries;
	finfo_struct.virtual_repository = repository;
	/* do_file_proc will fill in finfo_struct.file.  */

	frfile.finfo = &finfo_struct;
	frfile.frame = frame;

	/* process the files */
	err += walklist (filelist, do_file_proc, &frfile);

	/* unlock it */
	if (should_readlock)
	    Lock_Cleanup_Directory();

	/* clean up */
	if (filelist)
	dellist (&filelist);
    }

    /* call-back files done proc (if any) */
    if (process_this_directory && dodoneproc && frame->filesdoneproc != NULL)
	{
		err = frame->filesdoneproc (frame->callerdat, err, (char*)mapped_repository,
				    (char*)(update_dir[0] ? update_dir : "."),
				    entries);
	}

 skip_directory:
	if(repository && !current_parsed_root->isremote)
	{
		fileattr_write ();
		fileattr_free ();
	}

    /* process the directories (if necessary) */
    if (dirlist != NULL)
    {
		// BUGME!!!
		/* for some reason this code path is not entered some times when it SHOULD be, eg:
		   after a rename!  This means the .direcrory_history file is not created !!!! */
	struct frame_and_entries frent;

	frent.frame = frame;
	frent.entries = entries;
	err += walklist (dirlist, do_dir_proc, (void *) &frent);
    }
	if (dirlist)
    dellist (&dirlist);

    if (entries) 
    {
	Entries_Close (entries);
	entries = NULL;
    }

    /* free the saved copy of the pointer if necessary */
	xfree (srepository);
	xfree (mapped_repository);
	repository = NULL;

    return (err);
}
示例#12
0
文件: mkmodules.cpp 项目: acml/cvsnt
/* Rebuild the checked out administrative files in directory DIR.  */
int mkmodules (char *dir)
{
    struct saved_cwd cwd;
    char *temp;
    char *cp, *last, *fname;
#ifdef MY_NDBM
    DBM *db;
#endif
    FILE *fp;
    char *line = NULL;
    size_t line_allocated = 0;
    const struct admin_file *fileptr;
    mode_t mode;

    if (noexec)
	return 0;

    if (save_cwd (&cwd))
	error_exit ();

    if ( CVS_CHDIR (dir) < 0)
	error (1, errno, "cannot chdir to %s", dir);

    /*
     * First, do the work necessary to update the "modules" database.
     */
    temp = make_tempfile ();
    switch (checkout_file (CVSROOTADM_MODULES, dir, temp, NULL))
    {

	case 0:			/* everything ok */
#ifdef MY_NDBM
	    /* open it, to generate any duplicate errors */
	    if ((db = dbm_open (temp, O_RDONLY, 0666)) != NULL)
		dbm_close (db);
#else
	    write_dbmfile (temp);
	    rename_dbmfile (temp);
#endif
	    rename_rcsfile (temp, CVSROOTADM_MODULES);
	    break;

	default:
	    error (0, 0,
		"'cvs checkout' is less functional without a %s file",
		CVSROOTADM_MODULES);
	    break;
    }					/* switch on checkout_file() */

    if (unlink_file (temp) < 0
	&& !existence_error (errno))
	error (0, errno, "cannot remove %s", temp);
    xfree (temp);

    /* Checkout the files that need it in CVSROOT dir */
    for (fileptr = filelist; fileptr && fileptr->filename; fileptr++) {
	if (fileptr->errormsg == NULL)
	    continue;
	temp = make_tempfile ();
	if (checkout_file (fileptr->filename, dir, temp, NULL) == 0)
	    rename_rcsfile (temp, fileptr->filename);

	if (unlink_file (temp) < 0
	    && !existence_error (errno))
	    error (0, errno, "cannot remove %s", temp);
	xfree (temp);
    }

    fp = CVS_FOPEN (CVSROOTADM_CHECKOUTLIST, "r");
    if (fp)
    {
	/*
	 * File format:
	 *  [<whitespace>]<filename><whitespace><error message><end-of-line>
	 *
	 * comment lines begin with '#'
	 */
	while (getline (&line, &line_allocated, fp) >= 0)
	{
	    /* skip lines starting with # */
	    if (line[0] == '#')
		continue;

	    if ((last = strrchr (line, '\n')) != NULL)
		*last = '\0';			/* strip the newline */

	    /* Skip leading white space. */
	    for (fname = line;
		 *fname && isspace ((unsigned char) *fname);
		 fname++)
		;

	    /* Find end of filename. */
	    for (cp = fname; *cp && !isspace ((unsigned char) *cp); cp++)
		;
	    *cp = '\0';

	    if(isabsolute(fname) || pathname_levels(fname)>0 || !fncmp(fname,"checkoutlist"))
		{
			error(0,0,"Invalid filename '%s' in checkoutlist", fname);
			continue;
		}

	    temp = make_tempfile ();
	    if (checkout_file (fname, dir, temp, &mode) == 0)
	    {
	        chmod(temp,mode);
		rename_rcsfile (temp, fname);
	    }
	    else
	    {
		for (cp++;
		     cp < last && *last && isspace ((unsigned char) *last);
		     cp++)
		    ;
		if (cp < last && *cp)
		    error (0, 0, cp, fname);
	    }
	    if (unlink_file (temp) < 0
		&& !existence_error (errno))
		error (0, errno, "cannot remove %s", temp);
	    xfree (temp);
	}
	if (line)
	    xfree (line);
	if (ferror (fp))
	    error (0, errno, "cannot read %s", CVSROOTADM_CHECKOUTLIST);
	if (fclose (fp) < 0)
	    error (0, errno, "cannot close %s", CVSROOTADM_CHECKOUTLIST);
    }
    else
    {
	/* Error from CVS_FOPEN.  */
	if (!existence_error (errno))
	    error (0, errno, "cannot open %s", CVSROOTADM_CHECKOUTLIST);
    }

    if (restore_cwd (&cwd, NULL))
	error_exit ();
    free_cwd (&cwd);

    return (0);
}