Exemplo n.º 1
0
/*
 * Yeah, I know, there are NFS race conditions here.
 */
static char *
make_tempfile ()
{
    static int seed = 0;
    int fd;
    char *temp;

    if (seed == 0)
	seed = (int)getpid ();
    temp = (char*)xmalloc (sizeof (BAKPREFIX) + 40);
    while (1)
    {
	(void) sprintf (temp, "%s%d", BAKPREFIX, seed++);
	if ((fd = CVS_OPEN (temp, O_BINARY|O_CREAT|O_EXCL|O_RDWR, 0666)) != -1)
	    break;
	if (errno != EEXIST)
	    error (1, errno, "cannot create temporary file %s", temp);
    }
    if (close(fd) < 0)
	error(1, errno, "cannot close temporary file %s", temp);
    return temp;
}
Exemplo n.º 2
0
/* An empty LogHistory string in CVSROOT/config will turn logging off.
 */
void
history_write (int type, const char *update_dir, const char *revs,
               const char *name, const char *repository)
{
    const char *fname;
    char *workdir;
    char *username = getcaller ();
    int fd;
    char *line;
    char *slash = "", *cp;
    const char *cp2, *repos;
    int i;
    static char *tilde = "";
    static char *PrCurDir = NULL;
    time_t now;

    if (logoff)			/* History is turned off by noexec or
				 * readonlyfs.
				 */
	return;
    if (!strchr (config->logHistory, type))	
	return;

    if (nolock)
	goto out;

    repos = Short_Repository (repository);

    if (!PrCurDir)
    {
	char *pwdir;

	pwdir = get_homedir ();
	PrCurDir = CurDir;
	if (pwdir != NULL)
	{
	    /* Assumes neither CurDir nor pwdir ends in '/' */
	    i = strlen (pwdir);
	    if (!strncmp (CurDir, pwdir, i))
	    {
		PrCurDir += i;		/* Point to '/' separator */
		tilde = "~";
	    }
	    else
	    {
		/* Try harder to find a "homedir" */
		struct saved_cwd cwd;
		char *homedir;

		if (save_cwd (&cwd))
		    error (1, errno, "Failed to save current directory.");

		if (CVS_CHDIR (pwdir) < 0 || (homedir = xgetcwd ()) == NULL)
		    homedir = pwdir;

		if (restore_cwd (&cwd))
		    error (1, errno,
		           "Failed to restore current directory, `%s'.",
		           cwd.name);
		free_cwd (&cwd);

		i = strlen (homedir);
		if (!strncmp (CurDir, homedir, i))
		{
		    PrCurDir += i;	/* Point to '/' separator */
		    tilde = "~";
		}

		if (homedir != pwdir)
		    free (homedir);
	    }
	}
    }

    if (type == 'T')
    {
	repos = update_dir;
	update_dir = "";
    }
    else if (update_dir && *update_dir)
	slash = "/";
    else
	update_dir = "";

    workdir = Xasprintf ("%s%s%s%s", tilde, PrCurDir, slash, update_dir);

    /*
     * "workdir" is the directory where the file "name" is. ("^~" == $HOME)
     * "repos"	is the Repository, relative to $CVSROOT where the RCS file is.
     *
     * "$workdir/$name" is the working file name.
     * "$CVSROOT/$repos/$name,v" is the RCS file in the Repository.
     *
     * First, note that the history format was intended to save space, not
     * to be human readable.
     *
     * The working file directory ("workdir") and the Repository ("repos")
     * usually end with the same one or more directory elements.  To avoid
     * duplication (and save space), the "workdir" field ends with
     * an integer offset into the "repos" field.  This offset indicates the
     * beginning of the "tail" of "repos", after which all characters are
     * duplicates.
     *
     * In other words, if the "workdir" field has a '*' (a very stupid thing
     * to put in a filename) in it, then every thing following the last '*'
     * is a hex offset into "repos" of the first character from "repos" to
     * append to "workdir" to finish the pathname.
     *
     * It might be easier to look at an example:
     *
     *  M273b3463|dgg|~/work*9|usr/local/cvs/examples|1.2|loginfo
     *
     * Indicates that the workdir is really "~/work/cvs/examples", saving
     * 10 characters, where "~/work*d" would save 6 characters and mean that
     * the workdir is really "~/work/examples".  It will mean more on
     * directories like: usr/local/gnu/emacs/dist-19.17/lisp/term
     *
     * "workdir" is always an absolute pathname (~/xxx is an absolute path)
     * "repos" is always a relative pathname.  So we can assume that we will
     * never run into the top of "workdir" -- there will always be a '/' or
     * a '~' at the head of "workdir" that is not matched by anything in
     * "repos".  On the other hand, we *can* run off the top of "repos".
     *
     * Only "compress" if we save characters.
     */

    cp = workdir + strlen (workdir) - 1;
    cp2 = repos + strlen (repos) - 1;
    for (i = 0; cp2 >= repos && cp > workdir && *cp == *cp2--; cp--)
	i++;

    if (i > 2)
    {
	i = strlen (repos) - i;
	(void) sprintf ((cp + 1), "*%x", i);
    }

    if (!revs)
	revs = "";
    now = time (NULL);
    line = Xasprintf ("%c%08lx|%s|%s|%s|%s|%s\n", type, (long) now,
		      username, workdir, repos, revs, name);

    fname = get_history_log_name (now);

    if (!history_lock (current_parsed_root->directory))
	/* history_lock() will already have printed an error on failure.  */
	goto out;

    fd = CVS_OPEN (fname, O_WRONLY | O_APPEND | O_CREAT | OPEN_BINARY, 0666);
    if (fd < 0)
    {
	if (!really_quiet)
            error (0, errno,
		   "warning: cannot open history file `%s' for write", fname);
        goto out;
    }

    TRACE (TRACE_FUNCTION, "open (`%s', a)", fname);

    /* Lessen some race conditions on non-Posix-compliant hosts.
     *
     * FIXME:  I'm guessing the following was necessary for NFS when multiple
     * simultaneous writes to the same file are possible, since NFS does not
     * natively support append mode and it must be emulated via lseek().  Now
     * that the history file is locked for write, the following lseek() may be
     * unnecessary.
     */
    if (lseek (fd, (off_t) 0, SEEK_END) == -1)
	error (1, errno, "cannot seek to end of history file: %s", fname);

    if (write (fd, line, strlen (line)) < 0)
	error (1, errno, "cannot write to history file: %s", fname);
    free (line);
    if (close (fd) != 0)
	error (1, errno, "cannot close history file: %s", fname);
    free (workdir);
 out:
    clear_history_lock ();
}
Exemplo n.º 3
0
/* read_hrecs_file's job is to read a history file and fill in new "hrec"
 * (history record) array elements with the ones we need to print.
 *
 * Logic:
 * - Read a block from the file. 
 * - Walk through the block parsing line into hr records. 
 * - if the hr isn't used, free its strings, if it is, bump the hrec counter
 * - at the end of a block, copy the end of the current block to the start 
 * of space for the next block, then read in the next block.  If we get less
 * than the whole block, we're done. 
 */
