Beispiel #1
0
/* ARGSUSED */
static int
release_delete_dirleaveproc(void *callerdat, char *dir, int err, char *update_dir, List *entries)
{
    if (strchr (dir, '/') == NULL)
    {
		/* FIXME: chdir ("..") loses with symlinks.  */
		/* Prune empty dirs on the way out - if necessary */
		unlink_file_dir(CVSADM);
		(void) CVS_CHDIR ("..");
		if (force_delete || isemptydir (dir, 0))
		{
			List *list;
			/* I'm not sure the existence_error is actually possible (except
			in cases where we really should print a message), but since
			this code used to ignore all errors, I'll play it safe.	*/
			if (unlink_file_dir (dir) < 0 && !existence_error (errno))
				error (0, errno, "cannot remove %s directory", dir);
			if(isdir(CVSADM))
			{
				list = Entries_Open(0,NULL);
				Subdir_Deregister (list, (char *) NULL, dir);
				Entries_Close(list);
			}
		}
    }

    return (err);
}
Beispiel #2
0
/*
 * Unlink a file or dir, if possible.  If it is a directory do a deep
 * removal of all of the files in the directory.  Return -1 on error
 * (in which case errno is set).
 */
int unlink_file_dir (const char *f)
{
    struct stat sb;

    TRACE(1,"unlink_file_dir(%s)",PATCH_NULL(f));

    if (noexec)
        return (0);

    /* For at least some unices, if root tries to unlink() a directory,
       instead of doing something rational like returning EISDIR,
       the system will gleefully go ahead and corrupt the filesystem.
       So we first call stat() to see if it is OK to call unlink().  This
       doesn't quite work--if someone creates a directory between the
       call to stat() and the call to unlink(), we'll still corrupt
       the filesystem.  Where is the Unix Haters Handbook when you need
       it?  */
    if (stat (f, &sb) < 0)
    {
        if (existence_error (errno))
        {
            /* The file or directory doesn't exist anyhow.  */
            return -1;
        }
    }
    else if (S_ISDIR (sb.st_mode))
        return deep_remove_dir (f);

    return CVS_UNLINK (f);
}
Beispiel #3
0
/* ARGSUSED */
DBM *
mydbm_open (char *file, int flags, int mode)
{
    FILE *fp;
    DBM *db;

    fp = CVS_FOPEN (file, (flags & O_ACCMODE) != O_RDONLY
			  ?  FOPEN_BINARY_READWRITE : FOPEN_BINARY_READ);
    if (fp == NULL && !(existence_error (errno) && (flags & O_CREAT)))
	return NULL;

    db = xmalloc (sizeof (*db));
    db->dbm_list = getlist ();
    db->modified = 0;
    db->name = xstrdup (file);

    if (fp != NULL)
    {
	mydbm_load_file (fp, db->dbm_list, file);
	if (fclose (fp) < 0)
	    error (0, errno, "cannot close %s",
		   primary_root_inverse_translate (file));
    }
    return db;
}
Beispiel #4
0
/*
 * Unlink a file or dir, if possible.  If it is a directory do a deep
 * removal of all of the files in the directory.  Return -1 on error
 * (in which case errno is set).
 */
int
unlink_file_dir (const char *f)
{
    struct stat sb;

    /* This is called by the server parent process in contexts where
       it is not OK to send output (e.g. after we sent "ok" to the
       client).  */
    if (!server_active)
	TRACE (TRACE_FUNCTION, "unlink_file_dir(%s)", f);

    if (noexec)
	return 0;

    /* For at least some unices, if root tries to unlink() a directory,
       instead of doing something rational like returning EISDIR,
       the system will gleefully go ahead and corrupt the filesystem.
       So we first call stat() to see if it is OK to call unlink().  This
       doesn't quite work--if someone creates a directory between the
       call to stat() and the call to unlink(), we'll still corrupt
       the filesystem.  Where is the Unix Haters Handbook when you need
       it?  */
    if (stat (f, &sb) < 0)
    {
	if (existence_error (errno))
	{
	    /* The file or directory doesn't exist anyhow.  */
	    return -1;
	}
    }
    else if (S_ISDIR (sb.st_mode))
	return deep_remove_dir (f);

    return CVS_UNLINK (f);
}
Beispiel #5
0
Datei: ignore.c Projekt: aosm/cvs
/*
 * Open a file and read lines, feeding each line to a line parser. Arrange
 * for keeping a temporary list of wildcards at the end, if the "hold"
 * argument is set.
 */
void
ign_add_file (char *file, int hold)
{
    FILE *fp;
    char *line = NULL;
    size_t line_allocated = 0;

    /* restore the saved list (if any) */
    if (s_ign_list != NULL)
    {
	int i;

	for (i = 0; i < s_ign_count; i++)
	    ign_list[i] = s_ign_list[i];
	ign_count = s_ign_count;
	ign_list[ign_count] = NULL;

	s_ign_count = 0;
	free (s_ign_list);
	s_ign_list = NULL;
    }

    /* is this a temporary ignore file? */
    if (hold)
    {
	/* re-set if we had already done a temporary file */
	if (ign_hold >= 0)
	{
	    int i;

	    for (i = ign_hold; i < ign_count; i++)
		free (ign_list[i]);
	    ign_count = ign_hold;
	    ign_list[ign_count] = NULL;
	}
	else
	{
	    ign_hold = ign_count;
	}
    }

    /* load the file */
    fp = CVS_FOPEN (file, "r");
    if (fp == NULL)
    {
	if (! existence_error (errno))
	    error (0, errno, "cannot open %s", file);
	return;
    }
    while (getline (&line, &line_allocated, fp) >= 0)
	ign_add (line, hold);
    if (ferror (fp))
	error (0, errno, "cannot read %s", file);
    if (fclose (fp) < 0)
	error (0, errno, "cannot close %s", file);
    free (line);
}
Beispiel #6
0
static int
get_table_ex(term_t handle, Table *table)
{ int64_t l;

  if ( PL_get_int64(handle, &l) )
  { Table t = (Table)(intptr_t)l;

    if ( t->magic == TABLE_MAGIC )
    { *table = t;
      return TRUE;
    }

    return existence_error(handle, "table");
  }

  return type_error(handle, "table");
}
Beispiel #7
0
/*
 * Make a path to the argument directory, printing a message if something
 * goes wrong.
 */
void
make_directories (const char *name)
{
    char *cp;

    if (noexec)
	return;

    if (mkdir (name, 0777) == 0 || errno == EEXIST)
	return;
    if (! existence_error (errno))
    {
	error (0, errno, "cannot make path to %s", name);
	return;
    }
    if ((cp = strrchr (name, '/')) == NULL)
	return;
    *cp = '\0';
    make_directories (name);
    *cp++ = '/';
    if (*cp == '\0')
	return;
    (void) mkdir (name, 0777);
}
Beispiel #8
0
/*
 * Builds a temporary file using setup_tmpfile() and invokes the user's
 * editor on the file.  The header garbage in the resultant file is then
 * stripped and the log message is stored in the "message" argument.
 *
 * If REPOSITORY is non-NULL, process rcsinfo for that repository; if it
 * is NULL, use the CVSADM_TEMPLATE file instead.  REPOSITORY should be
 * NULL when running in client mode.
 *
 * GLOBALS
 *   Editor     Set to a default value by configure and overridable using the
 *              -e option to the CVS executable.
 */
