Import the latest snapshot of csup (20060313).
This commit is contained in:
parent
91be0d8ce3
commit
7d6ea92e92
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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"
|
||||
|
||||
|
421
contrib/csup/idcache.c
Normal file
421
contrib/csup/idcache.c
Normal file
@ -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);
|
||||
}
|
41
contrib/csup/idcache.h
Normal file
41
contrib/csup/idcache.h
Normal file
@ -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_ */
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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>
|
||||
@ -63,6 +64,24 @@ struct backoff_timer {
|
||||
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, ...)
|
||||
{
|
||||
|
@ -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_ */
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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_ */
|
||||
|
@ -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; }
|
||||
|
@ -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;
|
||||
|
||||
fattr_umask(sr->sr_clientattr, coll->co_umask);
|
||||
rv = fattr_install(sr->sr_clientattr, to, from);
|
||||
if (rv == -1) {
|
||||
if (from == NULL)
|
||||
xasprintf(&up->errmsg, "Cannot install \"%s\": %s",
|
||||
to, strerror(errno));
|
||||
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
|
||||
xasprintf(&up->errmsg,
|
||||
"Cannot install \"%s\" to \"%s\": %s",
|
||||
from, to, strerror(errno));
|
||||
updater_deletefile(fup->temppath);
|
||||
return (0);
|
||||
}
|
||||
|
||||
fattr_umask(sr->sr_clientattr, coll->co_umask);
|
||||
rv = fattr_install(sr->sr_clientattr, fup->destpath, fup->temppath);
|
||||
if (rv == -1) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user