static int
read_hrecs_file (Node *p, void *closure)
{
    char *cpstart, *cpend, *cp, *nl;
    char *hrline;
    int i;
    int fd;
    struct stat st_buf;
    const char *fname = p->key;

    if ((fd = CVS_OPEN (fname, O_RDONLY | OPEN_BINARY)) < 0)
    {
	error (0, errno, "cannot open history file `%s'", fname);
	return 0;
    }

    if (fstat (fd, &st_buf) < 0)
    {
	error (0, errno, "can't stat history file `%s'", fname);
	return 0;
    }

    if (!(st_buf.st_size))
    {
	error (0, 0, "history file `%s' is empty", fname);
	return 0;
    }

    cpstart = xnmalloc (2, STAT_BLOCKSIZE (st_buf));
    cpstart[0] = '\0';
    cp = cpend = cpstart;

    for (;;)
    {
	for (nl = cp; nl < cpend && *nl != '\n'; nl++)
	    if (!isprint (*nl)) *nl = ' ';

	if (nl >= cpend)
	{
	    if (nl - cp >= STAT_BLOCKSIZE (st_buf))
	    {
		error(1, 0, "history line %ld too long (> %lu)", hrec_idx + 1,
		      (unsigned long) STAT_BLOCKSIZE(st_buf));
	    }
	    if (nl > cp)
		memmove (cpstart, cp, nl - cp);
	    nl = cpstart + (nl - cp);
	    cp = cpstart;
	    i = read (fd, nl, STAT_BLOCKSIZE(st_buf));
	    if (i > 0)
	    {
		cpend = nl + i;
		*cpend = '\0';
		continue;
	    }
	    if (i < 0)
	    {
		error (0, errno, "error reading history file `%s'", fname);
		return 0;
	    }
	    if (nl == cp) break;
	    error (0, 0, "warning: no newline at end of history file `%s'",
		   fname);
	}
	*nl = '\0';

	if (hrec_count == hrec_max)
	{
	    struct hrec *old_head = hrec_head;

	    hrec_max += HREC_INCREMENT;
	    hrec_head = xnrealloc (hrec_head, hrec_max, sizeof (struct hrec));
	    if (last_since_tag)
		last_since_tag = hrec_head + (last_since_tag - old_head);
	    if (last_backto)
		last_backto = hrec_head + (last_backto - old_head);
	}

	/* fill_hrec dates from when history read the entire 
	   history file in one chunk, and then records were pulled out
	   by pointing to the various parts of this big chunk.  This is
	   why there are ugly hacks here:  I don't want to completely
	   re-write the whole history stuff right now.  */

	hrline = xstrdup (cp);
	fill_hrec (hrline, &hrec_head[hrec_count]);
	if (select_hrec (&hrec_head[hrec_count]))
	    hrec_count++;
	else 
	    free (hrline);

	cp = nl + 1;
    }
    free (cpstart);
    close (fd);
    return 1;
}
Exemplo n.º 4
0
/*
 * Compare "file1" to "file2". Return non-zero if they don't compare exactly.
 * If FILE1 and FILE2 are special files, compare their salient characteristics
 * (i.e. major/minor device numbers, links, etc.
 */