void
do_editor (const char *dir, char **messagep, const char *repository,
           List *changes)
{
    static int reuse_log_message = 0;
    char *line;
    int line_length;
    size_t line_chars_allocated;
    char *fname;
    struct stat pre_stbuf, post_stbuf;
    int retcode = 0;

    assert (!current_parsed_root->isremote != !repository);

    if (noexec || reuse_log_message)
        return;

    /* Abort before creation of the temp file if no editor is defined. */
    if (strcmp (Editor, "") == 0)
        error(1, 0, "no editor defined, must use -e or -m");

again:
    /* Create a temporary file.  */
    if( ( fp = cvs_temp_file( &fname ) ) == NULL )
        error( 1, errno, "cannot create temporary file" );

    if (*messagep)
    {
        (void) fputs (*messagep, fp);

        if ((*messagep)[0] == '\0' ||
                (*messagep)[strlen (*messagep) - 1] != '\n')
            (void) fprintf (fp, "\n");
    }
    else
        (void) fprintf (fp, "\n");

    if (repository != NULL)
        /* tack templates on if necessary */
        (void) Parse_Info (CVSROOTADM_RCSINFO, repository, rcsinfo_proc,
                           PIOPT_ALL, NULL);
    else
    {
        FILE *tfp;
        char buf[1024];
        size_t n;
        size_t nwrite;

        /* Why "b"?  */
        tfp = CVS_FOPEN (CVSADM_TEMPLATE, "rb");
        if (tfp == NULL)
        {
            if (!existence_error (errno))
                error (1, errno, "cannot read %s", CVSADM_TEMPLATE);
        }
        else
        {
            while (!feof (tfp))
            {
                char *p = buf;
                n = fread (buf, 1, sizeof buf, tfp);
                nwrite = n;
                while (nwrite > 0)
                {
                    n = fwrite (p, 1, nwrite, fp);
                    nwrite -= n;
                    p += n;
                }
                if (ferror (tfp))
                    error (1, errno, "cannot read %s", CVSADM_TEMPLATE);
            }
            if (fclose (tfp) < 0)
                error (0, errno, "cannot close %s", CVSADM_TEMPLATE);
        }
    }

    (void) fprintf (fp,
                    "%s----------------------------------------------------------------------\n",
                    CVSEDITPREFIX);
    (void) fprintf (fp,
                    "%sEnter Log.  Lines beginning with `%.*s' are removed automatically\n%s\n",
                    CVSEDITPREFIX, CVSEDITPREFIXLEN, CVSEDITPREFIX,
                    CVSEDITPREFIX);
    if (dir != NULL && *dir)
        (void) fprintf (fp, "%sCommitting in %s\n%s\n", CVSEDITPREFIX,
                        dir, CVSEDITPREFIX);
    if (changes != NULL)
        setup_tmpfile (fp, CVSEDITPREFIX, changes);
    (void) fprintf (fp,
                    "%s----------------------------------------------------------------------\n",
                    CVSEDITPREFIX);

    /* finish off the temp file */
    if (fclose (fp) == EOF)
        error (1, errno, "%s", fname);
    if (stat (fname, &pre_stbuf) == -1)
        pre_stbuf.st_mtime = 0;

    /* run the editor */
    run_setup (Editor);
    run_add_arg (fname);
    if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY,
                             RUN_NORMAL | RUN_SIGIGNORE | RUN_UNSETXID)) != 0)
        error (0, retcode == -1 ? errno : 0, "warning: editor session failed");

    /* put the entire message back into the *messagep variable */

    fp = xfopen (fname, "r");

    if (*messagep)
        free (*messagep);

    if (stat (fname, &post_stbuf) != 0)
        error (1, errno, "cannot find size of temp file %s", fname);

    if (post_stbuf.st_size == 0)
        *messagep = NULL;
    else
    {
        /* On NT, we might read less than st_size bytes, but we won't
           read more.  So this works.  */
        *messagep = (char *) xmalloc (post_stbuf.st_size + 1);
        (*messagep)[0] = '\0';
    }

    line = NULL;
    line_chars_allocated = 0;

    if (*messagep)
    {
        size_t message_len = post_stbuf.st_size + 1;
        size_t offset = 0;
        while (1)
        {
            line_length = getline (&line, &line_chars_allocated, fp);
            if (line_length == -1)
            {
                if (ferror (fp))
                    error (0, errno, "warning: cannot read %s", fname);
                break;
            }
            if (strncmp (line, CVSEDITPREFIX, CVSEDITPREFIXLEN) == 0)
                continue;
            if (offset + line_length >= message_len)
                expand_string (messagep, &message_len,
                               offset + line_length + 1);
            (void) strcpy (*messagep + offset, line);
            offset += line_length;
        }
    }
    if (fclose (fp) < 0)
        error (0, errno, "warning: cannot close %s", fname);

    /* canonicalize emply messages */
    if (*messagep != NULL &&
            (**messagep == '\0' || strcmp (*messagep, "\n") == 0))
    {
        free (*messagep);
        *messagep = NULL;
    }

    if (pre_stbuf.st_mtime == post_stbuf.st_mtime || *messagep == NULL)
    {
        for (;;)
        {
            (void) printf ("\nLog message unchanged or not specified\n");
            (void) printf ("a)bort, c)ontinue, e)dit, !)reuse this message unchanged for remaining dirs\n");
            (void) printf ("Action: (abort) ");
            (void) fflush (stdout);
            line_length = getline (&line, &line_chars_allocated, stdin);
            if (line_length < 0)
            {
                error (0, errno, "cannot read from stdin");
                if (unlink_file (fname) < 0)
                    error (0, errno,
                           "warning: cannot remove temp file %s", fname);
                error (1, 0, "aborting");
            }
            else if (line_length == 0
                     || *line == '\n' || *line == 'a' || *line == 'A')
            {
                if (unlink_file (fname) < 0)
                    error (0, errno, "warning: cannot remove temp file %s", fname);
                error (1, 0, "aborted by user");
            }
            if (*line == 'c' || *line == 'C')
                break;
            if (*line == 'e' || *line == 'E')
                goto again;
            if (*line == '!')
            {
                reuse_log_message = 1;
                break;
            }
            (void) printf ("Unknown input\n");
        }
    }
    if (line)
        free (line);
    if (unlink_file (fname) < 0)
        error (0, errno, "warning: cannot remove temp file %s", fname);
    free (fname);
}
Beispiel #9
0
static void
time_stamp_server (const char *file, Vers_TS *vers_ts, Entnode *entdata)
{
    struct stat sb;
    char *cp;

    TRACE (TRACE_FUNCTION, "time_stamp_server (%s, %s, %s, %s)",
	   file,
	   entdata && entdata->version ? entdata->version : "(null)",
	   entdata && entdata->timestamp ? entdata->timestamp : "(null)",
	   entdata && entdata->conflict ? entdata->conflict : "(null)");

    if (lstat (file, &sb) < 0)
    {
	if (! existence_error (errno))
	    error (1, errno, "cannot stat temp file");

	/* Missing file means lost or unmodified; check entries
	   file to see which.

	   XXX FIXME - If there's no entries file line, we
	   wouldn't be getting the file at all, so consider it
	   lost.  I don't know that that's right, but it's not
	   clear to me that either choice is.  Besides, would we
	   have an RCS string in that case anyways?  */
	if (entdata == NULL)
	    mark_lost (vers_ts);
	else if (entdata->timestamp
		 && entdata->timestamp[0] == '='
		 && entdata->timestamp[1] == '\0')
	    mark_unchanged (vers_ts);
	else if (entdata->conflict
		 && entdata->conflict[0] == '=')
	{
	    /* These just need matching content.  Might as well minimize it.  */
	    vers_ts->ts_user = xstrdup ("");
	    vers_ts->ts_conflict = xstrdup ("");
	}
	else if (entdata->timestamp
		 && (entdata->timestamp[0] == 'M'
		     || entdata->timestamp[0] == 'D')
		 && entdata->timestamp[1] == '\0')
	    vers_ts->ts_user = xstrdup ("Is-modified");
	else
	    mark_lost (vers_ts);
    }
    else if (sb.st_mtime == 0)
    {
	/* We shouldn't reach this case any more!  */
	abort ();
    }
    else
    {
        struct tm *tm_p;

	vers_ts->ts_user = xmalloc (25);
	/* We want to use the same timestamp format as is stored in the
	   st_mtime.  For unix (and NT I think) this *must* be universal
	   time (UT), so that files don't appear to be modified merely
	   because the timezone has changed.  For VMS, or hopefully other
	   systems where gmtime returns NULL, the modification time is
	   stored in local time, and therefore it is not possible to cause
	   st_mtime to be out of sync by changing the timezone.  */
	tm_p = gmtime (&sb.st_mtime);
	cp = tm_p ? asctime (tm_p) : ctime (&sb.st_mtime);
	cp[24] = 0;
	/* Fix non-standard format.  */
	if (cp[8] == '0') cp[8] = ' ';
	(void) strcpy (vers_ts->ts_user, cp);
    }
}
Beispiel #10
0
List *Find_Names (const char *repository, int which, int aflag, List **optentries, const char *virtual_repository)
{
    List *entries;
    List *files;
	const char *regex = NULL;

	if(!current_parsed_root->isremote)
		regex = lookup_regex(virtual_repository);

    /* make a list for the files */
    files = filelist = getlist ();

    /* look at entries (if necessary) */
    if (which & W_LOCAL)
    {
		/* parse the entries file (if it exists) */
		entries = Entries_Open (aflag, NULL);
		if (entries != NULL)
		{
			/* walk the entries file adding elements to the files list */
			(void) walklist (entries, add_entries_proc, NULL);

			/* if our caller wanted the entries list, return it; else free it */
			if (optentries != NULL)
				*optentries = entries;
			else
				Entries_Close (entries);
		}
    }

    if ((which & W_REPOS) && repository && !isreadable (CVSADM_ENTSTAT))
    {
		/* search the repository */
		if (find_rcs (repository, files, regex) != 0)
		{
			error (0, errno, "cannot open directory %s", fn_root(repository));
			goto error_exit;
		}

		/* search the attic too */
		{
			char *dir;
			dir = (char*)xmalloc (strlen (repository) + sizeof (CVSATTIC) + 10);
			(void) sprintf (dir, "%s/%s", repository, CVSATTIC);
			if (find_rcs (dir, files, regex) != 0
			&& !existence_error (errno))
			/* For now keep this a fatal error, seems less useful
			for access control than the case above.  */
			error (1, errno, "cannot open directory %s", fn_root(dir));
			xfree (dir);
		}

		if(find_virtual_rcs (virtual_repository, files) != 0)
		{
			error(1, errno, "find_virtual_rcs failed");
		}

		if(find_rename_rcs(virtual_repository, files) != 0)
		{
			error(1,errno, "find_renames failed");
		}
    }

	xfree(regex);

    /* sort the list into alphabetical order and return it */
    sortlist (files, fsortcmp);
    return (files);
 error_exit:
	xfree(regex);
    dellist (&files);
    return NULL;
}
Beispiel #11
0
/*
 * Copies "from" to "to", decompressing "from" on the fly
 */
