summaryrefslogtreecommitdiffstats
path: root/contrib
diff options
context:
space:
mode:
authormux <mux@FreeBSD.org>2006-03-14 03:51:13 +0000
committermux <mux@FreeBSD.org>2006-03-14 03:51:13 +0000
commit9062cc29a71793019862502ce51063b4cf3b8308 (patch)
tree80b6fdd284bd04cc067d4a1238cffafd9331f83b /contrib
parentdcd260f19108b1581242296d1dfa1a9bf429676b (diff)
downloadFreeBSD-src-9062cc29a71793019862502ce51063b4cf3b8308.zip
FreeBSD-src-9062cc29a71793019862502ce51063b4cf3b8308.tar.gz
Import the latest snapshot of csup (20060313).
Diffstat (limited to 'contrib')
-rw-r--r--contrib/csup/GNUmakefile8
-rw-r--r--contrib/csup/Makefile24
-rw-r--r--contrib/csup/TODO9
-rw-r--r--contrib/csup/config.c41
-rw-r--r--contrib/csup/config.h2
-rw-r--r--contrib/csup/csup.121
-rw-r--r--contrib/csup/fattr.c106
-rw-r--r--contrib/csup/globtree.c2
-rw-r--r--contrib/csup/idcache.c421
-rw-r--r--contrib/csup/idcache.h41
-rw-r--r--contrib/csup/lister.c3
-rw-r--r--contrib/csup/main.c56
-rw-r--r--contrib/csup/misc.c19
-rw-r--r--contrib/csup/misc.h2
-rw-r--r--contrib/csup/proto.c56
-rw-r--r--contrib/csup/token.h1
-rw-r--r--contrib/csup/token.l1
-rw-r--r--contrib/csup/updater.c201
18 files changed, 777 insertions, 237 deletions
diff --git a/contrib/csup/GNUmakefile b/contrib/csup/GNUmakefile
index 441a6b8..7aceccd 100644
--- a/contrib/csup/GNUmakefile
+++ b/contrib/csup/GNUmakefile
@@ -12,8 +12,8 @@ GROUP?= 0
UNAME= $(shell uname -s)
SRCS= attrstack.c config.c detailer.c diff.c fattr.c fixups.c fnmatch.c \
- globtree.c keyword.c lister.c main.c misc.c mux.c pathcomp.c parse.c \
- proto.c status.c stream.c threads.c token.c updater.c
+ globtree.c idcache.c keyword.c lister.c main.c misc.c mux.c pathcomp.c \
+ parse.c proto.c status.c stream.c threads.c token.c updater.c
OBJS= $(SRCS:.c=.o)
WARNS= -Wall -W -Wno-unused-parameter -Wmissing-prototypes -Wpointer-arith \
@@ -22,10 +22,10 @@ WARNS= -Wall -W -Wno-unused-parameter -Wmissing-prototypes -Wpointer-arith \
-Wnested-externs -Wredundant-decls -Wno-format-y2k
CFLAGS+= -g -O -pipe -DNDEBUG -I$(PREFIX)/include
-ifeq ($(UNAME), "Linux")
+ifeq ($(UNAME), Linux)
CFLAGS+= -D_XOPEN_SOURCE -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64
endif
-ifeq ($(UNAME), "Darwin")
+ifeq ($(UNAME), Darwin)
CFLAGS+= -DHAVE_FFLAGS
endif
CFLAGS+= $(WARNS)
diff --git a/contrib/csup/Makefile b/contrib/csup/Makefile
index 06f7b92..b672c5d 100644
--- a/contrib/csup/Makefile
+++ b/contrib/csup/Makefile
@@ -7,27 +7,9 @@ MANDIR?= ${PREFIX}/man/man
UNAME!= /usr/bin/uname -s
PROG= csup
-SRCS= attrstack.c attrstack.h \
- config.c config.h \
- detailer.c detailer.h \
- diff.c diff.h \
- fattr.c fattr.h fattr_bsd.h \
- fixups.c fixups.h \
- fnmatch.c fnmatch.h \
- globtree.c globtree.h \
- keyword.c keyword.h \
- lister.c lister.h \
- main.c main.h \
- misc.c misc.h \
- mux.c mux.h \
- parse.h parse.y \
- pathcomp.c pathcomp.h \
- proto.c proto.h \
- status.c status.h \
- stream.c stream.h \
- threads.c threads.h \
- token.h token.l \
- updater.c updater.h
+SRCS= attrstack.c config.c detailer.c diff.c fattr.c fixups.c fnmatch.c \
+ globtree.c idcache.c keyword.c lister.c main.c misc.c mux.c parse.y \
+ pathcomp.c proto.c status.c stream.c threads.c token.l updater.c
CFLAGS+= -I. -I${.CURDIR} -g -pthread -DHAVE_FFLAGS -DNDEBUG
WARNS?= 6
diff --git a/contrib/csup/TODO b/contrib/csup/TODO
index 5f67831..66988e1 100644
--- a/contrib/csup/TODO
+++ b/contrib/csup/TODO
@@ -9,9 +9,6 @@ BUGS:
has global variables because of yacc, but I think it should be possible
to do it better by using YYFUNC_PROTOTYPE or something. I think it
should also be possible to completely get rid of the lex file.
-- Some code uses getpwnam() while it should use the thread-safe variant,
- getpwnam_r(). Same for getpwuid() and getgrgid(). We probably need a
- UID/GID lookup cache here.
- The $Log$ CVS keyword is not supported.
- Add missing support for supfile keywords and add sanity checks for
some of them. Also, we're not supposed to choke on unknown keywords
@@ -22,9 +19,9 @@ MISSING FEATURES:
- Add support for authentication.
- Add support for shell commands sent by the server.
-- Add missing support for various CVSup options : -k, -d, -D,
- -a (requires authentication support), -e and -E (requires shell
- commands support) and the destDir parameter.
+- Add missing support for various CVSup options : -D, -a (requires
+ authentication support), -e and -E (requires shell commands support)
+ and the destDir parameter.
- For now, this code should build fine on FreeBSD, NetBSD, OpenBSD,
Linux and Darwin. Solaris support would also be nice at some point.
- Implement some new useful options : the ability to generate CVS
diff --git a/contrib/csup/config.c b/contrib/csup/config.c
index 73be865..5b71e74 100644
--- a/contrib/csup/config.c
+++ b/contrib/csup/config.c
@@ -53,6 +53,8 @@ extern FILE *yyin;
static STAILQ_HEAD(, coll) colls;
static struct coll *cur_coll;
static struct coll *defaults;
+static struct coll *ovcoll;
+static int ovmask;
static const char *cfgfile;
/*
@@ -78,13 +80,14 @@ config_init(const char *file, struct coll *override, int overridemask)
mask = umask(0);
umask(mask);
defaults->co_umask = mask;
+ ovcoll = override;
+ ovmask = overridemask;
/* Extract a list of collections from the configuration file. */
cur_coll = coll_new(defaults);
yyin = fopen(file, "r");
if (yyin == NULL) {
- lprintf(-1, "Cannot open \"%s\": %s\n", file,
- strerror(errno));
+ lprintf(-1, "Cannot open \"%s\": %s\n", file, strerror(errno));
goto bad;
}
cfgfile = file;
@@ -101,7 +104,6 @@ config_init(const char *file, struct coll *override, int overridemask)
/* Fixup the list of collections. */
STAILQ_FOREACH(coll, &config->colls, co_next) {
- coll_override(coll, override, overridemask);
if (coll->co_base == NULL)
coll->co_base = xstrdup("/usr/local/etc/cvsup");
if (coll->co_colldir == NULL)
@@ -229,13 +231,27 @@ static int
config_parse_refusefile(struct coll *coll, char *path)
{
struct stream *rd;
- char *line;
+ char *cp, *line, *pat;
rd = stream_open_file(path, O_RDONLY);
if (rd == NULL)
return (0);
- while ((line = stream_getln(rd, NULL)) != NULL)
- pattlist_add(coll->co_refusals, line);
+ while ((line = stream_getln(rd, NULL)) != NULL) {
+ pat = line;
+ for (;;) {
+ /* Trim leading whitespace. */
+ pat += strspn(pat, " \t");
+ if (pat[0] == '\0')
+ break;
+ cp = strpbrk(pat, " \t");
+ if (cp != NULL)
+ *cp = '\0';
+ pattlist_add(coll->co_refusals, pat);
+ if (cp == NULL)
+ break;
+ pat = cp + 1;
+ }
+ }
if (!stream_eof(rd)) {
stream_close(rd);
lprintf(-1, "Read failure from \"%s\": %s\n", path,
@@ -417,6 +433,7 @@ coll_add(char *name)
struct coll *coll;
cur_coll->co_name = name;
+ coll_override(cur_coll, ovcoll, ovmask);
if (cur_coll->co_release == NULL) {
lprintf(-1, "Release not specified for collection "
"\"%s\"\n", cur_coll->co_name);
@@ -472,6 +489,8 @@ coll_free(struct coll *coll)
globtree_free(coll->co_dirfilter);
if (coll->co_dirfilter != NULL)
globtree_free(coll->co_filefilter);
+ if (coll->co_norsync != NULL)
+ globtree_free(coll->co_norsync);
if (coll->co_accepts != NULL)
pattlist_free(coll->co_accepts);
if (coll->co_refusals != NULL)
@@ -483,6 +502,7 @@ void
coll_setopt(int opt, char *value)
{
struct coll *coll;
+ int error, mask;
coll = cur_coll;
switch (opt) {
@@ -529,14 +549,14 @@ coll_setopt(int opt, char *value)
coll->co_listsuffix = value;
break;
case PT_UMASK:
- errno = 0;
- coll->co_umask = strtol(value, NULL, 8);
+ error = asciitoint(value, &mask, 8);
free(value);
- if (errno) {
+ if (error) {
lprintf(-1, "Parse error in \"%s\": Invalid "
"umask value\n", cfgfile);
exit(1);
}
+ coll->co_umask = mask;
break;
case PT_USE_REL_SUFFIX:
coll->co_options |= CO_USERELSUFFIX;
@@ -547,6 +567,9 @@ coll_setopt(int opt, char *value)
case PT_COMPRESS:
coll->co_options |= CO_COMPRESS;
break;
+ case PT_NORSYNC:
+ coll->co_options |= CO_NORSYNC;
+ break;
}
}
diff --git a/contrib/csup/config.h b/contrib/csup/config.h
index aa12cb6..78b6995 100644
--- a/contrib/csup/config.h
+++ b/contrib/csup/config.h
@@ -86,6 +86,7 @@ struct coll {
struct pattlist *co_refusals;
struct globtree *co_dirfilter;
struct globtree *co_filefilter;
+ struct globtree *co_norsync;
const char *co_colldir;
char *co_listsuffix;
time_t co_scantime; /* Set by the detailer thread. */
@@ -101,6 +102,7 @@ struct config {
char *host;
struct sockaddr *laddr;
socklen_t laddrlen;
+ int deletelim;
int socket;
struct chan *chan0;
struct chan *chan1;
diff --git a/contrib/csup/csup.1 b/contrib/csup/csup.1
index 7a80c01..f8c7c13 100644
--- a/contrib/csup/csup.1
+++ b/contrib/csup/csup.1
@@ -32,10 +32,11 @@
.Nd network distribution package for CVS repositories
.Sh SYNOPSIS
.Nm
-.Op Fl 146svzZ
+.Op Fl 146ksvzZ
.Op Fl A Ar addr
.Op Fl b Ar base
.Op Fl c Ar collDir
+.Op Fl d Ar delLimit
.Op Fl h Ar host
.Op Fl i Ar pattern
.Op Fl l Ar lockfile
@@ -123,6 +124,13 @@ Specifies the subdirectory of
where the information about the collections is maintained.
The default is
.Pa sup .
+.It Fl d Ar delLimit
+Specifies the maximum number of files that may be deleted in a
+single update run.
+Any attempt to exceed the limit results in a fatal error.
+This can provide some protection against temporary configuration
+mistakes on the server.
+The default limit is infinity.
.It Fl h Ar host
Specifies the server host to contact, overriding any
.Cm host
@@ -148,6 +156,17 @@ is a standard file name pattern.
It is interpreted relative to the collection's prefix directory.
Slash characters are matched only by explicit slashes in the pattern.
Leading periods in file name are not treated specially.
+.It Fl k
+Causes
+.Nm
+to keep the temporary copies of any incorrectly edited files, in the
+event of checksum mismatches.
+This option is for debugging, to help determine why the files were
+edited incorrectly.
+Regardless of whether this option is specified, the permanent versions
+of faulty files are replaced with correct versions obtained by
+transferring the files in their entirety.
+Such transfers are called fixups.
.It Fl l Ar lockfile
Creates and locks the
.Ar lockfile
diff --git a/contrib/csup/fattr.c b/contrib/csup/fattr.c
index 59b6607..b29d73d 100644
--- a/contrib/csup/fattr.c
+++ b/contrib/csup/fattr.c
@@ -32,14 +32,13 @@
#include <assert.h>
#include <errno.h>
-#include <grp.h>
-#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "fattr.h"
+#include "idcache.h"
#include "misc.h"
/*
@@ -126,6 +125,8 @@ fattr_init(void)
fa->mask |= FA_MODE;
defaults[i] = fa;
}
+ /* Initialize the uid/gid lookup cache. */
+ idcache_init();
}
void
@@ -133,6 +134,7 @@ fattr_fini(void)
{
int i;
+ idcache_fini();
for (i = 0; i < FT_NUMBER; i++)
fattr_free(defaults[i]);
}
@@ -336,29 +338,26 @@ fattr_encode(const struct fattr *fa, fattr_support_t support, int ignore)
int extval;
char *ext;
} pieces[FA_NUMBER], *piece;
- struct passwd *pw;
- struct group *gr;
- char *cp, *s;
+ char *cp, *s, *username, *groupname;
size_t len, vallen;
mode_t mode, modemask;
int mask, n, i;
- pw = NULL;
- gr = NULL;
+ username = NULL;
+ groupname = NULL;
if (support == NULL)
mask = fa->mask;
else
mask = fa->mask & support[fa->type];
mask &= ~ignore;
- /* XXX - Use getpwuid_r() and getgrgid_r(). */
if (fa->mask & FA_OWNER) {
- pw = getpwuid(fa->uid);
- if (pw == NULL)
+ username = getuserbyid(fa->uid);
+ if (username == NULL)
mask &= ~FA_OWNER;
}
if (fa->mask & FA_GROUP) {
- gr = getgrgid(fa->gid);
- if (gr == NULL)
+ groupname = getgroupbyid(fa->gid);
+ if (groupname == NULL)
mask &= ~FA_GROUP;
}
if (fa->mask & FA_LINKCOUNT && fa->linkcount == 1)
@@ -408,17 +407,17 @@ fattr_encode(const struct fattr *fa, fattr_support_t support, int ignore)
piece++;
}
if (mask & FA_OWNER) {
- vallen = strlen(pw->pw_name);
+ vallen = strlen(username);
piece->extval = 1;
- piece->ext = pw->pw_name;
+ piece->ext = username;
len += snprintf(piece->len, sizeof(piece->len), "%lld",
(long long)vallen) + vallen + 1;
piece++;
}
if (mask & FA_GROUP) {
- vallen = strlen(gr->gr_name);
+ vallen = strlen(groupname);
piece->extval = 1;
- piece->ext = gr->gr_name;
+ piece->ext = groupname;
len += snprintf(piece->len, sizeof(piece->len), "%lld",
(long long)vallen) + vallen + 1;
piece++;
@@ -551,11 +550,10 @@ fattr_getlinkcount(const struct fattr *fa)
static char *
fattr_scanattr(struct fattr *fa, int type, const char *attr)
{
- struct passwd *pw;
- struct group *gr;
char *attrend, *attrstart, *end;
size_t len;
unsigned long attrlen;
+ int error;
mode_t modemask;
char tmp;
@@ -606,21 +604,13 @@ fattr_scanattr(struct fattr *fa, int type, const char *attr)
goto bad;
break;
case FA_OWNER:
- /*
- * XXX - We need to use getpwnam_r() since getpwnam()
- * is not thread-safe, and we also need to use a cache.
- */
- pw = getpwnam(attrstart);
- if (pw != NULL)
- fa->uid = pw->pw_uid;
- else
+ error = getuidbyname(attrstart, &fa->uid);
+ if (error)
fa->mask &= ~FA_OWNER;
break;
case FA_GROUP:
- gr = getgrnam(attrstart);
- if (gr != NULL)
- fa->gid = gr->gr_gid;
- else
+ error = getgidbyname(attrstart, &fa->gid);
+ if (error)
fa->mask &= ~FA_GROUP;
break;
case FA_MODE:
@@ -770,11 +760,13 @@ fattr_delete(const char *path)
return (-1);
}
+#ifdef HAVE_FFLAGS
/* Clear flags. */
if (fa->mask & FA_FLAGS && fa->flags != 0) {
fa->flags = 0;
(void)chflags(path, fa->flags);
}
+#endif
if (fa->type == FT_DIRECTORY)
error = rmdir(path);
@@ -812,35 +804,35 @@ fattr_install(struct fattr *fa, const char *topath, const char *frompath)
inplace = 1;
}
old = fattr_frompath(topath, FATTR_NOFOLLOW);
- if (old == NULL)
- return (-1);
- if (inplace && fattr_equal(fa, old)) {
- fattr_free(old);
- return (0);
- }
+ if (old != NULL) {
+ if (inplace && fattr_equal(fa, old)) {
+ fattr_free(old);
+ return (0);
+ }
#ifdef HAVE_FFLAGS
- /*
- * Determine whether we need to clear the flags of the target.
- * This is bogus in that it assumes a value of 0 is safe and
- * that non-zero is unsafe. I'm not really worried by that
- * since as far as I know that's the way things are.
- */
- if ((old->mask & FA_FLAGS) && old->flags > 0) {
- (void)chflags(topath, 0);
- old->flags = 0;
- }
+ /*
+ * Determine whether we need to clear the flags of the target.
+ * This is bogus in that it assumes a value of 0 is safe and
+ * that non-zero is unsafe. I'm not really worried by that
+ * since as far as I know that's the way things are.
+ */
+ if ((old->mask & FA_FLAGS) && old->flags > 0) {
+ (void)chflags(topath, 0);
+ old->flags = 0;
+ }
#endif
- /* Determine whether we need to remove the target first. */
- if (!inplace && (fa->type == FT_DIRECTORY) !=
- (old->type == FT_DIRECTORY)) {
- if (old->type == FT_DIRECTORY)
- error = rmdir(topath);
- else
- error = unlink(topath);
- if (error)
- goto bad;
+ /* Determine whether we need to remove the target first. */
+ if (!inplace && (fa->type == FT_DIRECTORY) !=
+ (old->type == FT_DIRECTORY)) {
+ if (old->type == FT_DIRECTORY)
+ error = rmdir(topath);
+ else
+ error = unlink(topath);
+ if (error)
+ goto bad;
+ }
}
/* Change those attributes that we can before moving the file
@@ -866,8 +858,8 @@ fattr_install(struct fattr *fa, const char *topath, const char *frompath)
}
if (mask & FA_MODE) {
newmode = fa->mode & modemask;
- /* Merge in set*id bits from the old attribute. XXX - Why? */
- if (old->mask & FA_MODE) {
+ /* Merge in set*id bits from the old attribute. */
+ if (old != NULL && old->mask & FA_MODE) {
newmode |= (old->mode & ~modemask);
newmode &= (FA_SETIDMASK | FA_PERMMASK);
}
diff --git a/contrib/csup/globtree.c b/contrib/csup/globtree.c
index 520931a..74ac2c1 100644
--- a/contrib/csup/globtree.c
+++ b/contrib/csup/globtree.c
@@ -29,10 +29,10 @@
#include <sys/types.h>
#include <assert.h>
-#include <fnmatch.h>
#include <regex.h>
#include <stdlib.h>
+#include "fnmatch.h"
#include "globtree.h"
#include "misc.h"
diff --git a/contrib/csup/idcache.c b/contrib/csup/idcache.c
new file mode 100644
index 0000000..47a3e71
--- /dev/null
+++ b/contrib/csup/idcache.c
@@ -0,0 +1,421 @@
+/*-
+ * Copyright (c) 2006, Maxime Henrion <mux@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <sys/types.h>
+
+#include <assert.h>
+#include <grp.h>
+#include <pthread.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "idcache.h"
+#include "misc.h"
+
+/*
+ * Constants and data structures used to implement the thread-safe
+ * group and password file caches. Cache sizes must be prime.
+ */
+#define UIDTONAME_SZ 317 /* Size of uid -> user name cache */
+#define NAMETOUID_SZ 317 /* Size of user name -> uid cache */
+#define GIDTONAME_SZ 317 /* Size of gid -> group name cache */
+#define NAMETOGID_SZ 317 /* Size of group name -> gid cache */
+
+/* Node structures used to cache lookups. */
+struct uidc {
+ char *name; /* user name */
+ uid_t uid; /* cached uid */
+ int valid; /* is this a valid or a miss entry */
+ struct uidc *next; /* for collisions */
+};
+
+struct gidc {
+ char *name; /* group name */
+ gid_t gid; /* cached gid */
+ int valid; /* is this a valid or a miss entry */
+ struct gidc *next; /* for collisions */
+};
+
+static struct uidc **uidtoname; /* uid to user name cache */
+static struct gidc **gidtoname; /* gid to group name cache */
+static struct uidc **nametouid; /* user name to uid cache */
+static struct gidc **nametogid; /* group name to gid cache */
+
+static pthread_mutex_t uid_mtx;
+static pthread_mutex_t gid_mtx;
+
+static void uid_lock(void);
+static void uid_unlock(void);
+static void gid_lock(void);
+static void gid_unlock(void);
+
+static uint32_t hash(const char *);
+
+/* A 32-bit version of Peter Weinberger's (PJW) hash algorithm,
+ as used by ELF for hashing function names. */
+static uint32_t
+hash(const char *name)
+{
+ uint32_t g, h;
+
+ h = 0;
+ while(*name != '\0') {
+ h = (h << 4) + *name++;
+ if ((g = h & 0xF0000000)) {
+ h ^= g >> 24;
+ h &= 0x0FFFFFFF;
+ }
+ }
+ return (h);
+}
+
+static void
+uid_lock(void)
+{
+ int error;
+
+ error = pthread_mutex_lock(&uid_mtx);
+ assert(!error);
+}
+
+static void
+uid_unlock(void)
+{
+ int error;
+
+ error = pthread_mutex_unlock(&uid_mtx);
+ assert(!error);
+}
+
+static void
+gid_lock(void)
+{
+ int error;
+
+ error = pthread_mutex_lock(&gid_mtx);
+ assert(!error);
+}
+
+static void
+gid_unlock(void)
+{
+ int error;
+
+ error = pthread_mutex_unlock(&gid_mtx);
+ assert(!error);
+}
+
+static void
+uidc_insert(struct uidc **tbl, struct uidc *uidc, uint32_t key)
+{
+
+ uidc->next = tbl[key];
+ tbl[key] = uidc;
+}
+
+static void
+gidc_insert(struct gidc **tbl, struct gidc *gidc, uint32_t key)
+{
+
+ gidc->next = tbl[key];
+ tbl[key] = gidc;
+}
+
+/* Return the user name for this uid, or NULL if it's not found. */
+char *
+getuserbyid(uid_t uid)
+{
+ struct passwd *pw;
+ struct uidc *uidc, *uidc2;
+ uint32_t key, key2;
+
+ key = uid % UIDTONAME_SZ;
+ uid_lock();
+ uidc = uidtoname[key];
+ while (uidc != NULL) {
+ if (uidc->uid == uid)
+ break;
+ uidc = uidc->next;
+ }
+
+ if (uidc == NULL) {
+ /* We didn't find this uid, look it up and add it. */
+ uidc = xmalloc(sizeof(struct uidc));
+ uidc->uid = uid;
+ pw = getpwuid(uid);
+ if (pw != NULL) {
+ /* This uid is in the password file. */
+ uidc->name = xstrdup(pw->pw_name);
+ uidc->valid = 1;
+ /* Also add it to the name -> gid table. */
+ uidc2 = xmalloc(sizeof(struct uidc));
+ uidc2->uid = uid;
+ uidc2->name = uidc->name; /* We reuse the pointer. */
+ uidc2->valid = 1;
+ key2 = hash(uidc->name) % NAMETOUID_SZ;
+ uidc_insert(nametouid, uidc2, key2);
+ } else {
+ /* Add a miss entry for this uid. */
+ uidc->name = NULL;
+ uidc->valid = 0;
+ }
+ uidc_insert(uidtoname, uidc, key);
+ }
+ /* It is safe to unlock here since the cache structure
+ is not going to get freed or changed. */
+ uid_unlock();
+ return (uidc->name);
+}
+
+/* Return the group name for this gid, or NULL if it's not found. */
+char *
+getgroupbyid(gid_t gid)
+{
+ struct group *gr;
+ struct gidc *gidc, *gidc2;
+ uint32_t key, key2;
+
+ key = gid % GIDTONAME_SZ;
+ gid_lock();
+ gidc = gidtoname[key];
+ while (gidc != NULL) {
+ if (gidc->gid == gid)
+ break;
+ gidc = gidc->next;
+ }
+
+ if (gidc == NULL) {
+ /* We didn't find this gid, look it up and add it. */
+ gidc = xmalloc(sizeof(struct gidc));
+ gidc->gid = gid;
+ gr = getgrgid(gid);
+ if (gr != NULL) {
+ /* This gid is in the group file. */
+ gidc->name = xstrdup(gr->gr_name);
+ gidc->valid = 1;
+ /* Also add it to the name -> gid table. */
+ gidc2 = xmalloc(sizeof(struct gidc));
+ gidc2->gid = gid;
+ gidc2->name = gidc->name; /* We reuse the pointer. */
+ gidc2->valid = 1;
+ key2 = hash(gidc->name) % NAMETOGID_SZ;
+ gidc_insert(nametogid, gidc2, key2);
+ } else {
+ /* Add a miss entry for this gid. */
+ gidc->name = NULL;
+ gidc->valid = 0;
+ }
+ gidc_insert(gidtoname, gidc, key);
+ }
+ /* It is safe to unlock here since the cache structure
+ is not going to get freed or changed. */
+ gid_unlock();
+ return (gidc->name);
+}
+
+/* Finds the uid for this user name. If it's found, the gid is stored
+ in *uid and 0 is returned. Otherwise, -1 is returned. */
+int
+getuidbyname(const char *name, uid_t *uid)
+{
+ struct passwd *pw;
+ struct uidc *uidc, *uidc2;
+ uint32_t key, key2;
+
+ uid_lock();
+ key = hash(name) % NAMETOUID_SZ;
+ uidc = nametouid[key];
+ while (uidc != NULL) {
+ if (strcmp(uidc->name, name) == 0)
+ break;
+ uidc = uidc->next;
+ }
+
+ if (uidc == NULL) {
+ uidc = xmalloc(sizeof(struct uidc));
+ uidc->name = xstrdup(name);
+ pw = getpwnam(name);
+ if (pw != NULL) {
+ /* This user name is in the password file. */
+ uidc->valid = 1;
+ uidc->uid = pw->pw_uid;
+ /* Also add it to the uid -> name table. */
+ uidc2 = xmalloc(sizeof(struct uidc));
+ uidc2->name = uidc->name; /* We reuse the pointer. */
+ uidc2->uid = uidc->uid;
+ uidc2->valid = 1;
+ key2 = uidc2->uid % UIDTONAME_SZ;
+ uidc_insert(uidtoname, uidc2, key2);
+ } else {
+ /* Add a miss entry for this user name. */
+ uidc->valid = 0;
+ uidc->uid = (uid_t)-1; /* Should not be accessed. */
+ }
+ uidc_insert(nametouid, uidc, key);
+ }
+ /* It is safe to unlock here since the cache structure
+ is not going to get freed or changed. */
+ uid_unlock();
+ if (!uidc->valid)
+ return (-1);
+ *uid = uidc->uid;
+ return (0);
+}
+
+/* Finds the gid for this group name. If it's found, the gid is stored
+ in *gid and 0 is returned. Otherwise, -1 is returned. */
+int
+getgidbyname(const char *name, gid_t *gid)
+{
+ struct group *gr;
+ struct gidc *gidc, *gidc2;
+ uint32_t key, key2;
+
+ gid_lock();
+ key = hash(name) % NAMETOGID_SZ;
+ gidc = nametogid[key];
+ while (gidc != NULL) {
+ if (strcmp(gidc->name, name) == 0)
+ break;
+ gidc = gidc->next;
+ }
+
+ if (gidc == NULL) {
+ gidc = xmalloc(sizeof(struct gidc));
+ gidc->name = xstrdup(name);
+ gr = getgrnam(name);
+ if (gr != NULL) {
+ /* This group name is in the group file. */
+ gidc->gid = gr->gr_gid;
+ gidc->valid = 1;
+ /* Also add it to the gid -> name table. */
+ gidc2 = xmalloc(sizeof(struct gidc));
+ gidc2->name = gidc->name; /* We reuse the pointer. */
+ gidc2->gid = gidc->gid;
+ gidc2->valid = 1;
+ key2 = gidc2->gid % GIDTONAME_SZ;
+ gidc_insert(gidtoname, gidc2, key2);
+ } else {
+ /* Add a miss entry for this group name. */
+ gidc->gid = (gid_t)-1; /* Should not be accessed. */
+ gidc->valid = 0;
+ }
+ gidc_insert(nametogid, gidc, key);
+ }
+ /* It is safe to unlock here since the cache structure
+ is not going to get freed or changed. */
+ gid_unlock();
+ if (!gidc->valid)
+ return (-1);
+ *gid = gidc->gid;
+ return (0);
+}
+
+/* Initialize the cache structures. */
+void
+idcache_init(void)
+{
+
+ pthread_mutex_init(&uid_mtx, NULL);
+ pthread_mutex_init(&gid_mtx, NULL);
+ uidtoname = xmalloc(UIDTONAME_SZ * sizeof(struct uidc *));
+ gidtoname = xmalloc(GIDTONAME_SZ * sizeof(struct gidc *));
+ nametouid = xmalloc(NAMETOUID_SZ * sizeof(struct uidc *));
+ nametogid = xmalloc(NAMETOGID_SZ * sizeof(struct gidc *));
+ memset(uidtoname, 0, UIDTONAME_SZ * sizeof(struct uidc *));
+ memset(gidtoname, 0, GIDTONAME_SZ * sizeof(struct gidc *));
+ memset(nametouid, 0, NAMETOUID_SZ * sizeof(struct uidc *));
+ memset(nametogid, 0, NAMETOGID_SZ * sizeof(struct gidc *));
+}
+
+/* Cleanup the cache structures. */
+void
+idcache_fini(void)
+{
+ struct uidc *uidc, *uidc2;
+ struct gidc *gidc, *gidc2;
+ size_t i;
+
+ for (i = 0; i < UIDTONAME_SZ; i++) {
+ uidc = uidtoname[i];
+ while (uidc != NULL) {
+ if (uidc->name != NULL) {
+ assert(uidc->valid);
+ free(uidc->name);
+ }
+ uidc2 = uidc->next;
+ free(uidc);
+ uidc = uidc2;
+ }
+ }
+ free(uidtoname);
+ for (i = 0; i < NAMETOUID_SZ; i++) {
+ uidc = nametouid[i];
+ while (uidc != NULL) {
+ assert(uidc->name != NULL);
+ /* If it's a valid entry, it has been added to both the
+ uidtoname and nametouid tables, and the name pointer
+ has been reused for both entries. Thus, the name
+ pointer has already been freed in the loop above. */
+ if (!uidc->valid)
+ free(uidc->name);
+ uidc2 = uidc->next;
+ free(uidc);
+ uidc = uidc2;
+ }
+ }
+ free(nametouid);
+ for (i = 0; i < GIDTONAME_SZ; i++) {
+ gidc = gidtoname[i];
+ while (gidc != NULL) {
+ if (gidc->name != NULL) {
+ assert(gidc->valid);
+ free(gidc->name);
+ }
+ gidc2 = gidc->next;
+ free(gidc);
+ gidc = gidc2;
+ }
+ }
+ free(gidtoname);
+ for (i = 0; i < NAMETOGID_SZ; i++) {
+ gidc = nametogid[i];
+ while (gidc != NULL) {
+ assert(gidc->name != NULL);
+ /* See above comment. */
+ if (!gidc->valid)
+ free(gidc->name);
+ gidc2 = gidc->next;
+ free(gidc);
+ gidc = gidc2;
+ }
+ }
+ free(nametogid);
+ pthread_mutex_destroy(&uid_mtx);
+ pthread_mutex_destroy(&gid_mtx);
+}
diff --git a/contrib/csup/idcache.h b/contrib/csup/idcache.h
new file mode 100644
index 0000000..558af0c
--- /dev/null
+++ b/contrib/csup/idcache.h
@@ -0,0 +1,41 @@
+/*-
+ * Copyright (c) 2006, Maxime Henrion <mux@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _IDCACHE_H_
+#define _IDCACHE_H_
+
+#include <sys/types.h>
+
+void idcache_init(void);
+void idcache_fini(void);
+
+char *getuserbyid(uid_t);
+char *getgroupbyid(gid_t);
+int getuidbyname(const char *, uid_t *);
+int getgidbyname(const char *, gid_t *);
+
+#endif /* !_IDCACHE_H_ */
diff --git a/contrib/csup/lister.c b/contrib/csup/lister.c
index a048d25..98a9c83 100644
--- a/contrib/csup/lister.c
+++ b/contrib/csup/lister.c
@@ -145,6 +145,7 @@ lister_coll(struct lister *l, struct coll *coll, struct status *st)
struct attrstack *as;
struct statusrec *sr;
struct fattr *fa;
+ size_t i;
int depth, error, ret, prunedepth;
wr = l->wr;
@@ -203,7 +204,7 @@ lister_coll(struct lister *l, struct coll *coll, struct status *st)
return (LISTER_ERR_WRITE);
return (0);
bad:
- while (depth-- > 0) {
+ for (i = 0; i < attrstack_size(as); i++) {
fa = attrstack_pop(as);
fattr_free(fa);
}
diff --git a/contrib/csup/main.c b/contrib/csup/main.c
index 33f5915..7415039 100644
--- a/contrib/csup/main.c
+++ b/contrib/csup/main.c
@@ -66,6 +66,8 @@ usage(char *argv0)
"Override supfile's \"base\" directory");
lprintf(-1, USAGE_OPTFMT, "-c collDir",
"Subdirectory of \"base\" for collections (default \"sup\")");
+ lprintf(-1, USAGE_OPTFMT, "-d delLimit",
+ "Allow at most \"delLimit\" file deletions (default unlimited)");
lprintf(-1, USAGE_OPTFMT, "-h host",
"Override supfile's \"host\" name");
lprintf(-1, USAGE_OPTFMT, "-i pattern",
@@ -73,6 +75,8 @@ usage(char *argv0)
lprintf(-1, USAGE_OPTFMTSUB,
"May be repeated for an OR operation. Default is");
lprintf(-1, USAGE_OPTFMTSUB, "to include each entire collection.");
+ lprintf(-1, USAGE_OPTFMT, "-k",
+ "Keep bad temporary files when fixups are required");
lprintf(-1, USAGE_OPTFMT, "-l lockfile",
"Lock file during update; fail if already locked");
lprintf(-1, USAGE_OPTFMT, "-L n",
@@ -102,13 +106,13 @@ main(int argc, char *argv[])
socklen_t laddrlen;
struct stream *lock;
char *argv0, *file, *lockfile;
- uint16_t port;
int family, error, lockfd, lflag, overridemask;
- int c, i, retries, status;
+ int c, i, deletelim, port, retries, status;
time_t nexttry;
error = 0;
family = PF_UNSPEC;
+ deletelim = -1;
port = 0;
lflag = 0;
lockfd = 0;
@@ -121,7 +125,8 @@ main(int argc, char *argv[])
override = coll_new(NULL);
overridemask = 0;
- while ((c = getopt(argc, argv, "146A:b:c:gh:i:l:L:p:P:r:svzZ")) != -1) {
+ while ((c = getopt(argc, argv,
+ "146A:b:c:d:gh:i:kl:L:p:P:r:svzZ")) != -1) {
switch (c) {
case '1':
retries = 0;
@@ -152,6 +157,14 @@ main(int argc, char *argv[])
case 'c':
override->co_colldir = optarg;
break;
+ case 'd':
+ error = asciitoint(optarg, &deletelim, 0);
+ if (error || deletelim < 0) {
+ lprintf(-1, "Invalid deletion limit\n");
+ usage(argv0);
+ return (1);
+ }
+ break;
case 'g':
/* For compatibility. */
break;
@@ -163,6 +176,10 @@ main(int argc, char *argv[])
case 'i':
pattlist_add(override->co_accepts, optarg);
break;
+ case 'k':
+ override->co_options |= CO_KEEPBADFILES;
+ overridemask |= CO_KEEPBADFILES;
+ break;
case 'l':
lockfile = optarg;
lflag = 1;
@@ -191,9 +208,8 @@ main(int argc, char *argv[])
stream_close(lock);
break;
case 'L':
- errno = 0;
- verbose = strtol(optarg, NULL, 0);
- if (errno == EINVAL) {
+ error = asciitoint(optarg, &verbose, 0);
+ if (error) {
lprintf(-1, "Invalid verbosity\n");
usage(argv0);
return (1);
@@ -201,13 +217,21 @@ main(int argc, char *argv[])
break;
case 'p':
/* Use specified server port. */
- errno = 0;
- port = strtol(optarg, NULL, 0);
- if (errno == EINVAL) {
+ error = asciitoint(optarg, &port, 0);
+ if (error) {
lprintf(-1, "Invalid server port\n");
usage(argv0);
return (1);
}
+ if (port <= 0 || port >= 65536) {
+ lprintf(-1, "Invalid port %d\n", port);
+ return (1);
+ }
+ if (port < 1024) {
+ lprintf(-1, "Reserved port %d not permitted\n",
+ port);
+ return (1);
+ }
break;
case 'P':
/* For compatibility. */
@@ -218,9 +242,8 @@ main(int argc, char *argv[])
}
break;
case 'r':
- errno = 0;
- retries = strtol(optarg, NULL, 0);
- if (errno == EINVAL || retries < 0) {
+ error = asciitoint(optarg, &retries, 0);
+ if (error || retries < 0) {
lprintf(-1, "Invalid retry limit\n");
usage(argv0);
return (1);
@@ -270,15 +293,16 @@ main(int argc, char *argv[])
if (config == NULL)
return (1);
- if (laddr != NULL) {
- config->laddr = laddr;
- config->laddrlen = laddrlen;
- }
if (config_checkcolls(config) == 0) {
lprintf(-1, "No collections selected\n");
return (1);
}
+ if (laddr != NULL) {
+ config->laddr = laddr;
+ config->laddrlen = laddrlen;
+ }
+ config->deletelim = deletelim;
lprintf(2, "Connecting to %s\n", config->host);
i = 0;
diff --git a/contrib/csup/misc.c b/contrib/csup/misc.c
index b97a542..97a02ab 100644
--- a/contrib/csup/misc.c
+++ b/contrib/csup/misc.c
@@ -34,6 +34,7 @@
#include <err.h>
#include <errno.h>
#include <fcntl.h>
+#include <limits.h>
#include <pthread.h>
#include <stdarg.h>
#include <stdio.h>
@@ -64,6 +65,24 @@ static void bt_update(struct backoff_timer *);
static void bt_addjitter(struct backoff_timer *);
int
+asciitoint(const char *s, int *val, int base)
+{
+ char *end;
+ long longval;
+
+ errno = 0;
+ longval = strtol(s, &end, base);
+ if (errno || *end != '\0')
+ return (-1);
+ if (longval > INT_MAX || longval < INT_MIN) {
+ errno = ERANGE;
+ return (-1);
+ }
+ *val = longval;
+ return (0);
+}
+
+int
lprintf(int level, const char *fmt, ...)
{
FILE *to;
diff --git a/contrib/csup/misc.h b/contrib/csup/misc.h
index 47f9767..f0d0352 100644
--- a/contrib/csup/misc.h
+++ b/contrib/csup/misc.h
@@ -99,6 +99,7 @@ struct backoff_timer;
struct pattlist;
struct tm;
+int asciitoint(const char *, int *, int);
int lprintf(int, const char *, ...) __printflike(2, 3);
int MD5_File(char *, char *);
void MD5_End(char *, MD5_CTX *);
@@ -125,4 +126,5 @@ struct backoff_timer *bt_new(time_t, time_t, float, float);
time_t bt_get(struct backoff_timer *);
void bt_pause(struct backoff_timer *);
void bt_free(struct backoff_timer *);
+
#endif /* !_MISC_H_ */
diff --git a/contrib/csup/proto.c b/contrib/csup/proto.c
index 04f5495..0a89858 100644
--- a/contrib/csup/proto.c
+++ b/contrib/csup/proto.c
@@ -35,7 +35,6 @@
#include <assert.h>
#include <err.h>
#include <errno.h>
-#include <limits.h>
#include <netdb.h>
#include <pthread.h>
#include <signal.h>
@@ -228,7 +227,7 @@ proto_negproto(struct config *config)
stream_flush(s);
line = stream_getln(s, NULL);
cmd = proto_get_ascii(&line);
- if (line == NULL)
+ if (cmd == NULL || line == NULL)
goto bad;
if (strcmp(cmd, "!") == 0) {
msg = proto_get_rest(&line);
@@ -256,13 +255,20 @@ static int
proto_login(struct config *config)
{
struct stream *s;
- char host[MAXHOSTNAMELEN];
- char *line, *cmd, *realm, *challenge, *msg;
+ char hostbuf[MAXHOSTNAMELEN];
+ char *line, *login, *host, *cmd, *realm, *challenge, *msg;
+ int error;
s = config->server;
- gethostname(host, sizeof(host));
- host[sizeof(host) - 1] = '\0';
- proto_printf(s, "USER %s %s\n", getlogin(), host);
+ error = gethostname(hostbuf, sizeof(hostbuf));
+ hostbuf[sizeof(hostbuf) - 1] = '\0';
+ if (error)
+ host = NULL;
+ else
+ host = hostbuf;
+ login = getlogin();
+ proto_printf(s, "USER %s %s\n", login != NULL ? login : "?",
+ host != NULL ? host : "?");
stream_flush(s);
line = stream_getln(s, NULL);
cmd = proto_get_ascii(&line);
@@ -279,6 +285,8 @@ proto_login(struct config *config)
stream_flush(s);
line = stream_getln(s, NULL);
cmd = proto_get_ascii(&line);
+ if (cmd == NULL || line == NULL)
+ goto bad;
if (strcmp(cmd, "OK") == 0)
return (STATUS_SUCCESS);
if (strcmp(cmd, "!") == 0) {
@@ -371,9 +379,11 @@ proto_xchgcoll(struct config *config)
}
proto_printf(s, ".\n");
stream_flush(s);
+
STAILQ_FOREACH(coll, &config->colls, co_next) {
if (coll->co_options & CO_SKIP)
continue;
+ coll->co_norsync = globtree_false();
line = stream_getln(s, NULL);
if (line == NULL)
goto bad;
@@ -430,7 +440,21 @@ proto_xchgcoll(struct config *config)
ident);
if (error)
goto bad;
- }
+ } else if (strcmp(cmd, "NORS") == 0) {
+ pat = proto_get_ascii(&line);
+ if (pat == NULL || line != NULL)
+ goto bad;
+ coll->co_norsync = globtree_or(coll->co_norsync,
+ globtree_match(pat, FNM_PATHNAME));
+ } else if (strcmp(cmd, "RNORS") == 0) {
+ pat = proto_get_ascii(&line);
+ if (pat == NULL || line != NULL)
+ goto bad;
+ coll->co_norsync = globtree_or(coll->co_norsync,
+ globtree_match(pat, FNM_PATHNAME |
+ FNM_LEADING_DIR));
+ } else
+ goto bad;
}
if (line == NULL)
goto bad;
@@ -904,22 +928,14 @@ proto_get_rest(char **s)
int
proto_get_int(char **s, int *val, int base)
{
- char *cp, *end;
- long longval;
+ char *cp;
+ int error;
cp = proto_get_ascii(s);
if (cp == NULL)
return (-1);
- errno = 0;
- longval = strtol(cp, &end, base);
- if (errno || *end != '\0')
- return (-1);
- if (longval > INT_MAX || longval < INT_MIN) {
- errno = ERANGE;
- return (-1);
- }
- *val = longval;
- return (0);
+ error = asciitoint(cp, val, base);
+ return (error);
}
/*
diff --git a/contrib/csup/token.h b/contrib/csup/token.h
index 45d4ed7..0dc3ec0 100644
--- a/contrib/csup/token.h
+++ b/contrib/csup/token.h
@@ -44,5 +44,6 @@ int yyparse(void);
#define PT_DELETE 8
#define PT_USE_REL_SUFFIX 9
#define PT_LIST 10
+#define PT_NORSYNC 11
#endif /* !_TOKEN_H_ */
diff --git a/contrib/csup/token.l b/contrib/csup/token.l
index 0def82d..267e61f 100644
--- a/contrib/csup/token.l
+++ b/contrib/csup/token.l
@@ -56,6 +56,7 @@ release { yylval.i = PT_RELEASE; return NAME; }
tag { yylval.i = PT_TAG; return NAME; }
umask { yylval.i = PT_UMASK; return NAME; }
list { yylval.i = PT_LIST; return NAME; }
+norsync { yylval.i = PT_NORSYNC; return NAME; }
= { return EQUAL; }
compress { yylval.i = PT_COMPRESS; return BOOLEAN; }
delete { yylval.i = PT_DELETE; return BOOLEAN; }
diff --git a/contrib/csup/updater.c b/contrib/csup/updater.c
index 235bfca..df74d52 100644
--- a/contrib/csup/updater.c
+++ b/contrib/csup/updater.c
@@ -54,11 +54,13 @@
#define UPDATER_ERR_PROTO (-1) /* Protocol error. */
#define UPDATER_ERR_MSG (-2) /* Error is in updater->errmsg. */
#define UPDATER_ERR_READ (-3) /* Error reading from server. */
+#define UPDATER_ERR_DELETELIM (-4) /* File deletion limit exceeded. */
/* Everything needed to update a file. */
struct file_update {
struct statusrec srbuf;
char *destpath;
+ char *temppath;
char *coname; /* Points somewhere in destpath. */
char *wantmd5;
struct coll *coll;
@@ -74,6 +76,7 @@ struct updater {
struct config *config;
struct stream *rd;
char *errmsg;
+ int deletecount;
};
static struct file_update *fup_new(struct coll *, struct status *);
@@ -84,14 +87,13 @@ static void fup_free(struct file_update *);
static void updater_prunedirs(char *, char *);
static int updater_batch(struct updater *, int);
static int updater_docoll(struct updater *, struct file_update *, int);
-static void updater_delete(struct file_update *);
+static int updater_delete(struct updater *, struct file_update *);
+static void updater_deletefile(const char *);
static int updater_checkout(struct updater *, struct file_update *, int);
static int updater_setattrs(struct updater *, struct file_update *,
char *, char *, char *, char *, char *, struct fattr *);
-static void updater_checkmd5(struct updater *, struct file_update *,
- const char *, int);
static int updater_updatefile(struct updater *, struct file_update *fup,
- const char *, const char *);
+ const char *, int);
static int updater_diff(struct updater *, struct file_update *);
static int updater_diff_batch(struct updater *, struct file_update *);
static int updater_diff_apply(struct updater *, struct file_update *,
@@ -134,6 +136,10 @@ fup_cleanup(struct file_update *fup)
free(fup->destpath);
fup->destpath = NULL;
}
+ if (fup->temppath != NULL) {
+ free(fup->temppath);
+ fup->temppath = NULL;
+ }
fup->coname = NULL;
if (fup->author != NULL) {
free(fup->author);
@@ -188,6 +194,7 @@ updater(void *arg)
up->config = args->config;
up->rd = args->rd;
up->errmsg = NULL;
+ up->deletecount = 0;
error = updater_batch(up, 0);
@@ -218,6 +225,11 @@ updater(void *arg)
}
args->status = STATUS_TRANSIENTFAILURE;
break;
+ case UPDATER_ERR_DELETELIM:
+ xasprintf(&args->errmsg, "Updater failed: "
+ "File deletion limit exceeded");
+ args->status = STATUS_FAILURE;
+ break;
default:
assert(error == 0);
args->status = STATUS_SUCCESS;
@@ -261,12 +273,11 @@ updater_batch(struct updater *up, int isfixups)
stream_filter_start(rd, STREAM_FILTER_ZLIB, NULL);
st = status_open(coll, coll->co_scantime, &errmsg);
- fup = fup_new(coll, st);
if (st == NULL) {
- fup_free(fup);
up->errmsg = errmsg;
return (UPDATER_ERR_MSG);
}
+ fup = fup_new(coll, st);
error = updater_docoll(up, fup, isfixups);
status_close(st, &errmsg);
fup_free(fup);
@@ -360,8 +371,11 @@ updater_docoll(struct updater *up, struct file_update *fup, int isfixups)
/* Theoritically, the file does not exist on the client.
Just to make sure, we'll delete it here, if it
exists. */
- if (access(fup->destpath, F_OK) == 0)
- updater_delete(fup);
+ if (access(fup->destpath, F_OK) == 0) {
+ error = updater_delete(up, fup);
+ if (error)
+ return (error);
+ }
sr = &srbuf;
sr->sr_type = SR_CHECKOUTDEAD;
@@ -410,6 +424,7 @@ updater_docoll(struct updater *up, struct file_update *fup, int isfixups)
return (UPDATER_ERR_PROTO);
fup->wantmd5 = xstrdup(wantmd5);
+ fup->temppath = tempname(fup->destpath);
error = updater_diff(up, fup);
if (error)
return (error);
@@ -426,7 +441,9 @@ updater_docoll(struct updater *up, struct file_update *fup, int isfixups)
error = fup_prepare(fup, name);
if (error)
return (UPDATER_ERR_PROTO);
- updater_delete(fup);
+ error = updater_delete(up, fup);
+ if (error)
+ return (error);
sr = &srbuf;
sr->sr_type = SR_CHECKOUTDEAD;
sr->sr_file = name;
@@ -478,6 +495,7 @@ updater_docoll(struct updater *up, struct file_update *fup, int isfixups)
error = fup_prepare(fup, name);
if (error)
return (UPDATER_ERR_PROTO);
+ fup->temppath = tempname(fup->destpath);
if (*cmd == 'Y')
error = updater_checkout(up, fup, 1);
else
@@ -493,7 +511,9 @@ updater_docoll(struct updater *up, struct file_update *fup, int isfixups)
error = fup_prepare(fup, name);
if (error)
return (UPDATER_ERR_PROTO);
- updater_delete(fup);
+ error = updater_delete(up, fup);
+ if (error)
+ return (error);
error = status_delete(fup->st, name, 0);
if (error) {
up->errmsg = status_errmsg(fup->st);
@@ -518,27 +538,39 @@ updater_docoll(struct updater *up, struct file_update *fup, int isfixups)
}
/* Delete file. */
-static void
-updater_delete(struct file_update *fup)
+static int
+updater_delete(struct updater *up, struct file_update *fup)
{
+ struct config *config;
struct coll *coll;
- int error;
- /* XXX - delete limit handling */
+ config = up->config;
coll = fup->coll;
if (coll->co_options & CO_DELETE) {
lprintf(1, " Delete %s\n", fup->coname);
- error = fattr_delete(fup->destpath);
- if (error) {
- lprintf(-1, "Cannot delete \"%s\": %s\n",
- fup->destpath, strerror(errno));
- return;
- }
+ if (config->deletelim >= 0 &&
+ up->deletecount >= config->deletelim)
+ return (UPDATER_ERR_DELETELIM);
+ up->deletecount++;
+ updater_deletefile(fup->destpath);
if (coll->co_options & CO_CHECKOUTMODE)
updater_prunedirs(coll->co_prefix, fup->destpath);
} else {
lprintf(1," NoDelete %s\n", fup->coname);
}
+ return (0);
+}
+
+static void
+updater_deletefile(const char *path)
+{
+ int error;
+
+ error = fattr_delete(path);
+ if (error && errno != ENOENT) {
+ lprintf(-1, "Cannot delete \"%s\": %s\n",
+ path, strerror(errno));
+ }
}
static int
@@ -613,34 +645,9 @@ updater_setattrs(struct updater *up, struct file_update *fup, char *name,
return (0);
}
-/*
- * Check that the file we created/updated has a correct MD5 checksum.
- * If it doesn't and that this is not a fixup update, add a fixup
- * request to checkout the whole file. If it's already a fixup update,
- * we just fail.
- */
-static void
-updater_checkmd5(struct updater *up, struct file_update *fup, const char *md5,
- int isfixup)
-{
- struct statusrec *sr;
-
- sr = &fup->srbuf;
- if (strcmp(fup->wantmd5, md5) == 0)
- return;
- if (isfixup) {
- lprintf(-1, "%s: Checksum mismatch -- file not updated\n",
- fup->destpath);
- return;
- }
- lprintf(-1, "%s: Checksum mismatch -- will transfer entire file\n",
- fup->destpath);
- fixups_put(up->config->fixups, fup->coll, sr->sr_file);
-}
-
static int
-updater_updatefile(struct updater *up, struct file_update *fup, const char *to,
- const char *from)
+updater_updatefile(struct updater *up, struct file_update *fup,
+ const char *md5, int isfixup)
{
struct coll *coll;
struct status *st;
@@ -652,16 +659,27 @@ updater_updatefile(struct updater *up, struct file_update *fup, const char *to,
sr = &fup->srbuf;
st = fup->st;
+ if (strcmp(fup->wantmd5, md5) != 0) {
+ if (isfixup) {
+ lprintf(-1, "%s: Checksum mismatch -- "
+ "file not updated\n", fup->destpath);
+ } else {
+ lprintf(-1, "%s: Checksum mismatch -- "
+ "will transfer entire file\n", fup->destpath);
+ fixups_put(up->config->fixups, fup->coll, sr->sr_file);
+ }
+ if (coll->co_options & CO_KEEPBADFILES)
+ lprintf(-1, "Bad version saved in %s\n", fup->temppath);
+ else
+ updater_deletefile(fup->temppath);
+ return (0);
+ }
+
fattr_umask(sr->sr_clientattr, coll->co_umask);
- rv = fattr_install(sr->sr_clientattr, to, from);
+ rv = fattr_install(sr->sr_clientattr, fup->destpath, fup->temppath);
if (rv == -1) {
- if (from == NULL)
- xasprintf(&up->errmsg, "Cannot install \"%s\": %s",
- to, strerror(errno));
- else
- xasprintf(&up->errmsg,
- "Cannot install \"%s\" to \"%s\": %s",
- from, to, strerror(errno));
+ xasprintf(&up->errmsg, "Cannot install \"%s\" to \"%s\": %s",
+ fup->temppath, fup->destpath, strerror(errno));
return (UPDATER_ERR_MSG);
}
@@ -676,9 +694,9 @@ updater_updatefile(struct updater *up, struct file_update *fup, const char *to,
* server. This is important for preserving hard links in mirror
* mode.
*/
- fileattr = fattr_frompath(to, FATTR_NOFOLLOW);
+ fileattr = fattr_frompath(fup->destpath, FATTR_NOFOLLOW);
if (fileattr == NULL) {
- xasprintf(&up->errmsg, "Cannot stat \"%s\": %s", to,
+ xasprintf(&up->errmsg, "Cannot stat \"%s\": %s", fup->destpath,
strerror(errno));
return (UPDATER_ERR_MSG);
}
@@ -715,10 +733,9 @@ updater_diff(struct updater *up, struct file_update *fup)
struct statusrec *sr;
struct fattr *fa, *tmp;
char *author, *path, *revnum, *revdate;
- char *line, *cmd, *temppath;
+ char *line, *cmd;
int error;
- temppath = NULL;
coll = fup->coll;
sr = &fup->srbuf;
path = fup->destpath;
@@ -728,18 +745,14 @@ updater_diff(struct updater *up, struct file_update *fup)
if (strcmp(line, ".") == 0)
break;
cmd = proto_get_ascii(&line);
- if (cmd == NULL || strcmp(cmd, "D") != 0) {
- error = UPDATER_ERR_PROTO;
- goto bad;
- }
+ if (cmd == NULL || strcmp(cmd, "D") != 0)
+ return (UPDATER_ERR_PROTO);
revnum = proto_get_ascii(&line);
proto_get_ascii(&line); /* XXX - diffbase */
revdate = proto_get_ascii(&line);
author = proto_get_ascii(&line);
- if (author == NULL || line != NULL) {
- error = UPDATER_ERR_PROTO;
- goto bad;
- }
+ if (author == NULL || line != NULL)
+ return (UPDATER_ERR_PROTO);
if (sr->sr_revnum != NULL)
free(sr->sr_revnum);
if (sr->sr_revdate != NULL)
@@ -755,36 +768,32 @@ updater_diff(struct updater *up, struct file_update *fup)
if (fup->orig == NULL) {
xasprintf(&up->errmsg, "%s: Cannot open: %s",
path, strerror(errno));
- error = UPDATER_ERR_MSG;
- goto bad;
+ return (UPDATER_ERR_MSG);
}
} else {
/* Subsequent patches. */
stream_close(fup->orig);
fup->orig = fup->to;
stream_rewind(fup->orig);
- unlink(temppath);
- free(temppath);
+ unlink(fup->temppath);
+ free(fup->temppath);
+ fup->temppath = tempname(path);
}
- temppath = tempname(path);
- fup->to = stream_open_file(temppath,
- O_RDWR | O_CREAT | O_EXCL, 0600);
+ fup->to = stream_open_file(fup->temppath,
+ O_RDWR | O_CREAT | O_TRUNC, 0600);
if (fup->to == NULL) {
xasprintf(&up->errmsg, "%s: Cannot open: %s",
- temppath, strerror(errno));
- error = UPDATER_ERR_MSG;
- goto bad;
+ fup->temppath, strerror(errno));
+ return (UPDATER_ERR_MSG);
}
lprintf(2, " Add delta %s %s %s\n", sr->sr_revnum,
sr->sr_revdate, fup->author);
error = updater_diff_batch(up, fup);
if (error)
- goto bad;
- }
- if (line == NULL) {
- error = UPDATER_ERR_READ;
- goto bad;
+ return (error);
}
+ if (line == NULL)
+ return (UPDATER_ERR_READ);
fa = fattr_frompath(path, FATTR_FOLLOW);
tmp = fattr_forcheckout(sr->sr_serverattr, coll->co_umask);
@@ -793,24 +802,13 @@ updater_diff(struct updater *up, struct file_update *fup)
fattr_maskout(fa, FA_MODTIME);
sr->sr_clientattr = fa;
- error = updater_updatefile(up, fup, path, temppath);
- if (error)
- goto bad;
-
- if (MD5_File(path, md5) == -1) {
+ if (MD5_File(fup->temppath, md5) == -1) {
xasprintf(&up->errmsg,
"Cannot calculate checksum for \"%s\": %s",
path, strerror(errno));
- error = UPDATER_ERR_MSG;
- goto bad;
+ return (UPDATER_ERR_MSG);
}
- updater_checkmd5(up, fup, md5, 0);
- free(temppath);
- return (0);
-bad:
- assert(error);
- if (temppath != NULL)
- free(temppath);
+ error = updater_updatefile(up, fup, md5, 0);
return (error);
}
@@ -934,10 +932,11 @@ updater_checkout(struct updater *up, struct file_update *fup, int isfixup)
return (UPDATER_ERR_MSG);
}
- to = stream_open_file(path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ to = stream_open_file(fup->temppath,
+ O_WRONLY | O_CREAT | O_TRUNC, 0600);
if (to == NULL) {
xasprintf(&up->errmsg, "%s: Cannot create: %s",
- path, strerror(errno));
+ fup->temppath, strerror(errno));
return (UPDATER_ERR_MSG);
}
stream_filter_start(to, STREAM_FILTER_MD5, md5);
@@ -980,14 +979,14 @@ updater_checkout(struct updater *up, struct file_update *fup, int isfixup)
fup->wantmd5 = proto_get_ascii(&line);
if (fup->wantmd5 == NULL || line != NULL || strcmp(cmd, "5") != 0)
return (UPDATER_ERR_PROTO);
- updater_checkmd5(up, fup, md5, isfixup);
+ error = updater_updatefile(up, fup, md5, isfixup);
fup->wantmd5 = NULL; /* So that it doesn't get freed. */
- error = updater_updatefile(up, fup, path, NULL);
if (error)
return (error);
return (0);
bad:
- xasprintf(&up->errmsg, "%s: Cannot write: %s", path, strerror(errno));
+ xasprintf(&up->errmsg, "%s: Cannot write: %s", fup->temppath,
+ strerror(errno));
return (UPDATER_ERR_MSG);
}
OpenPOWER on IntegriCloud