summaryrefslogtreecommitdiffstats
path: root/contrib/cvs/src/import.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/cvs/src/import.c')
-rw-r--r--contrib/cvs/src/import.c211
1 files changed, 172 insertions, 39 deletions
diff --git a/contrib/cvs/src/import.c b/contrib/cvs/src/import.c
index 11fc99d..18cd482 100644
--- a/contrib/cvs/src/import.c
+++ b/contrib/cvs/src/import.c
@@ -260,7 +260,11 @@ import (argc, argv)
tmpfile = cvs_temp_name ();
if ((logfp = CVS_FOPEN (tmpfile, "w+")) == NULL)
error (1, errno, "cannot create temporary file `%s'", tmpfile);
- (void) CVS_UNLINK (tmpfile); /* to be sure it goes away */
+ /* On systems where we can unlink an open file, do so, so it will go
+ away no matter how we exit. FIXME-maybe: Should be checking for
+ errors but I'm not sure which error(s) we get if we are on a system
+ where one can't unlink open files. */
+ (void) CVS_UNLINK (tmpfile);
(void) fprintf (logfp, "\nVendor Tag:\t%s\n", argv[1]);
(void) fprintf (logfp, "Release Tags:\t");
for (i = 2; i < argc; i++)
@@ -320,11 +324,13 @@ import (argc, argv)
(void) addnode (ulist, p);
Update_Logfile (repository, message, logfp, ulist);
dellist (&ulist);
- (void) fclose (logfp);
+ if (fclose (logfp) < 0)
+ error (0, errno, "error closing %s", tmpfile);
/* Make sure the temporary file goes away, even on systems that don't let
you delete a file that's in use. */
- CVS_UNLINK (tmpfile);
+ if (CVS_UNLINK (tmpfile) < 0 && !existence_error (errno))
+ error (0, errno, "cannot remove %s", tmpfile);
free (tmpfile);
if (message)
@@ -491,7 +497,7 @@ process_import_file (message, vfile, vtag, targc, targv)
/* Reading all the entries for each file is fairly silly, and
probably slow. But I am too lazy at the moment to do
anything else. */
- entries = Entries_Open (0);
+ entries = Entries_Open (0, NULL);
node = findnode_fn (entries, vfile);
if (node != NULL)
{
@@ -977,6 +983,7 @@ add_rcs_file (message, rcs, user, add_vhead, key_opt,
char *userfile;
char *local_opt = key_opt;
char *free_opt = NULL;
+ mode_t file_type;
if (noexec)
return (0);
@@ -1004,18 +1011,39 @@ add_rcs_file (message, rcs, user, add_vhead, key_opt,
which does not depend on what the client or server OS is, as
documented in cvsclient.texi), but as long as the server just
runs on unix it is a moot point. */
- fpuser = CVS_FOPEN (userfile,
- ((local_opt != NULL && strcmp (local_opt, "b") == 0)
- ? "rb"
- : "r")
- );
- if (fpuser == NULL)
+
+ /* If PreservePermissions is set, then make sure that the file
+ is a plain file before trying to open it. Longstanding (although
+ often unpopular) CVS behavior has been to follow symlinks, so we
+ maintain that behavior if PreservePermissions is not on.
+
+ NOTE: this error message used to be `cannot fstat', but is now
+ `cannot lstat'. I don't see a way around this, since we must
+ stat the file before opening it. -twp */
+
+ if (CVS_LSTAT (userfile, &sb) < 0)
+ error (1, errno, "cannot lstat %s", user);
+ file_type = sb.st_mode & S_IFMT;
+
+ fpuser = NULL;
+ if (!preserve_perms || file_type == S_IFREG)
{
- /* not fatal, continue import */
- fperror (add_logfp, 0, errno, "ERROR: cannot read file %s", userfile);
- error (0, errno, "ERROR: cannot read file %s", userfile);
- goto read_error;
+ fpuser = CVS_FOPEN (userfile,
+ ((local_opt != NULL && strcmp (local_opt, "b") == 0)
+ ? "rb"
+ : "r")
+ );
+ if (fpuser == NULL)
+ {
+ /* not fatal, continue import */
+ if (add_logfp != NULL)
+ fperror (add_logfp, 0, errno,
+ "ERROR: cannot read file %s", userfile);
+ error (0, errno, "ERROR: cannot read file %s", userfile);
+ goto read_error;
+ }
}
+
fprcs = CVS_FOPEN (rcs, "w+b");
if (fprcs == NULL)
{
@@ -1082,10 +1110,6 @@ add_rcs_file (message, rcs, user, add_vhead, key_opt,
if (fprintf (fprcs, "\012") < 0)
goto write_error;
- /* Get information on modtime and mode. */
- if (fstat (fileno (fpuser), &sb) < 0)
- error (1, errno, "cannot fstat %s", user);
-
/* Write the revision(s), with the date and author and so on
(that is "delta" rather than "deltatext" from rcsfile(5)). */
if (add_vhead != NULL)
@@ -1118,13 +1142,102 @@ add_rcs_file (message, rcs, user, add_vhead, key_opt,
if (fprintf (fprcs, "next ;\012") < 0)
goto write_error;
+
+#ifdef PRESERVE_PERMISSIONS_SUPPORT
+ /* Store initial permissions if necessary. */
+ if (preserve_perms)
+ {
+ if (file_type == S_IFLNK)
+ {
+ char *link = xreadlink (userfile);
+ if (fprintf (fprcs, "symlink\t@") < 0 ||
+ expand_at_signs (link, strlen (link), fprcs) < 0 ||
+ fprintf (fprcs, "@;\012") < 0)
+ goto write_error;
+ free (link);
+ }
+ else
+ {
+ if (fprintf (fprcs, "owner\t%u;\012", sb.st_uid) < 0)
+ goto write_error;
+ if (fprintf (fprcs, "group\t%u;\012", sb.st_gid) < 0)
+ goto write_error;
+ if (fprintf (fprcs, "permissions\t%o;\012",
+ sb.st_mode & 07777) < 0)
+ goto write_error;
+ switch (file_type)
+ {
+ case S_IFREG: break;
+ case S_IFCHR:
+ case S_IFBLK:
+ if (fprintf (fprcs, "special\t%s %lu;\012",
+ (file_type == S_IFCHR
+ ? "character"
+ : "block"),
+ (unsigned long) sb.st_rdev) < 0)
+ goto write_error;
+ break;
+ default:
+ error (0, 0,
+ "can't import %s: unknown kind of special file",
+ userfile);
+ }
+ }
+ }
+#endif
+
if (add_vbranch != NULL)
{
if (fprintf (fprcs, "\012%s.1\012", add_vbranch) < 0 ||
fprintf (fprcs, "date %s; author %s; state Exp;\012",
altdate1, author) < 0 ||
fprintf (fprcs, "branches ;\012") < 0 ||
- fprintf (fprcs, "next ;\012\012") < 0)
+ fprintf (fprcs, "next ;\012") < 0)
+ goto write_error;
+
+#ifdef PRESERVE_PERMISSIONS_SUPPORT
+ /* Store initial permissions if necessary. */
+ if (preserve_perms)
+ {
+ if (file_type == S_IFLNK)
+ {
+ char *link = xreadlink (userfile);
+ if (fprintf (fprcs, "symlink\t@") < 0 ||
+ expand_at_signs (link, strlen (link), fprcs) < 0 ||
+ fprintf (fprcs, "@;\012") < 0)
+ goto write_error;
+ free (link);
+ }
+ else
+ {
+ if (fprintf (fprcs, "owner\t%u;\012", sb.st_uid) < 0 ||
+ fprintf (fprcs, "group\t%u;\012", sb.st_gid) < 0 ||
+ fprintf (fprcs, "permissions\t%o;\012",
+ sb.st_mode & 07777) < 0)
+ goto write_error;
+
+ switch (file_type)
+ {
+ case S_IFREG: break;
+ case S_IFCHR:
+ case S_IFBLK:
+ if (fprintf (fprcs, "special\t%s %lu;\012",
+ (file_type == S_IFCHR
+ ? "character"
+ : "block"),
+ (unsigned long) sb.st_rdev) < 0)
+ goto write_error;
+ break;
+ default:
+ error (0, 0,
+ "cannot import %s: special file of unknown type",
+ userfile);
+ }
+ }
+ }
+#endif
+
+ if (fprintf (fprcs, "\012") < 0)
goto write_error;
}
}
@@ -1170,7 +1283,9 @@ add_rcs_file (message, rcs, user, add_vhead, key_opt,
goto write_error;
}
- /* Now copy over the contents of the file, expanding at signs. */
+ /* Now copy over the contents of the file, expanding at signs.
+ If preserve_perms is set, do this only for regular files. */
+ if (!preserve_perms || file_type == S_IFREG)
{
char buf[8192];
unsigned int len;
@@ -1208,7 +1323,12 @@ add_rcs_file (message, rcs, user, add_vhead, key_opt,
ierrno = errno;
goto write_error_noclose;
}
- (void) fclose (fpuser);
+ /* Close fpuser only if we opened it to begin with. */
+ if (fpuser != NULL)
+ {
+ if (fclose (fpuser) < 0)
+ error (0, errno, "cannot close %s", user);
+ }
/*
* Fix the modes on the RCS files. The user modes of the original
@@ -1224,8 +1344,9 @@ add_rcs_file (message, rcs, user, add_vhead, key_opt,
if (chmod (rcs, mode) < 0)
{
ierrno = errno;
- fperror (add_logfp, 0, ierrno,
- "WARNING: cannot change mode of file %s", rcs);
+ if (add_logfp != NULL)
+ fperror (add_logfp, 0, ierrno,
+ "WARNING: cannot change mode of file %s", rcs);
error (0, ierrno, "WARNING: cannot change mode of file %s", rcs);
err++;
}
@@ -1238,15 +1359,20 @@ add_rcs_file (message, rcs, user, add_vhead, key_opt,
write_error:
ierrno = errno;
- (void) fclose (fprcs);
+ if (fclose (fprcs) < 0)
+ error (0, errno, "cannot close %s", rcs);
write_error_noclose:
- (void) fclose (fpuser);
- fperror (add_logfp, 0, ierrno, "ERROR: cannot write file %s", rcs);
+ if (fclose (fpuser) < 0)
+ error (0, errno, "cannot close %s", user);
+ if (add_logfp != NULL)
+ fperror (add_logfp, 0, ierrno, "ERROR: cannot write file %s", rcs);
error (0, ierrno, "ERROR: cannot write file %s", rcs);
if (ierrno == ENOSPC)
{
- (void) CVS_UNLINK (rcs);
- fperror (add_logfp, 0, 0, "ERROR: out of space - aborting");
+ if (CVS_UNLINK (rcs) < 0)
+ error (0, errno, "cannot remove %s", rcs);
+ if (add_logfp != NULL)
+ fperror (add_logfp, 0, 0, "ERROR: out of space - aborting");
error (1, 0, "ERROR: out of space - aborting");
}
read_error:
@@ -1271,20 +1397,27 @@ expand_at_signs (buf, size, fp)
off_t size;
FILE *fp;
{
- char *cp, *end;
+ register char *cp, *next;
- errno = 0;
- for (cp = buf, end = buf + size; cp < end; cp++)
+ cp = buf;
+ while ((next = memchr (cp, '@', size)) != NULL)
{
- if (*cp == '@')
- {
- if (putc ('@', fp) == EOF && errno != 0)
- return EOF;
- }
- if (putc (*cp, fp) == EOF && errno != 0)
- return (EOF);
+ int len;
+
+ ++next;
+ len = next - cp;
+ if (fwrite (cp, 1, len, fp) != len)
+ return EOF;
+ if (putc ('@', fp) == EOF)
+ return EOF;
+ cp = next;
+ size -= len;
}
- return (1);
+
+ if (fwrite (cp, 1, size, fp) != size)
+ return EOF;
+
+ return 1;
}
/*
OpenPOWER on IntegriCloud