int copy_and_unzip_file (const char *from, const char *to, int force_overwrite, int must_exist)
{
    struct stat sb;
    struct utimbuf t;
    int fdin, fdout;
    z_stream zstr = {0};
    int zstatus;
    char buf[BUFSIZ*10];
    char zbuf[BUFSIZ*20];
    int n;
#ifdef UTIME_EXPECTS_WRITABLE
    int change_it_back = 0;
#endif

    TRACE(1,"copy_and_unzip(%s,%s)",PATCH_NULL(from),PATCH_NULL(to));
    if (noexec)
        return 0;

    /* If the file to be copied is a link or a device, then just create
       the new link or device appropriately. */
    if (islink (from))
    {
        char *source = xreadlink (from);
        symlink (source, to);
        xfree (source);
        return 0;
    }

    if (isdevice (from))
    {
#if defined(HAVE_MKNOD) && defined(HAVE_STRUCT_STAT_ST_RDEV)
        if (stat (from, &sb) < 0)
            error (1, errno, "cannot stat %s", fn_root(from));
        mknod (to, sb.st_mode, sb.st_rdev);
#else
        error (1, 0, "cannot copy device files on this system (%s)", fn_root(from));
#endif
    }
    else
    {
        /* Not a link or a device... probably a regular file. */
        if ((fdin = CVS_OPEN (from, O_RDONLY)) < 0)
        {
            if(must_exist)
                error (1, errno, "cannot open %s for copying", fn_root(from));
            else
                return -1;
        }
        if (fstat (fdin, &sb) < 0)
        {
            if(must_exist)
                error (1, errno, "cannot fstat %s", fn_root(from));
            else
            {
                close(fdin);
                return -1;
            }
        }
        if (force_overwrite && unlink_file (to) && !existence_error (errno))
            error (1, errno, "unable to remove %s", to);

        if ((fdout = creat (to, (int) sb.st_mode & 07777)) < 0)
            error (1, errno, "cannot create %s for copying", to);

        zstatus = inflateInit2 (&zstr, 47);
        if(zstatus != Z_OK)
            error(1, 0, "expansion error (INIT): (%d)%s", zstatus,zstr.msg);

        if (sb.st_size > 0)
        {
            for (;;)
            {
                n = read (fdin, buf, sizeof(buf));
                if (n == -1)
                {
#ifdef EINTR
                    if (errno == EINTR)
                        continue;
#endif
                    error (1, errno, "cannot read file %s for copying", fn_root(from));
                }
                else if (n == 0)
                    break;

                zstr.next_in = (Bytef*)buf;
                zstr.avail_in = n;
                while(zstr.avail_in)
                {
                    zstr.next_out = (Bytef*)zbuf;
                    zstr.avail_out = sizeof(zbuf);
                    zstatus = inflate (&zstr, 0);
                    if(zstatus != Z_OK && zstatus != Z_STREAM_END)
                        error(1,0, "expansion error (inflate): (%d)%s", zstatus,zstr.msg);

                    n = sizeof(zbuf)-zstr.avail_out;
                    if (n && write(fdout, zbuf, n) != n) {
                        error (1, errno, "cannot write file %s for copying", to);
                    }
                }
                if(zstatus == Z_STREAM_END)
                    break;
            }

#ifdef HAVE_FSYNC
            if (fsync (fdout))
                error (1, errno, "cannot fsync file %s after copying", fn_root(to));
#endif

        }

        zstr.next_out = (Bytef*)zbuf;
        zstr.avail_out = sizeof(zbuf);
        zstatus = inflate (&zstr, Z_FINISH);
        if(zstatus != Z_OK && zstatus != Z_STREAM_END)
            error(1,0, "expansion error (Z_FINISH): (%d)%s", zstatus,zstr.msg);
        n = sizeof(zbuf)-zstr.avail_out;
        if (n && write(fdout, zbuf, n) != n) {
            error (1, errno, "cannot write file %s for copying", fn_root(to));
        }

        zstr.next_in = (Bytef*)buf;
        zstr.avail_in = 0;
        zstr.next_out = (Bytef*)zbuf;
        zstr.avail_out = sizeof(zbuf);
        zstatus = inflateEnd(&zstr);
        if(zstatus != Z_OK)
            error(1,0, "expansion error: %s", zstr.msg);

        if (close (fdin) < 0)
            error (0, errno, "cannot close %s", fn_root(from));
        if (close (fdout) < 0)
            error (1, errno, "cannot close %s", fn_root(to));
    }

#ifdef UTIME_EXPECTS_WRITABLE
    if (!iswritable (to))
    {
        xchmod (to, 1);
        change_it_back = 1;
    }
#endif  /* UTIME_EXPECTS_WRITABLE  */
    /* now, set the times for the copied file to match those of the original */
    memset ((char *) &t, 0, sizeof (t));
    t.actime = sb.st_atime;
    t.modtime = sb.st_mtime;
    (void) utime (to, &t);
#ifdef UTIME_EXPECTS_WRITABLE
    if (change_it_back)
        xchmod (to, 0);
#endif  /*  UTIME_EXPECTS_WRITABLE  */
    return 0;
}
Beispiel #12
0
/* Diff revisions and/or files.  OPTS controls the format of the diff
   (it contains options such as "-w -c", &c), or "" for the default.
   OPTIONS controls keyword expansion, as a string starting with "-k",
   or "" to use the default.  REV1 is the first revision to compare
   against; it must be non-NULL.  If REV2 is non-NULL, compare REV1
   and REV2; if REV2 is NULL compare REV1 with the file in the working
   directory, whose name is WORKFILE.  LABEL1 and LABEL2 are default
   file labels, and (if non-NULL) should be added as -L options
   to diff.  Output goes to stdout.

   Return value is 0 for success, -1 for a failure which set errno,
   or positive for a failure which printed a message on stderr.

   This used to exec rcsdiff, but now calls RCS_checkout and diff_exec.

   An issue is what timezone is used for the dates which appear in the
   diff output.  rcsdiff uses the -z flag, which is not presently
   processed by CVS diff, but I'm not sure exactly how hard to worry
   about this--any such features are undocumented in the context of
   CVS, and I'm not sure how important to users.  */
