Example #1
0
File: chacl.cpp Project: acml/cvsnt
int chacl_fileproc(void *callerdat, struct file_info *finfo)
{
	CXmlNodePtr acl;

	/* If someone has specified 'chacl foo' and foo is a directory, you'll
       get a dirent plus every file in the directory.  We only want to set
	   the directory in this case */
	if(acl_directory_set && !strcmp(finfo->repository, acl_directory_set))
		return 0;

	Vers_TS *vers = Version_TS (finfo, NULL, NULL, NULL, 0, 0, 0);
	if(!vers->vn_user && !vers->vn_rcs)
	{
	    if (!really_quiet)
			error (0, 0, "nothing known about %s", fn_root(finfo->fullname));
		freevers_ts(&vers);
		return 0;
	}
	freevers_ts(&vers);

	if(!quiet)
		printf("%sing ACL for file %s\n",parms.del?"delet":"sett",finfo->file);
	
	acl = fileattr_getroot();
	acl->xpathVariable("name",finfo->file);
	if(!acl->Lookup("file[cvs:filename(@name,$name)]") || !acl->XPathResultNext())
	{
		acl = fileattr_getroot();
		acl->NewNode("file");
		acl->NewAttribute("name",finfo->file);
	}

	set_acl(acl);
	return 0;
}
Example #2
0
/*
 * Classify the state of a file
 */
