summaryrefslogtreecommitdiff
path: root/gnu/usr.bin
diff options
context:
space:
mode:
authorFederico G. Schwindt <fgsch@cvs.openbsd.org>2012-03-04 04:05:16 +0000
committerFederico G. Schwindt <fgsch@cvs.openbsd.org>2012-03-04 04:05:16 +0000
commitea5319421a589ebd8583734a461346e1f0d91bec (patch)
treef5bd7462d5be00f2b6c3ea91c579bd03d2ef6dce /gnu/usr.bin
parentc90e6f8af6e01b6bd2b8ec8057571ae41b0ddb00 (diff)
In preparation for getline and getdelim additions to libc, rename getline()
occurrences to get_line(). Based on a diff from Jan Klemkow <j-dot-klemkow-at-wemelug-dot-de> to tech.
Diffstat (limited to 'gnu/usr.bin')
-rw-r--r--gnu/usr.bin/cvs/lib/getline.c87
-rw-r--r--gnu/usr.bin/cvs/lib/getline.h10
-rw-r--r--gnu/usr.bin/cvs/src/client.c4
-rw-r--r--gnu/usr.bin/cvs/src/commit.c2
-rw-r--r--gnu/usr.bin/cvs/src/cvsrc.c120
-rw-r--r--gnu/usr.bin/cvs/src/edit.c419
-rw-r--r--gnu/usr.bin/cvs/src/entries.c1003
-rw-r--r--gnu/usr.bin/cvs/src/fileattr.c213
-rw-r--r--gnu/usr.bin/cvs/src/ignore.c2
-rw-r--r--gnu/usr.bin/cvs/src/login.c4
-rw-r--r--gnu/usr.bin/cvs/src/logmsg.c6
-rw-r--r--gnu/usr.bin/cvs/src/mkmodules.c2
-rw-r--r--gnu/usr.bin/cvs/src/parseinfo.c4
-rw-r--r--gnu/usr.bin/cvs/src/patch.c6
-rw-r--r--gnu/usr.bin/cvs/src/release.c416
-rw-r--r--gnu/usr.bin/cvs/src/repos.c201
-rw-r--r--gnu/usr.bin/cvs/src/root.c2
-rw-r--r--gnu/usr.bin/cvs/src/server.c6
-rw-r--r--gnu/usr.bin/cvs/src/subr.c2
-rw-r--r--gnu/usr.bin/cvs/src/update.c2
-rw-r--r--gnu/usr.bin/cvs/src/wrapper.c2
21 files changed, 1798 insertions, 715 deletions
diff --git a/gnu/usr.bin/cvs/lib/getline.c b/gnu/usr.bin/cvs/lib/getline.c
index c69946148f6..bda96e27e14 100644
--- a/gnu/usr.bin/cvs/lib/getline.c
+++ b/gnu/usr.bin/cvs/lib/getline.c
@@ -10,11 +10,7 @@ License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+General Public License for more details. */
/* Written by Jan Brittenson, bson@gnu.ai.mit.edu. */
@@ -24,8 +20,9 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <sys/types.h>
#include <stdio.h>
-#define NDEBUG
#include <assert.h>
+#include <errno.h>
+#include "getline.h"
#if STDC_HEADERS
#include <stdlib.h>
@@ -37,32 +34,45 @@ char *malloc (), *realloc ();
#define MIN_CHUNK 64
/* Read up to (and including) a TERMINATOR from STREAM into *LINEPTR
- + OFFSET (and null-terminate it). *LINEPTR is a pointer returned from
- malloc (or NULL), pointing to *N characters of space. It is realloc'd
- as necessary. Return the number of characters read (not including the
- null terminator), or -1 on error or EOF. */
+ + OFFSET (and null-terminate it). If LIMIT is non-negative, then
+ read no more than LIMIT chars.
+
+ *LINEPTR is a pointer returned from malloc (or NULL), pointing to
+ *N characters of space. It is realloc'd as necessary.
+
+ Return the number of characters read (not including the null
+ terminator), or -1 on error or EOF. On a -1 return, the caller
+ should check feof(), if not then errno has been set to indicate the
+ error. */
int
-getstr (lineptr, n, stream, terminator, offset)
+getstr (lineptr, n, stream, terminator, offset, limit)
char **lineptr;
size_t *n;
FILE *stream;
char terminator;
int offset;
+ int limit;
{
int nchars_avail; /* Allocated but unused chars in *LINEPTR. */
char *read_pos; /* Where we're reading into *LINEPTR. */
int ret;
if (!lineptr || !n || !stream)
- return -1;
+ {
+ errno = EINVAL;
+ return -1;
+ }
if (!*lineptr)
{
*n = MIN_CHUNK;
*lineptr = malloc (*n);
if (!*lineptr)
- return -1;
+ {
+ errno = ENOMEM;
+ return -1;
+ }
}
nchars_avail = *n - offset;
@@ -70,13 +80,28 @@ getstr (lineptr, n, stream, terminator, offset)
for (;;)
{
- register int c = getc (stream);
+ int save_errno;
+ register int c;
+
+ if (limit == 0)
+ break;
+ else
+ {
+ c = getc (stream);
+
+ /* If limit is negative, then we shouldn't pay attention to
+ it, so decrement only if positive. */
+ if (limit > 0)
+ limit--;
+ }
+
+ save_errno = errno;
/* We always want at least one char left in the buffer, since we
always (unless we get an error while reading the first char)
NUL-terminate the line buffer. */
- assert(*n - nchars_avail == read_pos - *lineptr);
+ assert((*lineptr + *n) == (read_pos + nchars_avail));
if (nchars_avail < 2)
{
if (*n > MIN_CHUNK)
@@ -87,12 +112,24 @@ getstr (lineptr, n, stream, terminator, offset)
nchars_avail = *n + *lineptr - read_pos;
*lineptr = realloc (*lineptr, *n);
if (!*lineptr)
- return -1;
+ {
+ errno = ENOMEM;
+ return -1;
+ }
read_pos = *n - nchars_avail + *lineptr;
- assert(*n - nchars_avail == read_pos - *lineptr);
+ assert((*lineptr + *n) == (read_pos + nchars_avail));
}
- if (c == EOF || ferror (stream))
+ if (ferror (stream))
+ {
+ /* Might like to return partial line, but there is no
+ place for us to store errno. And we don't want to just
+ lose errno. */
+ errno = save_errno;
+ return -1;
+ }
+
+ if (c == EOF)
{
/* Return partial line, if any. */
if (read_pos == *lineptr)
@@ -117,10 +154,20 @@ getstr (lineptr, n, stream, terminator, offset)
}
int
-getline (lineptr, n, stream)
+get_line (lineptr, n, stream)
+ char **lineptr;
+ size_t *n;
+ FILE *stream;
+{
+ return getstr (lineptr, n, stream, '\n', 0, GETLINE_NO_LIMIT);
+}
+
+int
+getline_safe (lineptr, n, stream, limit)
char **lineptr;
size_t *n;
FILE *stream;
+ int limit;
{
- return getstr (lineptr, n, stream, '\n', 0);
+ return getstr (lineptr, n, stream, '\n', 0, limit);
}
diff --git a/gnu/usr.bin/cvs/lib/getline.h b/gnu/usr.bin/cvs/lib/getline.h
index 30bcc258373..3c697c8e6e3 100644
--- a/gnu/usr.bin/cvs/lib/getline.h
+++ b/gnu/usr.bin/cvs/lib/getline.h
@@ -9,7 +9,15 @@
#define __PROTO(args) ()
#endif /* GCC. */
+#define GETLINE_NO_LIMIT -1
+
+int
+ get_line __PROTO ((char **_lineptr, size_t *_n, FILE *_stream));
+int
+ getline_safe __PROTO ((char **_lineptr, size_t *_n, FILE *_stream,
+ int limit));
int
- getline __PROTO ((char **_lineptr, size_t *_n, FILE *_stream));
+ getstr __PROTO ((char **_lineptr, size_t *_n, FILE *_stream,
+ char _terminator, int _offset, int limit));
#endif /* _getline_h_ */
diff --git a/gnu/usr.bin/cvs/src/client.c b/gnu/usr.bin/cvs/src/client.c
index 57739524ee2..0c0df1bc91d 100644
--- a/gnu/usr.bin/cvs/src/client.c
+++ b/gnu/usr.bin/cvs/src/client.c
@@ -5818,7 +5818,7 @@ notified_a_file (data, ent_list, short_pathname, filename)
char *p;
fp = open_file (CVSADM_NOTIFY, "r");
- if (getline (&line, &line_len, fp) < 0)
+ if (get_line (&line, &line_len, fp) < 0)
{
if (feof (fp))
error (0, 0, "cannot read %s: end of file", CVSADM_NOTIFY);
@@ -5839,7 +5839,7 @@ notified_a_file (data, ent_list, short_pathname, filename)
line + 1);
}
- if (getline (&line, &line_len, fp) < 0)
+ if (get_line (&line, &line_len, fp) < 0)
{
if (feof (fp))
{
diff --git a/gnu/usr.bin/cvs/src/commit.c b/gnu/usr.bin/cvs/src/commit.c
index 0fe9f9425d7..bb576d394ae 100644
--- a/gnu/usr.bin/cvs/src/commit.c
+++ b/gnu/usr.bin/cvs/src/commit.c
@@ -1482,7 +1482,7 @@ commit_filesdoneproc (callerdat, err, repository, update_dir, entries)
line = NULL;
line_chars_allocated = 0;
- line_length = getline (&line, &line_chars_allocated, fp);
+ line_length = get_line (&line, &line_chars_allocated, fp);
if (line_length > 0)
{
/* Remove any trailing newline. */
diff --git a/gnu/usr.bin/cvs/src/cvsrc.c b/gnu/usr.bin/cvs/src/cvsrc.c
index ec594eb5456..03dbb791683 100644
--- a/gnu/usr.bin/cvs/src/cvsrc.c
+++ b/gnu/usr.bin/cvs/src/cvsrc.c
@@ -1,20 +1,16 @@
/*
- * Copyright (c) 1993 david d zuhn
- *
- * written by david d `zoo' zuhn while at Cygnus Support
- *
- * You may distribute under the terms of the GNU General Public License
- * as specified in the README file that comes with the CVS 1.4 kit.
+ * Copyright (c) 1993 david d zuhn
+ *
+ * Written by david d `zoo' zuhn while at Cygnus Support
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with the CVS source distribution.
*
*/
#include "cvs.h"
-
-#ifndef lint
-static const char rcsid[] = "$CVSid: @(#)cvsrc.c 1.9 94/09/30 $";
-USE(rcsid);
-#endif /* lint */
+#include "getline.h"
/* this file is to be found in the user's home directory */
@@ -27,19 +23,26 @@ char cvsrc[] = CVSRC_FILENAME;
extern char *strtok ();
+/* Read cvsrc, processing options matching CMDNAME ("cvs" for global
+ options, and update *ARGC and *ARGV accordingly. */
+
void
-read_cvsrc (argc, argv)
- int *argc;
- char ***argv;
+read_cvsrc (argc, argv, cmdname)
+ int *argc;
+ char ***argv;
+ char *cmdname;
{
char *homedir;
char *homeinit;
FILE *cvsrcfile;
- char linebuf [MAXLINELEN];
-
+ char *line;
+ int line_length;
+ size_t line_chars_allocated;
+
char *optstart;
+ int command_len;
int found = 0;
int i;
@@ -48,20 +51,25 @@ read_cvsrc (argc, argv)
int max_new_argv;
char **new_argv;
+ /* old_argc and old_argv hold the values returned from the
+ previous invocation of read_cvsrc and are used to free the
+ allocated memory. The first invocation of read_cvsrc gets argv
+ from the system, this memory must not be free'd. */
+ static int old_argc = 0;
+ static char **old_argv = NULL;
+
/* don't do anything if argc is -1, since that implies "help" mode */
if (*argc == -1)
return;
- /* setup the new options list */
-
- new_argc = 1;
- max_new_argv = (*argc) + GROW;
- new_argv = (char **) xmalloc (max_new_argv * sizeof (char*));
- new_argv[0] = xstrdup ((*argv)[0]);
-
/* determine filename for ~/.cvsrc */
- homedir = getenv ("HOME");
+ homedir = get_homedir ();
+ /* If we can't find a home directory, ignore ~/.cvsrc. This may
+ make tracking down problems a bit of a pain, but on the other
+ hand it might be obnoxious to complain when CVS will function
+ just fine without .cvsrc (and many users won't even know what
+ .cvsrc is). */
if (!homedir)
return;
@@ -72,7 +80,7 @@ read_cvsrc (argc, argv)
/* if it can't be read, there's no point to continuing */
- if (access (homeinit, R_OK) != 0)
+ if (!isreadable (homeinit))
{
free (homeinit);
return;
@@ -80,59 +88,79 @@ read_cvsrc (argc, argv)
/* now scan the file until we find the line for the command in question */
+ line = NULL;
+ line_chars_allocated = 0;
+ command_len = strlen (cmdname);
cvsrcfile = open_file (homeinit, "r");
- while (fgets (linebuf, MAXLINELEN, cvsrcfile))
+ while ((line_length = get_line (&line, &line_chars_allocated, cvsrcfile))
+ >= 0)
{
/* skip over comment lines */
- if (linebuf[0] == '#')
+ if (line[0] == '#')
continue;
/* stop if we match the current command */
- if (!strncmp (linebuf, (*argv)[0], strlen ((*argv)[0])))
+ if (!strncmp (line, cmdname, command_len)
+ && isspace ((unsigned char) *(line + command_len)))
{
found = 1;
break;
}
}
+ if (line_length < 0 && !feof (cvsrcfile))
+ error (0, errno, "cannot read %s", homeinit);
+
fclose (cvsrcfile);
+ /* setup the new options list */
+
+ new_argc = 1;
+ max_new_argv = (*argc) + GROW;
+ new_argv = (char **) xmalloc (max_new_argv * sizeof (char*));
+ new_argv[0] = xstrdup ((*argv)[0]);
+
if (found)
{
/* skip over command in the options line */
- optstart = strtok(linebuf+strlen((*argv)[0]), "\t \n");
-
- do
+ for (optstart = strtok (line + command_len, "\t \n");
+ optstart;
+ optstart = strtok (NULL, "\t \n"))
{
- new_argv [new_argc] = xstrdup (optstart);
- new_argv [new_argc+1] = NULL;
- new_argc += 1;
+ new_argv [new_argc++] = xstrdup (optstart);
if (new_argc >= max_new_argv)
{
- char **tmp_argv;
max_new_argv += GROW;
- tmp_argv = (char **) xmalloc (max_new_argv * sizeof (char*));
- for (i = 0; i <= new_argc; i++)
- tmp_argv[i] = new_argv[i];
- free(new_argv);
- new_argv = tmp_argv;
+ new_argv = (char **) xrealloc (new_argv, max_new_argv * sizeof (char*));
}
-
}
- while ((optstart = strtok (NULL, "\t \n")) != NULL);
}
+ if (line != NULL)
+ free (line);
+
/* now copy the remaining arguments */
+ if (new_argc + *argc > max_new_argv)
+ {
+ max_new_argv = new_argc + *argc;
+ new_argv = (char **) xrealloc (new_argv, max_new_argv * sizeof (char*));
+ }
for (i=1; i < *argc; i++)
{
- new_argv [new_argc] = (*argv)[i];
- new_argc += 1;
+ new_argv [new_argc++] = xstrdup ((*argv)[i]);
+ }
+
+ if (old_argv != NULL)
+ {
+ /* Free the memory which was allocated in the previous
+ read_cvsrc call. */
+ free_names (&old_argc, old_argv);
}
- *argc = new_argc;
- *argv = new_argv;
+ old_argc = *argc = new_argc;
+ old_argv = *argv = new_argv;
free (homeinit);
return;
diff --git a/gnu/usr.bin/cvs/src/edit.c b/gnu/usr.bin/cvs/src/edit.c
index 8eeecb51e45..0e34eb0c71e 100644
--- a/gnu/usr.bin/cvs/src/edit.c
+++ b/gnu/usr.bin/cvs/src/edit.c
@@ -8,11 +8,7 @@
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+ GNU General Public License for more details. */
#include "cvs.h"
#include "getline.h"
@@ -29,27 +25,26 @@ static int setting_tedit;
static int setting_tunedit;
static int setting_tcommit;
-static int onoff_fileproc PROTO ((char *, char *, char *, List *, List *));
+static int onoff_fileproc PROTO ((void *callerdat, struct file_info *finfo));
static int
-onoff_fileproc (file, update_dir, repository, entries, srcfiles)
- char *file;
- char *update_dir;
- char *repository;
- List *entries;
- List *srcfiles;
+onoff_fileproc (callerdat, finfo)
+ void *callerdat;
+ struct file_info *finfo;
{
- fileattr_set (file, "_watched", turning_on ? "" : NULL);
+ fileattr_set (finfo->file, "_watched", turning_on ? "" : NULL);
return 0;
}
-static int onoff_filesdoneproc PROTO ((int, char *, char *));
+static int onoff_filesdoneproc PROTO ((void *, int, char *, char *, List *));
static int
-onoff_filesdoneproc (err, repository, update_dir)
+onoff_filesdoneproc (callerdat, err, repository, update_dir, entries)
+ void *callerdat;
int err;
char *repository;
char *update_dir;
+ List *entries;
{
if (setting_default)
fileattr_set (NULL, "_watched", turning_on ? "" : NULL);
@@ -65,14 +60,17 @@ watch_onoff (argc, argv)
int local = 0;
int err;
- optind = 1;
- while ((c = getopt (argc, argv, "l")) != -1)
+ optind = 0;
+ while ((c = getopt (argc, argv, "+lR")) != -1)
{
switch (c)
{
case 'l':
local = 1;
break;
+ case 'R':
+ local = 0;
+ break;
case '?':
default:
usage (watch_usage);
@@ -83,7 +81,7 @@ watch_onoff (argc, argv)
argv += optind;
#ifdef CLIENT_SUPPORT
- if (client_active)
+ if (current_parsed_root->isremote)
{
start_server ();
@@ -91,11 +89,8 @@ watch_onoff (argc, argv)
if (local)
send_arg ("-l");
- send_file_names (argc, argv);
- /* FIXME: We shouldn't have to send current files, but I'm not sure
- whether it works. So send the files --
- it's slower but it works. */
- send_files (argc, argv, local, 0);
+ send_files (argc, argv, local, 0, SEND_NO_CONTENTS);
+ send_file_names (argc, argv, SEND_EXPAND_WILD);
send_to_server (turning_on ? "watch-on\012" : "watch-off\012", 0);
return get_responses_and_close ();
}
@@ -103,14 +98,14 @@ watch_onoff (argc, argv)
setting_default = (argc <= 0);
- lock_tree_for_write (argc, argv, local, 0);
+ lock_tree_for_write (argc, argv, local, W_LOCAL, 0);
err = start_recursion (onoff_fileproc, onoff_filesdoneproc,
- (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL,
+ (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, NULL,
argc, argv, local, W_LOCAL, 0, 0, (char *)NULL,
- 0, 0);
+ 0);
- lock_tree_cleanup ();
+ Lock_Cleanup ();
return err;
}
@@ -132,15 +127,12 @@ watch_off (argc, argv)
return watch_onoff (argc, argv);
}
-static int dummy_fileproc PROTO ((char *, char *, char *, List *, List *));
+static int dummy_fileproc PROTO ((void *callerdat, struct file_info *finfo));
static int
-dummy_fileproc (file, update_dir, repository, entries, srcfiles)
- char *file;
- char *update_dir;
- char *repository;
- List *entries;
- List *srcfiles;
+dummy_fileproc (callerdat, finfo)
+ void *callerdat;
+ struct file_info *finfo;
{
/* This is a pretty hideous hack, but the gist of it is that recurse.c
won't call notify_check unless there is a fileproc, so we can't just
@@ -148,9 +140,7 @@ dummy_fileproc (file, update_dir, repository, entries, srcfiles)
return 0;
}
-static int ncheck_fileproc PROTO ((char *file, char *update_dir,
- char *repository,
- List * entries, List * srcfiles));
+static int ncheck_fileproc PROTO ((void *callerdat, struct file_info *finfo));
/* Check for and process notifications. Local only. I think that doing
this as a fileproc is the only way to catch all the
@@ -159,12 +149,9 @@ static int ncheck_fileproc PROTO ((char *file, char *update_dir,
processed the directory. */
static int
-ncheck_fileproc (file, update_dir, repository, entries, srcfiles)
- char *file;
- char *update_dir;
- char *repository;
- List *entries;
- List *srcfiles;
+ncheck_fileproc (callerdat, finfo)
+ void *callerdat;
+ struct file_info *finfo;
{
int notif_type;
char *filename;
@@ -179,14 +166,15 @@ ncheck_fileproc (file, update_dir, repository, entries, srcfiles)
/* We send notifications even if noexec. I'm not sure which behavior
is most sensible. */
- fp = fopen (CVSADM_NOTIFY, "r");
+ fp = CVS_FOPEN (CVSADM_NOTIFY, "r");
if (fp == NULL)
{
if (!existence_error (errno))
error (0, errno, "cannot open %s", CVSADM_NOTIFY);
return 0;
}
- while (getline (&line, &line_len, fp) > 0)
+
+ while (get_line (&line, &line_len, fp) > 0)
{
notif_type = line[0];
if (notif_type == '\0')
@@ -216,15 +204,16 @@ ncheck_fileproc (file, update_dir, repository, entries, srcfiles)
*cp = '\0';
notify_do (notif_type, filename, getcaller (), val, watches,
- repository);
+ finfo->repository);
}
+ free (line);
if (ferror (fp))
error (0, errno, "cannot read %s", CVSADM_NOTIFY);
if (fclose (fp) < 0)
error (0, errno, "cannot close %s", CVSADM_NOTIFY);
- if (unlink (CVSADM_NOTIFY) < 0)
+ if ( CVS_UNLINK (CVSADM_NOTIFY) < 0)
error (0, errno, "cannot remove %s", CVSADM_NOTIFY);
return 0;
@@ -246,7 +235,7 @@ send_notifications (argc, argv, local)
/* OK, we've done everything which needs to happen on the client side.
Now we can try to contact the server; if we fail, then the
notifications stay in CVSADM_NOTIFY to be sent next time. */
- if (client_active)
+ if (current_parsed_root->isremote)
{
if (strcmp (command_name, "release") != 0)
{
@@ -255,9 +244,9 @@ send_notifications (argc, argv, local)
}
err += start_recursion (dummy_fileproc, (FILESDONEPROC) NULL,
- (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL,
+ (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, NULL,
argc, argv, local, W_LOCAL, 0, 0, (char *)NULL,
- 0, 0);
+ 0);
send_to_server ("noop\012", 0);
if (strcmp (command_name, "release") == 0)
@@ -270,25 +259,22 @@ send_notifications (argc, argv, local)
{
/* Local. */
- lock_tree_for_write (argc, argv, local, 0);
+ lock_tree_for_write (argc, argv, local, W_LOCAL, 0);
err += start_recursion (ncheck_fileproc, (FILESDONEPROC) NULL,
- (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL,
+ (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, NULL,
argc, argv, local, W_LOCAL, 0, 0, (char *)NULL,
- 0, 0);
- lock_tree_cleanup ();
+ 0);
+ Lock_Cleanup ();
}
return err;
}
-static int edit_fileproc PROTO ((char *, char *, char *, List *, List *));
+static int edit_fileproc PROTO ((void *callerdat, struct file_info *finfo));
static int
-edit_fileproc (file, update_dir, repository, entries, srcfiles)
- char *file;
- char *update_dir;
- char *repository;
- List *entries;
- List *srcfiles;
+edit_fileproc (callerdat, finfo)
+ void *callerdat;
+ struct file_info *finfo;
{
FILE *fp;
time_t now;
@@ -298,12 +284,26 @@ edit_fileproc (file, update_dir, repository, entries, srcfiles)
if (noexec)
return 0;
+ /* This is a somewhat screwy way to check for this, because it
+ doesn't help errors other than the nonexistence of the file
+ (e.g. permissions problems). It might be better to rearrange
+ the code so that CVSADM_NOTIFY gets written only after the
+ various actions succeed (but what if only some of them
+ succeed). */
+ if (!isfile (finfo->file))
+ {
+ error (0, 0, "no such file %s; ignored", finfo->fullname);
+ return 0;
+ }
+
fp = open_file (CVSADM_NOTIFY, "a");
(void) time (&now);
ascnow = asctime (gmtime (&now));
ascnow[24] = '\0';
- fprintf (fp, "E%s\t%s GMT\t%s\t%s\t", file,
+ /* Fix non-standard format. */
+ if (ascnow[8] == '0') ascnow[8] = ' ';
+ fprintf (fp, "E%s\t%s GMT\t%s\t%s\t", finfo->file,
ascnow, hostname, CurDir);
if (setting_tedit)
fprintf (fp, "E");
@@ -315,48 +315,50 @@ edit_fileproc (file, update_dir, repository, entries, srcfiles)
if (fclose (fp) < 0)
{
- if (update_dir[0] == '\0')
- error (0, errno, "cannot close %s", file);
+ if (finfo->update_dir[0] == '\0')
+ error (0, errno, "cannot close %s", CVSADM_NOTIFY);
else
- error (0, errno, "cannot close %s/%s", update_dir, file);
+ error (0, errno, "cannot close %s/%s", finfo->update_dir,
+ CVSADM_NOTIFY);
}
- xchmod (file, 1);
+ xchmod (finfo->file, 1);
/* Now stash the file away in CVSADM so that unedit can revert even if
it can't communicate with the server. We stash away a writable
copy so that if the user removes the working file, then restores it
with "cvs update" (which clears _editors but does not update
CVSADM_BASE), then a future "cvs edit" can still win. */
- /* Could save a system call by only calling mkdir if trying to create
- the output file fails. But copy_file isn't set up to facilitate
- that. */
- if (CVS_MKDIR (CVSADM_BASE, 0777) < 0)
- {
- if (errno != EEXIST
-#ifdef EACCESS
- /* OS/2; see longer comment in client.c. */
- && errno != EACCESS
-#endif
- )
- error (1, errno, "cannot mkdir %s", CVSADM_BASE);
- }
- basefilename = xmalloc (10 + sizeof CVSADM_BASE + strlen (file));
+ /* Could save a system call by only calling mkdir_if_needed if
+ trying to create the output file fails. But copy_file isn't
+ set up to facilitate that. */
+ mkdir_if_needed (CVSADM_BASE);
+ basefilename = xmalloc (10 + sizeof CVSADM_BASE + strlen (finfo->file));
strcpy (basefilename, CVSADM_BASE);
strcat (basefilename, "/");
- strcat (basefilename, file);
- copy_file (file, basefilename);
+ strcat (basefilename, finfo->file);
+ copy_file (finfo->file, basefilename);
free (basefilename);
+ {
+ Node *node;
+
+ node = findnode_fn (finfo->entries, finfo->file);
+ if (node != NULL)
+ base_register (finfo, ((Entnode *) node->data)->version);
+ }
+
return 0;
}
static const char *const edit_usage[] =
{
- "Usage: %s %s [-l] [files...]\n",
+ "Usage: %s %s [-lR] [files...]\n",
"-l: Local directory only, not recursive\n",
+ "-R: Process directories recursively\n",
"-a: Specify what actions for temporary watch, one of\n",
- " edit,unedit,commit.all,none\n",
+ " edit,unedit,commit,all,none\n",
+ "(Specify the --help global option for a list of other help options)\n",
NULL
};
@@ -377,14 +379,17 @@ edit (argc, argv)
setting_tedit = 0;
setting_tunedit = 0;
setting_tcommit = 0;
- optind = 1;
- while ((c = getopt (argc, argv, "la:")) != -1)
+ optind = 0;
+ while ((c = getopt (argc, argv, "+lRa:")) != -1)
{
switch (c)
{
case 'l':
local = 1;
break;
+ case 'R':
+ local = 0;
+ break;
case 'a':
a_omitted = 0;
if (strcmp (optarg, "edit") == 0)
@@ -424,27 +429,33 @@ edit (argc, argv)
setting_tcommit = 1;
}
+ if (strpbrk (hostname, "+,>;=\t\n") != NULL)
+ error (1, 0,
+ "host name (%s) contains an invalid character (+,>;=\\t\\n)",
+ hostname);
+ if (strpbrk (CurDir, "+,>;=\t\n") != NULL)
+ error (1, 0,
+"current directory (%s) contains an invalid character (+,>;=\\t\\n)",
+ CurDir);
+
/* No need to readlock since we aren't doing anything to the
repository. */
err = start_recursion (edit_fileproc, (FILESDONEPROC) NULL,
- (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL,
+ (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, NULL,
argc, argv, local, W_LOCAL, 0, 0, (char *)NULL,
- 0, 0);
+ 0);
err += send_notifications (argc, argv, local);
return err;
}
-static int unedit_fileproc PROTO ((char *, char *, char *, List *, List *));
+static int unedit_fileproc PROTO ((void *callerdat, struct file_info *finfo));
static int
-unedit_fileproc (file, update_dir, repository, entries, srcfiles)
- char *file;
- char *update_dir;
- char *repository;
- List *entries;
- List *srcfiles;
+unedit_fileproc (callerdat, finfo)
+ void *callerdat;
+ struct file_info *finfo;
{
FILE *fp;
time_t now;
@@ -454,10 +465,10 @@ unedit_fileproc (file, update_dir, repository, entries, srcfiles)
if (noexec)
return 0;
- basefilename = xmalloc (10 + sizeof CVSADM_BASE + strlen (file));
+ basefilename = xmalloc (10 + sizeof CVSADM_BASE + strlen (finfo->file));
strcpy (basefilename, CVSADM_BASE);
strcat (basefilename, "/");
- strcat (basefilename, file);
+ strcat (basefilename, finfo->file);
if (!isfile (basefilename))
{
/* This file apparently was never cvs edit'd (e.g. we are uneditting
@@ -466,11 +477,9 @@ unedit_fileproc (file, update_dir, repository, entries, srcfiles)
return 0;
}
- if (xcmp (file, basefilename) != 0)
+ if (xcmp (finfo->file, basefilename) != 0)
{
- if (update_dir[0] != '\0')
- printf ("%s/", update_dir);
- printf ("%s has been modified; revert changes? ", file);
+ printf ("%s has been modified; revert changes? ", finfo->fullname);
if (!yesno ())
{
/* "no". */
@@ -478,7 +487,7 @@ unedit_fileproc (file, update_dir, repository, entries, srcfiles)
return 0;
}
}
- rename_file (basefilename, file);
+ rename_file (basefilename, finfo->file);
free (basefilename);
fp = open_file (CVSADM_NOTIFY, "a");
@@ -486,21 +495,86 @@ unedit_fileproc (file, update_dir, repository, entries, srcfiles)
(void) time (&now);
ascnow = asctime (gmtime (&now));
ascnow[24] = '\0';
- fprintf (fp, "U%s\t%s GMT\t%s\t%s\t\n", file,
+ /* Fix non-standard format. */
+ if (ascnow[8] == '0') ascnow[8] = ' ';
+ fprintf (fp, "U%s\t%s GMT\t%s\t%s\t\n", finfo->file,
ascnow, hostname, CurDir);
if (fclose (fp) < 0)
{
- if (update_dir[0] == '\0')
- error (0, errno, "cannot close %s", file);
+ if (finfo->update_dir[0] == '\0')
+ error (0, errno, "cannot close %s", CVSADM_NOTIFY);
else
- error (0, errno, "cannot close %s/%s", update_dir, file);
+ error (0, errno, "cannot close %s/%s", finfo->update_dir,
+ CVSADM_NOTIFY);
}
- xchmod (file, 0);
+ /* Now update the revision number in CVS/Entries from CVS/Baserev.
+ The basic idea here is that we are reverting to the revision
+ that the user edited. If we wanted "cvs update" to update
+ CVS/Base as we go along (so that an unedit could revert to the
+ current repository revision), we would need:
+
+ update (or all send_files?) (client) needs to send revision in
+ new Entry-base request. update (server/local) needs to check
+ revision against repository and send new Update-base response
+ (like Update-existing in that the file already exists. While
+ we are at it, might try to clean up the syntax by having the
+ mode only in a "Mode" response, not in the Update-base itself). */
+ {
+ char *baserev;
+ Node *node;
+ Entnode *entdata;
+
+ baserev = base_get (finfo);
+ node = findnode_fn (finfo->entries, finfo->file);
+ /* The case where node is NULL probably should be an error or
+ something, but I don't want to think about it too hard right
+ now. */
+ if (node != NULL)
+ {
+ entdata = (Entnode *) node->data;
+ if (baserev == NULL)
+ {
+ /* This can only happen if the CVS/Baserev file got
+ corrupted. We suspect it might be possible if the
+ user interrupts CVS, although I haven't verified
+ that. */
+ error (0, 0, "%s not mentioned in %s", finfo->fullname,
+ CVSADM_BASEREV);
+
+ /* Since we don't know what revision the file derives from,
+ keeping it around would be asking for trouble. */
+ if (unlink_file (finfo->file) < 0)
+ error (0, errno, "cannot remove %s", finfo->fullname);
+
+ /* This is cheesy, in a sense; why shouldn't we do the
+ update for the user? However, doing that would require
+ contacting the server, so maybe this is OK. */
+ error (0, 0, "run update to complete the unedit");
+ return 0;
+ }
+ Register (finfo->entries, finfo->file, baserev, entdata->timestamp,
+ entdata->options, entdata->tag, entdata->date,
+ entdata->conflict);
+ }
+ free (baserev);
+ base_deregister (finfo);
+ }
+
+ xchmod (finfo->file, 0);
return 0;
}
+static const char *const unedit_usage[] =
+{
+ "Usage: %s %s [-lR] [files...]\n",
+ "-l: Local directory only, not recursive\n",
+ "-R: Process directories recursively\n",
+ "(Specify the --help global option for a list of other help options)\n",
+ NULL
+};
+
int
unedit (argc, argv)
int argc;
@@ -511,19 +585,22 @@ unedit (argc, argv)
int err;
if (argc == -1)
- usage (edit_usage);
+ usage (unedit_usage);
- optind = 1;
- while ((c = getopt (argc, argv, "l")) != -1)
+ optind = 0;
+ while ((c = getopt (argc, argv, "+lR")) != -1)
{
switch (c)
{
case 'l':
local = 1;
break;
+ case 'R':
+ local = 0;
+ break;
case '?':
default:
- usage (edit_usage);
+ usage (unedit_usage);
break;
}
}
@@ -533,9 +610,9 @@ unedit (argc, argv)
/* No need to readlock since we aren't doing anything to the
repository. */
err = start_recursion (unedit_fileproc, (FILESDONEPROC) NULL,
- (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL,
+ (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, NULL,
argc, argv, local, W_LOCAL, 0, 0, (char *)NULL,
- 0, 0);
+ 0);
err += send_notifications (argc, argv, local);
@@ -571,14 +648,14 @@ editor_set (filename, editor, val)
edlist = fileattr_get0 (filename, "_editors");
newlist = fileattr_modify (edlist, editor, val, '>', ',');
- if (edlist != NULL)
- free (edlist);
/* If the attributes is unchanged, don't rewrite the attribute file. */
if (!((edlist == NULL && newlist == NULL)
|| (edlist != NULL
&& newlist != NULL
&& strcmp (edlist, newlist) == 0)))
fileattr_set (filename, "_editors", newlist);
+ if (edlist != NULL)
+ free (edlist);
if (newlist != NULL)
free (newlist);
}
@@ -607,6 +684,7 @@ notify_proc (repository, filter)
{
FILE *pipefp;
char *prog;
+ char *expanded_prog;
char *p;
char *q;
char *srepos;
@@ -636,11 +714,21 @@ notify_proc (repository, filter)
}
*q = '\0';
- pipefp = Popen (prog, "w");
+ /* FIXME: why are we calling expand_proc? Didn't we already
+ expand it in Parse_Info, before passing it to notify_proc? */
+ expanded_prog = expand_path (prog, "notify", 0);
+ if (!expanded_prog)
+ {
+ free (prog);
+ return 1;
+ }
+
+ pipefp = run_popen (expanded_prog, "w");
if (pipefp == NULL)
{
error (0, errno, "cannot write entry to notify filter: %s", prog);
free (prog);
+ free (expanded_prog);
return 1;
}
@@ -652,9 +740,13 @@ notify_proc (repository, filter)
logfile_write for inspiration. */
free (prog);
+ free (expanded_prog);
return (pclose (pipefp));
}
+/* FIXME: this function should have a way to report whether there was
+ an error so that server.c can know whether to report Notified back
+ to the client. */
void
notify_do (type, filename, who, val, watches, repository)
int type;
@@ -676,6 +768,11 @@ notify_do (type, filename, who, val, watches, repository)
switch (type)
{
case 'E':
+ if (strpbrk (val, ",>;=\n") != NULL)
+ {
+ error (0, 0, "invalid character in editor value");
+ return;
+ }
editor_set (filename, who, val);
break;
case 'U':
@@ -776,28 +873,35 @@ notify_do (type, filename, who, val, watches, repository)
size_t line_len = 0;
args.notifyee = NULL;
- usersname = xmalloc (strlen (CVSroot)
+ usersname = xmalloc (strlen (current_parsed_root->directory)
+ sizeof CVSROOTADM
+ sizeof CVSROOTADM_USERS
+ 20);
- strcpy (usersname, CVSroot);
+ strcpy (usersname, current_parsed_root->directory);
strcat (usersname, "/");
strcat (usersname, CVSROOTADM);
strcat (usersname, "/");
strcat (usersname, CVSROOTADM_USERS);
- fp = fopen (usersname, "r");
+ fp = CVS_FOPEN (usersname, "r");
if (fp == NULL && !existence_error (errno))
error (0, errno, "cannot read %s", usersname);
if (fp != NULL)
{
- while (getline (&line, &line_len, fp) >= 0)
+ while (get_line (&line, &line_len, fp) >= 0)
{
if (strncmp (line, p, len) == 0
&& line[len] == ':')
{
char *cp;
args.notifyee = xstrdup (line + len + 1);
- cp = strchr (args.notifyee, ':');
+
+ /* There may or may not be more
+ colon-separated fields added to this in the
+ future; in any case, we ignore them right
+ now, and if there are none we make sure to
+ chop off the final newline, if any. */
+ cp = strpbrk (args.notifyee, ":\n");
+
if (cp != NULL)
*cp = '\0';
break;
@@ -809,7 +913,8 @@ notify_do (type, filename, who, val, watches, repository)
error (0, errno, "cannot close %s", usersname);
}
free (usersname);
- free (line);
+ if (line != NULL)
+ free (line);
if (args.notifyee == NULL)
{
@@ -859,6 +964,7 @@ notify_do (type, filename, who, val, watches, repository)
}
}
+#ifdef CLIENT_SUPPORT
/* Check and send notifications. This is only for the client. */
void
notify_check (repository, update_dir)
@@ -878,14 +984,14 @@ notify_check (repository, update_dir)
/* We send notifications even if noexec. I'm not sure which behavior
is most sensible. */
- fp = fopen (CVSADM_NOTIFY, "r");
+ fp = CVS_FOPEN (CVSADM_NOTIFY, "r");
if (fp == NULL)
{
if (!existence_error (errno))
error (0, errno, "cannot open %s", CVSADM_NOTIFY);
return;
}
- while (getline (&line, &line_len, fp) > 0)
+ while (get_line (&line, &line_len, fp) > 0)
{
int notif_type;
char *filename;
@@ -904,7 +1010,8 @@ notify_check (repository, update_dir)
client_notify (repository, update_dir, filename, notif_type, val);
}
-
+ if (line)
+ free (line);
if (ferror (fp))
error (0, errno, "cannot read %s", CVSADM_NOTIFY);
if (fclose (fp) < 0)
@@ -913,56 +1020,55 @@ notify_check (repository, update_dir)
/* Leave the CVSADM_NOTIFY file there, until the server tells us it
has dealt with it. */
}
+#endif /* CLIENT_SUPPORT */
+
static const char *const editors_usage[] =
{
- "Usage: %s %s [files...]\n",
+ "Usage: %s %s [-lR] [files...]\n",
+ "\t-l\tProcess this directory only (not recursive).\n",
+ "\t-R\tProcess directories recursively.\n",
+ "(Specify the --help global option for a list of other help options)\n",
NULL
};
-static int editors_fileproc PROTO ((char *, char *, char *, List *, List *));
+static int editors_fileproc PROTO ((void *callerdat, struct file_info *finfo));
static int
-editors_fileproc (file, update_dir, repository, entries, srcfiles)
- char *file;
- char *update_dir;
- char *repository;
- List *entries;
- List *srcfiles;
+editors_fileproc (callerdat, finfo)
+ void *callerdat;
+ struct file_info *finfo;
{
char *them;
char *p;
- them = fileattr_get0 (file, "_editors");
+ them = fileattr_get0 (finfo->file, "_editors");
if (them == NULL)
return 0;
- if (update_dir[0] == '\0')
- printf ("%s", file);
- else
- printf ("%s/%s", update_dir, file);
+ cvs_output (finfo->fullname, 0);
p = them;
while (1)
{
- putc ('\t', stdout);
+ cvs_output ("\t", 1);
while (*p != '>' && *p != '\0')
- putc (*p++, stdout);
+ cvs_output (p++, 1);
if (*p == '\0')
{
/* Only happens if attribute is misformed. */
- putc ('\n', stdout);
+ cvs_output ("\n", 1);
break;
}
++p;
- putc ('\t', stdout);
+ cvs_output ("\t", 1);
while (1)
{
while (*p != '+' && *p != ',' && *p != '\0')
- putc (*p++, stdout);
+ cvs_output (p++, 1);
if (*p == '\0')
{
- putc ('\n', stdout);
+ cvs_output ("\n", 1);
goto out;
}
if (*p == ',')
@@ -971,11 +1077,12 @@ editors_fileproc (file, update_dir, repository, entries, srcfiles)
break;
}
++p;
- putc ('\t', stdout);
+ cvs_output ("\t", 1);
}
- putc ('\n', stdout);
+ cvs_output ("\n", 1);
}
out:;
+ free (them);
return 0;
}
@@ -990,14 +1097,17 @@ editors (argc, argv)
if (argc == -1)
usage (editors_usage);
- optind = 1;
- while ((c = getopt (argc, argv, "l")) != -1)
+ optind = 0;
+ while ((c = getopt (argc, argv, "+lR")) != -1)
{
switch (c)
{
case 'l':
local = 1;
break;
+ case 'R':
+ local = 0;
+ break;
case '?':
default:
usage (editors_usage);
@@ -1008,25 +1118,22 @@ editors (argc, argv)
argv += optind;
#ifdef CLIENT_SUPPORT
- if (client_active)
+ if (current_parsed_root->isremote)
{
start_server ();
ign_setup ();
if (local)
send_arg ("-l");
- send_file_names (argc, argv);
- /* FIXME: We shouldn't have to send current files, but I'm not sure
- whether it works. So send the files --
- it's slower but it works. */
- send_files (argc, argv, local, 0);
+ send_files (argc, argv, local, 0, SEND_NO_CONTENTS);
+ send_file_names (argc, argv, SEND_EXPAND_WILD);
send_to_server ("editors\012", 0);
return get_responses_and_close ();
}
#endif /* CLIENT_SUPPORT */
return start_recursion (editors_fileproc, (FILESDONEPROC) NULL,
- (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL,
+ (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, NULL,
argc, argv, local, W_LOCAL, 0, 1, (char *)NULL,
- 0, 0);
+ 0);
}
diff --git a/gnu/usr.bin/cvs/src/entries.c b/gnu/usr.bin/cvs/src/entries.c
index f5b40121632..4b8f235199a 100644
--- a/gnu/usr.bin/cvs/src/entries.c
+++ b/gnu/usr.bin/cvs/src/entries.c
@@ -3,7 +3,7 @@
* Copyright (c) 1989-1992, Brian Berliner
*
* You may distribute under the terms of the GNU General Public License as
- * specified in the README file that comes with the CVS 1.4 kit.
+ * specified in the README file that comes with the CVS source distribution.
*
* Entries file to Files file
*
@@ -12,20 +12,76 @@
*/
#include "cvs.h"
+#include "getline.h"
-#ifndef lint
-static const char rcsid[] = "$CVSid: @(#)entries.c 1.44 94/10/07 $";
-USE(rcsid);
-#endif
+static Node *AddEntryNode PROTO((List * list, Entnode *entnode));
+
+static Entnode *fgetentent PROTO((FILE *, char *, int *));
+static int fputentent PROTO((FILE *, Entnode *));
-static Node *AddEntryNode PROTO((List * list, char *name, char *version,
- char *timestamp, char *options, char *tag,
- char *date, char *conflict));
+static Entnode *subdir_record PROTO((int, const char *, const char *));
static FILE *entfile;
static char *entfilename; /* for error messages */
/*
+ * Construct an Entnode
+ */
+static Entnode *Entnode_Create PROTO ((enum ent_type, const char *,
+ const char *, const char *,
+ const char *, const char *,
+ const char *, const char *));
+
+static Entnode *
+Entnode_Create(type, user, vn, ts, options, tag, date, ts_conflict)
+ enum ent_type type;
+ const char *user;
+ const char *vn;
+ const char *ts;
+ const char *options;
+ const char *tag;
+ const char *date;
+ const char *ts_conflict;
+{
+ Entnode *ent;
+
+ /* Note that timestamp and options must be non-NULL */
+ ent = (Entnode *) xmalloc (sizeof (Entnode));
+ ent->type = type;
+ ent->user = xstrdup (user);
+ ent->version = xstrdup (vn);
+ ent->timestamp = xstrdup (ts ? ts : "");
+ ent->options = xstrdup (options ? options : "");
+ ent->tag = xstrdup (tag);
+ ent->date = xstrdup (date);
+ ent->conflict = xstrdup (ts_conflict);
+
+ return ent;
+}
+
+/*
+ * Destruct an Entnode
+ */
+static void Entnode_Destroy PROTO ((Entnode *));
+
+static void
+Entnode_Destroy (ent)
+ Entnode *ent;
+{
+ free (ent->user);
+ free (ent->version);
+ free (ent->timestamp);
+ free (ent->options);
+ if (ent->tag)
+ free (ent->tag);
+ if (ent->date)
+ free (ent->date);
+ if (ent->conflict)
+ free (ent->conflict);
+ free (ent);
+}
+
+/*
* Write out the line associated with a node of an entries file
*/
static int write_ent_proc PROTO ((Node *, void *));
@@ -34,32 +90,16 @@ write_ent_proc (node, closure)
Node *node;
void *closure;
{
- Entnode *p;
+ Entnode *entnode;
- p = (Entnode *) node->data;
- if (fprintf (entfile, "/%s/%s/%s", node->key, p->version,
- p->timestamp) == EOF)
- error (1, errno, "cannot write %s", entfilename);
- if (p->conflict)
- {
- if (fprintf (entfile, "+%s", p->conflict) < 0)
- error (1, errno, "cannot write %s", entfilename);
- }
- if (fprintf (entfile, "/%s/", p->options) < 0)
- error (1, errno, "cannot write %s", entfilename);
+ entnode = (Entnode *) node->data;
- if (p->tag)
- {
- if (fprintf (entfile, "T%s\n", p->tag) < 0)
- error (1, errno, "cannot write %s", entfilename);
- }
- else if (p->date)
- {
- if (fprintf (entfile, "D%s\n", p->date) < 0)
- error (1, errno, "cannot write %s", entfilename);
- }
- else if (fprintf (entfile, "\n") < 0)
+ if (closure != NULL && entnode->type != ENT_FILE)
+ *(int *) closure = 1;
+
+ if (fputentent(entfile, entnode))
error (1, errno, "cannot write %s", entfilename);
+
return (0);
}
@@ -71,10 +111,45 @@ static void
write_entries (list)
List *list;
{
+ int sawdir;
+
+ sawdir = 0;
+
/* open the new one and walk the list writing entries */
entfilename = CVSADM_ENTBAK;
- entfile = open_file (entfilename, "w+");
- (void) walklist (list, write_ent_proc, NULL);
+ entfile = CVS_FOPEN (entfilename, "w+");
+ if (entfile == NULL)
+ {
+ /* Make this a warning, not an error. For example, one user might
+ have checked out a working directory which, for whatever reason,
+ contains an Entries.Log file. A second user, without write access
+ to that working directory, might want to do a "cvs log". The
+ problem rewriting Entries shouldn't affect the ability of "cvs log"
+ to work, although the warning is probably a good idea so that
+ whether Entries gets rewritten is not an inexplicable process. */
+ /* FIXME: should be including update_dir in message. */
+ error (0, errno, "cannot rewrite %s", entfilename);
+
+ /* Now just return. We leave the Entries.Log file around. As far
+ as I know, there is never any data lying around in 'list' that
+ is not in Entries.Log at this time (if there is an error writing
+ Entries.Log that is a separate problem). */
+ return;
+ }
+
+ (void) walklist (list, write_ent_proc, (void *) &sawdir);
+ if (! sawdir)
+ {
+ struct stickydirtag *sdtp;
+
+ /* We didn't write out any directories. Check the list
+ private data to see whether subdirectory information is
+ known. If it is, we need to write out an empty D line. */
+ sdtp = (struct stickydirtag *) list->list->data;
+ if (sdtp == NULL || sdtp->subdirs)
+ if (fprintf (entfile, "D\n") < 0)
+ error (1, errno, "cannot write %s", entfilename);
+ }
if (fclose (entfile) == EOF)
error (1, errno, "error closing %s", entfilename);
@@ -82,7 +157,9 @@ write_entries (list)
rename_file (entfilename, CVSADM_ENT);
/* now, remove the log file */
- unlink_file (CVSADM_ENTLOG);
+ if (unlink_file (CVSADM_ENTLOG) < 0
+ && !existence_error (errno))
+ error (0, errno, "cannot remove %s", CVSADM_ENTLOG);
}
/*
@@ -96,23 +173,32 @@ Scratch_Entry (list, fname)
Node *node;
if (trace)
-#ifdef SERVER_SUPPORT
- (void) fprintf (stderr, "%c-> Scratch_Entry(%s)\n",
- (server_active) ? 'S' : ' ', fname);
-#else
- (void) fprintf (stderr, "-> Scratch_Entry(%s)\n", fname);
-#endif
+ (void) fprintf (stderr, "%s-> Scratch_Entry(%s)\n",
+ CLIENT_SERVER_STR, fname);
/* hashlookup to see if it is there */
- if ((node = findnode (list, fname)) != NULL)
+ if ((node = findnode_fn (list, fname)) != NULL)
{
+ if (!noexec)
+ {
+ entfilename = CVSADM_ENTLOG;
+ entfile = open_file (entfilename, "a");
+
+ if (fprintf (entfile, "R ") < 0)
+ error (1, errno, "cannot write %s", entfilename);
+
+ write_ent_proc (node, NULL);
+
+ if (fclose (entfile) == EOF)
+ error (1, errno, "error closing %s", entfilename);
+ }
+
delnode (node); /* delete the node */
+
#ifdef SERVER_SUPPORT
if (server_active)
server_scratch (fname);
#endif
- if (!noexec)
- write_entries (list); /* re-write the file */
}
}
@@ -131,6 +217,7 @@ Register (list, fname, vn, ts, options, tag, date, ts_conflict)
char *date;
char *ts_conflict;
{
+ Entnode *entnode;
Node *node;
#ifdef SERVER_SUPPORT
@@ -142,30 +229,37 @@ Register (list, fname, vn, ts, options, tag, date, ts_conflict)
if (trace)
{
-#ifdef SERVER_SUPPORT
- (void) fprintf (stderr, "%c-> Register(%s, %s, %s%s%s, %s, %s %s)\n",
- (server_active) ? 'S' : ' ',
- fname, vn, ts ? ts : "",
- ts_conflict ? "+" : "", ts_conflict ? ts_conflict : "",
- options, tag ? tag : "", date ? date : "");
-#else
- (void) fprintf (stderr, "-> Register(%s, %s, %s%s%s, %s, %s %s)\n",
+ (void) fprintf (stderr, "%s-> Register(%s, %s, %s%s%s, %s, %s %s)\n",
+ CLIENT_SERVER_STR,
fname, vn, ts ? ts : "",
ts_conflict ? "+" : "", ts_conflict ? ts_conflict : "",
options, tag ? tag : "", date ? date : "");
-#endif
}
- node = AddEntryNode (list, fname, vn, ts, options, tag, date, ts_conflict);
+ entnode = Entnode_Create (ENT_FILE, fname, vn, ts, options, tag, date,
+ ts_conflict);
+ node = AddEntryNode (list, entnode);
if (!noexec)
{
- entfile = open_file (CVSADM_ENTLOG, "a");
-
+ entfilename = CVSADM_ENTLOG;
+ entfile = CVS_FOPEN (entfilename, "a");
+
+ if (entfile == NULL)
+ {
+ /* Warning, not error, as in write_entries. */
+ /* FIXME-update-dir: should be including update_dir in message. */
+ error (0, errno, "cannot open %s", entfilename);
+ return;
+ }
+
+ if (fprintf (entfile, "A ") < 0)
+ error (1, errno, "cannot write %s", entfilename);
+
write_ent_proc (node, NULL);
if (fclose (entfile) == EOF)
- error (1, errno, "error closing %s", CVSADM_ENTLOG);
+ error (1, errno, "error closing %s", entfilename);
}
}
@@ -183,37 +277,66 @@ freesdt (p)
free (sdtp->tag);
if (sdtp->date)
free (sdtp->date);
- if (sdtp->options)
- free (sdtp->options);
free ((char *) sdtp);
}
-struct entent {
- char *user;
- char *vn;
- char *ts;
- char *options;
- char *tag;
- char *date;
- char *ts_conflict;
-};
+/* Return the next real Entries line. On end of file, returns NULL.
+ On error, prints an error message and returns NULL. */
-struct entent *
-fgetentent(fpin)
+static Entnode *
+fgetentent(fpin, cmd, sawdir)
FILE *fpin;
+ char *cmd;
+ int *sawdir;
{
- static struct entent ent;
- static char line[MAXLINELEN];
+ Entnode *ent;
+ char *line;
+ size_t line_chars_allocated;
register char *cp;
- char *user, *vn, *ts, *options;
+ enum ent_type type;
+ char *l, *user, *vn, *ts, *options;
char *tag_or_date, *tag, *date, *ts_conflict;
+ int line_length;
+
+ line = NULL;
+ line_chars_allocated = 0;
- while (fgets (line, sizeof (line), fpin) != NULL)
+ ent = NULL;
+ while ((line_length = get_line (&line, &line_chars_allocated, fpin)) > 0)
{
- if (line[0] != '/')
+ l = line;
+
+ /* If CMD is not NULL, we are reading an Entries.Log file.
+ Each line in the Entries.Log file starts with a single
+ character command followed by a space. For backward
+ compatibility, the absence of a space indicates an add
+ command. */
+ if (cmd != NULL)
+ {
+ if (l[1] != ' ')
+ *cmd = 'A';
+ else
+ {
+ *cmd = l[0];
+ l += 2;
+ }
+ }
+
+ type = ENT_FILE;
+
+ if (l[0] == 'D')
+ {
+ type = ENT_SUBDIR;
+ *sawdir = 1;
+ ++l;
+ /* An empty D line is permitted; it is a signal that this
+ Entries file lists all known subdirectories. */
+ }
+
+ if (l[0] != '/')
continue;
- user = line + 1;
+ user = l + 1;
if ((cp = strchr (user, '/')) == NULL)
continue;
*cp++ = '\0';
@@ -239,7 +362,7 @@ fgetentent(fpin)
tag = tag_or_date + 1;
else if (*tag_or_date == 'D')
date = tag_or_date + 1;
-
+
if ((ts_conflict = strchr (ts, '+')))
*ts_conflict++ = '\0';
@@ -255,11 +378,12 @@ fgetentent(fpin)
*/
{
struct stat sb;
- if (strlen (ts) > 30 && stat (user, &sb) == 0)
+ if (strlen (ts) > 30 && CVS_STAT (user, &sb) == 0)
{
- extern char *ctime ();
char *c = ctime (&sb.st_mtime);
-
+ /* Fix non-standard format. */
+ if (c[8] == '0') c[8] = ' ';
+
if (!strncmp (ts + 25, c, 24))
ts = time_stamp (user);
else
@@ -270,33 +394,81 @@ fgetentent(fpin)
}
}
- ent.user = user;
- ent.vn = vn;
- ent.ts = ts;
- ent.options = options;
- ent.tag = tag;
- ent.date = date;
- ent.ts_conflict = ts_conflict;
+ ent = Entnode_Create (type, user, vn, ts, options, tag, date,
+ ts_conflict);
+ break;
+ }
+
+ if (line_length < 0 && !feof (fpin))
+ error (0, errno, "cannot read entries file");
+
+ free (line);
+ return ent;
+}
+
+static int
+fputentent(fp, p)
+ FILE *fp;
+ Entnode *p;
+{
+ switch (p->type)
+ {
+ case ENT_FILE:
+ break;
+ case ENT_SUBDIR:
+ if (fprintf (fp, "D") < 0)
+ return 1;
+ break;
+ }
+
+ if (fprintf (fp, "/%s/%s/%s", p->user, p->version, p->timestamp) < 0)
+ return 1;
+ if (p->conflict)
+ {
+ if (fprintf (fp, "+%s", p->conflict) < 0)
+ return 1;
+ }
+ if (fprintf (fp, "/%s/", p->options) < 0)
+ return 1;
- return &ent;
+ if (p->tag)
+ {
+ if (fprintf (fp, "T%s\n", p->tag) < 0)
+ return 1;
+ }
+ else if (p->date)
+ {
+ if (fprintf (fp, "D%s\n", p->date) < 0)
+ return 1;
+ }
+ else
+ {
+ if (fprintf (fp, "\n") < 0)
+ return 1;
}
- return NULL;
+ return 0;
}
-/*
- * Read the entries file into a list, hashing on the file name.
- */
+/* Read the entries file into a list, hashing on the file name.
+
+ UPDATE_DIR is the name of the current directory, for use in error
+ messages, or NULL if not known (that is, noone has gotten around
+ to updating the caller to pass in the information). */
List *
-Entries_Open (aflag)
+Entries_Open (aflag, update_dir)
int aflag;
+ char *update_dir;
{
List *entries;
- struct entent *ent;
+ struct stickydirtag *sdtp = NULL;
+ Entnode *ent;
char *dirtag, *dirdate;
+ int dirnonbranch;
int do_rewrite = 0;
FILE *fpin;
+ int sawdir;
/* get a fresh list... */
entries = getlist ();
@@ -305,65 +477,90 @@ Entries_Open (aflag)
* Parse the CVS/Tag file, to get any default tag/date settings. Use
* list-private storage to tuck them away for Version_TS().
*/
- ParseTag (&dirtag, &dirdate);
+ ParseTag (&dirtag, &dirdate, &dirnonbranch);
if (aflag || dirtag || dirdate)
{
- struct stickydirtag *sdtp;
-
sdtp = (struct stickydirtag *) xmalloc (sizeof (*sdtp));
memset ((char *) sdtp, 0, sizeof (*sdtp));
sdtp->aflag = aflag;
sdtp->tag = xstrdup (dirtag);
sdtp->date = xstrdup (dirdate);
+ sdtp->nonbranch = dirnonbranch;
/* feed it into the list-private area */
entries->list->data = (char *) sdtp;
entries->list->delproc = freesdt;
}
- fpin = fopen (CVSADM_ENT, "r");
+ sawdir = 0;
+
+ fpin = CVS_FOPEN (CVSADM_ENT, "r");
if (fpin == NULL)
+ {
+ if (update_dir != NULL)
+ error (0, 0, "in directory %s:", update_dir);
error (0, errno, "cannot open %s for reading", CVSADM_ENT);
+ }
else
{
- while ((ent = fgetentent (fpin)) != NULL)
+ while ((ent = fgetentent (fpin, (char *) NULL, &sawdir)) != NULL)
{
- (void) AddEntryNode (entries,
- ent->user,
- ent->vn,
- ent->ts,
- ent->options,
- ent->tag,
- ent->date,
- ent->ts_conflict);
+ (void) AddEntryNode (entries, ent);
}
- fclose (fpin);
+ if (fclose (fpin) < 0)
+ /* FIXME-update-dir: should include update_dir in message. */
+ error (0, errno, "cannot close %s", CVSADM_ENT);
}
- fpin = fopen (CVSADM_ENTLOG, "r");
- if (fpin != NULL) {
- while ((ent = fgetentent (fpin)) != NULL)
+ fpin = CVS_FOPEN (CVSADM_ENTLOG, "r");
+ if (fpin != NULL)
+ {
+ char cmd;
+ Node *node;
+
+ while ((ent = fgetentent (fpin, &cmd, &sawdir)) != NULL)
{
- (void) AddEntryNode (entries,
- ent->user,
- ent->vn,
- ent->ts,
- ent->options,
- ent->tag,
- ent->date,
- ent->ts_conflict);
+ switch (cmd)
+ {
+ case 'A':
+ (void) AddEntryNode (entries, ent);
+ break;
+ case 'R':
+ node = findnode_fn (entries, ent->user);
+ if (node != NULL)
+ delnode (node);
+ Entnode_Destroy (ent);
+ break;
+ default:
+ /* Ignore unrecognized commands. */
+ break;
+ }
}
do_rewrite = 1;
- fclose (fpin);
+ if (fclose (fpin) < 0)
+ /* FIXME-update-dir: should include update_dir in message. */
+ error (0, errno, "cannot close %s", CVSADM_ENTLOG);
+ }
+
+ /* Update the list private data to indicate whether subdirectory
+ information is known. Nonexistent list private data is taken
+ to mean that it is known. */
+ if (sdtp != NULL)
+ sdtp->subdirs = sawdir;
+ else if (! sawdir)
+ {
+ sdtp = (struct stickydirtag *) xmalloc (sizeof (*sdtp));
+ memset ((char *) sdtp, 0, sizeof (*sdtp));
+ sdtp->subdirs = 0;
+ entries->list->data = (char *) sdtp;
+ entries->list->delproc = freesdt;
}
if (do_rewrite && !noexec)
write_entries (entries);
/* clean up and return */
- if (fpin)
- (void) fclose (fpin);
if (dirtag)
free (dirtag);
if (dirdate)
@@ -398,16 +595,7 @@ Entries_delproc (node)
Entnode *p;
p = (Entnode *) node->data;
- free (p->version);
- free (p->timestamp);
- free (p->options);
- if (p->tag)
- free (p->tag);
- if (p->date)
- free (p->date);
- if (p->conflict)
- free (p->conflict);
- free ((char *) p);
+ Entnode_Destroy(p);
}
/*
@@ -415,21 +603,14 @@ Entries_delproc (node)
* list
*/
static Node *
-AddEntryNode (list, name, version, timestamp, options, tag, date, conflict)
+AddEntryNode (list, entdata)
List *list;
- char *name;
- char *version;
- char *timestamp;
- char *options;
- char *tag;
- char *date;
- char *conflict;
+ Entnode *entdata;
{
Node *p;
- Entnode *entdata;
/* was it already there? */
- if ((p = findnode (list, name)) != NULL)
+ if ((p = findnode_fn (list, entdata->user)) != NULL)
{
/* take it out */
delnode (p);
@@ -441,21 +622,11 @@ AddEntryNode (list, name, version, timestamp, options, tag, date, conflict)
p->delproc = Entries_delproc;
/* this one gets a key of the name for hashing */
- p->key = xstrdup (name);
-
- /* malloc the data parts and fill them in */
- p->data = xmalloc (sizeof (Entnode));
- entdata = (Entnode *) p->data;
- entdata->version = xstrdup (version);
- entdata->timestamp = xstrdup (timestamp);
- if (entdata->timestamp == NULL)
- entdata->timestamp = xstrdup ("");/* must be non-NULL */
- entdata->options = xstrdup (options);
- if (entdata->options == NULL)
- entdata->options = xstrdup ("");/* must be non-NULL */
- entdata->conflict = xstrdup (conflict);
- entdata->tag = xstrdup (tag);
- entdata->date = xstrdup (date);
+ /* FIXME This results in duplicated data --- the hash package shouldn't
+ assume that the key is dynamically allocated. The user's free proc
+ should be responsible for freeing the key. */
+ p->key = xstrdup (entdata->user);
+ p->data = (char *) entdata;
/* put the node into the list */
addnode (list, p);
@@ -466,17 +637,23 @@ AddEntryNode (list, name, version, timestamp, options, tag, date, conflict)
* Write out/Clear the CVS/Tag file.
*/
void
-WriteTag (dir, tag, date)
+WriteTag (dir, tag, date, nonbranch, update_dir, repository)
char *dir;
char *tag;
char *date;
+ int nonbranch;
+ char *update_dir;
+ char *repository;
{
FILE *fout;
- char tmp[PATH_MAX];
+ char *tmp;
if (noexec)
return;
+ tmp = xmalloc ((dir ? strlen (dir) : 0)
+ + sizeof (CVSADM_TAG)
+ + 10);
if (dir == NULL)
(void) strcpy (tmp, CVSADM_TAG);
else
@@ -487,8 +664,16 @@ WriteTag (dir, tag, date)
fout = open_file (tmp, "w+");
if (tag)
{
- if (fprintf (fout, "T%s\n", tag) < 0)
- error (1, errno, "write to %s failed", tmp);
+ if (nonbranch)
+ {
+ if (fprintf (fout, "N%s\n", tag) < 0)
+ error (1, errno, "write to %s failed", tmp);
+ }
+ else
+ {
+ if (fprintf (fout, "T%s\n", tag) < 0)
+ error (1, errno, "write to %s failed", tmp);
+ }
}
else
{
@@ -499,38 +684,504 @@ WriteTag (dir, tag, date)
error (1, errno, "cannot close %s", tmp);
}
else
- if (unlink_file (tmp) < 0 && errno != ENOENT)
+ if (unlink_file (tmp) < 0 && ! existence_error (errno))
error (1, errno, "cannot remove %s", tmp);
+ free (tmp);
+#ifdef SERVER_SUPPORT
+ if (server_active)
+ server_set_sticky (update_dir, repository, tag, date, nonbranch);
+#endif
}
-/*
- * Parse the CVS/Tag file for the current directory.
- */
+/* Parse the CVS/Tag file for the current directory.
+
+ If it contains a date, sets *DATEP to the date in a newly malloc'd
+ string, *TAGP to NULL, and *NONBRANCHP to an unspecified value.
+
+ If it contains a branch tag, sets *TAGP to the tag in a newly
+ malloc'd string, *NONBRANCHP to 0, and *DATEP to NULL.
+
+ If it contains a nonbranch tag, sets *TAGP to the tag in a newly
+ malloc'd string, *NONBRANCHP to 1, and *DATEP to NULL.
+
+ If it does not exist, or contains something unrecognized by this
+ version of CVS, set *DATEP and *TAGP to NULL and *NONBRANCHP to
+ an unspecified value.
+
+ If there is an error, print an error message, set *DATEP and *TAGP
+ to NULL, and return. */
void
-ParseTag (tagp, datep)
+ParseTag (tagp, datep, nonbranchp)
char **tagp;
char **datep;
+ int *nonbranchp;
{
FILE *fp;
- char line[MAXLINELEN];
- char *cp;
if (tagp)
*tagp = (char *) NULL;
if (datep)
*datep = (char *) NULL;
- fp = fopen (CVSADM_TAG, "r");
+ /* Always store a value here, even in the 'D' case where the value
+ is unspecified. Shuts up tools which check for references to
+ uninitialized memory. */
+ if (nonbranchp != NULL)
+ *nonbranchp = 0;
+ fp = CVS_FOPEN (CVSADM_TAG, "r");
if (fp)
{
- if (fgets (line, sizeof (line), fp) != NULL)
+ char *line;
+ int line_length;
+ size_t line_chars_allocated;
+
+ line = NULL;
+ line_chars_allocated = 0;
+
+ if ((line_length = get_line (&line, &line_chars_allocated, fp)) > 0)
+ {
+ /* Remove any trailing newline. */
+ if (line[line_length - 1] == '\n')
+ line[--line_length] = '\0';
+ switch (*line)
+ {
+ case 'T':
+ if (tagp != NULL)
+ *tagp = xstrdup (line + 1);
+ break;
+ case 'D':
+ if (datep != NULL)
+ *datep = xstrdup (line + 1);
+ break;
+ case 'N':
+ if (tagp != NULL)
+ *tagp = xstrdup (line + 1);
+ if (nonbranchp != NULL)
+ *nonbranchp = 1;
+ break;
+ default:
+ /* Silently ignore it; it may have been
+ written by a future version of CVS which extends the
+ syntax. */
+ break;
+ }
+ }
+
+ if (line_length < 0)
+ {
+ /* FIXME-update-dir: should include update_dir in messages. */
+ if (feof (fp))
+ error (0, 0, "cannot read %s: end of file", CVSADM_TAG);
+ else
+ error (0, errno, "cannot read %s", CVSADM_TAG);
+ }
+
+ if (fclose (fp) < 0)
+ /* FIXME-update-dir: should include update_dir in message. */
+ error (0, errno, "cannot close %s", CVSADM_TAG);
+
+ free (line);
+ }
+ else if (!existence_error (errno))
+ /* FIXME-update-dir: should include update_dir in message. */
+ error (0, errno, "cannot open %s", CVSADM_TAG);
+}
+
+/*
+ * This is called if all subdirectory information is known, but there
+ * aren't any subdirectories. It records that fact in the list
+ * private data.
+ */
+
+void
+Subdirs_Known (entries)
+ List *entries;
+{
+ struct stickydirtag *sdtp;
+
+ /* If there is no list private data, that means that the
+ subdirectory information is known. */
+ sdtp = (struct stickydirtag *) entries->list->data;
+ if (sdtp != NULL && ! sdtp->subdirs)
+ {
+ FILE *fp;
+
+ sdtp->subdirs = 1;
+ if (!noexec)
{
- if ((cp = strrchr (line, '\n')) != NULL)
- *cp = '\0';
- if (*line == 'T' && tagp)
- *tagp = xstrdup (line + 1);
- else if (*line == 'D' && datep)
- *datep = xstrdup (line + 1);
+ /* Create Entries.Log so that Entries_Close will do something. */
+ entfilename = CVSADM_ENTLOG;
+ fp = CVS_FOPEN (entfilename, "a");
+ if (fp == NULL)
+ {
+ int save_errno = errno;
+
+ /* As in subdir_record, just silently skip the whole thing
+ if there is no CVSADM directory. */
+ if (! isdir (CVSADM))
+ return;
+ error (1, save_errno, "cannot open %s", entfilename);
+ }
+ else
+ {
+ if (fclose (fp) == EOF)
+ error (1, errno, "cannot close %s", entfilename);
+ }
}
- (void) fclose (fp);
}
}
+
+/* Record subdirectory information. */
+
+static Entnode *
+subdir_record (cmd, parent, dir)
+ int cmd;
+ const char *parent;
+ const char *dir;
+{
+ Entnode *entnode;
+
+ /* None of the information associated with a directory is
+ currently meaningful. */
+ entnode = Entnode_Create (ENT_SUBDIR, dir, "", "", "",
+ (char *) NULL, (char *) NULL,
+ (char *) NULL);
+
+ if (!noexec)
+ {
+ if (parent == NULL)
+ entfilename = CVSADM_ENTLOG;
+ else
+ {
+ entfilename = xmalloc (strlen (parent)
+ + sizeof CVSADM_ENTLOG
+ + 10);
+ sprintf (entfilename, "%s/%s", parent, CVSADM_ENTLOG);
+ }
+
+ entfile = CVS_FOPEN (entfilename, "a");
+ if (entfile == NULL)
+ {
+ int save_errno = errno;
+
+ /* It is not an error if there is no CVS administration
+ directory. Permitting this case simplifies some
+ calling code. */
+
+ if (parent == NULL)
+ {
+ if (! isdir (CVSADM))
+ return entnode;
+ }
+ else
+ {
+ sprintf (entfilename, "%s/%s", parent, CVSADM);
+ if (! isdir (entfilename))
+ {
+ free (entfilename);
+ entfilename = NULL;
+ return entnode;
+ }
+ }
+
+ error (1, save_errno, "cannot open %s", entfilename);
+ }
+
+ if (fprintf (entfile, "%c ", cmd) < 0)
+ error (1, errno, "cannot write %s", entfilename);
+
+ if (fputentent (entfile, entnode) != 0)
+ error (1, errno, "cannot write %s", entfilename);
+
+ if (fclose (entfile) == EOF)
+ error (1, errno, "error closing %s", entfilename);
+
+ if (parent != NULL)
+ {
+ free (entfilename);
+ entfilename = NULL;
+ }
+ }
+
+ return entnode;
+}
+
+/*
+ * Record the addition of a new subdirectory DIR in PARENT. PARENT
+ * may be NULL, which means the current directory. ENTRIES is the
+ * current entries list; it may be NULL, which means that it need not
+ * be updated.
+ */
+
+void
+Subdir_Register (entries, parent, dir)
+ List *entries;
+ const char *parent;
+ const char *dir;
+{
+ Entnode *entnode;
+
+ /* Ignore attempts to register ".". These can happen in the
+ server code. */
+ if (dir[0] == '.' && dir[1] == '\0')
+ return;
+
+ entnode = subdir_record ('A', parent, dir);
+
+ if (entries != NULL && (parent == NULL || strcmp (parent, ".") == 0))
+ (void) AddEntryNode (entries, entnode);
+ else
+ Entnode_Destroy (entnode);
+}
+
+/*
+ * Record the removal of a subdirectory. The arguments are the same
+ * as for Subdir_Register.
+ */
+
+void
+Subdir_Deregister (entries, parent, dir)
+ List *entries;
+ const char *parent;
+ const char *dir;
+{
+ Entnode *entnode;
+
+ entnode = subdir_record ('R', parent, dir);
+ Entnode_Destroy (entnode);
+
+ if (entries != NULL && (parent == NULL || strcmp (parent, ".") == 0))
+ {
+ Node *p;
+
+ p = findnode_fn (entries, dir);
+ if (p != NULL)
+ delnode (p);
+ }
+}
+
+
+
+/* OK, the following base_* code tracks the revisions of the files in
+ CVS/Base. We do this in a file CVS/Baserev. Separate from
+ CVS/Entries because it needs to go in separate data structures
+ anyway (the name in Entries must be unique), so this seemed
+ cleaner. The business of rewriting the whole file in
+ base_deregister and base_register is the kind of thing we used to
+ do for Entries and which turned out to be slow, which is why there
+ is now the Entries.Log machinery. So maybe from that point of
+ view it is a mistake to do this separately from Entries, I dunno.
+
+ We also need something analogous for:
+
+ 1. CVS/Template (so we can update the Template file automagically
+ without the user needing to check out a new working directory).
+ Updating would probably print a message (that part might be
+ optional, although probably it should be visible because not all
+ cvs commands would make the update happen and so it is a
+ user-visible behavior). Constructing version number for template
+ is a bit hairy (base it on the timestamp on the server? Or see if
+ the template is in checkoutlist and if yes use its versioning and
+ if no don't version it?)....
+
+ 2. cvsignore (need to keep a copy in the working directory to do
+ "cvs release" on the client side; see comment at src/release.c
+ (release). Would also allow us to stop needing Questionable. */
+
+enum base_walk {
+ /* Set the revision for FILE to *REV. */
+ BASE_REGISTER,
+ /* Get the revision for FILE and put it in a newly malloc'd string
+ in *REV, or put NULL if not mentioned. */
+ BASE_GET,
+ /* Remove FILE. */
+ BASE_DEREGISTER
+};
+
+static void base_walk PROTO ((enum base_walk, struct file_info *, char **));
+
+/* Read through the lines in CVS/Baserev, taking the actions as documented
+ for CODE. */
+
+static void
+base_walk (code, finfo, rev)
+ enum base_walk code;
+ struct file_info *finfo;
+ char **rev;
+{
+ FILE *fp;
+ char *line;
+ size_t line_allocated;
+ FILE *newf;
+ char *baserev_fullname;
+ char *baserevtmp_fullname;
+
+ line = NULL;
+ line_allocated = 0;
+ newf = NULL;
+
+ /* First compute the fullnames for the error messages. This
+ computation probably should be broken out into a separate function,
+ as recurse.c does it too and places like Entries_Open should be
+ doing it. */
+ baserev_fullname = xmalloc (sizeof (CVSADM_BASEREV)
+ + strlen (finfo->update_dir)
+ + 2);
+ baserev_fullname[0] = '\0';
+ baserevtmp_fullname = xmalloc (sizeof (CVSADM_BASEREVTMP)
+ + strlen (finfo->update_dir)
+ + 2);
+ baserevtmp_fullname[0] = '\0';
+ if (finfo->update_dir[0] != '\0')
+ {
+ strcat (baserev_fullname, finfo->update_dir);
+ strcat (baserev_fullname, "/");
+ strcat (baserevtmp_fullname, finfo->update_dir);
+ strcat (baserevtmp_fullname, "/");
+ }
+ strcat (baserev_fullname, CVSADM_BASEREV);
+ strcat (baserevtmp_fullname, CVSADM_BASEREVTMP);
+
+ fp = CVS_FOPEN (CVSADM_BASEREV, "r");
+ if (fp == NULL)
+ {
+ if (!existence_error (errno))
+ {
+ error (0, errno, "cannot open %s for reading", baserev_fullname);
+ goto out;
+ }
+ }
+
+ switch (code)
+ {
+ case BASE_REGISTER:
+ case BASE_DEREGISTER:
+ newf = CVS_FOPEN (CVSADM_BASEREVTMP, "w");
+ if (newf == NULL)
+ {
+ error (0, errno, "cannot open %s for writing",
+ baserevtmp_fullname);
+ goto out;
+ }
+ break;
+ case BASE_GET:
+ *rev = NULL;
+ break;
+ }
+
+ if (fp != NULL)
+ {
+ while (get_line (&line, &line_allocated, fp) >= 0)
+ {
+ char *linefile;
+ char *p;
+ char *linerev;
+
+ if (line[0] != 'B')
+ /* Ignore, for future expansion. */
+ continue;
+
+ linefile = line + 1;
+ p = strchr (linefile, '/');
+ if (p == NULL)
+ /* Syntax error, ignore. */
+ continue;
+ linerev = p + 1;
+ p = strchr (linerev, '/');
+ if (p == NULL)
+ continue;
+
+ linerev[-1] = '\0';
+ if (fncmp (linefile, finfo->file) == 0)
+ {
+ switch (code)
+ {
+ case BASE_REGISTER:
+ case BASE_DEREGISTER:
+ /* Don't copy over the old entry, we don't want it. */
+ break;
+ case BASE_GET:
+ *p = '\0';
+ *rev = xstrdup (linerev);
+ *p = '/';
+ goto got_it;
+ }
+ }
+ else
+ {
+ linerev[-1] = '/';
+ switch (code)
+ {
+ case BASE_REGISTER:
+ case BASE_DEREGISTER:
+ if (fprintf (newf, "%s\n", line) < 0)
+ error (0, errno, "error writing %s",
+ baserevtmp_fullname);
+ break;
+ case BASE_GET:
+ break;
+ }
+ }
+ }
+ if (ferror (fp))
+ error (0, errno, "cannot read %s", baserev_fullname);
+ }
+ got_it:
+
+ if (code == BASE_REGISTER)
+ {
+ if (fprintf (newf, "B%s/%s/\n", finfo->file, *rev) < 0)
+ error (0, errno, "error writing %s",
+ baserevtmp_fullname);
+ }
+
+ out:
+
+ if (line != NULL)
+ free (line);
+
+ if (fp != NULL)
+ {
+ if (fclose (fp) < 0)
+ error (0, errno, "cannot close %s", baserev_fullname);
+ }
+ if (newf != NULL)
+ {
+ if (fclose (newf) < 0)
+ error (0, errno, "cannot close %s", baserevtmp_fullname);
+ rename_file (CVSADM_BASEREVTMP, CVSADM_BASEREV);
+ }
+
+ free (baserev_fullname);
+ free (baserevtmp_fullname);
+}
+
+/* Return, in a newly malloc'd string, the revision for FILE in CVS/Baserev,
+ or NULL if not listed. */
+
+char *
+base_get (finfo)
+ struct file_info *finfo;
+{
+ char *rev;
+ base_walk (BASE_GET, finfo, &rev);
+ return rev;
+}
+
+/* Set the revision for FILE to REV. */
+
+void
+base_register (finfo, rev)
+ struct file_info *finfo;
+ char *rev;
+{
+ base_walk (BASE_REGISTER, finfo, &rev);
+}
+
+/* Remove FILE. */
+
+void
+base_deregister (finfo)
+ struct file_info *finfo;
+{
+ base_walk (BASE_DEREGISTER, finfo, NULL);
+}
diff --git a/gnu/usr.bin/cvs/src/fileattr.c b/gnu/usr.bin/cvs/src/fileattr.c
index 44987006bc8..24eda660cc0 100644
--- a/gnu/usr.bin/cvs/src/fileattr.c
+++ b/gnu/usr.bin/cvs/src/fileattr.c
@@ -8,11 +8,7 @@
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+ GNU General Public License for more details. */
#include "cvs.h"
#include "getline.h"
@@ -35,6 +31,14 @@ static int attr_read_attempted;
/* Have the in-memory attributes been modified since we read them? */
static int attrs_modified;
+/* More in-memory attributes: linked list of unrecognized
+ fileattr lines. We pass these on unchanged. */
+struct unrecog {
+ char *line;
+ struct unrecog *next;
+};
+static struct unrecog *unrecog_head;
+
/* Note that if noone calls fileattr_get, this is very cheap. No stat(),
no open(), no nothing. */
void
@@ -45,13 +49,16 @@ fileattr_startdir (repos)
fileattr_stored_repos = xstrdup (repos);
assert (attrlist == NULL);
attr_read_attempted = 0;
+ assert (unrecog_head == NULL);
}
static void
fileattr_delproc (node)
Node *node;
{
+ assert (node->data != NULL);
free (node->data);
+ node->data = NULL;
}
/* Read all the attributes for the current directory into memory. */
@@ -82,7 +89,7 @@ fileattr_read ()
strcat (fname, CVSREP_FILEATTR);
attr_read_attempted = 1;
- fp = fopen (fname, "r");
+ fp = CVS_FOPEN (fname, FOPEN_BINARY_READ);
if (fp == NULL)
{
if (!existence_error (errno))
@@ -93,7 +100,7 @@ fileattr_read ()
attrlist = getlist ();
while (1) {
int nread;
- nread = getline (&line, &line_len, fp);
+ nread = get_line (&line, &line_len, fp);
if (nread < 0)
break;
/* Remove trailing newline. */
@@ -104,13 +111,22 @@ fileattr_read ()
Node *newnode;
p = strchr (line, '\t');
+ if (p == NULL)
+ error (1, 0,
+ "file attribute database corruption: tab missing in %s",
+ fname);
*p++ = '\0';
newnode = getnode ();
newnode->type = FILEATTR;
newnode->delproc = fileattr_delproc;
newnode->key = xstrdup (line + 1);
newnode->data = xstrdup (p);
- addnode (attrlist, newnode);
+ if (addnode (attrlist, newnode) != 0)
+ /* If the same filename appears twice in the file, discard
+ any line other than the first for that filename. This
+ is the way that CVS has behaved since file attributes
+ were first introduced. */
+ freenode (newnode);
}
else if (line[0] == 'D')
{
@@ -118,10 +134,24 @@ fileattr_read ()
/* Currently nothing to skip here, but for future expansion,
ignore anything located here. */
p = strchr (line, '\t');
+ if (p == NULL)
+ error (1, 0,
+ "file attribute database corruption: tab missing in %s",
+ fname);
++p;
fileattr_default_attrs = xstrdup (p);
}
- /* else just ignore the line, for future expansion. */
+ else
+ {
+ /* Unrecognized type, we want to just preserve the line without
+ changing it, for future expansion. */
+ struct unrecog *new;
+
+ new = (struct unrecog *) xmalloc (sizeof (struct unrecog));
+ new->line = xstrdup (line);
+ new->next = unrecog_head;
+ unrecog_head = new;
+ }
}
if (ferror (fp))
error (0, errno, "cannot read %s", fname);
@@ -135,8 +165,8 @@ fileattr_read ()
char *
fileattr_get (filename, attrname)
- char *filename;
- char *attrname;
+ const char *filename;
+ const char *attrname;
{
Node *node;
size_t attrname_len = strlen (attrname);
@@ -149,12 +179,18 @@ fileattr_get (filename, attrname)
an error message. */
return NULL;
- node = findnode (attrlist, filename);
- if (node == NULL)
- /* A file not mentioned has no attributes. */
- return NULL;
- p = node->data;
- while (1) {
+ if (filename == NULL)
+ p = fileattr_default_attrs;
+ else
+ {
+ node = findnode (attrlist, filename);
+ if (node == NULL)
+ /* A file not mentioned has no attributes. */
+ return NULL;
+ p = node->data;
+ }
+ while (p)
+ {
if (strncmp (attrname, p, attrname_len) == 0
&& p[attrname_len] == '=')
{
@@ -172,8 +208,8 @@ fileattr_get (filename, attrname)
char *
fileattr_get0 (filename, attrname)
- char *filename;
- char *attrname;
+ const char *filename;
+ const char *attrname;
{
char *cp;
char *cpend;
@@ -194,8 +230,8 @@ fileattr_get0 (filename, attrname)
char *
fileattr_modify (list, attrname, attrval, namevalsep, entsep)
char *list;
- char *attrname;
- char *attrval;
+ const char *attrname;
+ const char *attrval;
int namevalsep;
int entsep;
{
@@ -290,15 +326,13 @@ fileattr_modify (list, attrname, attrval, namevalsep, entsep)
void
fileattr_set (filename, attrname, attrval)
- char *filename;
- char *attrname;
- char *attrval;
+ const char *filename;
+ const char *attrname;
+ const char *attrval;
{
Node *node;
char *p;
- attrs_modified = 1;
-
if (filename == NULL)
{
p = fileattr_modify (fileattr_default_attrs, attrname, attrval,
@@ -306,6 +340,7 @@ fileattr_set (filename, attrname, attrval)
if (fileattr_default_attrs != NULL)
free (fileattr_default_attrs);
fileattr_default_attrs = p;
+ attrs_modified = 1;
return;
}
if (attrlist == NULL)
@@ -338,16 +373,100 @@ fileattr_set (filename, attrname, attrval)
}
p = fileattr_modify (node->data, attrname, attrval, '=', ';');
- free (node->data);
if (p == NULL)
delnode (node);
else
+ {
+ free (node->data);
node->data = p;
+ }
+
+ attrs_modified = 1;
+}
+
+char *
+fileattr_getall (filename)
+ const char *filename;
+{
+ Node *node;
+ char *p;
+
+ if (attrlist == NULL)
+ fileattr_read ();
+ if (attrlist == NULL)
+ /* Either nothing has any attributes, or fileattr_read already printed
+ an error message. */
+ return NULL;
+
+ if (filename == NULL)
+ p = fileattr_default_attrs;
+ else
+ {
+ node = findnode (attrlist, filename);
+ if (node == NULL)
+ /* A file not mentioned has no attributes. */
+ return NULL;
+ p = node->data;
+ }
+ return xstrdup (p);
+}
+
+void
+fileattr_setall (filename, attrs)
+ const char *filename;
+ const char *attrs;
+{
+ Node *node;
+
+ if (filename == NULL)
+ {
+ if (fileattr_default_attrs != NULL)
+ free (fileattr_default_attrs);
+ fileattr_default_attrs = xstrdup (attrs);
+ attrs_modified = 1;
+ return;
+ }
+ if (attrlist == NULL)
+ fileattr_read ();
+ if (attrlist == NULL)
+ {
+ /* Not sure this is a graceful way to handle things
+ in the case where fileattr_read was unable to read the file. */
+ /* No attributes existed previously. */
+ attrlist = getlist ();
+ }
+
+ node = findnode (attrlist, filename);
+ if (node == NULL)
+ {
+ /* The file had no attributes. Add them if we have any to add. */
+ if (attrs != NULL)
+ {
+ node = getnode ();
+ node->type = FILEATTR;
+ node->delproc = fileattr_delproc;
+ node->key = xstrdup (filename);
+ node->data = xstrdup (attrs);
+ addnode (attrlist, node);
+ }
+ }
+ else
+ {
+ if (attrs == NULL)
+ delnode (node);
+ else
+ {
+ free (node->data);
+ node->data = xstrdup (attrs);
+ }
+ }
+
+ attrs_modified = 1;
}
void
fileattr_newfile (filename)
- char *filename;
+ const char *filename;
{
Node *node;
@@ -384,7 +503,7 @@ writeattr_proc (node, data)
fputs (node->key, fp);
fputs ("\t", fp);
fputs (node->data, fp);
- fputs ("\n", fp);
+ fputs ("\012", fp);
return 0;
}
@@ -394,6 +513,7 @@ fileattr_write ()
FILE *fp;
char *fname;
mode_t omask;
+ struct unrecog *p;
if (!attrs_modified)
return;
@@ -414,7 +534,9 @@ fileattr_write ()
strcat (fname, "/");
strcat (fname, CVSREP_FILEATTR);
- if (list_isempty (attrlist) && fileattr_default_attrs == NULL)
+ if (list_isempty (attrlist)
+ && fileattr_default_attrs == NULL
+ && unrecog_head == NULL)
{
/* There are no attributes. */
if (unlink_file (fname) < 0)
@@ -431,7 +553,7 @@ fileattr_write ()
strcpy (fname, fileattr_stored_repos);
strcat (fname, "/");
strcat (fname, CVSREP);
- if (rmdir (fname) < 0)
+ if (CVS_RMDIR (fname) < 0)
{
if (errno != ENOTEMPTY
@@ -447,7 +569,7 @@ fileattr_write ()
}
omask = umask (cvsumask);
- fp = fopen (fname, "w");
+ fp = CVS_FOPEN (fname, FOPEN_BINARY_WRITE);
if (fp == NULL)
{
if (existence_error (errno))
@@ -472,7 +594,7 @@ fileattr_write ()
}
free (repname);
- fp = fopen (fname, "w");
+ fp = CVS_FOPEN (fname, FOPEN_BINARY_WRITE);
}
if (fp == NULL)
{
@@ -482,13 +604,25 @@ fileattr_write ()
}
}
(void) umask (omask);
+
+ /* First write the "F" attributes. */
walklist (attrlist, writeattr_proc, fp);
+
+ /* Then the "D" attribute. */
if (fileattr_default_attrs != NULL)
{
fputs ("D\t", fp);
fputs (fileattr_default_attrs, fp);
- fputs ("\n", fp);
+ fputs ("\012", fp);
+ }
+
+ /* Then any other attributes. */
+ for (p = unrecog_head; p != NULL; p = p->next)
+ {
+ fputs (p->line, fp);
+ fputs ("\012", fp);
}
+
if (fclose (fp) < 0)
error (0, errno, "cannot close %s", fname);
attrs_modified = 0;
@@ -498,6 +632,10 @@ fileattr_write ()
void
fileattr_free ()
{
+ /* Note that attrs_modified will ordinarily be zero, but there are
+ a few cases in which fileattr_write will fail to zero it (if
+ noexec is set, or error conditions). This probably is the way
+ it should be. */
dellist (&attrlist);
if (fileattr_stored_repos != NULL)
free (fileattr_stored_repos);
@@ -505,4 +643,11 @@ fileattr_free ()
if (fileattr_default_attrs != NULL)
free (fileattr_default_attrs);
fileattr_default_attrs = NULL;
+ while (unrecog_head)
+ {
+ struct unrecog *p = unrecog_head;
+ unrecog_head = p->next;
+ free (p->line);
+ free (p);
+ }
}
diff --git a/gnu/usr.bin/cvs/src/ignore.c b/gnu/usr.bin/cvs/src/ignore.c
index f46bc5ed746..f1a3a0c88aa 100644
--- a/gnu/usr.bin/cvs/src/ignore.c
+++ b/gnu/usr.bin/cvs/src/ignore.c
@@ -158,7 +158,7 @@ ign_add_file (file, hold)
error (0, errno, "cannot open %s", file);
return;
}
- while (getline (&line, &line_allocated, fp) >= 0)
+ while (get_line (&line, &line_allocated, fp) >= 0)
ign_add (line, hold);
if (ferror (fp))
error (0, errno, "cannot read %s", file);
diff --git a/gnu/usr.bin/cvs/src/login.c b/gnu/usr.bin/cvs/src/login.c
index 8bbfe2406da..c23d31c453b 100644
--- a/gnu/usr.bin/cvs/src/login.c
+++ b/gnu/usr.bin/cvs/src/login.c
@@ -331,7 +331,7 @@ password_entry_operation (operation, root, newpassword)
/* Check each line to see if we have this entry already. */
line = 0;
- while ((line_length = getline (&linebuf, &linebuf_len, fp)) >= 0)
+ while ((line_length = get_line (&linebuf, &linebuf_len, fp)) >= 0)
{
line++;
password = password_entry_parseline(cvsroot_canonical, 1, line, linebuf);
@@ -400,7 +400,7 @@ process:
error (1, errno, "unable to open temp file %s", tmp_name);
line = 0;
- while ((line_length = getline (&linebuf, &linebuf_len, fp)) >= 0)
+ while ((line_length = get_line (&linebuf, &linebuf_len, fp)) >= 0)
{
line++;
if (line < found_at
diff --git a/gnu/usr.bin/cvs/src/logmsg.c b/gnu/usr.bin/cvs/src/logmsg.c
index 89e0ece72fa..ee7f90ed796 100644
--- a/gnu/usr.bin/cvs/src/logmsg.c
+++ b/gnu/usr.bin/cvs/src/logmsg.c
@@ -319,7 +319,7 @@ do_editor (dir, messagep, repository, changes)
size_t offset = 0;
while (1)
{
- line_length = getline (&line, &line_chars_allocated, fp);
+ line_length = get_line (&line, &line_chars_allocated, fp);
if (line_length == -1)
{
if (ferror (fp))
@@ -348,7 +348,7 @@ do_editor (dir, messagep, repository, changes)
(void) printf ("a)bort, c)ontinue, e)dit, !)reuse this message unchanged for remaining dirs\n");
(void) printf ("Action: (continue) ");
(void) fflush (stdout);
- line_length = getline (&line, &line_chars_allocated, stdin);
+ line_length = get_line (&line, &line_chars_allocated, stdin);
if (line_length < 0)
{
error (0, errno, "cannot read from stdin");
@@ -489,7 +489,7 @@ rcsinfo_proc (repository, template)
char *line = NULL;
size_t line_chars_allocated = 0;
- while (getline (&line, &line_chars_allocated, tfp) >= 0)
+ while (get_line (&line, &line_chars_allocated, tfp) >= 0)
(void) fputs (line, fp);
if (ferror (tfp))
error (0, errno, "warning: cannot read %s", template);
diff --git a/gnu/usr.bin/cvs/src/mkmodules.c b/gnu/usr.bin/cvs/src/mkmodules.c
index 48a5f4f1e2d..eb11afed42d 100644
--- a/gnu/usr.bin/cvs/src/mkmodules.c
+++ b/gnu/usr.bin/cvs/src/mkmodules.c
@@ -467,7 +467,7 @@ mkmodules (dir)
*
* comment lines begin with '#'
*/
- while (getline (&line, &line_allocated, fp) >= 0)
+ while (get_line (&line, &line_allocated, fp) >= 0)
{
/* skip lines starting with # */
if (line[0] == '#')
diff --git a/gnu/usr.bin/cvs/src/parseinfo.c b/gnu/usr.bin/cvs/src/parseinfo.c
index fbcc3a53c8c..c1482e63616 100644
--- a/gnu/usr.bin/cvs/src/parseinfo.c
+++ b/gnu/usr.bin/cvs/src/parseinfo.c
@@ -70,7 +70,7 @@ Parse_Info (infofile, repository, callproc, all)
/* search the info file for lines that match */
callback_done = line_number = 0;
- while (getline (&line, &line_allocated, fp_info) >= 0)
+ while (get_line (&line, &line_allocated, fp_info) >= 0)
{
line_number++;
@@ -259,7 +259,7 @@ parse_config (cvsroot)
return 0;
}
- while (getline (&line, &line_allocated, fp_info) >= 0)
+ while (get_line (&line, &line_allocated, fp_info) >= 0)
{
/* Skip comments. */
if (line[0] == '#')
diff --git a/gnu/usr.bin/cvs/src/patch.c b/gnu/usr.bin/cvs/src/patch.c
index 437c395be17..024bc5b9921 100644
--- a/gnu/usr.bin/cvs/src/patch.c
+++ b/gnu/usr.bin/cvs/src/patch.c
@@ -603,8 +603,8 @@ patch_fileproc (callerdat, finfo)
cvs_output ("\n", 1);
fp = open_file (tmpfile3, "r");
- if (getline (&line1, &line1_chars_allocated, fp) < 0 ||
- getline (&line2, &line2_chars_allocated, fp) < 0)
+ if (get_line (&line1, &line1_chars_allocated, fp) < 0 ||
+ get_line (&line2, &line2_chars_allocated, fp) < 0)
{
if (feof (fp))
error (0, 0, "\
@@ -709,7 +709,7 @@ failed to read diff file header %s for %s: end of file", tmpfile3, rcs);
/* spew the rest of the diff out */
while ((line_length
- = getline (&line1, &line1_chars_allocated, fp))
+ = get_line (&line1, &line1_chars_allocated, fp))
>= 0)
cvs_output (line1, 0);
if (line_length < 0 && !feof (fp))
diff --git a/gnu/usr.bin/cvs/src/release.c b/gnu/usr.bin/cvs/src/release.c
index 987edd0d301..5145cb40101 100644
--- a/gnu/usr.bin/cvs/src/release.c
+++ b/gnu/usr.bin/cvs/src/release.c
@@ -1,31 +1,64 @@
/*
* Release: "cancel" a checkout in the history log.
*
- * - Don't allow release if anything is active - Don't allow release if not
- * above or inside repository. - Don't allow release if ./CVS/Repository is
- * not the same as the directory specified in the module database.
- *
* - Enter a line in the history log indicating the "release". - If asked to,
* delete the local working directory.
*/
#include "cvs.h"
-
-#ifndef lint
-static const char rcsid[] = "$CVSid: @(#)release.c 1.23 94/09/21 $";
-USE(rcsid);
-#endif
-
-static void release_delete PROTO((char *dir));
+#include "savecwd.h"
+#include "getline.h"
static const char *const release_usage[] =
{
- "Usage: %s %s [-d] modules...\n",
+ "Usage: %s %s [-d] directories...\n",
"\t-d\tDelete the given directory.\n",
+ "(Specify the --help global option for a list of other help options)\n",
NULL
};
-static short delete;
+#ifdef SERVER_SUPPORT
+static int release_server PROTO ((int argc, char **argv));
+
+/* This is the server side of cvs release. */
+static int
+release_server (argc, argv)
+ int argc;
+ char **argv;
+{
+ int i;
+
+ /* Note that we skip argv[0]. */
+ for (i = 1; i < argc; ++i)
+ history_write ('F', argv[i], "", argv[i], "");
+ return 0;
+}
+
+#endif /* SERVER_SUPPORT */
+
+/* There are various things to improve about this implementation:
+
+ 1. Using run_popen to run "cvs update" could be replaced by a
+ fairly simple start_recursion/classify_file loop--a win for
+ portability, performance, and cleanliness. In particular, there is
+ no particularly good way to find the right "cvs".
+
+ 2. The fact that "cvs update" contacts the server slows things down;
+ it undermines the case for using "cvs release" rather than "rm -rf".
+ However, for correctly printing "? foo" and correctly handling
+ CVSROOTADM_IGNORE, we currently need to contact the server. (One
+ idea for how to fix this is to stash a copy of CVSROOTADM_IGNORE in
+ the working directories; see comment at base_* in entries.c for a
+ few thoughts on that).
+
+ 3. Would be nice to take processing things on the client side one step
+ further, and making it like edit/unedit in terms of working well if
+ disconnected from the network, and then sending a delayed
+ notification.
+
+ 4. Having separate network turnarounds for the "Notify" request
+ which we do as part of unedit, and for the "release" itself, is slow
+ and unnecessary. */
int
release (argc, argv)
@@ -33,229 +66,234 @@ release (argc, argv)
char **argv;
{
FILE *fp;
- register int i, c;
- char *repository, *srepos;
- char line[PATH_MAX], update_cmd[PATH_MAX];
+ int i, c;
+ char *repository;
+ char *line = NULL;
+ size_t line_allocated = 0;
+ char *update_cmd;
char *thisarg;
int arg_start_idx;
+ int err = 0;
+ short delete_flag = 0;
+ struct saved_cwd cwd;
#ifdef SERVER_SUPPORT
- if (!server_active)
- {
-#endif /* SERVER_SUPPORT */
- if (argc == -1)
- usage (release_usage);
- optind = 1;
- while ((c = getopt (argc, argv, "Qdq")) != -1)
- {
- switch (c)
- {
- case 'Q':
- case 'q':
-#ifdef SERVER_SUPPORT
- /* The CVS 1.5 client sends these options (in addition to
- Global_option requests), so we must ignore them. */
- if (!server_active)
+ if (server_active)
+ return release_server (argc, argv);
#endif
- error (1, 0,
- "-q or -Q must be specified before \"%s\"",
- command_name);
+
+ /* Everything from here on is client or local. */
+ if (argc == -1)
+ usage (release_usage);
+ optind = 0;
+ while ((c = getopt (argc, argv, "+Qdq")) != -1)
+ {
+ switch (c)
+ {
+ case 'Q':
+ case 'q':
+ error (1, 0,
+ "-q or -Q must be specified before \"%s\"",
+ command_name);
break;
- case 'd':
- delete++;
+ case 'd':
+ delete_flag++;
break;
- case '?':
- default:
+ case '?':
+ default:
usage (release_usage);
break;
- }
- }
- argc -= optind;
- argv += optind;
-#ifdef SERVER_SUPPORT
- }
-#endif /* SERVER_SUPPORT */
+ }
+ }
+ argc -= optind;
+ argv += optind;
/* We're going to run "cvs -n -q update" and check its output; if
* the output is sufficiently unalarming, then we release with no
* questions asked. Else we prompt, then maybe release.
+ * (Well, actually we ask no matter what. Our notion of "sufficiently
+ * unalarming" doesn't take into account "? foo.c" files, so it is
+ * up to the user to take note of them, at least currently
+ * (ignore-193 in testsuite)).
*/
/* Construct the update command. */
+ update_cmd = xmalloc (strlen (program_path)
+ + strlen (current_parsed_root->original)
+ + 20);
sprintf (update_cmd, "%s -n -q -d %s update",
- program_name, CVSroot);
+ program_path, current_parsed_root->original);
#ifdef CLIENT_SUPPORT
/* Start the server; we'll close it after looping. */
- if (client_active)
- {
+ if (current_parsed_root->isremote)
+ {
start_server ();
ign_setup ();
- }
+ }
#endif /* CLIENT_SUPPORT */
- /* If !server_active, we already skipped over argv[0] in the "argc
- -= optind;" statement above. But if server_active, we need to
- skip it now. */
-#ifdef SERVER_SUPPORT
- if (server_active)
- arg_start_idx = 1;
- else
- arg_start_idx = 0;
-#endif /* SERVER_SUPPORT */
+ /* Remember the directory where "cvs release" was invoked because
+ all args are relative to this directory and we chdir around.
+ */
+ if (save_cwd (&cwd))
+ error_exit ();
+
+ arg_start_idx = 0;
for (i = arg_start_idx; i < argc; i++)
{
- thisarg = argv[i];
-
-#ifdef SERVER_SUPPORT
- if (server_active)
- {
- /* Just log the release -- all the interesting stuff happened
- * on the client.
- */
- history_write ('F', thisarg, "", thisarg, ""); /* F == Free */
- }
- else
- {
-#endif /* SERVER_SUPPORT */
-
- /*
- * If we are in a repository, do it. Else if we are in the parent of
- * a directory with the same name as the module, "cd" into it and
- * look for a repository there.
- */
+ thisarg = argv[i];
+
if (isdir (thisarg))
{
- if (chdir (thisarg) < 0)
- {
- if (!really_quiet)
- error (0, 0, "can't chdir to: %s", thisarg);
- continue;
- }
- if (!isdir (CVSADM))
- {
- if (!really_quiet)
- error (0, 0, "no repository module: %s", thisarg);
- continue;
- }
+ if (CVS_CHDIR (thisarg) < 0)
+ {
+ if (!really_quiet)
+ error (0, errno, "can't chdir to: %s", thisarg);
+ continue;
+ }
+ if (!isdir (CVSADM))
+ {
+ if (!really_quiet)
+ error (0, 0, "no repository directory: %s", thisarg);
+ if (restore_cwd (&cwd, NULL))
+ error_exit ();
+ continue;
+ }
}
else
{
- if (!really_quiet)
- error (0, 0, "no such directory: %s", thisarg);
- continue;
+ if (!really_quiet)
+ error (0, 0, "no such directory: %s", thisarg);
+ continue;
}
repository = Name_Repository ((char *) NULL, (char *) NULL);
- srepos = Short_Repository (repository);
-
+
if (!really_quiet)
{
- /* The "release" command piggybacks on "update", which
- * does the real work of finding out if anything is not
- * up-to-date with the repository. Then "release" prompts
- * the user, telling her how many files have been
- * modified, and asking if she still wants to do the
- * release.
- *
- * This is "popen()" instead of "Popen()" since we
- * wouldn't want the `noexec' flag to stop it.
- */
- fp = popen (update_cmd, "r");
- c = 0;
-
- while (fgets (line, sizeof (line), fp))
- {
- if (strchr ("MARCZ", *line))
- c++;
- (void) printf (line);
- }
-
- /* If the update exited with an error, then we just want to
- * complain and go on to the next arg. Especially, we do
- * not want to delete the local copy, since it's obviously
- * not what the user thinks it is.
- */
- if ((pclose (fp)) != 0)
- {
- error (0, 0, "unable to release `%s'", thisarg);
- continue;
- }
-
- (void) printf ("You have [%d] altered files in this repository.\n",
- c);
- (void) printf ("Are you sure you want to release %smodule `%s': ",
- delete ? "(and delete) " : "", thisarg);
- c = !yesno ();
- if (c) /* "No" */
- {
- (void) fprintf (stderr, "** `%s' aborted by user choice.\n",
- command_name);
- free (repository);
- continue;
- }
+ int line_length;
+
+ /* The "release" command piggybacks on "update", which
+ does the real work of finding out if anything is not
+ up-to-date with the repository. Then "release" prompts
+ the user, telling her how many files have been
+ modified, and asking if she still wants to do the
+ release. */
+ fp = run_popen (update_cmd, "r");
+ if (fp == NULL)
+ error (1, 0, "cannot run command %s", update_cmd);
+
+ c = 0;
+
+ while ((line_length = get_line (&line, &line_allocated, fp)) >= 0)
+ {
+ if (strchr ("MARCZ", *line))
+ c++;
+ (void) fputs (line, stdout);
+ }
+ if (line_length < 0 && !feof (fp))
+ error (0, errno, "cannot read from subprocess");
+
+ /* If the update exited with an error, then we just want to
+ complain and go on to the next arg. Especially, we do
+ not want to delete the local copy, since it's obviously
+ not what the user thinks it is. */
+ if ((pclose (fp)) != 0)
+ {
+ error (0, 0, "unable to release `%s'", thisarg);
+ free (repository);
+ if (restore_cwd (&cwd, NULL))
+ error_exit ();
+ continue;
+ }
+
+ printf ("You have [%d] altered files in this repository.\n",
+ c);
+ printf ("Are you sure you want to release %sdirectory `%s': ",
+ delete_flag ? "(and delete) " : "", thisarg);
+ c = !yesno ();
+ if (c) /* "No" */
+ {
+ (void) fprintf (stderr, "** `%s' aborted by user choice.\n",
+ command_name);
+ free (repository);
+ if (restore_cwd (&cwd, NULL))
+ error_exit ();
+ continue;
+ }
+ }
+
+ if (1
+#ifdef CLIENT_SUPPORT
+ && !(current_parsed_root->isremote
+ && (!supported_request ("noop")
+ || !supported_request ("Notify")))
+#endif
+ )
+ {
+ /* We are chdir'ed into the directory in question.
+ So don't pass args to unedit. */
+ int argc = 1;
+ char *argv[3];
+ argv[0] = "dummy";
+ argv[1] = NULL;
+ err += unedit (argc, argv);
}
#ifdef CLIENT_SUPPORT
- if (client_active)
+ if (current_parsed_root->isremote)
{
- if (fprintf (to_server, "Argument %s\n", thisarg) < 0)
- error (1, errno, "writing to server");
- if (fprintf (to_server, "release\n") < 0)
- error (1, errno, "writing to server");
- }
+ send_to_server ("Argument ", 0);
+ send_to_server (thisarg, 0);
+ send_to_server ("\012", 1);
+ send_to_server ("release\012", 0);
+ }
else
- {
-#endif /* CLIENT_SUPPORT */
- history_write ('F', thisarg, "", thisarg, ""); /* F == Free */
-#ifdef CLIENT_SUPPORT
- } /* else client not active */
#endif /* CLIENT_SUPPORT */
-
+ {
+ history_write ('F', thisarg, "", thisarg, ""); /* F == Free */
+ }
+
free (repository);
- if (delete) release_delete (thisarg);
-
+
+ if (restore_cwd (&cwd, NULL))
+ error_exit ();
+
+ if (delete_flag)
+ {
+ /* FIXME? Shouldn't this just delete the CVS-controlled
+ files and, perhaps, the files that would normally be
+ ignored and leave everything else? */
+
+ if (unlink_file_dir (thisarg) < 0)
+ error (0, errno, "deletion of directory %s failed", thisarg);
+ }
+
#ifdef CLIENT_SUPPORT
- if (client_active)
- return get_responses_and_close ();
- else
+ if (current_parsed_root->isremote)
+ err += get_server_responses ();
#endif /* CLIENT_SUPPORT */
- return (0);
-
-#ifdef SERVER_SUPPORT
- } /* else server not active */
-#endif /* SERVER_SUPPORT */
- } /* `for' loop */
-}
+ }
+ if (restore_cwd (&cwd, NULL))
+ error_exit ();
+ free_cwd (&cwd);
-/* We want to "rm -r" the working directory, but let us be a little
- paranoid. */
-static void
-release_delete (dir)
- char *dir;
-{
- struct stat st;
- ino_t ino;
- int retcode = 0;
-
- (void) stat (".", &st);
- ino = st.st_ino;
- (void) chdir ("..");
- (void) stat (dir, &st);
- if (ino != st.st_ino)
+#ifdef CLIENT_SUPPORT
+ if (current_parsed_root->isremote)
{
- error (0, 0,
- "Parent dir on a different disk, delete of %s aborted", dir);
- return;
+ /* Unfortunately, client.c doesn't offer a way to close
+ the connection without waiting for responses. The extra
+ network turnaround here is quite unnecessary other than
+ that.... */
+ send_to_server ("noop\012", 0);
+ err += get_responses_and_close ();
}
- /*
- * XXX - shouldn't this just delete the CVS-controlled files and, perhaps,
- * the files that would normally be ignored and leave everything else?
- */
- run_setup ("%s -fr", RM);
- run_arg (dir);
- if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL)) != 0)
- error (0, retcode == -1 ? errno : 0,
- "deletion of module %s failed.", dir);
+#endif /* CLIENT_SUPPORT */
+
+ free (update_cmd);
+ if (line != NULL)
+ free (line);
+ return err;
}
diff --git a/gnu/usr.bin/cvs/src/repos.c b/gnu/usr.bin/cvs/src/repos.c
index 85664334afe..be425b14a29 100644
--- a/gnu/usr.bin/cvs/src/repos.c
+++ b/gnu/usr.bin/cvs/src/repos.c
@@ -3,19 +3,21 @@
* Copyright (c) 1989-1992, Brian Berliner
*
* You may distribute under the terms of the GNU General Public License as
- * specified in the README file that comes with the CVS 1.4 kit.
- *
- * Name of Repository
- *
- * Determine the name of the RCS repository and sets "Repository" accordingly.
+ * specified in the README file that comes with the CVS source distribution.
*/
+#include <assert.h>
#include "cvs.h"
+#include "getline.h"
-#ifndef lint
-static const char rcsid[] = "$CVSid: @(#)repos.c 1.32 94/09/23 $";
-USE(rcsid);
-#endif
+/* Determine the name of the RCS repository for directory DIR in the
+ current working directory, or for the current working directory
+ itself if DIR is NULL. Returns the name in a newly-malloc'd
+ string. On error, gives a fatal error and does not return.
+ UPDATE_DIR is the path from where cvs was invoked (for use in error
+ messages), and should contain DIR as its last component.
+ UPDATE_DIR can be NULL to signify the directory in which cvs was
+ invoked. */
char *
Name_Repository (dir, update_dir)
@@ -23,11 +25,10 @@ Name_Repository (dir, update_dir)
char *update_dir;
{
FILE *fpin;
- char *ret, *xupdate_dir;
- char repos[PATH_MAX];
- char path[PATH_MAX];
- char tmp[PATH_MAX];
- char cvsadm[PATH_MAX];
+ char *xupdate_dir;
+ char *repos = NULL;
+ size_t repos_allocated = 0;
+ char *tmp;
char *cp;
if (update_dir && *update_dir)
@@ -36,52 +37,67 @@ Name_Repository (dir, update_dir)
xupdate_dir = ".";
if (dir != NULL)
- (void) sprintf (cvsadm, "%s/%s", dir, CVSADM);
- else
- (void) strcpy (cvsadm, CVSADM);
-
- /* sanity checks */
- 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);
- }
-
- if (dir != NULL)
- (void) sprintf (tmp, "%s/%s", dir, CVSADM_ENT);
- else
- (void) strcpy (tmp, CVSADM_ENT);
-
- if (!isreadable (tmp))
{
- error (0, 0, "in directory %s:", xupdate_dir);
- error (1, 0, "*PANIC* administration files missing");
- }
-
- if (dir != NULL)
+ tmp = xmalloc (strlen (dir) + sizeof (CVSADM_REP) + 10);
(void) sprintf (tmp, "%s/%s", dir, CVSADM_REP);
- else
- (void) strcpy (tmp, CVSADM_REP);
-
- if (!isreadable (tmp))
- {
- error (0, 0, "in directory %s:", xupdate_dir);
- error (1, 0, "*PANIC* administration files missing");
}
+ else
+ tmp = xstrdup (CVSADM_REP);
/*
* The assumption here is that the repository is always contained in the
* first line of the "Repository" file.
*/
- fpin = open_file (tmp, "r");
+ fpin = CVS_FOPEN (tmp, "r");
+
+ if (fpin == NULL)
+ {
+ int save_errno = errno;
+ char *cvsadm;
+
+ if (dir != NULL)
+ {
+ cvsadm = xmalloc (strlen (dir) + sizeof (CVSADM) + 10);
+ (void) sprintf (cvsadm, "%s/%s", dir, CVSADM);
+ }
+ else
+ cvsadm = xstrdup (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);
+ }
+ free (cvsadm);
+
+ 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, "*PANIC* administration files missing");
+ }
+
+ error (1, save_errno, "cannot open %s", tmp);
+ }
- if (fgets (repos, PATH_MAX, fpin) == NULL)
+ if (get_line (&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", CVSADM_REP);
}
- (void) fclose (fpin);
+ if (fclose (fpin) < 0)
+ error (0, errno, "cannot close %s", tmp);
+ free (tmp);
+
if ((cp = strrchr (repos, '\n')) != NULL)
*cp = '\0'; /* strip the newline */
@@ -90,38 +106,32 @@ Name_Repository (dir, update_dir)
* one by tacking on the CVSROOT environment variable. If the CVSROOT
* environment variable is not set, die now.
*/
- if (strcmp (repos, "..") == 0 || strncmp (repos, "../", 3) == 0)
- {
- error (0, 0, "in directory %s:", xupdate_dir);
- error (0, 0, "`..'-relative repositories are not supported.");
- error (1, 0, "illegal source repository");
- }
if (! isabsolute(repos))
{
- if (CVSroot == NULL)
+ char *newrepos;
+
+ 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");
}
- (void) strcpy (path, repos);
- (void) sprintf (repos, "%s/%s", CVSroot, path);
- }
-#ifdef CLIENT_SUPPORT
- if (!client_active && !isdir (repos))
-#else
- if (!isdir (repos))
-#endif
- {
- error (0, 0, "in directory %s:", xupdate_dir);
- error (1, 0, "there is no repository %s", repos);
+ 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 = xmalloc (strlen (current_parsed_root->directory) + strlen (repos) + 2);
+ (void) sprintf (newrepos, "%s/%s", current_parsed_root->directory, repos);
+ free (repos);
+ repos = newrepos;
}
- /* allocate space to return and fill it in */
- strip_path (repos);
- ret = xstrdup (repos);
- return (ret);
+ Sanitize_Repository_Name (repos);
+
+ return repos;
}
/*
@@ -137,11 +147,60 @@ Short_Repository (repository)
/* If repository matches CVSroot at the beginning, strip off CVSroot */
/* And skip leading '/' in rep, in case CVSroot ended with '/'. */
- if (strncmp (CVSroot, repository, strlen (CVSroot)) == 0)
+ if (strncmp (current_parsed_root->directory, repository,
+ strlen (current_parsed_root->directory)) == 0)
{
- char *rep = repository + strlen (CVSroot);
+ char *rep = repository + strlen (current_parsed_root->directory);
return (*rep == '/') ? rep+1 : rep;
}
else
return (repository);
}
+
+/* Sanitize the repository name (in place) by removing trailing
+ * slashes and a trailing "." if present. It should be safe for
+ * callers to use strcat and friends to create repository names.
+ * Without this check, names like "/path/to/repos/./foo" and
+ * "/path/to/repos//foo" would be created. For example, one
+ * significant case is the CVSROOT-detection code in commit.c. It
+ * decides whether or not it needs to rebuild the administrative file
+ * database by doing a string compare. If we've done a `cvs co .' to
+ * get the CVSROOT files, "/path/to/repos/./CVSROOT" and
+ * "/path/to/repos/CVSROOT" are the arguments that are compared!
+ *
+ * This function ends up being called from the same places as
+ * strip_path, though what it does is much more conservative. Many
+ * comments about this operation (which was scattered around in
+ * several places in the source code) ran thus:
+ *
+ * ``repository ends with "/."; omit it. This sort of thing used
+ * to be taken care of by strip_path. Now we try to be more
+ * selective. I suspect that it would be even better to push it
+ * back further someday, so that the trailing "/." doesn't get into
+ * repository in the first place, but we haven't taken things that
+ * far yet.'' --Jim Kingdon (recurse.c, 07-Sep-97)
+ *
+ * Ahh, all too true. The major consideration is RELATIVE_REPOS. If
+ * the "/." doesn't end up in the repository while RELATIVE_REPOS is
+ * defined, there will be nothing in the CVS/Repository file. I
+ * haven't verified that the remote protocol will handle that
+ * correctly yet, so I've not made that change. */
+
+void
+Sanitize_Repository_Name (repository)
+ char *repository;
+{
+ size_t len;
+
+ assert (repository != NULL);
+
+ strip_trailing_slashes (repository);
+
+ len = strlen (repository);
+ if (len >= 2
+ && repository[len - 1] == '.'
+ && ISDIRSEP (repository[len - 2]))
+ {
+ repository[len - 2] = '\0';
+ }
+}
diff --git a/gnu/usr.bin/cvs/src/root.c b/gnu/usr.bin/cvs/src/root.c
index 08dab3e94a6..c9870b9e294 100644
--- a/gnu/usr.bin/cvs/src/root.c
+++ b/gnu/usr.bin/cvs/src/root.c
@@ -72,7 +72,7 @@ Name_Root (dir, update_dir)
*/
fpin = open_file (tmp, "r");
- if (getline (&root, &root_allocated, fpin) < 0)
+ if (get_line (&root, &root_allocated, fpin) < 0)
{
/* FIXME: should be checking for end of file separately; errno
is not set in that case. */
diff --git a/gnu/usr.bin/cvs/src/server.c b/gnu/usr.bin/cvs/src/server.c
index da7540f57bb..fa0a95ae689 100644
--- a/gnu/usr.bin/cvs/src/server.c
+++ b/gnu/usr.bin/cvs/src/server.c
@@ -2605,7 +2605,7 @@ check_command_legal_p (cmd_name)
}
else /* successfully opened readers file */
{
- while ((num_red = getline (&linebuf, &linebuf_len, fp)) >= 0)
+ while ((num_red = get_line (&linebuf, &linebuf_len, fp)) >= 0)
{
/* Hmmm, is it worth importing my own readline
library into CVS? It takes care of chopping
@@ -2666,7 +2666,7 @@ check_command_legal_p (cmd_name)
}
found_it = 0;
- while ((num_red = getline (&linebuf, &linebuf_len, fp)) >= 0)
+ while ((num_red = get_line (&linebuf, &linebuf_len, fp)) >= 0)
{
/* Chop newline by hand, for strcmp()'s sake. */
if (num_red > 0 && linebuf[num_red - 1] == '\n')
@@ -5582,7 +5582,7 @@ check_repository_password (username, password, repository, host_user_ptr)
/* Look for a relevant line -- one with this user's name. */
namelen = strlen (username);
- while (getline (&linebuf, &linebuf_len, fp) >= 0)
+ while (get_line (&linebuf, &linebuf_len, fp) >= 0)
{
if ((strncmp (linebuf, username, namelen) == 0)
&& (linebuf[namelen] == ':'))
diff --git a/gnu/usr.bin/cvs/src/subr.c b/gnu/usr.bin/cvs/src/subr.c
index bb647773bcf..597b2f137f6 100644
--- a/gnu/usr.bin/cvs/src/subr.c
+++ b/gnu/usr.bin/cvs/src/subr.c
@@ -605,7 +605,7 @@ file_has_markers (finfo)
fp = CVS_FOPEN (finfo->file, "r");
if (fp == NULL)
error (1, errno, "cannot open %s", finfo->fullname);
- while (getline (&line, &line_allocated, fp) > 0)
+ while (get_line (&line, &line_allocated, fp) > 0)
{
if (strncmp (line, RCS_MERGE_PAT_1, sizeof RCS_MERGE_PAT_1 - 1) == 0 ||
strncmp (line, RCS_MERGE_PAT_2, sizeof RCS_MERGE_PAT_2 - 1) == 0 ||
diff --git a/gnu/usr.bin/cvs/src/update.c b/gnu/usr.bin/cvs/src/update.c
index 16bcc04bdeb..1d11d24f2d5 100644
--- a/gnu/usr.bin/cvs/src/update.c
+++ b/gnu/usr.bin/cvs/src/update.c
@@ -1095,7 +1095,7 @@ update_dirleave_proc (callerdat, dir, err, update_dir, entries)
size_t line_allocated = 0;
repository = Name_Repository ((char *) NULL, update_dir);
- if (getline (&line, &line_allocated, fp) >= 0)
+ if (get_line (&line, &line_allocated, fp) >= 0)
{
if ((cp = strrchr (line, '\n')) != NULL)
*cp = '\0';
diff --git a/gnu/usr.bin/cvs/src/wrapper.c b/gnu/usr.bin/cvs/src/wrapper.c
index 91fdbafbbd0..1ee4e656fb9 100644
--- a/gnu/usr.bin/cvs/src/wrapper.c
+++ b/gnu/usr.bin/cvs/src/wrapper.c
@@ -294,7 +294,7 @@ wrap_add_file (file, temp)
error (0, errno, "cannot open %s", file);
return;
}
- while (getline (&line, &line_allocated, fp) >= 0)
+ while (get_line (&line, &line_allocated, fp) >= 0)
wrap_add (line, temp);
if (line)
free (line);