int
RCS_exec_rcsdiff (RCSNode *rcsfile, int diff_argc,
		  char * const *diff_argv, const char *options,
                  const char *rev1, const char *rev1_cache, const char *rev2,
                  const char *label1, const char *label2, const char *workfile)
{
    char *tmpfile1 = NULL;
    char *tmpfile2 = NULL;
    const char *use_file1, *use_file2;
    int status, retval;


    cvs_output ("\
===================================================================\n\
RCS file: ", 0);
    cvs_output (rcsfile->print_path, 0);
    cvs_output ("\n", 1);

    /* Historically, `cvs diff' has expanded the $Name keyword to the
       empty string when checking out revisions.  This is an accident,
       but no one has considered the issue thoroughly enough to determine
       what the best behavior is.  Passing NULL for the `nametag' argument
       preserves the existing behavior. */

    cvs_output ("retrieving revision ", 0);
    cvs_output (rev1, 0);
    cvs_output ("\n", 1);

    if (rev1_cache != NULL)
	use_file1 = rev1_cache;
    else
    {
	tmpfile1 = cvs_temp_name();
	status = RCS_checkout (rcsfile, NULL, rev1, NULL, options, tmpfile1,
	                       NULL, NULL);
	if (status > 0)
	{
	    retval = status;
	    goto error_return;
	}
	else if (status < 0)
	{
	    error( 0, errno,
	           "cannot check out revision %s of %s", rev1, rcsfile->path );
	    retval = 1;
	    goto error_return;
	}
	use_file1 = tmpfile1;
    }

    if (rev2 == NULL)
    {
	assert (workfile != NULL);
	use_file2 = workfile;
    }
    else
    {
	tmpfile2 = cvs_temp_name ();
	cvs_output ("retrieving revision ", 0);
	cvs_output (rev2, 0);
	cvs_output ("\n", 1);
	status = RCS_checkout (rcsfile, NULL, rev2, NULL, options,
			       tmpfile2, NULL, NULL);
	if (status > 0)
	{
	    retval = status;
	    goto error_return;
	}
	else if (status < 0)
	{
	    error (0, errno,
		   "cannot check out revision %s of %s", rev2, rcsfile->path);
	    return 1;
	}
	use_file2 = tmpfile2;
    }

    RCS_output_diff_options (diff_argc, diff_argv, rev1, rev2, workfile);
    status = diff_exec (use_file1, use_file2, label1, label2,
			diff_argc, diff_argv, RUN_TTY);
    if (status >= 0)
    {
	retval = status;
	goto error_return;
    }
    else if (status < 0)
    {
	error (0, errno,
	       "cannot diff %s and %s", use_file1, use_file2);
	retval = 1;
	goto error_return;
    }

 error_return:
    {
	/* Call CVS_UNLINK() below rather than unlink_file to avoid the check
	 * for noexec.
	 */
	if( tmpfile1 != NULL )
	{
	    if( CVS_UNLINK( tmpfile1 ) < 0 )
	    {
		if( !existence_error( errno ) )
		    error( 0, errno, "cannot remove temp file %s", tmpfile1 );
	    }
	    free( tmpfile1 );
	}
	if( tmpfile2 != NULL )
	{
	    if( CVS_UNLINK( tmpfile2 ) < 0 )
	    {
		if( !existence_error( errno ) )
		    error( 0, errno, "cannot remove temp file %s", tmpfile2 );
	    }
	    free (tmpfile2);
	}
    }

    return retval;
}
Beispiel #13
0
int
RCS_merge (RCSNode *rcs, const char *path, const char *workfile,
           const char *options, const char *rev1, const char *rev2)
{
    char *xrev1, *xrev2;
    char *tmp1, *tmp2;
    char *diffout = NULL;
    int retval;

    if (options != NULL && options[0] != '\0')
      assert (options[0] == '-' && options[1] == 'k');

    cvs_output ("RCS file: ", 0);
    cvs_output (rcs->print_path, 0);
    cvs_output ("\n", 1);

    /* Calculate numeric revision numbers from rev1 and rev2 (may be
       symbolic).
       FIXME - No they can't.  Both calls to RCS_merge are passing in
       numeric revisions.  */
    xrev1 = RCS_gettag (rcs, rev1, 0, NULL);
    xrev2 = RCS_gettag (rcs, rev2, 0, NULL);
    assert (xrev1 && xrev2);

    /* Check out chosen revisions.  The error message when RCS_checkout
       fails is not very informative -- it is taken verbatim from RCS 5.7,
       and relies on RCS_checkout saying something intelligent upon failure. */
    cvs_output ("retrieving revision ", 0);
    cvs_output (xrev1, 0);
    cvs_output ("\n", 1);

    tmp1 = cvs_temp_name();
    if (RCS_checkout (rcs, NULL, xrev1, rev1, options, tmp1, NULL, NULL))
    {
	cvs_outerr ("rcsmerge: co failed\n", 0);
	exit (EXIT_FAILURE);
    }

    cvs_output ("retrieving revision ", 0);
    cvs_output (xrev2, 0);
    cvs_output ("\n", 1);

    tmp2 = cvs_temp_name();
    if (RCS_checkout (rcs, NULL, xrev2, rev2, options, tmp2, NULL, NULL))
    {
	cvs_outerr ("rcsmerge: co failed\n", 0);
	exit (EXIT_FAILURE);
    }

    /* Merge changes. */
    cvs_output ("Merging differences between ", 0);
    cvs_output (xrev1, 0);
    cvs_output (" and ", 0);
    cvs_output (xrev2, 0);
    cvs_output (" into ", 0);
    cvs_output (workfile, 0);
    cvs_output ("\n", 1);

    /* Remember that the first word in the `call_diff_setup' string is used now
       only for diagnostic messages -- CVS no longer forks to run diff3. */
    diffout = cvs_temp_name();
    call_diff_setup ("diff3", 0, NULL);
    call_diff_add_arg ("-E");
    call_diff_add_arg ("-am");

    call_diff_add_arg ("-L");
    call_diff_add_arg (workfile);
    call_diff_add_arg ("-L");
    call_diff_add_arg (xrev1);
    call_diff_add_arg ("-L");
    call_diff_add_arg (xrev2);

    call_diff_add_arg ("--");
    call_diff_add_arg (workfile);
    call_diff_add_arg (tmp1);
    call_diff_add_arg (tmp2);

    retval = call_diff3 (diffout);

    if (retval == 1)
	cvs_outerr ("rcsmerge: warning: conflicts during merge\n", 0);
    else if (retval == 2)
	exit (EXIT_FAILURE);

    if (diffout)
	copy_file (diffout, workfile);

    /* Clean up. */
    {
	int save_noexec = noexec;
	noexec = 0;
	if (unlink_file (tmp1) < 0)
	{
	    if (!existence_error (errno))
		error (0, errno, "cannot remove temp file %s", tmp1);
	}
	free (tmp1);
	if (unlink_file (tmp2) < 0)
	{
	    if (!existence_error (errno))
		error (0, errno, "cannot remove temp file %s", tmp2);
	}
	free (tmp2);
	if (diffout)
	{
	    if (unlink_file (diffout) < 0)
	    {
		if (!existence_error (errno))
		    error (0, errno, "cannot remove temp file %s", diffout);
	    }
	    free (diffout);
	}
	free (xrev1);
	free (xrev2);
	noexec = save_noexec;
    }

    return retval;
}
Beispiel #14
0
/* 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);
}
Beispiel #15
0
/*
 * Copies "from" to "to", decompressing "from" on the fly
 */