Ctype Classify_File (struct file_info *finfo, const char *tag, const char *date,
    const char *options, int force_tag_match, int aflag, Vers_TS **versp,
    int pipeout, int force_time_mismatch, int ignore_keywords)
    /* Keyword expansion options can be either NULL or "" to
       indicate none are specified here.  */
{
    Vers_TS *vers;
    Ctype ret;
	kflag kf,kf_ent;

    TRACE(3,"Classify_File (%s)",PATCH_NULL(finfo->file));
    /* get all kinds of good data about the file */
    vers = Version_TS (finfo, options, tag, date, force_tag_match, 0, 0);
    TRACE(3,"vn_rcs=%s",PATCH_NULL(vers->vn_rcs));	

	RCS_get_kflags(vers->options,false,kf);
	if(vers->entdata)
		RCS_get_kflags(vers->entdata->options,false,kf_ent);

	if(force_time_mismatch)
	{
		xfree(vers->ts_user);
		vers->ts_user=xstrdup("modified");
	}

    if (vers->vn_user == NULL)
    {
	/* No entry available, ts_rcs is invalid */
	if (vers->vn_rcs == NULL)
	{
	    /* there is no RCS file either */
	    if (vers->ts_user == NULL)
	    {
		/* there is no user file */
		/* FIXME: Why do we skip this message if vers->tag or
		   vers->date is set?  It causes "cvs update -r tag98 foo"
		   to silently do nothing, which is seriously confusing
		   behavior.  "cvs update foo" gives this message, which
		   is what I would expect.  */
		if (!force_tag_match || !(vers->tag || vers->date))
		{
		    if (!really_quiet)
				error (0, 0, "nothing known about %s", fn_root(finfo->fullname));
		}
		ret = T_UNKNOWN;
	    }
	    else
	    {
		/* there is a user file */
		/* FIXME: Why do we skip this message if vers->tag or
		   vers->date is set?  It causes "cvs update -r tag98 foo"
		   to silently do nothing, which is seriously confusing
		   behavior.  "cvs update foo" gives this message, which
		   is what I would expect.  */
		if (!force_tag_match || !(vers->tag || vers->date))
		    if (!really_quiet)
			error (0, 0, "use `%s add' to create an entry for %s",
			       program_name, fn_root(finfo->fullname));
		ret = T_UNKNOWN;
	    }
	}
	else if (RCS_isdead (vers->srcfile, vers->vn_rcs))
	{
	    /* there is an RCS file, but it's dead */
	    if (vers->ts_user == NULL)
		ret = T_UPTODATE;
	    else
	    {
		error (0, 0, "use `%s add' to create an entry for %s",
		       program_name, fn_root(finfo->fullname));
		ret = T_UNKNOWN;
	    }
	}
	else if (vers->ts_user && !strcmp(vers->ts_user,"0") && !strcmp(finfo->file,RCSREPOVERSION))
	{
		/* It's a directory entry, but there isn't one in the repository */
		ret = T_UNKNOWN;
	}
	else if (!pipeout && vers->ts_user && No_Difference(finfo, vers, (kf.flags&KFLAG_STATIC || kf_ent.flags&KFLAG_STATIC), ignore_keywords))
	{
	    /* the files were different so it is a conflict */
	    if (!really_quiet)
		error (0, 0, "move away %s; it is in the way",
		       fn_root(finfo->fullname));
	    ret = T_CONFLICT;
	}
	else
	{
	    /* no user file or no difference, just checkout */
	    ret = T_CHECKOUT;
	}
    }
    else if (strcmp (vers->vn_user, "0") == 0)
    {
	/* An entry for a new-born file; ts_rcs is dummy */

	if (vers->ts_user == NULL)
	{
	    /*
	     * There is no user file, but there should be one; remove the
	     * entry
	     */
		if(!really_quiet)
			error (0, 0, "warning: new-born %s has disappeared", fn_root(finfo->fullname));
		ret = T_REMOVE_ENTRY;
	}
	else if (vers->vn_rcs == NULL ||
		 RCS_isdead (vers->srcfile, vers->vn_rcs))
	    /* No RCS file or RCS file revision is dead  */
	    ret = T_ADDED;
	else
	{
	    if (vers->srcfile->flags & VALID)
	    {
		/* This file has been added on some branch other than
		   the one we are looking at.  In the branch we are
		   looking at, the file was already valid.  */
		if (!really_quiet)
		    error (0, 0,
			   "conflict: %s has been added, but already exists",
			   fn_root(finfo->fullname));
	    }
	    else
	    {
		/*
		 * There is an RCS file, so someone else must have checked
		 * one in behind our back; conflict
		 */
		if (!really_quiet)
		    error (0, 0,
			   "conflict: %s created independently by second party",
			   fn_root(finfo->fullname));
	    }
	    ret = T_CONFLICT;
	}
    }
    else if (vers->vn_user[0] == '-')
    {
	/* An entry for a removed file, ts_rcs is invalid */

	if (vers->ts_user == NULL)
	{
	    /* There is no user file (as it should be) */

	    if (vers->vn_rcs == NULL
		|| RCS_isdead (vers->srcfile, vers->vn_rcs))
	    {

		/*
		 * There is no RCS file; this is all-right, but it has been
		 * removed independently by a second party; remove the entry
		 */
		ret = T_REMOVE_ENTRY;
	    }
	    else if (strcmp (vers->vn_rcs, vers->vn_user + 1) == 0)
		/*
		 * The RCS file is the same version as the user file was, and
		 * that's OK; remove it
		 */
		ret = T_REMOVED;
	    else if (pipeout)
		/*
		 * The RCS file doesn't match the user's file, but it doesn't
		 * matter in this case
		 */
		ret = T_NEEDS_MERGE;
	    else
	    {

		/*
		 * The RCS file is a newer version than the removed user file
		 * and this is definitely not OK; make it a conflict.
		 */
		if (!really_quiet)
		    error (0, 0,
			   "conflict: removed %s was modified by second party",
			   fn_root(finfo->fullname));
		ret = T_CONFLICT;
	    }
	}
	else
	{
	    /* The user file shouldn't be there */
	    if (!really_quiet)
		error (0, 0, "%s should be removed and is still there",
		       fn_root(finfo->fullname));
	    ret = T_REMOVED;
	}
    }
    else
    {
	/* A normal entry, TS_Rcs is valid */
	if (vers->vn_rcs == NULL || RCS_isdead (vers->srcfile, vers->vn_rcs))
	{
	    /* There is no RCS file */

	    if (vers->ts_user == NULL)
	    {
		/* There is no user file, so just remove the entry */
		if (!really_quiet)
		    error (0, 0, "warning: %s is not (any longer) pertinent",
			   fn_root(finfo->fullname));
		ret = T_REMOVE_ENTRY;
	    }
	    else if (!strcmp (vers->ts_user, vers->ts_rcs))
	    {
		/*
		 * The user file is still unmodified, so just remove it from
		 * the entry list
		 */
		if (!really_quiet)
		    error (0, 0, "%s is no longer in the repository",
			   fn_root(finfo->fullname));
		ret = T_REMOVE_ENTRY;
	    }
		else if (No_Difference (finfo, vers, (kf.flags&KFLAG_STATIC || kf_ent.flags&KFLAG_STATIC), ignore_keywords))
	    {
		/* they are different -> conflict */
		if (!really_quiet)
		    error (0, 0,
	       "conflict: %s is modified but no longer in the repository",
			   fn_root(finfo->fullname));
		ret = T_CONFLICT;
	    }
	    else
	    {
		/* they weren't really different */
		if (!really_quiet)
		    error (0, 0,
			   "warning: %s is not (any longer) pertinent",
			   fn_root(finfo->fullname));
		ret = T_REMOVE_ENTRY;
	    }
	}
	else if (strcmp (vers->vn_rcs, vers->vn_user) == 0)
	{
	    /* The RCS file is the same version as the user file */

	    if (vers->ts_user == NULL)
	    {
		/*
		 * There is no user file, so note that it was lost and
		 * extract a new version
		 */
		/* Comparing the command_name against "update", in
		   addition to being an ugly way to operate, means
		   that this message does not get printed by the
		   server.  That might be considered just a straight
		   bug, although there is one subtlety: that case also
		   gets hit when a patch fails and the client fetches
		   a file.  I'm not sure there is currently any way
		   for the server to distinguish those two cases.  */
		if (strcmp (command_name, "update") == 0)
		    if (!really_quiet)
			error (0, 0, "warning: %s was lost", fn_root(finfo->fullname));
		ret = T_CHECKOUT;
	    }
		else if (!strcmp(vers->ts_user,"0") && !strcmp(finfo->file,RCSREPOVERSION))
		{
			/* This is a directory... The only important entry is the version*/
			ret = T_UPTODATE;
		}
	    else if (strcmp (vers->ts_user, vers->ts_rcs) == 0)
	    {
			/* Check for expansion option changes */
			if (options && !options_same(vers->entdata->options,vers->options))
				ret = T_CHECKOUT;
			else
			{
				if(aflag && !options_same(vers->entdata->options, vers->options))
					ret = T_CHECKOUT;
				else
					ret = T_UPTODATE;
				/* Changing the expansion option now requires a commit -f, which makes
				   sense (since you might have a sandbox specially checked out as -kb for example) */
				sticky_ck (finfo, aflag, vers);
			}
	    }
	    else if (vers->entdata->merge_from_tag_1[0]) 
		{
			ret = T_MODIFIED;
		}
		else if (No_Difference (finfo, vers, (kf.flags&KFLAG_STATIC || kf_ent.flags&KFLAG_STATIC), ignore_keywords))
	    {
			ret = T_MODIFIED;
			sticky_ck (finfo, aflag, vers);
	    }
	    else if (!options_same(vers->entdata->options,vers->options))
	    {
			/* file has not changed; check out if -k changed */
			ret = T_CHECKOUT;
	    }
	    else
	    {

		/*
		 * else -> note that No_Difference will Register the
		 * file already for us, using the new tag/date. This
		 * is the desired behaviour
		 */
		ret = T_UPTODATE;
	    }
	}
	else
	{
	    /* The RCS file is a newer version than the user file */

	    if (vers->ts_user == NULL)
	    {
		/* There is no user file, so just get it */

		/* See comment at other "update" compare, for more
		   thoughts on this comparison.  */
		if (strcmp (command_name, "update") == 0)
		    if (!really_quiet)
			error (0, 0, "warning: %s was lost", fn_root(finfo->fullname));
		ret = T_CHECKOUT;
	    }
	    else if (!strcmp (vers->ts_user, vers->ts_rcs))
	    {

		/*
		 * The user file is still unmodified, so just get it as well
		 */
		if (!options_same(vers->entdata->options,vers->options))
		    ret = T_CHECKOUT;
		else
		    ret = T_PATCH;
	    }
		else if (No_Difference (finfo, vers, (kf.flags&KFLAG_STATIC || kf_ent.flags&KFLAG_STATIC), ignore_keywords))
			/* really modified, needs to merge */
			ret = T_NEEDS_MERGE;
	    else if(!options_same(vers->entdata->options,vers->options))
			/* not really modified, check it out */
			ret = T_CHECKOUT;
	    else
			ret = T_PATCH;
	}
    }

    /* free up the vers struct, or just return it */
    if (versp != (Vers_TS **) NULL)
	*versp = vers;
    else
	freevers_ts (&vers);

    /* return the status of the file */
    return (ret);
}
Example #3
0
/* The purpose of "select_hrec" is to apply the selection criteria based on
 * the command arguments and defaults and return a flag indicating whether
 * this record should be remembered for printing.
 */
