From owner-svn-src-all@FreeBSD.ORG Tue Mar 17 06:54:42 2009 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id B04C5106564A; Tue, 17 Mar 2009 06:54:42 +0000 (UTC) (envelope-from lulf@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 9BE798FC0A; Tue, 17 Mar 2009 06:54:42 +0000 (UTC) (envelope-from lulf@FreeBSD.org) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id n2H6sg0t085516; Tue, 17 Mar 2009 06:54:42 GMT (envelope-from lulf@svn.freebsd.org) Received: (from lulf@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id n2H6sgpu085502; Tue, 17 Mar 2009 06:54:42 GMT (envelope-from lulf@svn.freebsd.org) Message-Id: <200903170654.n2H6sgpu085502@svn.freebsd.org> From: Ulf Lilleengen Date: Tue, 17 Mar 2009 06:54:42 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-7@freebsd.org X-SVN-Group: stable-7 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r189918 - in stable/7: contrib/csup usr.bin/csup X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 17 Mar 2009 06:54:43 -0000 Author: lulf Date: Tue Mar 17 06:54:41 2009 New Revision: 189918 URL: http://svn.freebsd.org/changeset/base/189918 Log: MFH: r186781 Merge support for CVSMode (aka. mirror mode) into csup. This means csup can now fetch a complete CVS repository. Support for rsync update of regular files are also included, but are not yet enabled. The change should not have an impact on existing csup usage, as little of the existing code has changed. r186871 - Update manpage now that cvs mode is supported. r188405 - Fix an issue where file attributes were not installed correctly during a Touch and SetAttrs operation. - SetAttrs and Touch were incorrectly switched. r188644 - Do not free the pattern lists immediately after use, as they might be needed again in case the connection is interrupted and csup have to reconnect. The lists will be freed after the collection has been completely processed. r189455 - Try to handle rcsfile write failures in the same way as cvsup, as they are not necessarily fatal. If the file was incorrectly written, the checksum will detect it and the file will be retransferred. Added: stable/7/contrib/csup/lex.rcs.c - copied unchanged from r186781, head/contrib/csup/lex.rcs.c stable/7/contrib/csup/rcsfile.c - copied unchanged from r186781, head/contrib/csup/rcsfile.c stable/7/contrib/csup/rcsfile.h - copied unchanged from r186781, head/contrib/csup/rcsfile.h stable/7/contrib/csup/rcsparse.c - copied unchanged from r186781, head/contrib/csup/rcsparse.c stable/7/contrib/csup/rcsparse.h - copied unchanged from r186781, head/contrib/csup/rcsparse.h stable/7/contrib/csup/rcstokenizer.h - copied unchanged from r186781, head/contrib/csup/rcstokenizer.h stable/7/contrib/csup/rcstokenizer.l - copied unchanged from r186781, head/contrib/csup/rcstokenizer.l stable/7/contrib/csup/rsyncfile.c - copied unchanged from r186781, head/contrib/csup/rsyncfile.c stable/7/contrib/csup/rsyncfile.h - copied unchanged from r186781, head/contrib/csup/rsyncfile.h Modified: stable/7/contrib/csup/ (props changed) stable/7/contrib/csup/GNUmakefile stable/7/contrib/csup/Makefile stable/7/contrib/csup/TODO stable/7/contrib/csup/config.c stable/7/contrib/csup/csup.1 stable/7/contrib/csup/detailer.c stable/7/contrib/csup/diff.c stable/7/contrib/csup/diff.h stable/7/contrib/csup/fattr.c stable/7/contrib/csup/fattr.h stable/7/contrib/csup/keyword.c stable/7/contrib/csup/keyword.h stable/7/contrib/csup/lister.c stable/7/contrib/csup/misc.c stable/7/contrib/csup/misc.h stable/7/contrib/csup/mux.c stable/7/contrib/csup/proto.c stable/7/contrib/csup/proto.h stable/7/contrib/csup/status.c stable/7/contrib/csup/stream.c stable/7/contrib/csup/stream.h stable/7/contrib/csup/updater.c stable/7/usr.bin/csup/ (props changed) stable/7/usr.bin/csup/Makefile Modified: stable/7/contrib/csup/GNUmakefile ============================================================================== --- stable/7/contrib/csup/GNUmakefile Tue Mar 17 05:57:43 2009 (r189917) +++ stable/7/contrib/csup/GNUmakefile Tue Mar 17 06:54:41 2009 (r189918) @@ -12,8 +12,9 @@ GROUP?= 0 UNAME= $(shell uname -s) 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 pathcomp.c \ - parse.c proto.c status.c stream.c threads.c token.c updater.c + globtree.c idcache.c keyword.c lex.rcs.c lister.c main.c misc.c mux.c \ + pathcomp.c parse.c proto.c rcsfile.c rcsparse.c rsyncfile.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 \ Modified: stable/7/contrib/csup/Makefile ============================================================================== --- stable/7/contrib/csup/Makefile Tue Mar 17 05:57:43 2009 (r189917) +++ stable/7/contrib/csup/Makefile Tue Mar 17 06:54:41 2009 (r189918) @@ -9,10 +9,11 @@ UNAME!= /usr/bin/uname -s PROG= csup 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 + pathcomp.c proto.c status.c stream.c threads.c token.l updater.c \ + rcsfile.c rcsparse.c lex.rcs.c rsyncfile.c CFLAGS+= -I. -I${.CURDIR} -g -pthread -DHAVE_FFLAGS -DNDEBUG -WARNS?= 6 +WARNS?= 1 # A bit of tweaking is needed to get this Makefile working # with the bsd.prog.mk of all the *BSD OSes... Modified: stable/7/contrib/csup/TODO ============================================================================== --- stable/7/contrib/csup/TODO Tue Mar 17 05:57:43 2009 (r189917) +++ stable/7/contrib/csup/TODO Tue Mar 17 06:54:41 2009 (r189918) @@ -28,4 +28,3 @@ MISSING FEATURES: checkout files (files in CVS/ subdirectores), a command line override to only update a specific collection and a third verbosity level to display commit log messages. -- Add support for CVS mode (maybe?). Modified: stable/7/contrib/csup/config.c ============================================================================== --- stable/7/contrib/csup/config.c Tue Mar 17 05:57:43 2009 (r189917) +++ stable/7/contrib/csup/config.c Tue Mar 17 06:54:41 2009 (r189918) @@ -133,7 +133,6 @@ config_init(const char *file, struct col coll->co_options &= ~CO_CHECKRCS; /* In recent versions, we always try to set the file modes. */ coll->co_options |= CO_SETMODE; - /* XXX We don't support the rsync updating algorithm yet. */ coll->co_options |= CO_NORSYNC; error = config_parse_refusefiles(coll); if (error) @@ -444,10 +443,6 @@ coll_add(char *name) "\"%s\"\n", cur_coll->co_name); exit(1); } - if (!(cur_coll->co_options & CO_CHECKOUTMODE)) { - lprintf(-1, "Client only supports checkout mode\n"); - exit(1); - } if (!STAILQ_EMPTY(&colls)) { coll = STAILQ_LAST(&colls, coll, co_next); if (strcmp(coll->co_host, cur_coll->co_host) != 0) { Modified: stable/7/contrib/csup/csup.1 ============================================================================== --- stable/7/contrib/csup/csup.1 Tue Mar 17 05:57:43 2009 (r189917) +++ stable/7/contrib/csup/csup.1 Tue Mar 17 06:54:41 2009 (r189918) @@ -442,8 +442,6 @@ They are called mode and .Em checkout mode. -.Nm -only supports the checkout mode for now. .Pp In CVS mode, the client receives copies of the actual RCS files making up the master CVS repository. CVS mode is the default mode of operation. Modified: stable/7/contrib/csup/detailer.c ============================================================================== --- stable/7/contrib/csup/detailer.c Tue Mar 17 05:57:43 2009 (r189917) +++ stable/7/contrib/csup/detailer.c Tue Mar 17 06:54:41 2009 (r189918) @@ -30,13 +30,21 @@ #include #include #include +#include + +#include +#include +#include #include "config.h" #include "detailer.h" #include "fixups.h" +#include "globtree.h" #include "misc.h" #include "mux.h" #include "proto.h" +#include "rcsfile.h" +#include "rsyncfile.h" #include "status.h" #include "stream.h" @@ -56,8 +64,16 @@ struct detailer { static int detailer_batch(struct detailer *); static int detailer_coll(struct detailer *, struct coll *, struct status *); -static int detailer_dofile(struct detailer *, struct coll *, +static int detailer_dofile_co(struct detailer *, struct coll *, struct status *, char *); +static int detailer_dofile_rcs(struct detailer *, struct coll *, + char *, char *); +static int detailer_dofile_regular(struct detailer *, char *, char *); +static int detailer_dofile_rsync(struct detailer *, char *, char *); +static int detailer_checkrcsattr(struct detailer *, struct coll *, char *, + struct fattr *, int); +int detailer_send_details(struct detailer *, struct coll *, char *, + char *, struct fattr *); void * detailer(void *arg) @@ -186,8 +202,13 @@ detailer_batch(struct detailer *d) } if (fixup->f_coll != coll) break; - error = proto_printf(wr, "Y %s %s %s\n", fixup->f_name, - coll->co_tag, coll->co_date); + if (coll->co_options & CO_CHECKOUTMODE) + error = proto_printf(wr, "Y %s %s %s\n", + fixup->f_name, coll->co_tag, coll->co_date); + else { + error = proto_printf(wr, "A %s\n", + fixup->f_name); + } if (error) return (DETAILER_ERR_WRITE); fixup = NULL; @@ -208,12 +229,14 @@ detailer_batch(struct detailer *d) static int detailer_coll(struct detailer *d, struct coll *coll, struct status *st) { + struct fattr *rcsattr; struct stream *rd, *wr; - char *cmd, *file, *line, *msg; - int error; + char *attr, *cmd, *file, *line, *msg, *path, *target; + int error, attic; rd = d->rd; wr = d->wr; + attic = 0; line = stream_getln(rd, NULL); if (line == NULL) return (DETAILER_ERR_READ); @@ -226,17 +249,84 @@ detailer_coll(struct detailer *d, struct /* Delete file. */ file = proto_get_ascii(&line); if (file == NULL || line != NULL) - return (DETAILER_ERR_PROTO); + return (DETAILER_ERR_PROTO); error = proto_printf(wr, "D %s\n", file); if (error) return (DETAILER_ERR_WRITE); break; + case 'I': + case 'i': + case 'j': + /* Directory operations. */ + file = proto_get_ascii(&line); + if (file == NULL || line != NULL) + return (DETAILER_ERR_PROTO); + error = proto_printf(wr, "%s %s\n", cmd, file); + if (error) + return (DETAILER_ERR_WRITE); + break; + case 'J': + /* Set directory attributes. */ + file = proto_get_ascii(&line); + attr = proto_get_ascii(&line); + if (file == NULL || line != NULL || attr == NULL) + return (DETAILER_ERR_PROTO); + error = proto_printf(wr, "%s %s %s\n", cmd, file, attr); + if (error) + return (DETAILER_ERR_WRITE); + break; + case 'H': + case 'h': + /* Create a hard link. */ + file = proto_get_ascii(&line); + target = proto_get_ascii(&line); + if (file == NULL || target == NULL) + return (DETAILER_ERR_PROTO); + error = proto_printf(wr, "%s %s %s\n", cmd, file, + target); + break; + case 't': + file = proto_get_ascii(&line); + attr = proto_get_ascii(&line); + if (file == NULL || attr == NULL || line != NULL) { + return (DETAILER_ERR_PROTO); + } + rcsattr = fattr_decode(attr); + if (rcsattr == NULL) { + return (DETAILER_ERR_PROTO); + } + error = detailer_checkrcsattr(d, coll, file, rcsattr, + 1); + break; + + case 'T': + file = proto_get_ascii(&line); + attr = proto_get_ascii(&line); + if (file == NULL || attr == NULL || line != NULL) + return (DETAILER_ERR_PROTO); + rcsattr = fattr_decode(attr); + if (rcsattr == NULL) + return (DETAILER_ERR_PROTO); + error = detailer_checkrcsattr(d, coll, file, rcsattr, + 0); + break; + case 'U': /* Add or update file. */ file = proto_get_ascii(&line); if (file == NULL || line != NULL) return (DETAILER_ERR_PROTO); - error = detailer_dofile(d, coll, st, file); + if (coll->co_options & CO_CHECKOUTMODE) { + error = detailer_dofile_co(d, coll, st, file); + } else { + path = cvspath(coll->co_prefix, file, 0); + rcsattr = fattr_frompath(path, FATTR_NOFOLLOW); + error = detailer_send_details(d, coll, file, + path, rcsattr); + if (rcsattr != NULL) + fattr_free(rcsattr); + free(path); + } if (error) return (error); break; @@ -261,14 +351,110 @@ detailer_coll(struct detailer *d, struct return (0); } +/* + * Tell the server to update a regular file. + */ static int -detailer_dofile(struct detailer *d, struct coll *coll, struct status *st, - char *file) +detailer_dofile_regular(struct detailer *d, char *name, char *path) { + struct stream *wr; + struct stat st; char md5[MD5_DIGEST_SIZE]; + int error; + + wr = d->wr; + error = stat(path, &st); + /* If we don't have it or it's unaccessible, we want it again. */ + if (error) { + proto_printf(wr, "A %s\n", name); + return (0); + } + + /* If not, we want the file to be updated. */ + error = MD5_File(path, md5); + if (error) { + lprintf(-1, "Error reading \"%s\"\n", name); + return (error); + } + error = proto_printf(wr, "R %s %O %s\n", name, st.st_size, md5); + if (error) + return (DETAILER_ERR_WRITE); + return (0); +} + +/* + * Tell the server to update a file with the rsync algorithm. + */ +static int +detailer_dofile_rsync(struct detailer *d, char *name, char *path) +{ + struct stream *wr; + struct rsyncfile *rf; + + wr = d->wr; + rf = rsync_open(path, 0, 1); + if (rf == NULL) { + /* Fallback if we fail in opening it. */ + proto_printf(wr, "A %s\n", name); + return (0); + } + proto_printf(wr, "r %s %z %z\n", name, rsync_filesize(rf), + rsync_blocksize(rf)); + /* Detail the blocks. */ + while (rsync_nextblock(rf) != 0) + proto_printf(wr, "%s %s\n", rsync_rsum(rf), rsync_blockmd5(rf)); + proto_printf(wr, ".\n"); + rsync_close(rf); + return (0); +} + +/* + * Tell the server to update an RCS file that we have, or send it if we don't. + */ +static int +detailer_dofile_rcs(struct detailer *d, struct coll *coll, char *name, + char *path) +{ + struct stream *wr; + struct fattr *fa; + struct rcsfile *rf; + int error; + + wr = d->wr; + path = atticpath(coll->co_prefix, name); + fa = fattr_frompath(path, FATTR_NOFOLLOW); + if (fa == NULL) { + /* We don't have it, so send request to get it. */ + error = proto_printf(wr, "A %s\n", name); + if (error) + return (DETAILER_ERR_WRITE); + free(path); + return (0); + } + + rf = rcsfile_frompath(path, name, coll->co_cvsroot, coll->co_tag, 1); + free(path); + if (rf == NULL) { + error = proto_printf(wr, "A %s\n", name); + if (error) + return (DETAILER_ERR_WRITE); + return (0); + } + /* Tell to update the RCS file. The client version details follow. */ + rcsfile_send_details(rf, wr); + rcsfile_free(rf); + fattr_free(fa); + return (0); +} + +static int +detailer_dofile_co(struct detailer *d, struct coll *coll, struct status *st, + char *file) +{ struct stream *wr; struct fattr *fa; struct statusrec *sr; + char md5[MD5_DIGEST_SIZE]; char *path; int error, ret; @@ -337,3 +523,81 @@ detailer_dofile(struct detailer *d, stru return (DETAILER_ERR_WRITE); return (0); } + +int +detailer_checkrcsattr(struct detailer *d, struct coll *coll, char *name, + struct fattr *server_attr, int attic) +{ + struct fattr *client_attr; + char *attr, *path; + int error; + + /* + * I don't think we can use the status file, since it only records file + * attributes in cvsmode. + */ + client_attr = NULL; + path = cvspath(coll->co_prefix, name, attic); + if (path == NULL) { + return (DETAILER_ERR_PROTO); + } + + if (access(path, F_OK) == 0 && + ((client_attr = fattr_frompath(path, FATTR_NOFOLLOW)) != NULL) && + fattr_equal(client_attr, server_attr)) { + attr = fattr_encode(client_attr, NULL, 0); + if (attic) { + error = proto_printf(d->wr, "l %s %s\n", name, attr); + } else { + error = proto_printf(d->wr, "L %s %s\n", name, attr); + } + free(attr); + free(path); + fattr_free(client_attr); + if (error) + return (DETAILER_ERR_WRITE); + return (0); + } + /* We don't have it, so tell the server to send it. */ + error = detailer_send_details(d, coll, name, path, client_attr); + fattr_free(client_attr); + free(path); + return (error); +} + +int +detailer_send_details(struct detailer *d, struct coll *coll, char *name, + char *path, struct fattr *fa) +{ + int error; + size_t len; + + /* + * Try to check if the file exists either live or dead to see if we can + * edit it and put it live or dead, rather than receiving the entire + * file. + */ + if (fa == NULL) { + path = atticpath(coll->co_prefix, name); + fa = fattr_frompath(path, FATTR_NOFOLLOW); + } + if (fa == NULL) { + error = proto_printf(d->wr, "A %s\n", name); + if (error) + return (DETAILER_ERR_WRITE); + } else if (fattr_type(fa) == FT_FILE) { + if (isrcs(name, &len) && !(coll->co_options & CO_NORCS)) { + detailer_dofile_rcs(d, coll, name, path); + } else if (!(coll->co_options & CO_NORSYNC) && + !globtree_test(coll->co_norsync, name)) { + detailer_dofile_rsync(d, name, path); + } else { + detailer_dofile_regular(d, name, path); + } + } else { + error = proto_printf(d->wr, "N %s\n", name); + if (error) + return (DETAILER_ERR_WRITE); + } + return (0); +} Modified: stable/7/contrib/csup/diff.c ============================================================================== --- stable/7/contrib/csup/diff.c Tue Mar 17 05:57:43 2009 (r189917) +++ stable/7/contrib/csup/diff.c Tue Mar 17 06:54:41 2009 (r189918) @@ -26,9 +26,12 @@ * $FreeBSD$ */ +#include + #include #include #include +#include #include #include @@ -36,15 +39,20 @@ #include "keyword.h" #include "misc.h" #include "stream.h" +#include "queue.h" typedef long lineno_t; #define EC_ADD 0 #define EC_DEL 1 +#define MAXKEY LONG_MAX /* Editing command and state. */ struct editcmd { int cmd; + long key; + int havetext; + int offset; lineno_t where; lineno_t count; lineno_t lasta; @@ -55,20 +63,28 @@ struct editcmd { struct diffinfo *di; struct stream *orig; struct stream *dest; + LIST_ENTRY(editcmd) next; +}; + +struct diffstart { + LIST_HEAD(, editcmd) dhead; }; static int diff_geteditcmd(struct editcmd *, char *); static int diff_copyln(struct editcmd *, lineno_t); +static int diff_ignoreln(struct editcmd *, lineno_t); static void diff_write(struct editcmd *, void *, size_t); +static int diff_insert_edit(struct diffstart *, struct editcmd *); +static void diff_free(struct diffstart *); int diff_apply(struct stream *rd, struct stream *orig, struct stream *dest, - struct keyword *keyword, struct diffinfo *di) + struct keyword *keyword, struct diffinfo *di, int comode) { struct editcmd ec; lineno_t i; - char *line; size_t size; + char *line; int empty, error, noeol; memset(&ec, 0, sizeof(ec)); @@ -104,7 +120,7 @@ diff_apply(struct stream *rd, struct str line = stream_getln(rd, &size); if (line == NULL) return (-1); - if (line[0] == '.') { + if (comode && line[0] == '.') { line++; size--; } @@ -124,10 +140,10 @@ diff_apply(struct stream *rd, struct str } line = stream_getln(rd, NULL); } - if (line == NULL) + if (comode && line == NULL) return (-1); /* If we got ".+", there's no ending newline. */ - if (strcmp(line, ".+") == 0 && !empty) + if (comode && strcmp(line, ".+") == 0 && !empty) noeol = 1; ec.where = 0; while ((line = stream_getln(orig, &size)) != NULL) @@ -143,6 +159,198 @@ diff_apply(struct stream *rd, struct str return (0); } +/* + * Reverse a diff using the same algorithm as in cvsup. + */ +static int +diff_write_reverse(struct stream *dest, struct diffstart *ds) +{ + struct editcmd *ec, *nextec; + long editline, endline, firstoutputlinedeleted; + long num_added, num_deleted, startline; + int num; + + nextec = LIST_FIRST(&ds->dhead); + editline = 0; + num = 0; + while (nextec != NULL) { + ec = nextec; + nextec = LIST_NEXT(nextec, next); + if (nextec == NULL) + break; + num++; + num_deleted = 0; + if (ec->havetext) + num_deleted = ec->count; + num_added = num_deleted + nextec->offset - ec->offset; + if (num_deleted > 0) { + firstoutputlinedeleted = ec->key - num_deleted + 1; + stream_printf(dest, "d%ld %ld\n", firstoutputlinedeleted, + num_deleted); + if (num_added <= 0) + continue; + } + if (num_added > 0) { + stream_printf(dest, "a%ld %ld\n", ec->key, num_added); + startline = ec->key - num_deleted + 1 + ec->offset; + endline = startline + num_added - 1; + + /* Copy lines from original file. First ignore some. */ + ec->editline = editline; + diff_ignoreln(ec, startline - 1); + diff_copyln(ec, endline); + editline = ec->editline; + } + } + return (0); +} + +/* + * Insert a diff into the list sorted on key. Should perhaps use quicker + * algorithms than insertion sort, but do this for now. + */ +static int +diff_insert_edit(struct diffstart *ds, struct editcmd *ec) +{ + struct editcmd *curec; + + if (ec == NULL) + return (0); + + if (LIST_EMPTY(&ds->dhead)) { + LIST_INSERT_HEAD(&ds->dhead, ec, next); + return (0); + } + + /* Insertion sort based on key. */ + LIST_FOREACH(curec, &ds->dhead, next) { + if (ec->key < curec->key) { + LIST_INSERT_BEFORE(curec, ec, next); + return (0); + } + if (LIST_NEXT(curec, next) == NULL) + break; + } + /* Just insert it after. */ + LIST_INSERT_AFTER(curec, ec, next); + return (0); +} + +static void +diff_free(struct diffstart *ds) +{ + struct editcmd *ec; + + while(!LIST_EMPTY(&ds->dhead)) { + ec = LIST_FIRST(&ds->dhead); + LIST_REMOVE(ec, next); + free(ec); + } +} + +/* + * Write the reverse diff from the diff in rd, and original file into + * destination. This algorithm is the same as used in cvsup. + */ +int +diff_reverse(struct stream *rd, struct stream *orig, struct stream *dest, + struct keyword *keyword, struct diffinfo *di) +{ + struct diffstart ds; + struct editcmd ec, *addec, *delec; + lineno_t i; + char *line; + int error, offset; + + memset(&ec, 0, sizeof(ec)); + ec.orig = orig; + ec.dest = dest; + ec.keyword = keyword; + ec.di = di; + addec = NULL; + delec = NULL; + ec.havetext = 0; + offset = 0; + LIST_INIT(&ds.dhead); + + /* Start with next since we need it. */ + line = stream_getln(rd, NULL); + /* First we build up the list of diffs from input. */ + while (line != NULL) { + error = diff_geteditcmd(&ec, line); + if (error) + break; + if (ec.cmd == EC_ADD) { + addec = xmalloc(sizeof(struct editcmd)); + *addec = ec; + addec->havetext = 1; + /* Ignore the lines we was supposed to add. */ + for (i = 0; i < ec.count; i++) { + line = stream_getln(rd, NULL); + if (line == NULL) + return (-1); + } + + /* Get the next diff command if we have one. */ + addec->key = addec->where + addec->count - offset; + if (delec != NULL && + delec->key == addec->key - addec->count) { + delec->key = addec->key; + delec->havetext = addec->havetext; + delec->count = addec->count; + diff_insert_edit(&ds, delec); + free(addec); + delec = NULL; + addec = NULL; + } else { + if (delec != NULL) { + diff_insert_edit(&ds, delec); + } + delec = NULL; + addec->offset = offset; + diff_insert_edit(&ds, addec); + addec = NULL; + } + offset -= ec.count; + } else if (ec.cmd == EC_DEL) { + if (delec != NULL) { + /* Update offset to our next. */ + diff_insert_edit(&ds, delec); + delec = NULL; + } + delec = xmalloc(sizeof(struct editcmd)); + *delec = ec; + delec->key = delec->where - 1 - offset; + delec->offset = offset; + delec->count = 0; + delec->havetext = 0; + /* Important to use the count we had before reset.*/ + offset += ec.count; + } + line = stream_getln(rd, NULL); + } + + while (line != NULL) + line = stream_getln(rd, NULL); + if (delec != NULL) { + diff_insert_edit(&ds, delec); + delec = NULL; + } + + addec = xmalloc(sizeof(struct editcmd)); + /* Should be filesize, but we set it to max value. */ + addec->key = MAXKEY; + addec->offset = offset; + addec->havetext = 0; + addec->count = 0; + diff_insert_edit(&ds, addec); + addec = NULL; + diff_write_reverse(dest, &ds); + diff_free(&ds); + stream_flush(dest); + return (0); +} + /* Get an editing command from the diff. */ static int diff_geteditcmd(struct editcmd *ec, char *line) @@ -181,8 +389,8 @@ diff_geteditcmd(struct editcmd *ec, char static int diff_copyln(struct editcmd *ec, lineno_t to) { - char *line; size_t size; + char *line; while (ec->editline < to) { line = stream_getln(ec->orig, &size); @@ -194,12 +402,28 @@ diff_copyln(struct editcmd *ec, lineno_t return (0); } +/* Ignore lines from the original version of the file up to line "to". */ +static int +diff_ignoreln(struct editcmd *ec, lineno_t to) +{ + size_t size; + char *line; + + while (ec->editline < to) { + line = stream_getln(ec->orig, &size); + if (line == NULL) + return (-1); + ec->editline++; + } + return (0); +} + /* Write a new line to the file, expanding RCS keywords appropriately. */ static void diff_write(struct editcmd *ec, void *buf, size_t size) { - char *line, *newline; size_t newsize; + char *line, *newline; int ret; line = buf; Modified: stable/7/contrib/csup/diff.h ============================================================================== --- stable/7/contrib/csup/diff.h Tue Mar 17 05:57:43 2009 (r189917) +++ stable/7/contrib/csup/diff.h Tue Mar 17 06:54:41 2009 (r189918) @@ -45,6 +45,8 @@ struct diffinfo { }; int diff_apply(struct stream *, struct stream *, struct stream *, - struct keyword *, struct diffinfo *); + struct keyword *, struct diffinfo *, int); +int diff_reverse(struct stream *, struct stream *, + struct stream *, struct keyword *, struct diffinfo *); #endif /* !_DIFF_H_ */ Modified: stable/7/contrib/csup/fattr.c ============================================================================== --- stable/7/contrib/csup/fattr.c Tue Mar 17 05:57:43 2009 (r189917) +++ stable/7/contrib/csup/fattr.c Tue Mar 17 06:54:41 2009 (r189918) @@ -44,7 +44,7 @@ /* * Include the appropriate definition for the file attributes we support. * There are two different files: fattr_bsd.h for BSD-like systems that - * support the extended file flags à la chflags() and fattr_posix.h for + * support the extended file flags a la chflags() and fattr_posix.h for * bare POSIX systems that don't. */ #ifdef HAVE_FFLAGS @@ -449,7 +449,7 @@ fattr_encode(const struct fattr *fa, fat piece++; } if (mask & FA_DEV) { - vallen = snprintf(piece->val, sizeof(piece->val), "%lld", + vallen = snprintf(piece->val, sizeof(piece->val), "%llx", (long long)fa->dev); len += snprintf(piece->len, sizeof(piece->len), "%lld", (long long)vallen) + vallen + 1; @@ -534,6 +534,13 @@ fattr_getlinkcount(const struct fattr *f return (fa->linkcount); } +char * +fattr_getlinktarget(const struct fattr *fa) +{ + + return (fa->linktarget); +} + /* * Eat the specified attribute and put it in the file attribute * structure. Returns NULL on error, or a pointer to the next @@ -732,18 +739,28 @@ fattr_makenode(const struct fattr *fa, c mode_t modemask, mode; int error; + error = 0; + if (fa->mask & FA_OWNER && fa->mask & FA_GROUP) modemask = FA_SETIDMASK | FA_PERMMASK; else modemask = FA_PERMMASK; /* We only implement fattr_makenode() for dirs for now. */ - assert(fa->type == FT_DIRECTORY); if (fa->mask & FA_MODE) mode = fa->mode & modemask; else mode = 0700; - error = mkdir(path, mode); + + if (fa->type == FT_DIRECTORY) + error = mkdir(path, mode); + else if (fa->type == FT_SYMLINK) { + error = symlink(fa->linktarget, path); + } else if (fa->type == FT_CDEV) { + lprintf(-1, "Character devices not supported!\n"); + } else if (fa->type == FT_BDEV) { + lprintf(-1, "Block devices not supported!\n"); + } return (error); } @@ -823,6 +840,19 @@ fattr_install(struct fattr *fa, const ch } #endif + /* + * If it is changed from a file to a symlink, remove the file + * and create the symlink. + */ + if (inplace && (fa->type == FT_SYMLINK) && + (old->type == FT_FILE)) { + error = unlink(topath); + if (error) + goto bad; + error = symlink(fa->linktarget, topath); + if (error) + goto bad; + } /* Determine whether we need to remove the target first. */ if (!inplace && (fa->type == FT_DIRECTORY) != (old->type == FT_DIRECTORY)) { @@ -853,8 +883,9 @@ fattr_install(struct fattr *fa, const ch if (mask & FA_GROUP) gid = fa->gid; error = chown(frompath, uid, gid); - if (error) + if (error) { goto bad; + } } if (mask & FA_MODE) { newmode = fa->mode & modemask; @@ -901,6 +932,9 @@ fattr_equal(const struct fattr *fa1, con mask = fa1->mask & fa2->mask; if (fa1->type == FT_UNKNOWN || fa2->type == FT_UNKNOWN) return (0); + if (mask & FA_FILETYPE) + if (fa1->type != fa2->type) + return (0); if (mask & FA_MODTIME) if (fa1->modtime != fa2->modtime) return (0); @@ -936,3 +970,12 @@ fattr_equal(const struct fattr *fa1, con return (0); return (1); } + +/* + * Must have to get the correct filesize sendt by the server. + */ +off_t +fattr_filesize(const struct fattr *fa) +{ + return (fa->size); +} Modified: stable/7/contrib/csup/fattr.h ============================================================================== --- stable/7/contrib/csup/fattr.h Tue Mar 17 05:57:43 2009 (r189917) +++ stable/7/contrib/csup/fattr.h Tue Mar 17 06:54:41 2009 (r189918) @@ -101,6 +101,7 @@ int fattr_type(const struct fattr *); void fattr_maskout(struct fattr *, int); int fattr_getmask(const struct fattr *); nlink_t fattr_getlinkcount(const struct fattr *); +char *fattr_getlinktarget(const struct fattr *); void fattr_umask(struct fattr *, mode_t); void fattr_merge(struct fattr *, const struct fattr *); void fattr_mergedefault(struct fattr *); @@ -111,5 +112,7 @@ int fattr_install(struct fattr *, cons int fattr_equal(const struct fattr *, const struct fattr *); void fattr_free(struct fattr *); int fattr_supported(int); +off_t fattr_filesize(const struct fattr *); + #endif /* !_FATTR_H_ */ Modified: stable/7/contrib/csup/keyword.c ============================================================================== --- stable/7/contrib/csup/keyword.c Tue Mar 17 05:57:43 2009 (r189917) +++ stable/7/contrib/csup/keyword.c Tue Mar 17 06:54:41 2009 (r189918) @@ -152,6 +152,29 @@ keyword_decode_expand(const char *expand return (-1); } +const char * +keyword_encode_expand(int expand) +{ + + switch (expand) { + case EXPAND_DEFAULT: + return ("."); + case EXPAND_KEYVALUE: + return ("kv"); + case EXPAND_KEYVALUELOCKER: + return ("kvl"); + case EXPAND_KEY: + return ("k"); + case EXPAND_OLD: + return ("o"); + case EXPAND_BINARY: + return ("b"); + case EXPAND_VALUE: + return ("v"); + } + return (NULL); +} + void keyword_free(struct keyword *keyword) { Modified: stable/7/contrib/csup/keyword.h ============================================================================== --- stable/7/contrib/csup/keyword.h Tue Mar 17 05:57:43 2009 (r189917) +++ stable/7/contrib/csup/keyword.h Tue Mar 17 06:54:41 2009 (r189918) @@ -42,6 +42,7 @@ struct keyword; struct keyword *keyword_new(void); int keyword_decode_expand(const char *); +const char *keyword_encode_expand(int); int keyword_alias(struct keyword *, const char *, const char *); int keyword_enable(struct keyword *, const char *); int keyword_disable(struct keyword *, const char *); Copied: stable/7/contrib/csup/lex.rcs.c (from r186781, head/contrib/csup/lex.rcs.c) ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ stable/7/contrib/csup/lex.rcs.c Tue Mar 17 06:54:41 2009 (r189918, copy of r186781, head/contrib/csup/lex.rcs.c) @@ -0,0 +1,2094 @@ + +#line 3 "lex.rcs.c" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 +#define YY_FLEX_SUBMINOR_VERSION 35 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include +#include +#include +#include + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have . Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***