int copy_and_unzip_file (const char *from, const char *to, int force_overwrite, int must_exist)
{
    struct stat sb;
    struct utimbuf t;
    int fdin, fdout;
    z_stream zstr = {0};
    int zstatus;
    char buf[BUFSIZ*10];
    char zbuf[BUFSIZ*20];
    int n;
#ifdef UTIME_EXPECTS_WRITABLE
    int change_it_back = 0;
#endif

	TRACE(1,"copy_and_unzip(%s,%s)",from,to);
    if (noexec)
		return 0;

    if ((fdin = open (from, O_RDONLY | O_BINARY,0)) < 0)
	{
		if(must_exist)
			error (1, errno, "cannot open %s for copying", from);
		else
			return -1;
	}
	if (fstat (fdin, &sb) < 0)
	{
		if(must_exist)
			error (1, errno, "cannot fstat %s", from);
		else
		{
			close(fdin);
			return -1;
		}
	}
	if (force_overwrite && unlink_file (to) && !existence_error (errno))
	    error (1, errno, "unable to remove %s", to);

    if ((fdout = open (to, O_CREAT | O_TRUNC | O_RDWR | O_BINARY, 0600))<0)
	    error (1, errno, "cannot create %s for copying", to);

	zstatus = inflateInit2 (&zstr, 47);
	if(zstatus != Z_OK)
	   error(1, 0, "expansion error (INIT): (%d)%s", zstatus,zstr.msg);
     
	if (sb.st_size > 0)
	{
	    for (;;) 
	    {
		n = read (fdin, buf, sizeof(buf));
		if (n == -1)
		{
#ifdef EINTR
		    if (errno == EINTR)
			continue;
#endif
		    error (1, errno, "cannot read file %s for copying", from);
		}
		else if (n == 0) 
		    break;

		zstr.next_in = buf;
		zstr.avail_in = n;	
		while(zstr.avail_in)
		{
			zstr.next_out = zbuf;
			zstr.avail_out = sizeof(zbuf);
			zstatus = inflate (&zstr, 0);
			if(zstatus != Z_OK && zstatus != Z_STREAM_END)	
			error(1,0, "expansion error (inflate): (%d)%s", zstatus,zstr.msg);
			
			n = sizeof(zbuf)-zstr.avail_out;	
			if (n && write(fdout, zbuf, n) != n) {
				error (1, errno, "cannot write file %s for copying", to);
			}
		}
		if(zstatus == Z_STREAM_END)
			break;
		}

#ifdef HAVE_FSYNC
	    if (fsync (fdout)) 
		error (1, errno, "cannot fsync file %s after copying", to);
#endif
	
	}

	zstr.next_out = zbuf;
	zstr.avail_out = sizeof(zbuf);
	zstatus = inflate (&zstr, Z_FINISH);
	if(zstatus != Z_OK && zstatus != Z_STREAM_END)	
	      error(1,0, "expansion error (Z_FINISH): (%d)%s", zstatus,zstr.msg);
	n = sizeof(zbuf)-zstr.avail_out;	
	if (n && write(fdout, zbuf, n) != n) {
	   error (1, errno, "cannot write file %s for copying", to);
	}
	
	zstr.next_in = buf;
	zstr.avail_in = 0;
	zstr.next_out = zbuf;
	zstr.avail_out = sizeof(zbuf);
	zstatus = inflateEnd(&zstr);
	if(zstatus != Z_OK)
	  error(1,0, "expansion error: %s", zstr.msg);

	if (close (fdin) < 0) 
	    error (0, errno, "cannot close %s", from);
	if (close (fdout) < 0)
	    error (1, errno, "cannot close %s", to);

#ifdef UTIME_EXPECTS_WRITABLE
	if (!iswritable (to))
	{
		xchmod (to, 1);
		change_it_back = 1;
	}
#endif  /* UTIME_EXPECTS_WRITABLE  */
    /* now, set the times for the copied file to match those of the original */
    memset ((char *) &t, 0, sizeof (t));
    t.actime = sb.st_atime;
    t.modtime = sb.st_mtime;
    utime (to, &t);
	chmod(to,sb.st_mode);
#ifdef UTIME_EXPECTS_WRITABLE
	if (change_it_back)
		xchmod (to, 0);
#endif  /*  UTIME_EXPECTS_WRITABLE  */
	return 0;
}
Beispiel #16
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);
}
Beispiel #17
0
/*ARGSUSED*/
static int remove_force_fileproc (void *callerdat, struct file_info *finfo)
{
    if (CVS_UNLINK (finfo->file) < 0 && ! existence_error (errno))
	error (0, errno, "unable to remove %s", fn_root(finfo->fullname));
    return 0;
}
Beispiel #18
0
/*
 * Copies "from" to "to".
 */