int xcmp (const char *file1, const char *file2)
{
    char *buf1, *buf2;
    struct stat sb1, sb2;
    int fd1, fd2;
    int ret;

    if (CVS_LSTAT (file1, &sb1) < 0)
        error (1, errno, "cannot lstat %s", fn_root(file1));
    if (CVS_LSTAT (file2, &sb2) < 0)
        error (1, errno, "cannot lstat %s", fn_root(file2));

    /* If FILE1 and FILE2 are not the same file type, they are unequal. */
    if ((sb1.st_mode & S_IFMT) != (sb2.st_mode & S_IFMT))
        return 1;

    /* If FILE1 and FILE2 are symlinks, they are equal if they point to
       the same thing. */
    if (S_ISLNK (sb1.st_mode) && S_ISLNK (sb2.st_mode))
    {
        int result;
        buf1 = xreadlink (file1);
        buf2 = xreadlink (file2);
        result = (strcmp (buf1, buf2) == 0);
        xfree (buf1);
        xfree (buf2);
        return result;
    }

    /* If FILE1 and FILE2 are devices, they are equal if their device
       numbers match. */
    if (S_ISBLK (sb1.st_mode) || S_ISCHR (sb1.st_mode))
    {
#ifdef HAVE_STRUCT_STAT_ST_RDEV
        if (sb1.st_rdev == sb2.st_rdev)
            return 0;
        else
            return 1;
#else
        error (1, 0, "cannot compare device files on this system (%s and %s)",
               file1, file2);
#endif
    }

    if ((fd1 = CVS_OPEN (file1, O_RDONLY)) < 0)
        error (1, errno, "cannot open file %s for comparing", fn_root(file1));
    if ((fd2 = CVS_OPEN (file2, O_RDONLY)) < 0)
        error (1, errno, "cannot open file %s for comparing", fn_root(file2));

    /* A generic file compare routine might compare st_dev & st_ino here
       to see if the two files being compared are actually the same file.
       But that won't happen in CVS, so we won't bother. */

    if (sb1.st_size != sb2.st_size)
        ret = 1;
    else if (sb1.st_size == 0)
        ret = 0;
    else
    {
        /* FIXME: compute the optimal buffer size by computing the least
           common multiple of the files st_blocks field */
        size_t buf_size = 8 * 1024;
        size_t read1;
        size_t read2;

        buf1 = (char*)xmalloc (buf_size);
        buf2 = (char*)xmalloc (buf_size);

        do
        {
            read1 = block_read (fd1, buf1, buf_size);
            if (read1 == (size_t)-1)
                error (1, errno, "cannot read file %s for comparing", fn_root(file1));

            read2 = block_read (fd2, buf2, buf_size);
            if (read2 == (size_t)-1)
                error (1, errno, "cannot read file %s for comparing", fn_root(file2));

            /* assert (read1 == read2); */

            ret = memcmp(buf1, buf2, read1);
        } while (ret == 0 && read1 == buf_size);

        xfree (buf1);
        xfree (buf2);
    }

    (void) close (fd1);
    (void) close (fd2);
    return (ret);
}
Exemplo n.º 5
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;
}
Exemplo n.º 6
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;
}