static int
select_hrec (struct hrec *hr)
{
    char **cpp, *cp, *cp2;
    struct file_list_str *fl;
    int count;

    /* basic validity checking */
    if (!hr->type || !hr->user || !hr->dir || !hr->repos || !hr->rev ||
	!hr->file || !hr->end)
    {
	error (0, 0, "warning: history line %ld invalid", hr->idx);
	return 0;
    }

    /* "Since" checking:  The argument parser guarantees that only one of the
     *			  following four choices is set:
     *
     * 1. If "since_date" is set, it contains the date specified on the
     *    command line. hr->date fields earlier than "since_date" are ignored.
     * 2. If "since_rev" is set, it contains either an RCS "dotted" revision
     *    number (which is of limited use) or a symbolic TAG.  Each RCS file
     *    is examined and the date on the specified revision (or the revision
     *    corresponding to the TAG) in the RCS file (CVSROOT/repos/file) is
     *    compared against hr->date as in 1. above.
     * 3. If "since_tag" is set, matching tag records are saved.  The field
     *    "last_since_tag" is set to the last one of these.  Since we don't
     *    know where the last one will be, all records are saved from the
     *    first occurrence of the TAG.  Later, at the end of "select_hrec"
     *    records before the last occurrence of "since_tag" are skipped.
     * 4. If "backto" is set, all records with a module name or file name
     *    matching "backto" are saved.  In addition, all records with a
     *    repository field with a *prefix* matching "backto" are saved.
     *    The field "last_backto" is set to the last one of these.  As in
     *    3. above, "select_hrec" adjusts to include the last one later on.
     */
    if (since_date)
    {
	char *ourdate = date_from_time_t (hr->date);
	count = RCS_datecmp (ourdate, since_date);
	free (ourdate);
	if (count < 0)
	    return 0;
    }
    else if (*since_rev)
    {
	Vers_TS *vers;
	time_t t;
	struct file_info finfo;

	memset (&finfo, 0, sizeof finfo);
	finfo.file = hr->file;
	/* Not used, so don't worry about it.  */
	finfo.update_dir = NULL;
	finfo.fullname = finfo.file;
	finfo.repository = hr->repos;
	finfo.entries = NULL;
	finfo.rcs = NULL;

	vers = Version_TS (&finfo, NULL, since_rev, NULL, 1, 0);
	if (vers->vn_rcs)
	{
	    if ((t = RCS_getrevtime (vers->srcfile, vers->vn_rcs, NULL, 0))
		!= (time_t) 0)
	    {
		if (hr->date < t)
		{
		    freevers_ts (&vers);
		    return 0;
		}
	    }
	}
	freevers_ts (&vers);
    }
    else if (*since_tag)
    {
	if (*(hr->type) == 'T')
	{
	    /*
	     * A 'T'ag record, the "rev" field holds the tag to be set,
	     * while the "repos" field holds "D"elete, "A"dd or a rev.
	     */
	    if (within (since_tag, hr->rev))
	    {
		last_since_tag = hr;
		return 1;
	    }
	    else
		return 0;
	}
	if (!last_since_tag)
	    return 0;
    }
    else if (*backto)
    {
	if (within (backto, hr->file) || within (backto, hr->mod) ||
	    within (backto, hr->repos))
	    last_backto = hr;
	else
	    return 0;
    }

    /* User checking:
     *
     * Run down "user_list", match username ("" matches anything)
     * If "" is not there and actual username is not there, return failure.
     */
    if (user_list && hr->user)
    {
	for (cpp = user_list, count = user_count; count; cpp++, count--)
	{
	    if (!**cpp)
		break;			/* null user == accept */
	    if (!strcmp (hr->user, *cpp))	/* found listed user */
		break;
	}
	if (!count)
	    return 0;			/* Not this user */
    }

    /* Record type checking:
     *
     * 1. If Record type is not in rec_types field, skip it.
     * 2. If mod_list is null, keep everything.  Otherwise keep only modules
     *    on mod_list.
     * 3. If neither a 'T', 'F' nor 'O' record, run through "file_list".  If
     *    file_list is null, keep everything.  Otherwise, keep only files on
     *    file_list, matched appropriately.
     */
    if (!strchr (rec_types, *(hr->type)))
	return 0;
    if (!strchr ("TFOE", *(hr->type)))	/* Don't bother with "file" if "TFOE" */
    {
	if (file_list)			/* If file_list is null, accept all */
	{
	    for (fl = file_list, count = file_count; count; fl++, count--)
	    {
		/* 1. If file_list entry starts with '*', skip the '*' and
		 *    compare it against the repository in the hrec.
		 * 2. If file_list entry has a '/' in it, compare it against
		 *    the concatenation of the repository and file from hrec.
		 * 3. Else compare the file_list entry against the hrec file.
		 */
		char *cmpfile = NULL;

		if (*(cp = fl->l_file) == '*')
		{
		    cp++;
		    /* if argument to -p is a prefix of repository */
		    if (!strncmp (cp, hr->repos, strlen (cp)))
		    {
			hr->mod = fl->l_module;
			break;
		    }
		}
		else
		{
		    if (strchr (cp, '/'))
		    {
			cmpfile = Xasprintf ("%s/%s", hr->repos, hr->file);
			cp2 = cmpfile;
		    }
		    else
		    {
			cp2 = hr->file;
		    }

		    /* if requested file is found within {repos}/file fields */
		    if (within (cp, cp2))
		    {
			hr->mod = fl->l_module;
			if (cmpfile != NULL)
			    free (cmpfile);
			break;
		    }
		    if (cmpfile != NULL)
			free (cmpfile);
		}
	    }
	    if (!count)
		return 0;		/* String specified and no match */
	}
    }
    if (mod_list)
    {
	for (cpp = mod_list, count = mod_count; count; cpp++, count--)
	{
	    if (hr->mod && !strcmp (hr->mod, *cpp))	/* found module */
		break;
	}
	if (!count)
	    return 0;	/* Module specified & this record is not one of them. */
    }

    return 1;		/* Select this record unless rejected above. */
}
Example #4
0
/* ARGSUSED */
static int diff_fileproc (void *callerdat, struct file_info *finfo)
{
    int status, err = 2;		/* 2 == trouble, like rcsdiff */
    Vers_TS *vers;
    enum diff_file empty_file = DIFF_DIFFERENT;
    char *tmp;
    char *fname;
    char *label1;
    char *label2;
    char *default_branch;

    /* Initialize these solely to avoid warnings from gcc -Wall about
       variables that might be used uninitialized.  */
    tmp = NULL;
    fname = NULL;

    user_file_rev = 0;
    vers = Version_TS (finfo, NULL, NULL, NULL, 1, 0, 0);
    if(vers->tag && RCS_isbranch(finfo->rcs, vers->tag))
        default_branch = vers->tag;
    else
        default_branch = NULL;

    if (diff_rev2 != NULL || diff_date2 != NULL)
    {
        /* Skip all the following checks regarding the user file; we're
           not using it.  */
    }
    else if (vers->vn_user == NULL)
    {
        /* The file does not exist in the working directory.  */
        if ((diff_rev1 != NULL || diff_date1 != NULL)
                && vers->srcfile != NULL)
        {
            /* The file does exist in the repository.  */
            if (empty_files)
                empty_file = DIFF_REMOVED;
            else
            {
                int exists;

                exists = 0;
                /* special handling for TAG_HEAD */
                if (diff_rev1 && strcmp (diff_rev1, TAG_HEAD) == 0)
                {
                    char *head =
                        (vers->vn_rcs == NULL
                         ? NULL
                         : RCS_branch_head (vers->srcfile, vers->vn_rcs));
                    exists = head != NULL;
                    if (head != NULL)
                        xfree (head);
                }
                else
                {
                    Vers_TS *xvers;

                    xvers = Version_TS (finfo, NULL, diff_rev1?diff_rev1:default_branch, diff_date1,
                                        1, 0, 0);
                    exists = xvers->vn_rcs != NULL;
                    freevers_ts (&xvers);
                }
                if (exists)
                    error (0, 0,
                           "%s no longer exists, no comparison available",
                           fn_root(finfo->fullname));
                freevers_ts (&vers);
                diff_mark_errors (err);
                return (err);
            }
        }
        else
        {
            error (0, 0, "I know nothing about %s", fn_root(finfo->fullname));
            freevers_ts (&vers);
            diff_mark_errors (err);
            return (err);
        }
    }
    else if (vers->vn_user[0] == '0' && vers->vn_user[1] == '\0')
    {
        if (empty_files)
            empty_file = DIFF_ADDED;
        else
        {
            error (0, 0, "%s is a new entry, no comparison available",
                   fn_root(finfo->fullname));
            freevers_ts (&vers);
            diff_mark_errors (err);
            return (err);
        }
    }
    else if (vers->vn_user[0] == '-')
    {
        if (empty_files)
            empty_file = DIFF_REMOVED;
        else
        {
            error (0, 0, "%s was removed, no comparison available",
                   fn_root(finfo->fullname));
            freevers_ts (&vers);
            diff_mark_errors (err);
            return (err);
        }
    }
    else
    {
        if (vers->vn_rcs == NULL && vers->srcfile == NULL)
        {
            error (0, 0, "cannot find revision control file for %s",
                   fn_root(finfo->fullname));
            freevers_ts (&vers);
            diff_mark_errors (err);
            return (err);
        }
        else
        {
            if (vers->ts_user == NULL)
            {
                error (0, 0, "cannot find %s", fn_root(finfo->fullname));
                freevers_ts (&vers);
                diff_mark_errors (err);
                return (err);
            }
            else if (!strcmp (vers->ts_user, vers->ts_rcs))
            {
                /* The user file matches some revision in the repository
                   Diff against the repository (for remote CVS, we might not
                   have a copy of the user file around).  */
                user_file_rev = vers->vn_user;
            }
        }
    }
    empty_file = diff_file_nodiff (finfo, vers, empty_file, default_branch);
    if (empty_file == DIFF_SAME || empty_file == DIFF_ERROR)
    {
        freevers_ts (&vers);
        if (empty_file == DIFF_SAME)
        {
            /* In the server case, would be nice to send a "Checked-in"
               response, so that the client can rewrite its timestamp.
               server_checked_in by itself isn't the right thing (it
               needs a server_register), but I'm not sure what is.
               It isn't clear to me how "cvs status" handles this (that
               is, for a client which sends Modified not Is-modified to
               "cvs status"), but it does.  */
            return (0);
        }
        else
        {
            diff_mark_errors (err);
            return (err);
        }
    }

    if (empty_file == DIFF_DIFFERENT)
    {
        int dead1, dead2;

        if (use_rev1 == NULL)
            dead1 = 0;
        else
            dead1 = RCS_isdead (vers->srcfile, use_rev1);
        if (use_rev2 == NULL)
            dead2 = 0;
        else
            dead2 = RCS_isdead (vers->srcfile, use_rev2);

        if (dead1 && dead2)
        {
            freevers_ts (&vers);
            return (0);
        }
        else if (dead1)
        {
            if (empty_files)
                empty_file = DIFF_ADDED;
            else
            {
                error (0, 0, "%s is a new entry, no comparison available",
                       fn_root(finfo->fullname));
                freevers_ts (&vers);
                diff_mark_errors (err);
                return (err);
            }
        }
        else if (dead2)
        {
            if (empty_files)
                empty_file = DIFF_REMOVED;
            else
            {
                error (0, 0, "%s was removed, no comparison available",
                       fn_root(finfo->fullname));
                freevers_ts (&vers);
                diff_mark_errors (err);
                return (err);
            }
        }
    }

    /* Output an "Index:" line for patch to use */
    if(!is_rcs)
    {
        cvs_output ("Index: ", 0);
        cvs_output (fn_root(finfo->fullname), 0);
        cvs_output ("\n", 1);
    }

    /* Set up file labels appropriate for compatibility with the Larry Wall
     * implementation of patch if the user didn't specify.  This is irrelevant
     * according to the POSIX.2 specification.
     */
    label1 = NULL;
    label2 = NULL;
    if (!have_rev1_label)
    {
        if (empty_file == DIFF_ADDED)
        {
            TRACE(3,"diff_fileproc(); !have_rev1_label; empty_file == DIFF_ADDED make_file_label(is_rcs=%d)",is_rcs);

            label1 =
                make_file_label (DEVNULL, NULL, NULL, is_rcs);
        }
        else
        {
            TRACE(3,"diff_fileproc(); !have_rev1_label; empty_file != DIFF_ADDED make_file_label(is_rcs=%d)",is_rcs);

            label1 =
                make_file_label (is_rcs?fn_root(finfo->file):fn_root(finfo->fullname), use_rev1, vers ? vers->srcfile : NULL, is_rcs);
        }
    }

    if (!have_rev2_label)
    {
        if (empty_file == DIFF_REMOVED)
        {
            TRACE(3,"diff_fileproc(); !have_rev2_label; empty_file == DIFF_REMOVED make_file_label(is_rcs=%d)",is_rcs);

            label2 =
                make_file_label (DEVNULL, NULL, NULL, is_rcs);
        }
        else
        {
            TRACE(3,"diff_fileproc(); !have_rev2_label; empty_file != DIFF_REMOVED make_file_label(is_rcs=%d)",is_rcs);

            label2 =
                make_file_label (is_rcs?fn_root(finfo->file):fn_root(finfo->fullname), use_rev2, vers ? vers->srcfile : NULL, is_rcs);
        }
    }

    if (empty_file == DIFF_ADDED || empty_file == DIFF_REMOVED)
    {
        /* This is fullname, not file, possibly despite the POSIX.2
         * specification, because that's the way all the Larry Wall
         * implementations of patch (are there other implementations?) want
         * things and the POSIX.2 spec appears to leave room for this.
         */
        cvs_output ("\
===================================================================\n\
RCS file: ", 0);
        cvs_output (fn_root(finfo->fullname), 0);
        cvs_output ("\n", 1);

        cvs_output ("diff -N ", 0);
        cvs_output (fn_root(finfo->fullname), 0);
        cvs_output ("\n", 1);

        if (empty_file == DIFF_ADDED)
        {
            if (use_rev2 == NULL)
                status = diff_exec (DEVNULL, finfo->file, label1, label2, opts, RUN_TTY);
            else
            {
                int retcode;

                tmp = cvs_temp_name ();
                retcode = RCS_checkout (vers->srcfile, (char *) NULL,
                                        use_rev2, (char *) NULL,
                                        vers->options,
                                        tmp, (RCSCHECKOUTPROC) NULL,
                                        (void *) NULL, NULL);
                if (retcode != 0)
                {
                    diff_mark_errors (err);
                    return err;
                }

                status = diff_exec (DEVNULL, tmp, label1, label2, opts, RUN_TTY);
            }
        }
        else
        {
            int retcode;

            tmp = cvs_temp_name ();
            retcode = RCS_checkout (vers->srcfile, (char *) NULL,
                                    use_rev1, (char *) NULL,
                                    *options ? options : vers->options,
                                    tmp, (RCSCHECKOUTPROC) NULL,
                                    (void *) NULL, NULL);
            if (retcode != 0)
            {
                diff_mark_errors (err);
                return err;
            }

            status = diff_exec (tmp, DEVNULL, label1, label2, opts, RUN_TTY);
        }
    }
Example #5
0
/* ARGSUSED */
static int status_fileproc (void *callerdat, struct file_info *finfo)
{
    Ctype status;
    char *sstat;
    Vers_TS *vers;
	Node *node;

    status = Classify_File (finfo, (char *) NULL, (char *) NULL, (char *) NULL,
			    1, 0, &vers, 0, 0, 0);
    sstat = "Classify Error";
    switch (status)
    {
	case T_UNKNOWN:
	    sstat = "Unknown";
	    break;
	case T_CHECKOUT:
	    sstat = "Needs Checkout";
	    break;
	case T_PATCH:
	    sstat = "Needs Patch";
	    break;
	case T_CONFLICT:
	    /* I _think_ that "unresolved" is correct; that if it has
	       been resolved then the status will change.  But I'm not
	       sure about that.  */
	    sstat = "Unresolved Conflict";
	    break;
	case T_ADDED:
	    sstat = "Locally Added";
	    break;
	case T_REMOVED:
	    sstat = "Locally Removed";
	    break;
	case T_MODIFIED:
	    if (vers->ts_conflict)
		sstat = "File had conflicts on merge";
	    else
		sstat = "Locally Modified";
	    break;
	case T_REMOVE_ENTRY:
	    sstat = "Entry Invalid";
	    break;
	case T_UPTODATE:
	    sstat = "Up-to-date";
	    break;
	case T_NEEDS_MERGE:
	    sstat = "Needs Merge";
	    break;
	case T_TITLE:
	    /* I don't think this case can occur here.  Just print
	       "Classify Error".  */
	    break;
    }
	if(quick>=2 && status == T_UPTODATE)
	{
		freevers_ts(&vers);
		return 0;
	}
	if(!quick)
	{
    cvs_output ("\
===================================================================\n", 0);
	}
Example #6
0
/* ARGSUSED */
static int
ls_fileproc (void *callerdat, struct file_info *finfo)
{
    Vers_TS *vers;
    char *regex_err;
    Node *p, *n;
    bool isdead;
    const char *filename;

    if (regexp_match)
    {
#ifdef FILENAMES_CASE_INSENSITIVE
	  re_set_syntax (REG_ICASE|RE_SYNTAX_EGREP);
#else
	  re_set_syntax (RE_SYNTAX_EGREP);
#endif
	  if ((regex_err = re_comp (regexp_match)) != NULL)
	  {
	      error (1, 0, "bad regular expression passed to 'ls': %s",
                     regex_err);
	  }
	  if (re_exec (finfo->file) == 0)
	      return 0;				/* no match */
    }

    vers = Version_TS (finfo, NULL, show_tag, show_date, 1, 0);
    /* Skip dead revisions unless specifically requested to do otherwise.
     * We also bother to check for long_format so we can print the state.
     */
    if (vers->vn_rcs && (!show_dead_revs || long_format))
	isdead = RCS_isdead (finfo->rcs, vers->vn_rcs);
    else
	isdead = false;
    if (!vers->vn_rcs || (!show_dead_revs && isdead))
    {
        freevers_ts (&vers);
	return 0;
    }

    p = findnode (callerdat, finfo->update_dir);
    if (!p)
    {
	/* This only occurs when a complete path to a file is specified on the
	 * command line.  Put the file in the root list.
	 */
	filename = finfo->fullname;

	/* Add update_dir node.  */
	p = findnode (callerdat, ".");
	if (!p)
	{
	    p = getnode ();
	    p->key = xstrdup (".");
	    p->data = getlist ();
	    p->delproc = ls_delproc;
	    addnode (callerdat, p);
	}
    }
    else
	filename = finfo->file;

    n = getnode();
    if (entries_format)
    {
	char *outdate = entries_time (RCS_getrevtime (finfo->rcs, vers->vn_rcs,
                                                      0, 0));
	n->data = Xasprintf ("/%s/%s/%s/%s/%s%s\n",
                             filename, vers->vn_rcs,
                             outdate, vers->options,
                             show_tag ? "T" : "", show_tag ? show_tag : "");
	free (outdate);
    }
    else if (long_format)
    {
	struct long_format_data *out =
		xmalloc (sizeof (struct long_format_data));
	out->header = Xasprintf ("%-5.5s",
                                 vers->options[0] != '\0' ? vers->options
                                                          : "----");
	/* FIXME: Do we want to mimc the real `ls' command's date format?  */
	out->time = gmformat_time_t (RCS_getrevtime (finfo->rcs, vers->vn_rcs,
                                                     0, 0));
	out->footer = Xasprintf (" %-9.9s%s %s%s", vers->vn_rcs,
                                 strlen (vers->vn_rcs) > 9 ? "+" : " ",
                                 show_dead_revs ? (isdead ? "dead " : "     ")
                                                : "",
                                 filename);
	n->data = out;
	n->delproc = long_format_data_delproc;
    }
    else
	n->data = Xasprintf ("%s\n", filename);

    addnode (p->data, n);

    freevers_ts (&vers);
    return 0;
}
Example #7
0
/* ARGSUSED */
static int remove_fileproc (void *callerdat, struct file_info *finfo)
{
    Vers_TS *vers;

    if (force)
    {
	if (!noexec)
	{
	    if ( CVS_UNLINK (finfo->file) < 0 && ! existence_error (errno))
	    {
		error (0, errno, "unable to remove %s", fn_root(finfo->fullname));
	    }
	}
	/* else FIXME should probably act as if the file doesn't exist
	   in doing the following checks.  */
    }

    vers = Version_TS (finfo, NULL, NULL, NULL, 0, 0, 0);

    if (vers->ts_user && (!vers->vn_user || strcmp(vers->vn_user,"0")))
    {
	existing_files++;
	if (!quiet)
	    error (0, 0, "file `%s' still in working directory",
		   fn_root(finfo->fullname));
    }
    else if (vers->vn_user == NULL)
    {
	if (!quiet)
	    error (0, 0, "nothing known about `%s'", fn_root(finfo->fullname));
    }
    else if (vers->vn_user[0] == '0' && vers->vn_user[1] == '\0')
    {
	char *fname;

	/*
	 * It's a file that has been added, but not commited yet. So,
	 * remove the ,t file for it and scratch it from the
	 * entries file.  */
	Scratch_Entry (finfo->entries, finfo->file);
	fname = (char*)xmalloc (strlen (finfo->file)
			 + sizeof (CVSADM)
			 + sizeof (CVSEXT_LOG)
			 + 10);
	(void) sprintf (fname, "%s/%s%s", CVSADM, finfo->file, CVSEXT_LOG);
	if (unlink_file (fname) < 0
	    && !existence_error (errno))
	    error (0, errno, "cannot remove %s", CVSEXT_LOG);
	if (!quiet)
	    error (0, 0, "removed `%s'", fn_root(finfo->fullname));

#ifdef SERVER_SUPPORT
	if (server_active)
	    server_checked_in (finfo->file, finfo->update_dir, finfo->repository);
#endif
	xfree (fname);
    }
    else if (vers->vn_user[0] == '-')
    {
	if (!quiet)
	    error (0, 0, "file `%s' already scheduled for removal",
		   fn_root(finfo->fullname));
    }
    else if (vers->tag != NULL && ((isdigit ((unsigned char) *vers->tag)) || !RCS_isbranch(finfo->rcs, vers->tag)))
    {
	/* Commit will just give an error, and so there seems to be
	   little reason to allow the remove.  I mean, conflicts that
	   arise out of parallel development are one thing, but conflicts
	   that arise from sticky tags are quite another.  */
	error (0, 0, "\
cannot remove file `%s' which has a sticky tag of `%s'",
	       fn_root(finfo->fullname), vers->tag);
	bad_files++;
    }
    else
    {
	char *fname;

	/* Re-register it with a negative version number.  */
	fname = (char*)xmalloc (strlen (vers->vn_user) + 5);
	(void) strcpy (fname, "-");
	(void) strcat (fname, vers->vn_user);
	Register (finfo->entries, finfo->file, fname, vers->ts_rcs, vers->options,
		  vers->tag, vers->date, vers->ts_conflict, NULL, NULL, vers->tt_rcs, vers->edit_revision, vers->edit_tag, vers->edit_bugid, NULL);
	if (!quiet)
	    error (0, 0, "scheduling `%s' for removal", fn_root(finfo->fullname));
	removed_files++;

#ifdef SERVER_SUPPORT
	if (server_active)
	    server_checked_in (finfo->file, finfo->update_dir, finfo->repository);
#endif
	xfree (fname);
    }

    freevers_ts (&vers);
    return (0);
}