int copy_file (const char *from, const char *to, int force_overwrite, int must_exist)
{
    struct stat sb;
    struct utimbuf t;
    int fdin, fdout;
#ifdef UTIME_EXPECTS_WRITABLE
    int change_it_back = 0;
#endif

    TRACE(1,"copy(%s,%s)",PATCH_NULL(from),PATCH_NULL(to));
    if (noexec)
        return 0;

    /* If the file to be copied is a link or a device, then just create
       the new link or device appropriately. */
    if (islink (from))
    {
        char *source = xreadlink (from);
        symlink (source, to);
        xfree (source);
        return 0;
    }

    if (isdevice (from))
    {
#if defined(HAVE_MKNOD) && defined(HAVE_STRUCT_STAT_ST_RDEV)
        if (stat (from, &sb) < 0)
            error (1, errno, "cannot stat %s", fn_root(from));
        mknod (to, sb.st_mode, sb.st_rdev);
#else
        error (1, 0, "cannot copy device files on this system (%s)", fn_root(from));
#endif
    }
    else
    {
#ifdef MAC_HFS_STUFF
        /* Only use the mac specific copying routine in the client, since
           the server shouldn't have any need to handle resource forks
           (all the resource fork handling is done in the client -
            the server only handles flat files) */
        if ( !server_active ) {
            if (stat (from, &sb) < 0)
            {
                if(must_exist)
                    error (1, errno, "cannot stat %s", fn_root(from));
                else
                    return -1;
            }
            mac_copy_file(from, to, force_overwrite, must_exist);
        } else {
#endif
            /* Not a link or a device... probably a regular file. */
            if ((fdin = CVS_OPEN (from, O_RDONLY)) < 0)
            {
                if(must_exist)
                    error (1, errno, "cannot open %s for copying", fn_root(from));
                else
                    return -1;
            }
            if (fstat (fdin, &sb) < 0)
            {
                if(must_exist)
                    error (1, errno, "cannot fstat %s", fn_root(from));
                else
                {
                    close(fdin);
                    return -1;
                }
            }
            if (force_overwrite && unlink_file (to) && !existence_error (errno))
                error (1, errno, "unable to remove %s", to);

            if ((fdout = creat (to, (int) sb.st_mode & 07777)) < 0)
                error (1, errno, "cannot create %s for copying", fn_root(to));
            if (sb.st_size > 0)
            {
                char buf[BUFSIZ];
                int n;

                for (;;)
                {
                    n = read (fdin, buf, sizeof(buf));
                    if (n == -1)
                    {
#ifdef EINTR
                        if (errno == EINTR)
                            continue;
#endif
                        error (1, errno, "cannot read file %s for copying", fn_root(from));
                    }
                    else if (n == 0)
                        break;

                    if (write(fdout, buf, n) != n) {
                        error (1, errno, "cannot write file %s for copying", fn_root(to));
                    }
                }

#ifdef HAVE_FSYNC
                if (fsync (fdout))
                    error (1, errno, "cannot fsync file %s after copying", fn_root(to));
#endif
            }

            if (close (fdin) < 0)
                error (0, errno, "cannot close %s", fn_root(from));
            if (close (fdout) < 0)
                error (1, errno, "cannot close %s", fn_root(to));
#ifdef MAC_HFS_STUFF
        }
#endif
    }


#ifdef UTIME_EXPECTS_WRITABLE
    if (!iswritable (to))
    {
        xchmod (to, 1);
        change_it_back = 1;
    }
#endif  /* UTIME_EXPECTS_WRITABLE  */
    /* now, set the times for the copied file to match those of the original */
    memset ((char *) &t, 0, sizeof (t));
    t.actime = sb.st_atime;
    t.modtime = sb.st_mtime;
    (void) utime (to, &t);
#ifdef UTIME_EXPECTS_WRITABLE
    if (change_it_back)
        xchmod (to, 0);
#endif  /*  UTIME_EXPECTS_WRITABLE  */
    return 0;
}
Beispiel #19
0
char *Name_Repository (const char *dir, const char *update_dir)
{
    FILE *fpin;
    const char *xupdate_dir;
    char *repos = NULL;
    size_t repos_allocated = 0;
    char *tmp=NULL;
    char *cp;

    TRACE(3,"Name_Repository(%s,%s)",PATCH_NULL(dir),PATCH_NULL(update_dir));
    if (update_dir && *update_dir)
		xupdate_dir = update_dir;
    else
		xupdate_dir = ".";

    if (dir != NULL)
    {
		size_t tmpsz=strlen (dir) + sizeof (CVSADM_REP) + 10;
		tmp = (char*)xmalloc (tmpsz+sizeof(CVSADM_VIRTREPOS));
		sprintf (tmp, "%s/%s", dir, CVSADM_VIRTREPOS);
		size_t tmplen1 = strlen(tmp);
		if(!isfile(tmp))
			sprintf(tmp, "%s/%s", dir, CVSADM_REP);
		size_t tmplen2 = strlen(tmp);
	    TRACE(3,"Name_Repository allocate tmp of size %d, len1=%d, len2=%d",(int)tmpsz,(int)tmplen1,(int)tmplen2);
    }
    else
	{
		tmp = xstrdup (CVSADM_VIRTREPOS);
	    TRACE(3,"Name_Repository dup tmp is len",(int)strlen(tmp));
		if(!isfile(tmp))
		{
			xfree(tmp);
			tmp=NULL;
			tmp=xstrdup(CVSADM_REP);
		    TRACE(3,"Name_Repository dup tmp is now len",(int)strlen(tmp));
		}
	}
    /*
     * The assumption here is that the repository is always contained in the
     * first line of the "Repository" file.
     */
    TRACE(3,"Name_Repository open %s",tmp);
    fpin = CVS_FOPEN (tmp, "r");

    if (fpin == NULL)
    {
	int save_errno = errno;
	char *cvsadm=NULL;

	if (dir != NULL)
	{
	    cvsadm = (char*)xmalloc (strlen (dir) + sizeof (CVSADM) + 100);
	    (void) sprintf (cvsadm, "%s/%s", dir, CVSADM);
	}
	else
	    cvsadm = xstrdup (CVSADM);
    TRACE(3,"Name_Repository failed to open %s so try %s",tmp,cvsadm);
	if (!isdir (cvsadm))
	{
	    error (0, 0, "in directory %s:", xupdate_dir);
	    error (1, 0, "there is no version here; do '%s checkout' first",
		   program_name);
	}
	xfree (cvsadm);
	cvsadm=NULL;

	if (existence_error (save_errno))
	{
	    /* FIXME: This is a very poorly worded error message.  It
	       occurs at least in the case where the user manually
	       creates a directory named CVS, so the error message
	       should be more along the lines of "CVS directory found
	       without administrative files; use CVS to create the CVS
	       directory, or rename it to something else if the
	       intention is to store something besides CVS
	       administrative files".  */
	    error (0, 0, "in directory %s:", xupdate_dir);
	    error (1, 0, "CVS directory without administration files present.  Cannot continue until this directory is deleted or renamed.");
	}

	error (1, save_errno, "cannot open %s", tmp);
    }

    TRACE(3,"Name_Repository opened %s ok so read a line",tmp);
    if (getline (&repos, &repos_allocated, fpin) < 0)
    {
	/* FIXME: should be checking for end of file separately.  */
	error (0, 0, "in directory %s:", xupdate_dir);
	error (1, errno, "cannot read %s", tmp);
    }
    if (fclose (fpin) < 0)
	error (0, errno, "cannot close %s", tmp);
    TRACE(3,"Name_Repository closed %s",tmp);
    xfree (tmp);
	tmp=NULL;

    TRACE(3,"Name_Repository read 1 %s",repos);
    if ((cp = strrchr (repos, '\n')) != NULL)
	*cp = '\0';			/* strip the newline */
    TRACE(3,"Name_Repository read 2 %s",repos);

    /*
     * If this is a relative repository pathname, turn it into an absolute
     * one by tacking on the CVSROOT environment variable. If the CVSROOT
     * environment variable is not set, die now.
     */
    TRACE(3,"Name_Repository isabsolute( %s )?",repos);
	char *newrepos=NULL;
    if (! isabsolute(repos))
    {

    TRACE(3,"Name_Repository isabsolute( %s )!",repos);
	if (current_parsed_root == NULL)
	{
	    error (0, 0, "in directory %s:", xupdate_dir);
	    error (0, 0, "must set the CVSROOT environment variable\n");
	    error (0, 0, "or specify the '-d' option to %s.", program_name);
	    error (1, 0, "illegal repository setting");
	}
	if (pathname_levels (repos) > 0)
	{
	    error (0, 0, "in directory %s:", xupdate_dir);
	    error (0, 0, "`..'-relative repositories are not supported.");
	    error (1, 0, "illegal source repository");
	}
	newrepos = (char*)xmalloc (strlen (current_parsed_root->directory) + strlen (repos) + 2);
	(void) sprintf (newrepos, "%s/%s", current_parsed_root->directory, repos);
#ifndef HAVE_GETLINE
	xfree (repos);
#else
	free(repos);
#endif
	repos = newrepos;
    }
	else
	{
    TRACE(3,"Name_Repository not isabsolute( %s )",repos);
	newrepos = (char*)xmalloc (strlen (repos) + 2);
	(void) sprintf (newrepos, "%s", repos);
#ifndef HAVE_GETLINE
	xfree (repos);
#else
	free(repos);
#endif
	repos = newrepos;
	}

    TRACE(3,"Name_Repository Sanitize_Repository_Name( %s )!",repos);
	Sanitize_Repository_Name (&repos);

    TRACE(3,"Name_Repository return ( %s )!",repos);
    return repos;
}
Beispiel #20
0
static foreign_t
cgi_property(term_t cgi, term_t prop)
{ IOSTREAM *s;
  cgi_context *ctx;
  term_t arg = PL_new_term_ref();
  atom_t name;
  int arity;
  int rc = TRUE;

  if ( !get_cgi_stream(cgi, &s, &ctx) )
    return FALSE;

  if ( !PL_get_name_arity(prop, &name, &arity) || arity != 1 )
  { rc = type_error(prop, "cgi_property");
    goto out;
  }

  _PL_get_arg(1, prop, arg);
  if ( name == ATOM_request )
  { if ( ctx->request )
      rc = unify_record(arg, ctx->request);
    else
      rc = PL_unify_nil(arg);
  } else if ( name == ATOM_header )
  { if ( ctx->header )
      rc = unify_record(arg, ctx->header);
     else
      rc = PL_unify_nil(arg);
  } else if ( name == ATOM_id )
  { rc = PL_unify_int64(arg, ctx->id);
  } else if ( name == ATOM_client )
  { rc = PL_unify_stream(arg, ctx->stream);
  } else if ( name == ATOM_transfer_encoding )
  { rc = PL_unify_atom(arg, ctx->transfer_encoding);
  } else if ( name == ATOM_connection )
  { rc = PL_unify_atom(arg, ctx->connection ? ctx->connection : ATOM_close);
  } else if ( name == ATOM_content_length )
  { if ( ctx->transfer_encoding == ATOM_chunked )
      rc = PL_unify_int64(arg, ctx->chunked_written);
    else
      rc = PL_unify_int64(arg, ctx->datasize - ctx->data_offset);
  } else if ( name == ATOM_header_codes )
  { if ( ctx->data_offset > 0 )
      rc = PL_unify_chars(arg, PL_CODE_LIST, ctx->data_offset, ctx->data);
    else					/* incomplete header */
      rc = PL_unify_chars(arg, PL_CODE_LIST, ctx->datasize, ctx->data);
  } else if ( name == ATOM_state )
  { atom_t state;

    switch(ctx->state)
    { case CGI_HDR:       state = ATOM_header; break;
      case CGI_DATA:      state = ATOM_data; break;
      case CGI_DISCARDED: state = ATOM_discarded; break;
      default:
	assert(0);
    }

    rc = PL_unify_atom(arg, state);
  } else
  { rc = existence_error(prop, "cgi_property");
  }

out:
  if ( !PL_release_stream(s) )
  { if ( PL_exception(0) )
      PL_clear_exception();
  }

  return rc;
}
Beispiel #21
0
/* Copies "from" to "to".  Note that the functionality here is similar
   to the win32 function CopyFile, but (1) we copy LastAccessTime and
   CopyFile doesn't, (2) we set file attributes to the default set by
   the C library and CopyFile copies them.  Neither #1 nor #2 was intentional
   as far as I know, but changing them could be confusing, unless there
   is some reason they should be changed (this would need more
   investigation).  */
