summaryrefslogtreecommitdiffstats
path: root/contrib/csup/updater.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/csup/updater.c')
-rw-r--r--contrib/csup/updater.c201
1 files changed, 100 insertions, 101 deletions
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