1/*-
2 * Copyright (c) 2003-2006, Maxime Henrion <mux@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD$
27 */
28
29#include <sys/types.h>
30#include <sys/stat.h>
31
32#include <assert.h>
33#include <err.h>
34#include <errno.h>
35#include <fcntl.h>
36#include <stddef.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <string.h>
40#include <unistd.h>
41
42#include "config.h"
43#include "diff.h"
44#include "fattr.h"
45#include "fixups.h"
46#include "keyword.h"
47#include "updater.h"
48#include "misc.h"
49#include "mux.h"
50#include "proto.h"
51#include "rcsfile.h"
52#include "status.h"
53#include "stream.h"
54
55/* Internal error codes. */
56#define	UPDATER_ERR_PROTO	(-1)	/* Protocol error. */
57#define	UPDATER_ERR_MSG		(-2)	/* Error is in updater->errmsg. */
58#define	UPDATER_ERR_READ	(-3)	/* Error reading from server. */
59#define	UPDATER_ERR_DELETELIM	(-4)	/* File deletion limit exceeded. */
60
61#define BUFSIZE 4096
62
63/* Everything needed to update a file. */
64struct file_update {
65	struct statusrec srbuf;
66	char *destpath;
67	char *temppath;
68	char *origpath;
69	char *coname;		/* Points somewhere in destpath. */
70	char *wantmd5;
71	struct coll *coll;
72	struct status *st;
73	/* Those are only used for diff updating. */
74	char *author;
75	struct stream *orig;
76	struct stream *to;
77	int attic;
78	int expand;
79};
80
81struct updater {
82	struct config *config;
83	struct stream *rd;
84	char *errmsg;
85	int deletecount;
86};
87
88static struct file_update	*fup_new(struct coll *, struct status *);
89static int	 fup_prepare(struct file_update *, char *, int);
90static void	 fup_cleanup(struct file_update *);
91static void	 fup_free(struct file_update *);
92
93static void	 updater_prunedirs(char *, char *);
94static int	 updater_batch(struct updater *, int);
95static int	 updater_docoll(struct updater *, struct file_update *, int);
96static int	 updater_delete(struct updater *, struct file_update *);
97static void	 updater_deletefile(const char *);
98static int	 updater_checkout(struct updater *, struct file_update *, int);
99static int	 updater_addfile(struct updater *, struct file_update *,
100		     char *, int);
101int		 updater_addelta(struct rcsfile *, struct stream *, char *);
102static int	 updater_setattrs(struct updater *, struct file_update *,
103		     char *, char *, char *, char *, char *, struct fattr *);
104static int	updater_setdirattrs(struct updater *, struct coll *,
105		     struct file_update *, char *, char *);
106static int	 updater_updatefile(struct updater *, struct file_update *fup,
107		     const char *, int);
108static int	 updater_updatenode(struct updater *, struct coll *,
109		     struct file_update *, char *, char *);
110static int	 updater_diff(struct updater *, struct file_update *);
111static int	 updater_diff_batch(struct updater *, struct file_update *);
112static int	 updater_diff_apply(struct updater *, struct file_update *,
113		     char *);
114static int	 updater_rcsedit(struct updater *, struct file_update *, char *,
115		     char *);
116int		 updater_append_file(struct updater *, struct file_update *,
117		     off_t);
118static int	 updater_rsync(struct updater *, struct file_update *, size_t);
119static int	 updater_read_checkout(struct stream *, struct stream *);
120
121static struct file_update *
122fup_new(struct coll *coll, struct status *st)
123{
124	struct file_update *fup;
125
126	fup = xmalloc(sizeof(struct file_update));
127	memset(fup, 0, sizeof(*fup));
128	fup->coll = coll;
129	fup->st = st;
130	return (fup);
131}
132
133static int
134fup_prepare(struct file_update *fup, char *name, int attic)
135{
136	struct coll *coll;
137
138	coll = fup->coll;
139	fup->attic = 0;
140	fup->origpath = NULL;
141
142	if (coll->co_options & CO_CHECKOUTMODE)
143		fup->destpath = checkoutpath(coll->co_prefix, name);
144	else {
145		fup->destpath = cvspath(coll->co_prefix, name, attic);
146		fup->origpath = atticpath(coll->co_prefix, name);
147		/* If they're equal, we don't need special care. */
148		if (fup->origpath != NULL &&
149		    strcmp(fup->origpath, fup->destpath) == 0) {
150			free(fup->origpath);
151			fup->origpath = NULL;
152		}
153		fup->attic = attic;
154	}
155	if (fup->destpath == NULL)
156		return (-1);
157	fup->coname = fup->destpath + coll->co_prefixlen + 1;
158	return (0);
159}
160
161/* Called after each file update to reinit the structure. */
162static void
163fup_cleanup(struct file_update *fup)
164{
165	struct statusrec *sr;
166
167	sr = &fup->srbuf;
168
169	if (fup->destpath != NULL) {
170		free(fup->destpath);
171		fup->destpath = NULL;
172	}
173	if (fup->temppath != NULL) {
174		free(fup->temppath);
175		fup->temppath = NULL;
176	}
177	if (fup->origpath != NULL) {
178		free(fup->origpath);
179		fup->origpath = NULL;
180	}
181	fup->coname = NULL;
182	if (fup->author != NULL) {
183		free(fup->author);
184		fup->author = NULL;
185	}
186	fup->expand = 0;
187	if (fup->wantmd5 != NULL) {
188		free(fup->wantmd5);
189		fup->wantmd5 = NULL;
190	}
191	if (fup->orig != NULL) {
192		stream_close(fup->orig);
193		fup->orig = NULL;
194	}
195	if (fup->to != NULL) {
196		stream_close(fup->to);
197		fup->to = NULL;
198	}
199	if (sr->sr_file != NULL)
200		free(sr->sr_file);
201	if (sr->sr_tag != NULL)
202		free(sr->sr_tag);
203	if (sr->sr_date != NULL)
204		free(sr->sr_date);
205	if (sr->sr_revnum != NULL)
206		free(sr->sr_revnum);
207	if (sr->sr_revdate != NULL)
208		free(sr->sr_revdate);
209	fattr_free(sr->sr_clientattr);
210	fattr_free(sr->sr_serverattr);
211	memset(sr, 0, sizeof(*sr));
212}
213
214static void
215fup_free(struct file_update *fup)
216{
217
218	fup_cleanup(fup);
219	free(fup);
220}
221
222void *
223updater(void *arg)
224{
225	struct thread_args *args;
226	struct updater upbuf, *up;
227	int error;
228
229	args = arg;
230
231	up = &upbuf;
232	up->config = args->config;
233	up->rd = args->rd;
234	up->errmsg = NULL;
235	up->deletecount = 0;
236
237	error = updater_batch(up, 0);
238
239	/*
240	 * Make sure to close the fixups even in case of an error,
241	 * so that the detailer thread doesn't block indefinitely.
242	 */
243	fixups_close(up->config->fixups);
244	if (!error)
245		error = updater_batch(up, 1);
246	switch (error) {
247	case UPDATER_ERR_PROTO:
248		xasprintf(&args->errmsg, "Updater failed: Protocol error");
249		args->status = STATUS_FAILURE;
250		break;
251	case UPDATER_ERR_MSG:
252		xasprintf(&args->errmsg, "Updater failed: %s", up->errmsg);
253		free(up->errmsg);
254		args->status = STATUS_FAILURE;
255		break;
256	case UPDATER_ERR_READ:
257		if (stream_eof(up->rd)) {
258			xasprintf(&args->errmsg, "Updater failed: "
259			    "Premature EOF from server");
260		} else {
261			xasprintf(&args->errmsg, "Updater failed: "
262			    "Network read failure: %s", strerror(errno));
263		}
264		args->status = STATUS_TRANSIENTFAILURE;
265		break;
266	case UPDATER_ERR_DELETELIM:
267		xasprintf(&args->errmsg, "Updater failed: "
268		    "File deletion limit exceeded");
269		args->status = STATUS_FAILURE;
270		break;
271	default:
272		assert(error == 0);
273		args->status = STATUS_SUCCESS;
274	};
275	return (NULL);
276}
277
278static int
279updater_batch(struct updater *up, int isfixups)
280{
281	struct stream *rd;
282	struct coll *coll;
283	struct status *st;
284	struct file_update *fup;
285	char *line, *cmd, *errmsg, *collname, *release;
286	int error;
287
288	rd = up->rd;
289	STAILQ_FOREACH(coll, &up->config->colls, co_next) {
290		if (coll->co_options & CO_SKIP)
291			continue;
292		umask(coll->co_umask);
293		line = stream_getln(rd, NULL);
294		if (line == NULL)
295			return (UPDATER_ERR_READ);
296		cmd = proto_get_ascii(&line);
297		collname = proto_get_ascii(&line);
298		release = proto_get_ascii(&line);
299		if (release == NULL || line != NULL)
300			return (UPDATER_ERR_PROTO);
301		if (strcmp(cmd, "COLL") != 0 ||
302		    strcmp(collname, coll->co_name) != 0 ||
303		    strcmp(release, coll->co_release) != 0)
304			return (UPDATER_ERR_PROTO);
305
306		if (!isfixups)
307			lprintf(1, "Updating collection %s/%s\n", coll->co_name,
308			    coll->co_release);
309
310		if (coll->co_options & CO_COMPRESS)
311			stream_filter_start(rd, STREAM_FILTER_ZLIB, NULL);
312
313		st = status_open(coll, coll->co_scantime, &errmsg);
314		if (st == NULL) {
315			up->errmsg = errmsg;
316			return (UPDATER_ERR_MSG);
317		}
318		fup = fup_new(coll, st);
319		error = updater_docoll(up, fup, isfixups);
320		status_close(st, &errmsg);
321		fup_free(fup);
322		if (errmsg != NULL) {
323			/* Discard previous error. */
324			if (up->errmsg != NULL)
325				free(up->errmsg);
326			up->errmsg = errmsg;
327			return (UPDATER_ERR_MSG);
328		}
329		if (error)
330			return (error);
331
332		if (coll->co_options & CO_COMPRESS)
333			stream_filter_stop(rd);
334	}
335	line = stream_getln(rd, NULL);
336	if (line == NULL)
337		return (UPDATER_ERR_READ);
338	if (strcmp(line, ".") != 0)
339		return (UPDATER_ERR_PROTO);
340	return (0);
341}
342
343static int
344updater_docoll(struct updater *up, struct file_update *fup, int isfixups)
345{
346	struct stream *rd;
347	struct coll *coll;
348	struct statusrec srbuf, *sr;
349	struct fattr *rcsattr, *tmp;
350	char *attr, *cmd, *blocksize, *line, *msg;
351	char *name, *tag, *date, *revdate;
352	char *expand, *wantmd5, *revnum;
353	char *optstr, *rcsopt, *pos;
354	time_t t;
355	off_t position;
356	int attic, error, needfixupmsg;
357
358	error = 0;
359	rd = up->rd;
360	coll = fup->coll;
361	needfixupmsg = isfixups;
362	while ((line = stream_getln(rd, NULL)) != NULL) {
363		if (strcmp(line, ".") == 0)
364			break;
365		memset(&srbuf, 0, sizeof(srbuf));
366		if (needfixupmsg) {
367			lprintf(1, "Applying fixups for collection %s/%s\n",
368			    coll->co_name, coll->co_release);
369			needfixupmsg = 0;
370		}
371		cmd = proto_get_ascii(&line);
372		if (cmd == NULL || strlen(cmd) != 1)
373			return (UPDATER_ERR_PROTO);
374		switch (cmd[0]) {
375		case 'T':
376			/* Update recorded information for checked-out file. */
377			name = proto_get_ascii(&line);
378			tag = proto_get_ascii(&line);
379			date = proto_get_ascii(&line);
380			revnum = proto_get_ascii(&line);
381			revdate = proto_get_ascii(&line);
382			attr = proto_get_ascii(&line);
383			if (attr == NULL || line != NULL)
384				return (UPDATER_ERR_PROTO);
385
386			rcsattr = fattr_decode(attr);
387			if (rcsattr == NULL)
388				return (UPDATER_ERR_PROTO);
389
390			error = fup_prepare(fup, name, 0);
391			if (error)
392				return (UPDATER_ERR_PROTO);
393			error = updater_setattrs(up, fup, name, tag, date,
394			    revnum, revdate, rcsattr);
395			fattr_free(rcsattr);
396			if (error)
397				return (error);
398			break;
399		case 'c':
400			/* Checkout dead file. */
401			name = proto_get_ascii(&line);
402			tag = proto_get_ascii(&line);
403			date = proto_get_ascii(&line);
404			attr = proto_get_ascii(&line);
405			if (attr == NULL || line != NULL)
406				return (UPDATER_ERR_PROTO);
407
408			error = fup_prepare(fup, name, 0);
409			if (error)
410				return (UPDATER_ERR_PROTO);
411			/* Theoritically, the file does not exist on the client.
412			   Just to make sure, we'll delete it here, if it
413			   exists. */
414			if (access(fup->destpath, F_OK) == 0) {
415				error = updater_delete(up, fup);
416				if (error)
417					return (error);
418			}
419
420			sr = &srbuf;
421			sr->sr_type = SR_CHECKOUTDEAD;
422			sr->sr_file = name;
423			sr->sr_tag = tag;
424			sr->sr_date = date;
425			sr->sr_serverattr = fattr_decode(attr);
426			if (sr->sr_serverattr == NULL)
427				return (UPDATER_ERR_PROTO);
428
429			error = status_put(fup->st, sr);
430			fattr_free(sr->sr_serverattr);
431			if (error) {
432				up->errmsg = status_errmsg(fup->st);
433				return (UPDATER_ERR_MSG);
434			}
435			break;
436		case 'U':
437			/* Update live checked-out file. */
438			name = proto_get_ascii(&line);
439			tag = proto_get_ascii(&line);
440			date = proto_get_ascii(&line);
441			proto_get_ascii(&line);	/* XXX - oldRevNum */
442			proto_get_ascii(&line);	/* XXX - fromAttic */
443			proto_get_ascii(&line);	/* XXX - logLines */
444			expand = proto_get_ascii(&line);
445			attr = proto_get_ascii(&line);
446			wantmd5 = proto_get_ascii(&line);
447			if (wantmd5 == NULL || line != NULL)
448				return (UPDATER_ERR_PROTO);
449
450			sr = &fup->srbuf;
451			sr->sr_type = SR_CHECKOUTLIVE;
452			sr->sr_file = xstrdup(name);
453			sr->sr_date = xstrdup(date);
454			sr->sr_tag = xstrdup(tag);
455			sr->sr_serverattr = fattr_decode(attr);
456			if (sr->sr_serverattr == NULL)
457				return (UPDATER_ERR_PROTO);
458
459			fup->expand = keyword_decode_expand(expand);
460			if (fup->expand == -1)
461				return (UPDATER_ERR_PROTO);
462			error = fup_prepare(fup, name, 0);
463			if (error)
464				return (UPDATER_ERR_PROTO);
465
466			fup->wantmd5 = xstrdup(wantmd5);
467			fup->temppath = tempname(fup->destpath);
468			error = updater_diff(up, fup);
469			if (error)
470				return (error);
471			break;
472		case 'u':
473			/* Update dead checked-out file. */
474			name = proto_get_ascii(&line);
475			tag = proto_get_ascii(&line);
476			date = proto_get_ascii(&line);
477			attr = proto_get_ascii(&line);
478			if (attr == NULL || line != NULL)
479				return (UPDATER_ERR_PROTO);
480
481			error = fup_prepare(fup, name, 0);
482			if (error)
483				return (UPDATER_ERR_PROTO);
484			error = updater_delete(up, fup);
485			if (error)
486				return (error);
487			sr = &srbuf;
488			sr->sr_type = SR_CHECKOUTDEAD;
489			sr->sr_file = name;
490			sr->sr_tag = tag;
491			sr->sr_date = date;
492			sr->sr_serverattr = fattr_decode(attr);
493			if (sr->sr_serverattr == NULL)
494				return (UPDATER_ERR_PROTO);
495			error = status_put(fup->st, sr);
496			fattr_free(sr->sr_serverattr);
497			if (error) {
498				up->errmsg = status_errmsg(fup->st);
499				return (UPDATER_ERR_MSG);
500			}
501			break;
502		case 'C':
503		case 'Y':
504			/* Checkout file. */
505			name = proto_get_ascii(&line);
506			tag = proto_get_ascii(&line);
507			date = proto_get_ascii(&line);
508			revnum = proto_get_ascii(&line);
509			revdate = proto_get_ascii(&line);
510			attr = proto_get_ascii(&line);
511			if (attr == NULL || line != NULL)
512				return (UPDATER_ERR_PROTO);
513
514			sr = &fup->srbuf;
515			sr->sr_type = SR_CHECKOUTLIVE;
516			sr->sr_file = xstrdup(name);
517			sr->sr_tag = xstrdup(tag);
518			sr->sr_date = xstrdup(date);
519			sr->sr_revnum = xstrdup(revnum);
520			sr->sr_revdate = xstrdup(revdate);
521			sr->sr_serverattr = fattr_decode(attr);
522			if (sr->sr_serverattr == NULL)
523				return (UPDATER_ERR_PROTO);
524
525			t = rcsdatetotime(revdate);
526			if (t == -1)
527				return (UPDATER_ERR_PROTO);
528
529			sr->sr_clientattr = fattr_new(FT_FILE, t);
530			tmp = fattr_forcheckout(sr->sr_serverattr,
531			    coll->co_umask);
532			fattr_override(sr->sr_clientattr, tmp, FA_MASK);
533			fattr_free(tmp);
534			fattr_mergedefault(sr->sr_clientattr);
535			error = fup_prepare(fup, name, 0);
536			if (error)
537				return (UPDATER_ERR_PROTO);
538			fup->temppath = tempname(fup->destpath);
539			if (*cmd == 'Y')
540				error = updater_checkout(up, fup, 1);
541			else
542				error = updater_checkout(up, fup, 0);
543			if (error)
544				return (error);
545			break;
546		case 'D':
547			/* Delete file. */
548			name = proto_get_ascii(&line);
549			if (name == NULL || line != NULL)
550				return (UPDATER_ERR_PROTO);
551			error = fup_prepare(fup, name, 0);
552			if (error)
553				return (UPDATER_ERR_PROTO);
554			error = updater_delete(up, fup);
555			if (error)
556				return (error);
557			error = status_delete(fup->st, name, 0);
558			if (error) {
559				up->errmsg = status_errmsg(fup->st);
560				return (UPDATER_ERR_MSG);
561			}
562			break;
563		case 'A':
564		case 'a':
565		case 'R':
566			name = proto_get_ascii(&line);
567			attr = proto_get_ascii(&line);
568			if (name == NULL || attr == NULL || line != NULL)
569				return (UPDATER_ERR_PROTO);
570			attic = (cmd[0] == 'a');
571			error = fup_prepare(fup, name, attic);
572			if (error)
573				return (UPDATER_ERR_PROTO);
574
575			fup->temppath = tempname(fup->destpath);
576			sr = &fup->srbuf;
577			sr->sr_type = attic ? SR_FILEDEAD : SR_FILELIVE;
578			sr->sr_file = xstrdup(name);
579			sr->sr_serverattr = fattr_decode(attr);
580			if (sr->sr_serverattr == NULL)
581				return (UPDATER_ERR_PROTO);
582			if (attic)
583				lprintf(1, " Create %s -> Attic\n", name);
584			else
585				lprintf(1, " Create %s\n", name);
586			error = updater_addfile(up, fup, attr, 0);
587			if (error)
588				return (error);
589			break;
590		case 'r':
591			name = proto_get_ascii(&line);
592			attr = proto_get_ascii(&line);
593			blocksize = proto_get_ascii(&line);
594			wantmd5 = proto_get_ascii(&line);
595			if (name == NULL || attr == NULL || blocksize == NULL ||
596			    wantmd5 == NULL) {
597				return (UPDATER_ERR_PROTO);
598			}
599			error = fup_prepare(fup, name, 0);
600			if (error)
601				return (UPDATER_ERR_PROTO);
602			fup->wantmd5 = xstrdup(wantmd5);
603			fup->temppath = tempname(fup->destpath);
604			sr = &fup->srbuf;
605			sr->sr_file = xstrdup(name);
606			sr->sr_serverattr = fattr_decode(attr);
607			sr->sr_type = SR_FILELIVE;
608			if (sr->sr_serverattr == NULL)
609				return (UPDATER_ERR_PROTO);
610			error = updater_rsync(up, fup, strtol(blocksize, NULL,
611			    10));
612			if (error)
613				return (error);
614			break;
615		case 'I':
616			/*
617			 * Create directory and add DirDown entry in status
618			 * file.
619			 */
620			name = proto_get_ascii(&line);
621			if (name == NULL || line != NULL)
622				return (UPDATER_ERR_PROTO);
623			error = fup_prepare(fup, name, 0);
624			if (error)
625				return (UPDATER_ERR_PROTO);
626			sr = &fup->srbuf;
627			sr->sr_type = SR_DIRDOWN;
628			sr->sr_file = xstrdup(name);
629			sr->sr_serverattr = NULL;
630			sr->sr_clientattr = fattr_new(FT_DIRECTORY, -1);
631			fattr_mergedefault(sr->sr_clientattr);
632
633			error = mkdirhier(fup->destpath, coll->co_umask);
634			if (error)
635				return (UPDATER_ERR_PROTO);
636			if (access(fup->destpath, F_OK) != 0) {
637				lprintf(1, " Mkdir %s\n", name);
638				error = fattr_makenode(sr->sr_clientattr,
639				    fup->destpath);
640				if (error)
641					return (UPDATER_ERR_PROTO);
642			}
643			error = status_put(fup->st, sr);
644			if (error) {
645				up->errmsg = status_errmsg(fup->st);
646				return (UPDATER_ERR_MSG);
647			}
648			break;
649		case 'i':
650			/* Remove DirDown entry in status file. */
651			name = proto_get_ascii(&line);
652			if (name == NULL || line != NULL)
653				return (UPDATER_ERR_PROTO);
654			error = fup_prepare(fup, name, 0);
655			if (error)
656				return (UPDATER_ERR_PROTO);
657			error = status_delete(fup->st, name, 0);
658			if (error) {
659				up->errmsg = status_errmsg(fup->st);
660				return (UPDATER_ERR_MSG);
661			}
662			break;
663		case 'J':
664			/*
665			 * Set attributes of directory and update DirUp entry in
666			 * status file.
667			 */
668			name = proto_get_ascii(&line);
669			if (name == NULL)
670				return (UPDATER_ERR_PROTO);
671			attr = proto_get_ascii(&line);
672			if (attr == NULL || line != NULL)
673				return (UPDATER_ERR_PROTO);
674			error = fup_prepare(fup, name, 0);
675			if (error)
676				return (UPDATER_ERR_PROTO);
677			error = updater_setdirattrs(up, coll, fup, name, attr);
678			if (error)
679				return (error);
680			break;
681		case 'j':
682			/*
683			 * Remove directory and delete its DirUp entry in status
684			 * file.
685			 */
686			name = proto_get_ascii(&line);
687			if (name == NULL || line != NULL)
688				return (UPDATER_ERR_PROTO);
689			error = fup_prepare(fup, name, 0);
690			if (error)
691				return (UPDATER_ERR_PROTO);
692			lprintf(1, " Rmdir %s\n", name);
693			updater_deletefile(fup->destpath);
694			error = status_delete(fup->st, name, 0);
695			if (error) {
696				up->errmsg = status_errmsg(fup->st);
697				return (UPDATER_ERR_MSG);
698			}
699			break;
700		case 'L':
701		case 'l':
702			name = proto_get_ascii(&line);
703			if (name == NULL)
704				return (UPDATER_ERR_PROTO);
705			attr = proto_get_ascii(&line);
706			if (attr == NULL || line != NULL)
707				return (UPDATER_ERR_PROTO);
708			attic = (cmd[0] == 'l');
709			sr = &fup->srbuf;
710			sr->sr_type = attic ? SR_FILEDEAD : SR_FILELIVE;
711			sr->sr_file = xstrdup(name);
712			sr->sr_serverattr = fattr_decode(attr);
713			sr->sr_clientattr = fattr_decode(attr);
714			if (sr->sr_serverattr == NULL ||
715			    sr->sr_clientattr == NULL)
716				return (UPDATER_ERR_PROTO);
717
718			/* Save space. Described in detail in updatefile. */
719			if (!(fattr_getmask(sr->sr_clientattr) & FA_LINKCOUNT)
720			    || fattr_getlinkcount(sr->sr_clientattr) <= 1)
721				fattr_maskout(sr->sr_clientattr,
722				    FA_DEV | FA_INODE);
723			fattr_maskout(sr->sr_clientattr, FA_FLAGS);
724			error = status_put(fup->st, sr);
725			if (error) {
726				up->errmsg = status_errmsg(fup->st);
727				return (UPDATER_ERR_MSG);
728			}
729			break;
730		case 'N':
731		case 'n':
732			name = proto_get_ascii(&line);
733			attr = proto_get_ascii(&line);
734			if (name == NULL || attr == NULL || line != NULL)
735				return (UPDATER_ERR_PROTO);
736			attic = (cmd[0] == 'n');
737			error = fup_prepare(fup, name, attic);
738			if (error)
739				return (UPDATER_ERR_PROTO);
740			sr = &fup->srbuf;
741			sr->sr_type = (attic ? SR_FILEDEAD : SR_FILELIVE);
742			sr->sr_file = xstrdup(name);
743			sr->sr_serverattr = fattr_decode(attr);
744			sr->sr_clientattr = fattr_new(FT_SYMLINK, -1);
745			fattr_mergedefault(sr->sr_clientattr);
746			fattr_maskout(sr->sr_clientattr, FA_FLAGS);
747			error = updater_updatenode(up, coll, fup, name, attr);
748			if (error)
749				return (error);
750			break;
751		case 'V':
752		case 'v':
753			name = proto_get_ascii(&line);
754			attr = proto_get_ascii(&line);
755			optstr = proto_get_ascii(&line);
756			wantmd5 = proto_get_ascii(&line);
757			rcsopt = NULL; /* XXX: Not supported. */
758			if (attr == NULL || line != NULL || wantmd5 == NULL)
759				return (UPDATER_ERR_PROTO);
760			attic = (cmd[0] == 'v');
761			error = fup_prepare(fup, name, attic);
762			if (error)
763				return (UPDATER_ERR_PROTO);
764			fup->temppath = tempname(fup->destpath);
765			fup->wantmd5 = xstrdup(wantmd5);
766			sr = &fup->srbuf;
767			sr->sr_type = attic ? SR_FILEDEAD : SR_FILELIVE;
768			sr->sr_file = xstrdup(name);
769			sr->sr_serverattr = fattr_decode(attr);
770			if (sr->sr_serverattr == NULL)
771				return (UPDATER_ERR_PROTO);
772
773			error = updater_rcsedit(up, fup, name, rcsopt);
774			if (error)
775				return (error);
776			break;
777		case 'X':
778		case 'x':
779			name = proto_get_ascii(&line);
780			attr = proto_get_ascii(&line);
781			if (name == NULL || attr == NULL || line != NULL)
782				return (UPDATER_ERR_PROTO);
783			attic = (cmd[0] == 'x');
784			error = fup_prepare(fup, name, attic);
785			if (error)
786				return (UPDATER_ERR_PROTO);
787
788			fup->temppath = tempname(fup->destpath);
789			sr = &fup->srbuf;
790			sr->sr_type = attic ? SR_FILEDEAD : SR_FILELIVE;
791			sr->sr_file = xstrdup(name);
792			sr->sr_serverattr = fattr_decode(attr);
793			if (sr->sr_serverattr == NULL)
794				return (UPDATER_ERR_PROTO);
795			lprintf(1, " Fixup %s\n", name);
796			error = updater_addfile(up, fup, attr, 1);
797			if (error)
798				return (error);
799			break;
800		case 'Z':
801			name = proto_get_ascii(&line);
802			attr = proto_get_ascii(&line);
803			pos  = proto_get_ascii(&line);
804			if (name == NULL || attr == NULL || pos == NULL ||
805			    line != NULL)
806				return (UPDATER_ERR_PROTO);
807			error = fup_prepare(fup, name, 0);
808			fup->temppath = tempname(fup->destpath);
809			sr = &fup->srbuf;
810			sr->sr_type = SR_FILELIVE;
811			sr->sr_file = xstrdup(name);
812			sr->sr_serverattr = fattr_decode(attr);
813			if (sr->sr_serverattr == NULL)
814				return (UPDATER_ERR_PROTO);
815			position = strtol(pos, NULL, 10);
816			lprintf(1, " Append to %s\n", name);
817			error = updater_append_file(up, fup, position);
818			if (error)
819				return (error);
820			break;
821		case '!':
822			/* Warning from server. */
823			msg = proto_get_rest(&line);
824			if (msg == NULL)
825				return (UPDATER_ERR_PROTO);
826			lprintf(-1, "Server warning: %s\n", msg);
827			break;
828		default:
829			return (UPDATER_ERR_PROTO);
830		}
831		fup_cleanup(fup);
832	}
833	if (line == NULL)
834		return (UPDATER_ERR_READ);
835	return (0);
836}
837
838/* Delete file. */
839static int
840updater_delete(struct updater *up, struct file_update *fup)
841{
842	struct config *config;
843	struct coll *coll;
844
845	config = up->config;
846	coll = fup->coll;
847	if (coll->co_options & CO_DELETE) {
848		lprintf(1, " Delete %s\n", fup->coname);
849		if (config->deletelim >= 0 &&
850		    up->deletecount >= config->deletelim)
851			return (UPDATER_ERR_DELETELIM);
852		up->deletecount++;
853		updater_deletefile(fup->destpath);
854		if (coll->co_options & CO_CHECKOUTMODE)
855			updater_prunedirs(coll->co_prefix, fup->destpath);
856	} else {
857		lprintf(1," NoDelete %s\n", fup->coname);
858	}
859	return (0);
860}
861
862static void
863updater_deletefile(const char *path)
864{
865	int error;
866
867	error = fattr_delete(path);
868	if (error && errno != ENOENT) {
869		lprintf(-1, "Cannot delete \"%s\": %s\n",
870		    path, strerror(errno));
871	}
872}
873
874static int
875updater_setattrs(struct updater *up, struct file_update *fup, char *name,
876    char *tag, char *date, char *revnum, char *revdate, struct fattr *rcsattr)
877{
878	struct statusrec sr;
879	struct status *st;
880	struct coll *coll;
881	struct fattr *fileattr, *fa;
882	char *path;
883	int error, rv;
884
885	coll = fup->coll;
886	st = fup->st;
887	path = fup->destpath;
888
889	fileattr = fattr_frompath(path, FATTR_NOFOLLOW);
890	if (fileattr == NULL) {
891		/* The file has vanished. */
892		error = status_delete(st, name, 0);
893		if (error) {
894			up->errmsg = status_errmsg(st);
895			return (UPDATER_ERR_MSG);
896		}
897		return (0);
898	}
899	fa = fattr_forcheckout(rcsattr, coll->co_umask);
900	fattr_override(fileattr, fa, FA_MASK);
901	fattr_free(fa);
902
903	rv = fattr_install(fileattr, path, NULL);
904	if (rv == -1) {
905		lprintf(1, " SetAttrs %s\n", fup->coname);
906		fattr_free(fileattr);
907		xasprintf(&up->errmsg, "Cannot set attributes for \"%s\": %s",
908		    path, strerror(errno));
909		return (UPDATER_ERR_MSG);
910	}
911	if (rv == 1) {
912		lprintf(1, " SetAttrs %s\n", fup->coname);
913		fattr_free(fileattr);
914		fileattr = fattr_frompath(path, FATTR_NOFOLLOW);
915		if (fileattr == NULL) {
916			/* We're being very unlucky. */
917			error = status_delete(st, name, 0);
918			if (error) {
919				up->errmsg = status_errmsg(st);
920				return (UPDATER_ERR_MSG);
921			}
922			return (0);
923		}
924	}
925
926	fattr_maskout(fileattr, FA_COIGNORE);
927
928	sr.sr_type = SR_CHECKOUTLIVE;
929	sr.sr_file = name;
930	sr.sr_tag = tag;
931	sr.sr_date = date;
932	sr.sr_revnum = revnum;
933	sr.sr_revdate = revdate;
934	sr.sr_clientattr = fileattr;
935	sr.sr_serverattr = rcsattr;
936
937	error = status_put(st, &sr);
938	fattr_free(fileattr);
939	if (error) {
940		up->errmsg = status_errmsg(st);
941		return (UPDATER_ERR_MSG);
942	}
943	return (0);
944}
945
946static int
947updater_updatefile(struct updater *up, struct file_update *fup,
948    const char *md5, int isfixup)
949{
950	struct coll *coll;
951	struct status *st;
952	struct statusrec *sr;
953	struct fattr *fileattr;
954	int error, rv;
955
956	coll = fup->coll;
957	sr = &fup->srbuf;
958	st = fup->st;
959
960	if (strcmp(fup->wantmd5, md5) != 0) {
961		if (isfixup) {
962			lprintf(-1, "%s: Checksum mismatch -- "
963			    "file not updated\n", fup->destpath);
964		} else {
965			lprintf(-1, "%s: Checksum mismatch -- "
966			    "will transfer entire file\n", fup->destpath);
967			fixups_put(up->config->fixups, fup->coll, sr->sr_file);
968		}
969		if (coll->co_options & CO_KEEPBADFILES)
970			lprintf(-1, "Bad version saved in %s\n", fup->temppath);
971		else
972			updater_deletefile(fup->temppath);
973		return (0);
974	}
975
976	fattr_umask(sr->sr_clientattr, coll->co_umask);
977	rv = fattr_install(sr->sr_clientattr, fup->destpath, fup->temppath);
978	if (rv == -1) {
979		xasprintf(&up->errmsg, "Cannot install \"%s\" to \"%s\": %s",
980		    fup->temppath, fup->destpath, strerror(errno));
981		return (UPDATER_ERR_MSG);
982	}
983
984	/* XXX Executes */
985	/*
986	 * We weren't necessarily able to set all the file attributes to the
987	 * desired values, and any executes may have altered the attributes.
988	 * To make sure we record the actual attribute values, we fetch
989	 * them from the file.
990	 *
991	 * However, we preserve the link count as received from the
992	 * server.  This is important for preserving hard links in mirror
993	 * mode.
994	 */
995	fileattr = fattr_frompath(fup->destpath, FATTR_NOFOLLOW);
996	if (fileattr == NULL) {
997		xasprintf(&up->errmsg, "Cannot stat \"%s\": %s", fup->destpath,
998		    strerror(errno));
999		return (UPDATER_ERR_MSG);
1000	}
1001	fattr_override(fileattr, sr->sr_clientattr, FA_LINKCOUNT);
1002	fattr_free(sr->sr_clientattr);
1003	sr->sr_clientattr = fileattr;
1004
1005	/*
1006	 * To save space, don't write out the device and inode unless
1007	 * the link count is greater than 1.  These attributes are used
1008	 * only for detecting hard links.  If the link count is 1 then we
1009	 * know there aren't any hard links.
1010	 */
1011	if (!(fattr_getmask(sr->sr_clientattr) & FA_LINKCOUNT) ||
1012	    fattr_getlinkcount(sr->sr_clientattr) <= 1)
1013		fattr_maskout(sr->sr_clientattr, FA_DEV | FA_INODE);
1014
1015	if (coll->co_options & CO_CHECKOUTMODE)
1016		fattr_maskout(sr->sr_clientattr, FA_COIGNORE);
1017
1018	error = status_put(st, sr);
1019	if (error) {
1020		up->errmsg = status_errmsg(st);
1021		return (UPDATER_ERR_MSG);
1022	}
1023	return (0);
1024}
1025
1026/*
1027 * Update attributes of a directory.
1028 */
1029static int
1030updater_setdirattrs(struct updater *up, struct coll *coll,
1031    struct file_update *fup, char *name, char *attr)
1032{
1033	struct statusrec *sr;
1034	struct fattr *fa;
1035	int error, rv;
1036
1037	sr = &fup->srbuf;
1038	sr->sr_type = SR_DIRUP;
1039	sr->sr_file = xstrdup(name);
1040	sr->sr_clientattr = fattr_decode(attr);
1041	sr->sr_serverattr = fattr_decode(attr);
1042	if (sr->sr_clientattr == NULL || sr->sr_serverattr == NULL)
1043		return (UPDATER_ERR_PROTO);
1044	fattr_mergedefault(sr->sr_clientattr);
1045	fattr_umask(sr->sr_clientattr, coll->co_umask);
1046	rv = fattr_install(sr->sr_clientattr, fup->destpath, NULL);
1047	lprintf(1, " SetAttrs %s\n", name);
1048	if (rv == -1) {
1049		xasprintf(&up->errmsg, "Cannot install \"%s\" to \"%s\": %s",
1050		    fup->temppath, fup->destpath, strerror(errno));
1051		return (UPDATER_ERR_MSG);
1052	}
1053	/*
1054	 * Now, make sure they were set and record what was set in the status
1055	 * file.
1056	 */
1057	fa = fattr_frompath(fup->destpath, FATTR_NOFOLLOW);
1058	if (fa == NULL) {
1059		xasprintf(&up->errmsg, "Cannot open \%s\": %s", fup->destpath,
1060		    strerror(errno));
1061		return (UPDATER_ERR_MSG);
1062	}
1063	fattr_free(sr->sr_clientattr);
1064	fattr_maskout(fa, FA_FLAGS);
1065	sr->sr_clientattr = fa;
1066	error = status_put(fup->st, sr);
1067	if (error) {
1068		up->errmsg = status_errmsg(fup->st);
1069		return (UPDATER_ERR_MSG);
1070	}
1071
1072	return (0);
1073}
1074
1075static int
1076updater_diff(struct updater *up, struct file_update *fup)
1077{
1078	char md5[MD5_DIGEST_SIZE];
1079	struct coll *coll;
1080	struct statusrec *sr;
1081	struct fattr *fa, *tmp;
1082	char *author, *path, *revnum, *revdate;
1083	char *line, *cmd;
1084	int error;
1085
1086	coll = fup->coll;
1087	sr = &fup->srbuf;
1088	path = fup->destpath;
1089
1090	lprintf(1, " Edit %s\n", fup->coname);
1091	while ((line = stream_getln(up->rd, NULL)) != NULL) {
1092		if (strcmp(line, ".") == 0)
1093			break;
1094		cmd = proto_get_ascii(&line);
1095		if (cmd == NULL || strcmp(cmd, "D") != 0)
1096			return (UPDATER_ERR_PROTO);
1097		revnum = proto_get_ascii(&line);
1098		proto_get_ascii(&line); /* XXX - diffbase */
1099		revdate = proto_get_ascii(&line);
1100		author = proto_get_ascii(&line);
1101		if (author == NULL || line != NULL)
1102			return (UPDATER_ERR_PROTO);
1103		if (sr->sr_revnum != NULL)
1104			free(sr->sr_revnum);
1105		if (sr->sr_revdate != NULL)
1106			free(sr->sr_revdate);
1107		if (fup->author != NULL)
1108			free(fup->author);
1109		sr->sr_revnum = xstrdup(revnum);
1110		sr->sr_revdate = xstrdup(revdate);
1111		fup->author = xstrdup(author);
1112		if (fup->orig == NULL) {
1113			/* First patch, the "origin" file is the one we have. */
1114			fup->orig = stream_open_file(path, O_RDONLY);
1115			if (fup->orig == NULL) {
1116				xasprintf(&up->errmsg, "%s: Cannot open: %s",
1117				    path, strerror(errno));
1118				return (UPDATER_ERR_MSG);
1119			}
1120		} else {
1121			/* Subsequent patches. */
1122			stream_close(fup->orig);
1123			fup->orig = fup->to;
1124			stream_rewind(fup->orig);
1125			unlink(fup->temppath);
1126			free(fup->temppath);
1127			fup->temppath = tempname(path);
1128		}
1129		fup->to = stream_open_file(fup->temppath,
1130		    O_RDWR | O_CREAT | O_TRUNC, 0600);
1131		if (fup->to == NULL) {
1132			xasprintf(&up->errmsg, "%s: Cannot open: %s",
1133			    fup->temppath, strerror(errno));
1134			return (UPDATER_ERR_MSG);
1135		}
1136		lprintf(2, "  Add delta %s %s %s\n", sr->sr_revnum,
1137		    sr->sr_revdate, fup->author);
1138		error = updater_diff_batch(up, fup);
1139		if (error)
1140			return (error);
1141	}
1142	if (line == NULL)
1143		return (UPDATER_ERR_READ);
1144
1145	fa = fattr_frompath(path, FATTR_FOLLOW);
1146	tmp = fattr_forcheckout(sr->sr_serverattr, coll->co_umask);
1147	fattr_override(fa, tmp, FA_MASK);
1148	fattr_free(tmp);
1149	fattr_maskout(fa, FA_MODTIME);
1150	sr->sr_clientattr = fa;
1151
1152	if (MD5_File(fup->temppath, md5) == -1) {
1153		xasprintf(&up->errmsg,
1154		    "Cannot calculate checksum for \"%s\": %s",
1155		    path, strerror(errno));
1156		return (UPDATER_ERR_MSG);
1157	}
1158	error = updater_updatefile(up, fup, md5, 0);
1159	return (error);
1160}
1161
1162/*
1163 * Edit a file and add delta.
1164 */
1165static int
1166updater_diff_batch(struct updater *up, struct file_update *fup)
1167{
1168	struct stream *rd;
1169	char *cmd, *line, *state, *tok;
1170	int error;
1171
1172	state = NULL;
1173	rd = up->rd;
1174	while ((line = stream_getln(rd, NULL)) != NULL) {
1175		if (strcmp(line, ".") == 0)
1176			break;
1177		cmd = proto_get_ascii(&line);
1178		if (cmd == NULL || strlen(cmd) != 1) {
1179			error = UPDATER_ERR_PROTO;
1180			goto bad;
1181		}
1182		switch (cmd[0]) {
1183		case 'L':
1184			line = stream_getln(rd, NULL);
1185			/* XXX - We're just eating the log for now. */
1186			while (line != NULL && strcmp(line, ".") != 0 &&
1187			    strcmp(line, ".+") != 0)
1188				line = stream_getln(rd, NULL);
1189			if (line == NULL) {
1190				error = UPDATER_ERR_READ;
1191				goto bad;
1192			}
1193			break;
1194		case 'S':
1195			tok = proto_get_ascii(&line);
1196			if (tok == NULL || line != NULL) {
1197				error = UPDATER_ERR_PROTO;
1198				goto bad;
1199			}
1200			if (state != NULL)
1201				free(state);
1202			state = xstrdup(tok);
1203			break;
1204		case 'T':
1205			error = updater_diff_apply(up, fup, state);
1206			if (error)
1207				goto bad;
1208			break;
1209		default:
1210			error = UPDATER_ERR_PROTO;
1211			goto bad;
1212		}
1213	}
1214	if (line == NULL) {
1215		error = UPDATER_ERR_READ;
1216		goto bad;
1217	}
1218	if (state != NULL)
1219		free(state);
1220	return (0);
1221bad:
1222	if (state != NULL)
1223		free(state);
1224	return (error);
1225}
1226
1227int
1228updater_diff_apply(struct updater *up, struct file_update *fup, char *state)
1229{
1230	struct diffinfo dibuf, *di;
1231	struct coll *coll;
1232	struct statusrec *sr;
1233	int error;
1234
1235	coll = fup->coll;
1236	sr = &fup->srbuf;
1237	di = &dibuf;
1238
1239	di->di_rcsfile = sr->sr_file;
1240	di->di_cvsroot = coll->co_cvsroot;
1241	di->di_revnum = sr->sr_revnum;
1242	di->di_revdate = sr->sr_revdate;
1243	di->di_author = fup->author;
1244	di->di_tag = sr->sr_tag;
1245	di->di_state = state;
1246	di->di_expand = fup->expand;
1247
1248	error = diff_apply(up->rd, fup->orig, fup->to, coll->co_keyword, di, 1);
1249	if (error) {
1250		/* XXX Bad error message */
1251		xasprintf(&up->errmsg, "Bad diff from server");
1252		return (UPDATER_ERR_MSG);
1253	}
1254	return (0);
1255}
1256
1257/* Update or create a node. */
1258static int
1259updater_updatenode(struct updater *up, struct coll *coll,
1260    struct file_update *fup, char *name, char *attr)
1261{
1262	struct fattr *fa, *fileattr;
1263	struct status *st;
1264	struct statusrec *sr;
1265	int error, rv;
1266
1267	sr = &fup->srbuf;
1268	st = fup->st;
1269	fa = fattr_decode(attr);
1270
1271	if (fattr_type(fa) == FT_SYMLINK) {
1272		lprintf(1, " Symlink %s -> %s\n", name,
1273		    fattr_getlinktarget(fa));
1274	} else {
1275		lprintf(1, " Mknod %s\n", name);
1276	}
1277
1278	/* Create directory. */
1279	error = mkdirhier(fup->destpath, coll->co_umask);
1280	if (error)
1281		return (UPDATER_ERR_PROTO);
1282
1283	/* If it does not exist, create it. */
1284	if (access(fup->destpath, F_OK) != 0)
1285		fattr_makenode(fa, fup->destpath);
1286
1287	/*
1288	 * Coming from attic? I don't think this is a problem since we have
1289	 * determined attic before we call this function (Look at UpdateNode in
1290	 * cvsup).
1291	 */
1292	fattr_umask(fa, coll->co_umask);
1293	rv = fattr_install(fa, fup->destpath, fup->temppath);
1294	if (rv == -1) {
1295		xasprintf(&up->errmsg, "Cannot update attributes on "
1296	    "\"%s\": %s", fup->destpath, strerror(errno));
1297		return (UPDATER_ERR_MSG);
1298	}
1299	/*
1300	 * XXX: Executes not implemented. Have not encountered much use for it
1301	 * yet.
1302	 */
1303	/*
1304	 * We weren't necessarily able to set all the file attributes to the
1305	 * desired values, and any executes may have altered the attributes.
1306	 * To make sure we record the actual attribute values, we fetch
1307	 * them from the file.
1308	 *
1309	 * However, we preserve the link count as received from the
1310	 * server.  This is important for preserving hard links in mirror
1311	 * mode.
1312	 */
1313	fileattr = fattr_frompath(fup->destpath, FATTR_NOFOLLOW);
1314	if (fileattr == NULL) {
1315		xasprintf(&up->errmsg, "Cannot stat \"%s\": %s", fup->destpath,
1316		    strerror(errno));
1317		return (UPDATER_ERR_MSG);
1318	}
1319	fattr_override(fileattr, sr->sr_clientattr, FA_LINKCOUNT);
1320	fattr_free(sr->sr_clientattr);
1321	sr->sr_clientattr = fileattr;
1322
1323	/*
1324	 * To save space, don't write out the device and inode unless
1325	 * the link count is greater than 1.  These attributes are used
1326	 * only for detecting hard links.  If the link count is 1 then we
1327	 * know there aren't any hard links.
1328	 */
1329	if (!(fattr_getmask(sr->sr_clientattr) & FA_LINKCOUNT) ||
1330	    fattr_getlinkcount(sr->sr_clientattr) <= 1)
1331		fattr_maskout(sr->sr_clientattr, FA_DEV | FA_INODE);
1332
1333	/* If it is a symlink, write only out it's path. */
1334	if (fattr_type(fa) == FT_SYMLINK) {
1335		fattr_maskout(sr->sr_clientattr, ~(FA_FILETYPE |
1336		    FA_LINKTARGET));
1337	}
1338	fattr_maskout(sr->sr_clientattr, FA_FLAGS);
1339	error = status_put(st, sr);
1340	if (error) {
1341		up->errmsg = status_errmsg(st);
1342		return (UPDATER_ERR_MSG);
1343	}
1344	fattr_free(fa);
1345
1346	return (0);
1347}
1348
1349/*
1350 * Fetches a new file in CVS mode.
1351 */
1352static int
1353updater_addfile(struct updater *up, struct file_update *fup, char *attr,
1354    int isfixup)
1355{
1356	struct coll *coll;
1357	struct stream *to;
1358	struct statusrec *sr;
1359	struct fattr *fa;
1360	char buf[BUFSIZE];
1361	char md5[MD5_DIGEST_SIZE];
1362	ssize_t nread;
1363	off_t fsize, remains;
1364	char *cmd, *line, *path;
1365	int error;
1366
1367	coll = fup->coll;
1368	path = fup->destpath;
1369	sr = &fup->srbuf;
1370	fa = fattr_decode(attr);
1371	fsize = fattr_filesize(fa);
1372
1373	error = mkdirhier(path, coll->co_umask);
1374	if (error)
1375		return (UPDATER_ERR_PROTO);
1376	to = stream_open_file(fup->temppath, O_WRONLY | O_CREAT | O_TRUNC, 0755);
1377	if (to == NULL) {
1378		xasprintf(&up->errmsg, "%s: Cannot create: %s",
1379		    fup->temppath, strerror(errno));
1380		return (UPDATER_ERR_MSG);
1381	}
1382	stream_filter_start(to, STREAM_FILTER_MD5, md5);
1383	remains = fsize;
1384	do {
1385		nread = stream_read(up->rd, buf, (BUFSIZE > remains ?
1386		    remains : BUFSIZE));
1387		if (nread == -1)
1388			return (UPDATER_ERR_PROTO);
1389		remains -= nread;
1390		if (stream_write(to, buf, nread) == -1)
1391			goto bad;
1392	} while (remains > 0);
1393	stream_close(to);
1394	line = stream_getln(up->rd, NULL);
1395	if (line == NULL)
1396		return (UPDATER_ERR_PROTO);
1397	/* Check for EOF. */
1398	if (!(*line == '.' || (strncmp(line, ".<", 2) != 0)))
1399		return (UPDATER_ERR_PROTO);
1400	line = stream_getln(up->rd, NULL);
1401	if (line == NULL)
1402		return (UPDATER_ERR_PROTO);
1403
1404	cmd = proto_get_ascii(&line);
1405	fup->wantmd5 = proto_get_ascii(&line);
1406	if (fup->wantmd5 == NULL || line != NULL || strcmp(cmd, "5") != 0)
1407		return (UPDATER_ERR_PROTO);
1408
1409	sr->sr_clientattr = fattr_frompath(fup->temppath, FATTR_NOFOLLOW);
1410	if (sr->sr_clientattr == NULL)
1411		return (UPDATER_ERR_PROTO);
1412	fattr_override(sr->sr_clientattr, sr->sr_serverattr,
1413	    FA_MODTIME | FA_MASK);
1414	error = updater_updatefile(up, fup, md5, isfixup);
1415	fup->wantmd5 = NULL;	/* So that it doesn't get freed. */
1416	return (error);
1417bad:
1418	xasprintf(&up->errmsg, "%s: Cannot write: %s", fup->temppath,
1419	    strerror(errno));
1420	return (UPDATER_ERR_MSG);
1421}
1422
1423static int
1424updater_checkout(struct updater *up, struct file_update *fup, int isfixup)
1425{
1426	char md5[MD5_DIGEST_SIZE];
1427	struct statusrec *sr;
1428	struct coll *coll;
1429	struct stream *to;
1430	ssize_t nbytes;
1431	size_t size;
1432	char *cmd, *path, *line;
1433	int error, first;
1434
1435	coll = fup->coll;
1436	sr = &fup->srbuf;
1437	path = fup->destpath;
1438
1439	if (isfixup)
1440		lprintf(1, " Fixup %s\n", fup->coname);
1441	else
1442		lprintf(1, " Checkout %s\n", fup->coname);
1443	error = mkdirhier(path, coll->co_umask);
1444	if (error) {
1445		xasprintf(&up->errmsg,
1446		    "Cannot create directories leading to \"%s\": %s",
1447		    path, strerror(errno));
1448		return (UPDATER_ERR_MSG);
1449	}
1450
1451	to = stream_open_file(fup->temppath,
1452	    O_WRONLY | O_CREAT | O_TRUNC, 0600);
1453	if (to == NULL) {
1454		xasprintf(&up->errmsg, "%s: Cannot create: %s",
1455		    fup->temppath, strerror(errno));
1456		return (UPDATER_ERR_MSG);
1457	}
1458	stream_filter_start(to, STREAM_FILTER_MD5, md5);
1459	line = stream_getln(up->rd, &size);
1460	first = 1;
1461	while (line != NULL) {
1462		if (line[size - 1] == '\n')
1463			size--;
1464	       	if ((size == 1 && *line == '.') ||
1465		    (size == 2 && memcmp(line, ".+", 2) == 0))
1466			break;
1467		if (size >= 2 && memcmp(line, "..", 2) == 0) {
1468			size--;
1469			line++;
1470		}
1471		if (!first) {
1472			nbytes = stream_write(to, "\n", 1);
1473			if (nbytes == -1)
1474				goto bad;
1475		}
1476		nbytes = stream_write(to, line, size);
1477		if (nbytes == -1)
1478			goto bad;
1479		line = stream_getln(up->rd, &size);
1480		first = 0;
1481	}
1482	if (line == NULL) {
1483		stream_close(to);
1484		return (UPDATER_ERR_READ);
1485	}
1486	if (size == 1 && *line == '.') {
1487		nbytes = stream_write(to, "\n", 1);
1488		if (nbytes == -1)
1489			goto bad;
1490	}
1491	stream_close(to);
1492	/* Get the checksum line. */
1493	line = stream_getln(up->rd, NULL);
1494	if (line == NULL)
1495		return (UPDATER_ERR_READ);
1496	cmd = proto_get_ascii(&line);
1497	fup->wantmd5 = proto_get_ascii(&line);
1498	if (fup->wantmd5 == NULL || line != NULL || strcmp(cmd, "5") != 0)
1499		return (UPDATER_ERR_PROTO);
1500	error = updater_updatefile(up, fup, md5, isfixup);
1501	fup->wantmd5 = NULL;	/* So that it doesn't get freed. */
1502	if (error)
1503		return (error);
1504	return (0);
1505bad:
1506	xasprintf(&up->errmsg, "%s: Cannot write: %s", fup->temppath,
1507	    strerror(errno));
1508	return (UPDATER_ERR_MSG);
1509}
1510
1511/*
1512 * Remove all empty directories below file.
1513 * This function will trash the path passed to it.
1514 */
1515static void
1516updater_prunedirs(char *base, char *file)
1517{
1518	char *cp;
1519	int error;
1520
1521	while ((cp = strrchr(file, '/')) != NULL) {
1522		*cp = '\0';
1523		if (strcmp(base, file) == 0)
1524			return;
1525		error = rmdir(file);
1526		if (error)
1527			return;
1528	}
1529}
1530
1531/*
1532 * Edit an RCS file.
1533 */
1534static int
1535updater_rcsedit(struct updater *up, struct file_update *fup, char *name,
1536    char *rcsopt)
1537{
1538	struct coll *coll;
1539	struct stream *dest;
1540	struct statusrec *sr;
1541	struct status *st;
1542	struct rcsfile *rf;
1543	struct fattr *oldfattr;
1544	char md5[MD5_DIGEST_SIZE];
1545	char *branch, *cmd, *expand, *line, *path, *revnum, *tag, *temppath;
1546	int error;
1547
1548	coll = fup->coll;
1549	sr = &fup->srbuf;
1550	st = fup->st;
1551	temppath = fup->temppath;
1552	path = fup->origpath != NULL ? fup->origpath : fup->destpath;
1553	error = 0;
1554
1555	/* If the path is new, we must create the Attic dir if needed. */
1556	if (fup->origpath != NULL) {
1557		error = mkdirhier(fup->destpath, coll->co_umask);
1558		if (error) {
1559			xasprintf(&up->errmsg, "Unable to create Attic dir for "
1560			    "%s\n", fup->origpath);
1561			return (UPDATER_ERR_MSG);
1562		}
1563	}
1564	/*
1565	 * XXX: we could avoid parsing overhead if we're reading ahead before we
1566	 * parse the file.
1567	 */
1568	oldfattr = fattr_frompath(path, FATTR_NOFOLLOW);
1569	if (oldfattr == NULL) {
1570		xasprintf(&up->errmsg, "%s: Cannot get attributes: %s", path,
1571		    strerror(errno));
1572		return (UPDATER_ERR_MSG);
1573	}
1574	fattr_merge(sr->sr_serverattr, oldfattr);
1575	rf = NULL;
1576
1577	/* Macro for making touching an RCS file faster. */
1578#define UPDATER_OPENRCS(rf, up, path, name, cvsroot, tag) do {		\
1579	if ((rf) == NULL) {						\
1580		lprintf(1, " Edit %s", fup->coname);			\
1581		if (fup->attic)						\
1582			lprintf(1, " -> Attic");			\
1583		lprintf(1, "\n");					\
1584		(rf) = rcsfile_frompath((path), (name), (cvsroot),	\
1585		    (tag), 0);						\
1586		if ((rf) == NULL) {					\
1587			xasprintf(&(up)->errmsg,			\
1588			    "Error reading rcsfile %s\n", (name));	\
1589			return (UPDATER_ERR_MSG);			\
1590		}							\
1591	}								\
1592} while (0)
1593
1594	while ((line = stream_getln(up->rd, NULL)) != NULL) {
1595		if (strcmp(line, ".") == 0)
1596			break;
1597		cmd = proto_get_ascii(&line);
1598		if (cmd == NULL) {
1599			lprintf(-1, "Error editing %s\n", name);
1600			return (UPDATER_ERR_PROTO);
1601		}
1602		switch(cmd[0]) {
1603			case 'B':
1604				branch = proto_get_ascii(&line);
1605				if (branch == NULL || line != NULL)
1606					return (UPDATER_ERR_PROTO);
1607				UPDATER_OPENRCS(rf, up, path, name,
1608				    coll->co_cvsroot, coll->co_tag);
1609				break;
1610			case 'b':
1611				UPDATER_OPENRCS(rf, up, path, name,
1612				    coll->co_cvsroot, coll->co_tag);
1613				rcsfile_setval(rf, RCSFILE_BRANCH, NULL);
1614				break;
1615			case 'D':
1616				UPDATER_OPENRCS(rf, up, path, name,
1617				    coll->co_cvsroot, coll->co_tag);
1618				error = updater_addelta(rf, up->rd, line);
1619				if (error)
1620					return (error);
1621				break;
1622			case 'd':
1623				revnum = proto_get_ascii(&line);
1624				if (revnum == NULL || line != NULL)
1625					return (UPDATER_ERR_PROTO);
1626				UPDATER_OPENRCS(rf, up, path, name,
1627				    coll->co_cvsroot, coll->co_tag);
1628				rcsfile_deleterev(rf, revnum);
1629				break;
1630			case 'E':
1631				expand = proto_get_ascii(&line);
1632				if (expand == NULL || line != NULL)
1633					return (UPDATER_ERR_PROTO);
1634				UPDATER_OPENRCS(rf, up, path, name,
1635				    coll->co_cvsroot, coll->co_tag);
1636				rcsfile_setval(rf, RCSFILE_EXPAND, expand);
1637				break;
1638			case 'T':
1639				tag = proto_get_ascii(&line);
1640				revnum = proto_get_ascii(&line);
1641				if (tag == NULL || revnum == NULL ||
1642				    line != NULL)
1643					return (UPDATER_ERR_PROTO);
1644				UPDATER_OPENRCS(rf, up, path, name,
1645				    coll->co_cvsroot, coll->co_tag);
1646				rcsfile_addtag(rf, tag, revnum);
1647				break;
1648			case 't':
1649				tag = proto_get_ascii(&line);
1650				revnum = proto_get_ascii(&line);
1651				if (tag == NULL || revnum == NULL ||
1652				    line != NULL)
1653					return (UPDATER_ERR_PROTO);
1654				UPDATER_OPENRCS(rf, up, path, name,
1655				    coll->co_cvsroot, coll->co_tag);
1656				rcsfile_deletetag(rf, tag, revnum);
1657				break;
1658			default:
1659				return (UPDATER_ERR_PROTO);
1660		}
1661	}
1662
1663	if (rf == NULL) {
1664		fattr_maskout(oldfattr, ~FA_MODTIME);
1665		if (fattr_equal(oldfattr, sr->sr_serverattr))
1666		 	lprintf(1, " SetAttrs %s", fup->coname);
1667		else
1668			lprintf(1, " Touch %s", fup->coname);
1669		/* Install new attributes. */
1670		fattr_umask(sr->sr_serverattr, coll->co_umask);
1671		fattr_install(sr->sr_serverattr, fup->destpath, NULL);
1672		if (fup->attic)
1673			lprintf(1, " -> Attic");
1674		lprintf(1, "\n");
1675		fattr_free(oldfattr);
1676		goto finish;
1677	}
1678
1679	/* Write and rename temp file. */
1680	dest = stream_open_file(fup->temppath,
1681	    O_RDWR | O_CREAT | O_TRUNC, 0600);
1682	if (dest == NULL) {
1683		xasprintf(&up->errmsg, "Error opening file %s for writing: %s\n",
1684		    fup->temppath, strerror(errno));
1685		return (UPDATER_ERR_MSG);
1686	}
1687	stream_filter_start(dest, STREAM_FILTER_MD5RCS, md5);
1688	error = rcsfile_write(rf, dest);
1689	stream_close(dest);
1690	rcsfile_free(rf);
1691	if (error) {
1692		xasprintf(&up->errmsg, "%s: Cannot write: %s", fup->temppath,
1693		    strerror(errno));
1694		return (UPDATER_ERR_MSG);
1695	}
1696
1697finish:
1698	sr->sr_clientattr = fattr_frompath(path, FATTR_NOFOLLOW);
1699	if (sr->sr_clientattr == NULL) {
1700		xasprintf(&up->errmsg, "%s: Cannot get attributes: %s",
1701		    fup->destpath, strerror(errno));
1702		return (UPDATER_ERR_MSG);
1703	}
1704	fattr_override(sr->sr_clientattr, sr->sr_serverattr,
1705	    FA_MODTIME | FA_MASK);
1706	if (rf != NULL) {
1707		error = updater_updatefile(up, fup, md5, 0);
1708		fup->wantmd5 = NULL;	/* So that it doesn't get freed. */
1709		if (error)
1710			return (error);
1711	} else {
1712		/* Record its attributes since we touched it. */
1713		if (!(fattr_getmask(sr->sr_clientattr) & FA_LINKCOUNT) ||
1714		    fattr_getlinkcount(sr->sr_clientattr) <= 1)
1715		fattr_maskout(sr->sr_clientattr, FA_DEV | FA_INODE);
1716		error = status_put(st, sr);
1717		if (error) {
1718			up->errmsg = status_errmsg(st);
1719			return (UPDATER_ERR_MSG);
1720		}
1721	}
1722
1723	/* In this case, we need to remove the old file afterwards. */
1724	/* XXX: Can we be sure that a file not edited is moved? I don't think
1725	 * this is a problem, since if a file is moved, it should be edited to
1726	 * show if it's dead or not.
1727	 */
1728	if (fup->origpath != NULL)
1729		updater_deletefile(fup->origpath);
1730	return (0);
1731}
1732
1733/*
1734 * Add a delta to a RCS file.
1735 */
1736int
1737updater_addelta(struct rcsfile *rf, struct stream *rd, char *cmdline)
1738{
1739	struct delta *d;
1740	size_t size;
1741	char *author, *cmd, *diffbase, *line, *logline;
1742	char *revdate, *revnum, *state, *textline;
1743
1744	revnum = proto_get_ascii(&cmdline);
1745	diffbase = proto_get_ascii(&cmdline);
1746	revdate = proto_get_ascii(&cmdline);
1747	author = proto_get_ascii(&cmdline);
1748	size = 0;
1749
1750	if (revnum == NULL || revdate == NULL || author == NULL)
1751		return (UPDATER_ERR_PROTO);
1752
1753	/* First add the delta so we have it. */
1754	d = rcsfile_addelta(rf, revnum, revdate, author, diffbase);
1755	if (d == NULL) {
1756		lprintf(-1, "Error adding delta %s\n", revnum);
1757		return (UPDATER_ERR_READ);
1758	}
1759	while ((line = stream_getln(rd, NULL)) != NULL) {
1760		if (strcmp(line, ".") == 0)
1761			break;
1762		cmd = proto_get_ascii(&line);
1763		switch (cmd[0]) {
1764			case 'L':
1765				/* Do the same as in 'C' command. */
1766				logline = stream_getln(rd, &size);
1767				while (logline != NULL) {
1768					if (size == 2 && *logline == '.')
1769						break;
1770					if (size == 3 &&
1771					    memcmp(logline, ".+", 2) == 0) {
1772						rcsdelta_truncatelog(d, -1);
1773						break;
1774					}
1775					if (size >= 3 &&
1776					    memcmp(logline, "..", 2) == 0) {
1777						size--;
1778						logline++;
1779					}
1780					if (rcsdelta_appendlog(d, logline, size)
1781					    < 0)
1782						return (-1);
1783					logline = stream_getln(rd, &size);
1784				}
1785			break;
1786			case 'N':
1787			case 'n':
1788				/* XXX: Not supported. */
1789			break;
1790			case 'S':
1791				state = proto_get_ascii(&line);
1792				if (state == NULL)
1793					return (UPDATER_ERR_PROTO);
1794				rcsdelta_setstate(d, state);
1795			break;
1796			case 'T':
1797				/* Do the same as in 'C' command. */
1798				textline = stream_getln(rd, &size);
1799				while (textline != NULL) {
1800					if (size == 2 && *textline == '.')
1801						break;
1802					if (size == 3 &&
1803					    memcmp(textline, ".+", 2) == 0) {
1804						/* Truncate newline. */
1805						rcsdelta_truncatetext(d, -1);
1806						break;
1807					}
1808					if (size >= 3 &&
1809					    memcmp(textline, "..", 2) == 0) {
1810						size--;
1811						textline++;
1812					}
1813					if (rcsdelta_appendtext(d, textline,
1814					    size) < 0)
1815						return (-1);
1816					textline = stream_getln(rd, &size);
1817				}
1818			break;
1819		}
1820	}
1821
1822	return (0);
1823}
1824
1825int
1826updater_append_file(struct updater *up, struct file_update *fup, off_t pos)
1827{
1828	struct fattr *fa;
1829	struct stream *to;
1830	struct statusrec *sr;
1831	ssize_t nread;
1832	off_t bytes;
1833	char buf[BUFSIZE], md5[MD5_DIGEST_SIZE];
1834	char *line, *cmd;
1835	int error, fd;
1836
1837	sr = &fup->srbuf;
1838	fa = sr->sr_serverattr;
1839	to = stream_open_file(fup->temppath, O_WRONLY | O_CREAT | O_TRUNC,
1840	    0755);
1841	if (to == NULL) {
1842		xasprintf(&up->errmsg, "%s: Cannot open: %s", fup->temppath,
1843		    strerror(errno));
1844		return (UPDATER_ERR_MSG);
1845	}
1846	fd = open(fup->destpath, O_RDONLY);
1847	if (fd < 0) {
1848		xasprintf(&up->errmsg, "%s: Cannot open: %s", fup->destpath,
1849		    strerror(errno));
1850		return (UPDATER_ERR_MSG);
1851	}
1852
1853	stream_filter_start(to, STREAM_FILTER_MD5, md5);
1854	/* First write the existing content. */
1855	while ((nread = read(fd, buf, BUFSIZE)) > 0) {
1856		if (stream_write(to, buf, nread) == -1)
1857			goto bad;
1858	}
1859	if (nread == -1) {
1860		xasprintf(&up->errmsg, "%s: Error reading: %s", fup->destpath,
1861		    strerror(errno));
1862		return (UPDATER_ERR_MSG);
1863	}
1864	close(fd);
1865
1866	bytes = fattr_filesize(fa) - pos;
1867	/* Append the new data. */
1868	do {
1869		nread = stream_read(up->rd, buf,
1870		    (BUFSIZE > bytes) ? bytes : BUFSIZE);
1871		if (nread == -1)
1872			return (UPDATER_ERR_PROTO);
1873		bytes -= nread;
1874		if (stream_write(to, buf, nread) == -1)
1875			goto bad;
1876	} while (bytes > 0);
1877	stream_close(to);
1878
1879	line = stream_getln(up->rd, NULL);
1880	if (line == NULL)
1881		return (UPDATER_ERR_PROTO);
1882	/* Check for EOF. */
1883	if (!(*line == '.' || (strncmp(line, ".<", 2) != 0)))
1884		return (UPDATER_ERR_PROTO);
1885	line = stream_getln(up->rd, NULL);
1886	if (line == NULL)
1887		return (UPDATER_ERR_PROTO);
1888
1889	cmd = proto_get_ascii(&line);
1890	fup->wantmd5 = proto_get_ascii(&line);
1891	if (fup->wantmd5 == NULL || line != NULL || strcmp(cmd, "5") != 0)
1892		return (UPDATER_ERR_PROTO);
1893
1894	sr->sr_clientattr = fattr_frompath(fup->destpath, FATTR_NOFOLLOW);
1895	if (sr->sr_clientattr == NULL)
1896		return (UPDATER_ERR_PROTO);
1897	fattr_override(sr->sr_clientattr, sr->sr_serverattr,
1898	    FA_MODTIME | FA_MASK);
1899	error = updater_updatefile(up, fup, md5, 0);
1900	fup->wantmd5 = NULL;	/* So that it doesn't get freed. */
1901	return (error);
1902bad:
1903	xasprintf(&up->errmsg, "%s: Cannot write: %s", fup->temppath,
1904	    strerror(errno));
1905	return (UPDATER_ERR_MSG);
1906}
1907
1908/*
1909 * Read file data from stream of checkout commands, and write it to the
1910 * destination.
1911 */
1912static int
1913updater_read_checkout(struct stream *src, struct stream *dest)
1914{
1915	ssize_t nbytes;
1916	size_t size;
1917	char *line;
1918	int first;
1919
1920	first = 1;
1921	line = stream_getln(src, &size);
1922	while (line != NULL) {
1923		if (line[size - 1] == '\n')
1924			size--;
1925		if ((size == 1 && *line == '.') ||
1926		    (size == 2 && strncmp(line, ".+", 2) == 0))
1927			break;
1928		if (size >= 2 && strncmp(line, "..", 2) == 0) {
1929			size--;
1930			line++;
1931		}
1932		if (!first) {
1933			nbytes = stream_write(dest, "\n", 1);
1934			if (nbytes == -1)
1935				return (UPDATER_ERR_MSG);
1936		}
1937		nbytes = stream_write(dest, line, size);
1938		if (nbytes == -1)
1939			return (UPDATER_ERR_MSG);
1940		line = stream_getln(src, &size);
1941		first = 0;
1942	}
1943	if (line == NULL)
1944		return (UPDATER_ERR_READ);
1945	if (size == 1 && *line == '.') {
1946		nbytes = stream_write(dest, "\n", 1);
1947		if (nbytes == -1)
1948			return (UPDATER_ERR_MSG);
1949	}
1950	return (0);
1951}
1952
1953/* Update file using the rsync protocol. */
1954static int
1955updater_rsync(struct updater *up, struct file_update *fup, size_t blocksize)
1956{
1957	struct statusrec *sr;
1958	struct stream *to;
1959	char md5[MD5_DIGEST_SIZE];
1960	ssize_t nbytes;
1961	size_t blocknum, blockstart, blockcount;
1962	char *buf, *line;
1963	int error, orig;
1964
1965	sr = &fup->srbuf;
1966
1967	lprintf(1, " Rsync %s\n", fup->coname);
1968	/* First open all files that we are going to work on. */
1969	to = stream_open_file(fup->temppath, O_WRONLY | O_CREAT | O_TRUNC,
1970	    0600);
1971	if (to == NULL) {
1972		xasprintf(&up->errmsg, "%s: Cannot create: %s",
1973		    fup->temppath, strerror(errno));
1974		return (UPDATER_ERR_MSG);
1975	}
1976	orig = open(fup->destpath, O_RDONLY);
1977	if (orig < 0) {
1978		xasprintf(&up->errmsg, "%s: Cannot open: %s",
1979		    fup->destpath, strerror(errno));
1980		return (UPDATER_ERR_MSG);
1981	}
1982	stream_filter_start(to, STREAM_FILTER_MD5, md5);
1983
1984	error = updater_read_checkout(up->rd, to);
1985	if (error) {
1986		xasprintf(&up->errmsg, "%s: Cannot write: %s", fup->temppath,
1987		    strerror(errno));
1988		return (error);
1989	}
1990
1991	/* Buffer must contain blocksize bytes. */
1992	buf = xmalloc(blocksize);
1993	/* Done with the initial text, read and write chunks. */
1994	line = stream_getln(up->rd, NULL);
1995	while (line != NULL) {
1996		if (strcmp(line, ".") == 0)
1997			break;
1998		error = UPDATER_ERR_PROTO;
1999		if (proto_get_sizet(&line, &blockstart, 10) != 0)
2000			goto bad;
2001		if (proto_get_sizet(&line, &blockcount, 10) != 0)
2002			goto bad;
2003		/* Read blocks from original file. */
2004		lseek(orig, (blocksize * blockstart), SEEK_SET);
2005		error = UPDATER_ERR_MSG;
2006		for (blocknum = 0; blocknum < blockcount; blocknum++) {
2007			nbytes = read(orig, buf, blocksize);
2008			if (nbytes < 0) {
2009				xasprintf(&up->errmsg, "%s: Cannot read: %s",
2010				    fup->destpath, strerror(errno));
2011				goto bad;
2012			}
2013			nbytes = stream_write(to, buf, nbytes);
2014			if (nbytes == -1) {
2015				xasprintf(&up->errmsg, "%s: Cannot write: %s",
2016				    fup->temppath, strerror(errno));
2017				goto bad;
2018			}
2019		}
2020		/* Get the remaining text from the server. */
2021		error = updater_read_checkout(up->rd, to);
2022		if (error) {
2023			xasprintf(&up->errmsg, "%s: Cannot write: %s",
2024			    fup->temppath, strerror(errno));
2025			goto bad;
2026		}
2027		line = stream_getln(up->rd, NULL);
2028	}
2029	stream_close(to);
2030	close(orig);
2031
2032	sr->sr_clientattr = fattr_frompath(fup->destpath, FATTR_NOFOLLOW);
2033	if (sr->sr_clientattr == NULL)
2034		return (UPDATER_ERR_PROTO);
2035	fattr_override(sr->sr_clientattr, sr->sr_serverattr,
2036	    FA_MODTIME | FA_MASK);
2037
2038	error = updater_updatefile(up, fup, md5, 0);
2039	fup->wantmd5 = NULL;	/* So that it doesn't get freed. */
2040bad:
2041	free(buf);
2042	return (error);
2043}
2044