int copy_file (const char *from, const char *to, int force_overwrite, int must_exist)
{
    struct stat sb;
    struct utimbuf t;
    int fdin, fdout;
#ifdef UTIME_EXPECTS_WRITABLE
    int change_it_back = 0;
#endif

	TRACE(1,"copy(%s,%s)",from,to);
    if (noexec)
		return 0;

    if ((fdin = open (from, O_RDONLY | O_BINARY,0)) < 0)
	{
		if(must_exist)
			error (1, errno, "cannot open %s for copying", from);
		else
			return -1;
	}
    if (fstat (fdin, &sb) < 0)
	{
		if(must_exist)
			error (1, errno, "cannot fstat %s", from);
		else
		{
			close(fdin);
			return -1;
		}
	}
	if (force_overwrite && unlink_file (to) && !existence_error (errno))
	    error (1, errno, "unable to remove %s", to);
		
    if ((fdout = open (to, O_CREAT | O_TRUNC | O_RDWR | O_BINARY, 0600)) < 0)
		error (1, errno, "cannot create %s for copying", to);
    if (sb.st_size > 0)
    {
	char buf[BUFSIZ];
	int n;

	for (;;) 
	{
	    n = read (fdin, buf, sizeof(buf));
	    if (n == -1)
	    {
#ifdef EINTR
		if (errno == EINTR)
		    continue;
#endif
		error (1, errno, "cannot read file %s for copying", from);
	    }
            else if (n == 0) 
		break;
  
	    if (write(fdout, buf, n) != n) {
		error (1, errno, "cannot write file %s for copying", to);
	    }
	}

#ifdef HAVE_FSYNC
	if (fsync (fdout)) 
	    error (1, errno, "cannot fsync file %s after copying", to);
#endif
    }

    if (close (fdin) < 0) 
	error (0, errno, "cannot close %s", from);
    if (close (fdout) < 0)
	error (1, errno, "cannot close %s", to);

#ifdef UTIME_EXPECTS_WRITABLE
	if (!iswritable (to))
	{
		xchmod (to, 1);
		change_it_back = 1;
	}
#endif  /* UTIME_EXPECTS_WRITABLE  */
    /* now, set the times for the copied file to match those of the original */
    memset ((char *) &t, 0, sizeof (t));
    t.actime = sb.st_atime;
    t.modtime = sb.st_mtime;
    utime (to, &t);
	chmod(to,sb.st_mode);
#ifdef UTIME_EXPECTS_WRITABLE
	if (change_it_back)
		xchmod (to, 0);
#endif  /*  UTIME_EXPECTS_WRITABLE  */
	return 0;
}
Beispiel #22
0
/*
 * Builds a temporary file using setup_tmpfile() and invokes the user's
 * editor on the file.  The header garbage in the resultant file is then
 * stripped and the log message is stored in the "message" argument.
 * 
 * If REPOSITORY is non-NULL, process rcsinfo for that repository; if it
 * is NULL, use the CVSADM_TEMPLATE file instead.
 */
void do_editor (const char *dir, char **messagep, const char *repository, List *changes)
{
    static int reuse_log_message = 0;
    char *line;
    int line_length;
    size_t line_chars_allocated;
    char *fname;
    struct stat pre_stbuf, post_stbuf;
    int retcode = 0;

    if (noexec || reuse_log_message)
		return;

    /* Abort creation of temp file if no editor is defined */
    if (strcmp (Editor, "") == 0)
		error(1, 0, "no editor defined, must use -e or -m");

	/* Create a temporary file */
	/* FIXME - It's possible we should be relying on cvs_temp_file to open
	* the file here - we get race conditions otherwise.
	*/
	fname = cvs_temp_name ();
again:
	if ((fp = CVS_FOPEN (fname, "w+")) == NULL)
		error (1, 0, "cannot create temporary file %s", fname);

	if (*messagep)
	{
		fprintf (fp, "%s", *messagep);

		if ((*messagep)[0] == '\0' ||
			(*messagep)[strlen (*messagep) - 1] != '\n')
			fprintf (fp, "\n");
	}

    if (repository != NULL)
	{
		rcsinfo_param_t args;
		args.directory = Short_Repository(repository);
		args.message=NULL;
		/* tack templates on if necessary */
		TRACE(3,"run rcsinfo trigger");
		if(!run_trigger(&args,rcsinfo_proc) && args.message)
		{
			fprintf(fp,"%s",args.message);
			if (args.message[0] == '\0' || args.message[strlen(args.message) - 1] != '\n')
				fprintf (fp, "\n");
		}
	}
    else
    {
		FILE *tfp;
		char buf[1024];
		size_t n;
		size_t nwrite;

		/* Why "b"?  */
		tfp = CVS_FOPEN (CVSADM_TEMPLATE, "rb");
		if (tfp == NULL)
		{
			if (!existence_error (errno))
			error (1, errno, "cannot read %s", CVSADM_TEMPLATE);
		}
		else
		{
			while (!feof (tfp))
			{
				char *p = buf;
				n = fread (buf, 1, sizeof buf, tfp);
				nwrite = n;
				while (nwrite > 0)
				{
					n = fwrite (p, 1, nwrite, fp);
					nwrite -= n;
					p += n;
				}
				if (ferror (tfp))
					error (1, errno, "cannot read %s", CVSADM_TEMPLATE);
			}
			if (fclose (tfp) < 0)
				error (0, errno, "cannot close %s", CVSADM_TEMPLATE);
		}
	}

	fprintf (fp,"%s----------------------------------------------------------------------\n",CVSEDITPREFIX);
#ifdef _WIN32
#if (CVSNT_SPECIAL_BUILD_FLAG != 0)
	if (strcasecmp(CVSNT_SPECIAL_BUILD,"Suite")!=0)
#endif
	{
	fprintf (fp,"%s     Committed on the Free edition of March Hare Software CVSNT Server\n",CVSEDITPREFIX);
	fprintf (fp,"%s     Upgrade to CVS Suite for more features and support:\n",CVSEDITPREFIX);
	fprintf (fp,"%s           http://march-hare.com/cvsnt/\n",CVSEDITPREFIX);
	fprintf (fp,"%s----------------------------------------------------------------------\n",CVSEDITPREFIX);
    }
#endif
	fprintf (fp,"%sEnter Log.  Lines beginning with `%.*s' are removed automatically\n%s\n",
				CVSEDITPREFIX, CVSEDITPREFIXLEN, CVSEDITPREFIX,CVSEDITPREFIX);
	if (dir != NULL && *dir)
		fprintf (fp, "%sCommitting in %s\n%s\n", CVSEDITPREFIX,	dir, CVSEDITPREFIX);
	if (changes != NULL)
		setup_tmpfile (fp, CVSEDITPREFIX, changes);
	fprintf (fp,"%s----------------------------------------------------------------------\n",
				CVSEDITPREFIX);

	/* finish off the temp file */
	if (fclose (fp) == EOF)
		error (1, errno, "%s", fname);
	if ( CVS_STAT (fname, &pre_stbuf) == -1)
		pre_stbuf.st_mtime = 0;

	/* run the editor */
	run_setup (Editor);
	run_arg (fname);
	if ((retcode = run_exec (true)) != 0)
		error (0, retcode == -1 ? errno : 0, "warning: editor session failed");

	/* put the entire message back into the *messagep variable */
	fp = open_file (fname, "r");

	if (*messagep)
		xfree (*messagep);

	if ( CVS_STAT (fname, &post_stbuf) != 0)
		error (1, errno, "cannot find size of temp file %s", fname);

	if (post_stbuf.st_size == 0)
		*messagep = NULL;
	else
	{
		/* On NT, we might read less than st_size bytes, but we won't
		read more.  So this works.  */
		*messagep = (char *) xmalloc (post_stbuf.st_size + 1);
 		*messagep[0] = '\0';
	}

	line = NULL;
	line_chars_allocated = 0;

	if (*messagep)
	{
		size_t message_len = post_stbuf.st_size + 1;
		size_t offset = 0;
		while (1)
		{
			line_length = getline (&line, &line_chars_allocated, fp);
			if (line_length == -1)
			{
				if (ferror (fp))
					error (0, errno, "warning: cannot read %s", fname);
				break;
			}
			if (strncmp (line, CVSEDITPREFIX, CVSEDITPREFIXLEN) == 0)
				continue;
			if (offset + line_length >= message_len)
			expand_string (messagep, &message_len, offset + line_length + 1);
			strcpy (*messagep + offset, line);
			offset += line_length;
		}
	}
	
	if (fclose (fp) < 0)
		error (0, errno, "warning: cannot close %s", fname);

	if (pre_stbuf.st_mtime == post_stbuf.st_mtime || *messagep == NULL || strcmp (*messagep, "\n") == 0)
	{
		for (;;)
		{
			printf ("\nLog message unchanged or not specified\n");
			printf ("a)bort, c)ontinue, e)dit, !)reuse this message unchanged for remaining dirs\n");
			printf ("Action: (continue) ");
			fflush (stderr);
			fflush (stdout);
			line_length = getline (&line, &line_chars_allocated, stdin);
			if (line_length < 0)
			{
				error (0, errno, "cannot read from stdin");
				if (unlink_file (fname) < 0)
					error (0, errno, "warning: cannot remove temp file %s", fname);
				error (1, 0, "aborting");
			}
			else if (line_length == 0 || *line == '\n' || *line == 'c' || *line == 'C')
				break;
			if (*line == 'a' || *line == 'A')
			{
				if (unlink_file (fname) < 0)
					error (0, errno, "warning: cannot remove temp file %s", fname);
				error (1, 0, "aborted by user");
			}
			if (*line == 'e' || *line == 'E')
				goto again;
			if (*line == '!')
			{
				reuse_log_message = 1;
				break;
			}
			printf ("Unknown input\n");
		}
    }
    if (line)
		xfree (line);
    if (unlink_file (fname) < 0)
		error (0, errno, "warning: cannot remove temp file %s", fname);
    xfree (fname);
}