1
0
mirror of https://git.FreeBSD.org/ports.git synced 2024-11-19 00:13:33 +00:00

Apply changes developed by Stephen Montgomery-Smith and required to

actually use CTM to distribute FreeBSD updates. They have been further
refined by Julian H. Stacey.

These changes add support for delta numbers with more than 5 digits
and better compression formats.

Submitted by:	Stephen Montgomery-Smith, Julian H. Stacey
Approved by:	antoine (implicit)
This commit is contained in:
Stefan Eßer 2018-12-23 07:19:01 +00:00
parent e4b7f14414
commit 4d6c49aae2
Notes: svn2git 2021-03-31 03:12:20 +00:00
svn path=/head/; revision=488168
12 changed files with 857 additions and 0 deletions

View File

@ -2,6 +2,7 @@
PORTNAME= ctm
PORTVERSION= 2.0
PORTREVISION= 1
CATEGORIES= misc
MAINTAINER= se@FreeBSD.org

View File

@ -0,0 +1,30 @@
--- ctm_rmail/ctm_rmail.8.orig 2018-10-27 15:56:22 UTC
+++ ctm_rmail/ctm_rmail.8
@@ -7,7 +7,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd January 24, 1995
+.Dd December 23, 2018
.Dt CTM_MAIL 8
.Os
.Sh NAME
@@ -35,6 +35,7 @@ deltas via mail
.Op Fl p Ar piecedir
.Op Fl d Ar deltadir
.Op Fl b Ar basedir
+.Op Fl B Ar backup_dir
.Op Ar
.Sh DESCRIPTION
In conjunction with the
@@ -191,6 +192,10 @@ file in
(or if
.Li .ctm_status
does not exist).
+.It Fl B Ar backup_dir
+Specify a backup directory for use by
+.Nm ctm
+.Fl B
.It Fl D
Delete deltas after successful application by
.Xr ctm .

View File

@ -0,0 +1,30 @@
--- ctm_rmail/ctm_rmail.c.orig 2018-12-23 07:00:45 UTC
+++ ctm_rmail/ctm_rmail.c
@@ -152,6 +152,7 @@ apply_complete()
char fname[PATH_MAX];
char here[PATH_MAX];
char buf[PATH_MAX*2];
+ char *deltanamescheme[] = { "%s.%04d.gz", "%s.%04d.xz", "%s.%05d.gz", "%s.%05d.xz", NULL };
/*
* Grab a lock on the ctm mutex file so that we can be sure we are
@@ -200,10 +201,16 @@ apply_complete()
*/
for (;;)
{
- sprintf(delta, "%s.%04d.gz", class, ++dn);
- mk_delta_name(fname, delta);
+ ++dn;
+ for (i=0; deltanamescheme[i]; i++)
+ {
+ sprintf(delta, deltanamescheme[i], class, dn);
+ mk_delta_name(fname, delta);
- if (stat(fname, &sb) < 0)
+ if (stat(fname, &sb) >= 0)
+ break;
+ }
+ if (!deltanamescheme[i])
break;
sprintf(buf, "(cd %s && ctm %s%s%s%s%s%s) 2>&1", base_dir,

View File

@ -0,0 +1,40 @@
--- ctm/ctm.8.orig 2018-10-27 15:56:22 UTC
+++ ctm/ctm.8
@@ -12,7 +12,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd April 14, 2016
+.Dd December 23, 2018
.Dt CTM 8
.Os
.Sh NAME
@@ -52,8 +52,11 @@ command.
You can pass a CTM delta on stdin, or you can give the
filename as an argument.
If you do the latter, you make life a lot
-easier for your self, since the program can accept gzip'ed files and
+easier for your self, since the program can accept gzip'ed,
+bzip2'ed, or xz'ed files and
since it will not have to make a temporary copy of your file.
+(If you pass it an xz'ed file, and xz is not part of your base system,
+you will have to install xz from the ports.)
You can
specify multiple deltas at one time, they will be processed one at a
time.
@@ -272,6 +275,15 @@ contains the sequence number of the last CTM delta app
Changing
or removing this file will greatly confuse
.Nm .
+.sp
+.Pa .svn_revision
+contains the revision number emitted by SVN
+.\" eg from approx
+.\" svn up src | tail -1 | \
+.\" sed -E 's/[^[:digit:]]//g' > src/.svn_revision
+(to reference when discussing sources with users of
+.Nm svn
+direct).
.Pp
Using the
.Fl e

View File

@ -0,0 +1,25 @@
--- ctm/ctm.c.orig 2018-10-27 15:56:22 UTC
+++ ctm/ctm.c
@@ -213,6 +213,22 @@ Proc(char *filename, unsigned applied)
strcat(p,filename);
f = popen(p,"r");
if(!f) { warn("%s", p); return Exit_Garbage; }
+ } else if(p && !strcmp(p,".bz2")) {
+ p = alloca(20 + strlen(filename));
+ strcpy(p,"bzcat < ");
+ strcat(p,filename);
+ f = popen(p,"r");
+ if(!f) { warn("%s", p); return Exit_Garbage; }
+ } else if(p && !strcmp(p,".xz")) {
+ if (system("which -s xz") != 0) {
+ fprintf(stderr, "xz is not found in $PATH. You can install it from ports, or adjust $PATH.\n");
+ return Exit_Garbage;
+ }
+ p = alloca(20 + strlen(filename));
+ strcpy(p,"xz -dc < ");
+ strcat(p,filename);
+ f = popen(p,"r");
+ if(!f) { warn("%s", p); return Exit_Garbage; }
} else {
p = 0;
f = fopen(filename,"r");

View File

@ -0,0 +1,51 @@
--- ctm/ctm.h.orig 2018-10-27 15:56:22 UTC
+++ ctm/ctm.h
@@ -24,6 +24,7 @@
#include <sys/stat.h>
#include <sys/file.h>
#include <sys/time.h>
+#include <stdint.h>
#define VERSION "2.0"
@@ -40,6 +41,8 @@
#define CTM_F_MD5 0x05
#define CTM_F_Count 0x06
#define CTM_F_Bytes 0x07
+#define CTM_F_Release 0x08
+#define CTM_F_Forward 0x09
/* The qualifiers... */
#define CTM_Q_MASK 0xff00
@@ -47,10 +50,13 @@
#define CTM_Q_Name_Dir 0x0200
#define CTM_Q_Name_New 0x0400
#define CTM_Q_Name_Subst 0x0800
+#define CTM_Q_Name_Svnbase 0x1000
#define CTM_Q_MD5_After 0x0100
#define CTM_Q_MD5_Before 0x0200
#define CTM_Q_MD5_Chunk 0x0400
#define CTM_Q_MD5_Force 0x0800
+#define CTM_Q_Forward_Tar 0x0100
+#define CTM_Q_Forward_SVN 0x0200
struct CTM_Syntax {
char *Key; /* CTM key for operation */
@@ -145,14 +151,16 @@ void Fatal_(int ln, char *fn, char *kind);
u_char * Ffield(FILE *fd, MD5_CTX *ctx,u_char term);
u_char * Fname(FILE *fd, MD5_CTX *ctx,u_char term,int qual, int verbose);
-int Fbytecnt(FILE *fd, MD5_CTX *ctx, u_char term);
+intmax_t Fbytecnt(FILE *fd, MD5_CTX *ctx, u_char term);
u_char * Fdata(FILE *fd, int u_chars, MD5_CTX *ctx);
+int Fforward(FILE *fd, intmax_t u_chars, MD5_CTX *ctx, FILE *fd_to);
#define GETFIELD(p,q) if(!((p)=Ffield(fd,&ctx,(q)))) return BADREAD
#define GETFIELDCOPY(p,q) if(!((p)=Ffield(fd,&ctx,(q)))) return BADREAD; else p=String(p)
#define GETBYTECNT(p,q) if(0 >((p)= Fbytecnt(fd,&ctx,(q)))) return BADREAD
#define GETDATA(p,q) if(!((p) = Fdata(fd,(q),&ctx))) return BADREAD
+#define GETFORWARD(p,q) if(!Fforward(fd,(p),&ctx,q)) return BADREAD
#define GETNAMECOPY(p,q,r,v) if(!((p)=Fname(fd,&ctx,(q),(r),(v)))) return BADREAD; else p=String(p)
int Pass1(FILE *fd, unsigned applied);

View File

@ -0,0 +1,59 @@
--- ctm/ctm_input.c.orig 2018-10-27 15:56:22 UTC
+++ ctm/ctm_input.c
@@ -63,11 +63,11 @@ Ffield(FILE *fd, MD5_CTX *ctx,u_char term)
return buf;
}
-int
+intmax_t
Fbytecnt(FILE *fd, MD5_CTX *ctx, u_char term)
{
u_char *p,*q;
- int u_chars=0;
+ intmax_t u_chars=0;
p = Ffield(fd,ctx,term);
if(!p) return -1;
@@ -101,6 +101,42 @@ Fdata(FILE *fd, int u_chars, MD5_CTX *ctx)
p[u_chars] = '\0';
return p;
}
+
+int Fforward(FILE *fd, intmax_t u_chars, MD5_CTX *ctx, FILE *fd_to)
+{
+ u_char buf[BUFSIZ];
+ intmax_t amount_read = 0;
+ int amount_to_read;
+
+ while (amount_read < u_chars) {
+ if (u_chars - amount_read >= BUFSIZ)
+ amount_to_read = BUFSIZ;
+ else
+ amount_to_read = u_chars - amount_read;
+ if(amount_to_read != fread(buf, 1, amount_to_read, fd)) {
+ Fatal("Truncated patch.");
+ return 0;
+ }
+ MD5Update(ctx,buf,amount_to_read);
+ if (fd_to != NULL) {
+ if (amount_to_read != fwrite(buf, 1, amount_to_read, fd_to)) {
+ Fatal("Write error.");
+ return 0;
+ }
+ }
+ amount_read += amount_to_read;
+ }
+
+ if(getc(fd) != '\n') {
+ if(Verbose > 3)
+ printf("FileData wasn't followed by a newline.\n");
+ Fatal("Corrupt patch.");
+ return 0;
+ }
+ MD5Update(ctx,"\n",1);
+ return 1;
+}
+
/*---------------------------------------------------------------------------*/
/* get the filename in the next field, prepend BaseDir and give back the result

View File

@ -0,0 +1,39 @@
--- ctm/ctm_pass1.c.orig 2018-10-27 15:56:22 UTC
+++ ctm/ctm_pass1.c
@@ -24,7 +24,8 @@ Pass1(FILE *fd, unsigned applied)
{
u_char *p,*q;
MD5_CTX ctx;
- int i,j,sep,cnt;
+ int i,j,sep;
+ intmax_t cnt, rel;
u_char *md5=0,*name=0,*trash=0;
struct CTM_Syntax *sp;
int slashwarn=0, match=0, total_matches=0;
@@ -98,7 +99,7 @@ Pass1(FILE *fd, unsigned applied)
if(Verbose > 5)
fprintf(stderr,"%s ",sp->Key);
for(i=0;(j = sp->List[i]);i++) {
- if (sp->List[i+1] && (sp->List[i+1] & CTM_F_MASK) != CTM_F_Bytes)
+ if (sp->List[i+1] && (sp->List[i+1] & CTM_F_MASK) != CTM_F_Bytes && (sp->List[i+1] & CTM_F_MASK) != CTM_F_Forward)
sep = ' ';
else
sep = '\n';
@@ -213,6 +214,17 @@ Pass1(FILE *fd, unsigned applied)
if(md5 && strcmp(md5,p)) {
Fatal("Internal MD5 failed.");
return Exit_Garbage;
+ case CTM_F_Release:
+ GETBYTECNT(rel,sep);
+ break;
+ case CTM_F_Forward:
+ if(cnt < 0) WRONG
+ if ((j & CTM_Q_MASK) == CTM_Q_Forward_SVN && system("which -s svnadmin") != 0) {
+ fprintf(stderr, "svn is not found in $PATH. You can install it from ports/devel/subversion, or adjust $PATH.\n");
+ return Exit_Garbage;
+ }
+ GETFORWARD(cnt,NULL);
+ break;
default:
fprintf(stderr,"List = 0x%x\n",j);
Fatal("List had garbage.");

View File

@ -0,0 +1,99 @@
--- ctm/ctm_pass2.c.orig 2018-10-27 15:56:22 UTC
+++ ctm/ctm_pass2.c
@@ -24,7 +24,11 @@ Pass2(FILE *fd)
{
u_char *p,*q,*md5=0;
MD5_CTX ctx;
- int i,j,sep,cnt,fdesc;
+ int i,j,sep,fdesc;
+ intmax_t cnt, rel;
+ int rel2;
+ FILE *current;
+ char *current_file_name = NULL;
u_char *trash=0,*name=0;
struct CTM_Syntax *sp;
struct stat st;
@@ -32,7 +36,7 @@ Pass2(FILE *fd)
int match = 0;
char md5_1[33];
struct CTM_Filter *filter;
- FILE *ed = NULL;
+ FILE *ed = NULL, *fd_to = NULL;
static char *template = NULL;
if(Verbose>3)
@@ -74,7 +78,7 @@ Pass2(FILE *fd)
WRONG
found:
for(i=0;(j = sp->List[i]);i++) {
- if (sp->List[i+1] && (sp->List[i+1] & CTM_F_MASK) != CTM_F_Bytes)
+ if (sp->List[i+1] && (sp->List[i+1] & CTM_F_MASK) != CTM_F_Bytes && (sp->List[i+1] & CTM_F_MASK) != CTM_F_Forward)
sep = ' ';
else
sep = '\n';
@@ -130,6 +134,22 @@ Pass2(FILE *fd)
sp->Key,name);
ret |= Exit_NotOK;
}
+ if (j & CTM_Q_Name_Svnbase) {
+ current_file_name = alloca(strlen(name)+128);
+ strcpy(current_file_name,name);
+ strcat(current_file_name,"/db/current");
+ current = fopen(current_file_name,"r");
+ if (current==NULL) {
+ fprintf(stderr,"Cannot open %s\n",current_file_name);
+ WRONG
+ }
+ if (fscanf(current,"%d",&rel2) != 1) {
+ fprintf(stderr,"Cannot find release number in %s\n",current_file_name);
+ fclose(current);
+ WRONG
+ }
+ fclose(current);
+ }
break;
}
if (j & CTM_Q_Name_File) {
@@ -285,6 +305,42 @@ Pass2(FILE *fd)
Free(p);
}
+ break;
+ case CTM_F_Release:
+ GETBYTECNT(rel,sep);
+ if(Verbose > 3)
+ printf("Expecting release number %jd\n",rel);
+ if(Verbose > 3)
+ printf("Actual release number %d\n",rel2);
+ if (rel != rel2) {
+ fprintf(stderr,"Release number mismatch: found %d, need %jd\n",rel2,rel);
+ WRONG
+ }
+ break;
+ case CTM_F_Forward:
+ if ((j & CTM_Q_MASK) == CTM_Q_Forward_SVN) {
+ if(Verbose>3)
+ printf("This is a svn dump file and there is no certainty that it will apply cleanly.\n");
+ GETFORWARD(cnt,NULL);
+ }
+ else if ((j & CTM_Q_MASK) == CTM_Q_Forward_Tar) {
+ if(Verbose>3) {
+ printf("This is a tar file and there is no certainty that it will apply cleanly even if it passes the following test.\n");
+ fd_to = popen("tar tvf -","w");
+ } else
+ fd_to = popen("tar tf - >/dev/null 2>&1","w");
+ if (fd_to == NULL) {
+ fprintf(stderr,"Cannot forward\n");
+ WRONG
+ }
+ GETFORWARD(cnt,fd_to);
+ if (pclose(fd_to)) {
+ fprintf(stderr,"Tar failed to close properly\n");
+ WRONG
+ } else
+ if (Verbose > 3)
+ printf("Tar file test was good\n");
+ }
break;
default: WRONG
}

View File

@ -0,0 +1,170 @@
--- ctm/ctm_pass3.c.orig 2018-10-27 15:56:22 UTC
+++ ctm/ctm_pass3.c
@@ -35,10 +35,12 @@ Pass3(FILE *fd)
{
u_char *p,*q,buf[BUFSIZ];
MD5_CTX ctx;
- int i,j,sep,cnt;
+ int i,j,sep;
+ intmax_t cnt,rel;
+ char *svn_command = NULL;
u_char *md5=0,*md5before=0,*trash=0,*name=0,*uid=0,*gid=0,*mode=0;
struct CTM_Syntax *sp;
- FILE *ed=0;
+ FILE *ed=0, *fd_to;
struct stat st;
char md5_1[33];
int match=0;
@@ -131,7 +133,7 @@ Pass3(FILE *fd)
WRONG
found:
for(i=0;(j = sp->List[i]);i++) {
- if (sp->List[i+1] && (sp->List[i+1] & CTM_F_MASK) != CTM_F_Bytes)
+ if (sp->List[i+1] && (sp->List[i+1] & CTM_F_MASK) != CTM_F_Bytes && (sp->List[i+1] & CTM_F_MASK) != CTM_F_Forward)
sep = ' ';
else
sep = '\n';
@@ -149,53 +151,98 @@ Pass3(FILE *fd)
break;
case CTM_F_Count: GETBYTECNT(cnt,sep); break;
case CTM_F_Bytes: GETDATA(trash,cnt); break;
+ case CTM_F_Release: GETBYTECNT(rel,sep); break;
+ case CTM_F_Forward:
+ if ((j & CTM_Q_MASK) == CTM_Q_Forward_Tar) {
+ if (Verbose > 0)
+ fd_to = popen("tar xvf -","w");
+ else
+ fd_to = popen("tar xvf - >/dev/null 2>&1","w");
+ } else if ((j & CTM_Q_MASK) == CTM_Q_Forward_SVN) {
+ svn_command = alloca(strlen(name)+128);
+ if (Verbose > 0)
+ snprintf(svn_command,strlen(name)+127,"svnadmin load %s\n", name);
+ else
+ snprintf(svn_command,strlen(name)+127,"svnadmin load %s > /dev/null 2>&1\n", name);
+ fd_to = popen(svn_command,"w");
+ } else WRONG
+ if (fd_to == NULL) {
+ fprintf(stderr,"Cannot forward\n");
+ WRONG
+ }
+ if (Verbose > 0) {
+ if (!strcmp(sp->Key,"TR"))
+ fprintf(stderr,"> %s\n",sp->Key);
+ else
+ fprintf(stderr,"> %s %s\n",sp->Key,name);
+ }
+ GETFORWARD(cnt,fd_to);
+ if (pclose(fd_to)) {
+ if ((j & CTM_Q_MASK) == CTM_Q_Forward_Tar)
+ fprintf(stderr,"Tar failed to close properly\n");
+ else if ((j & CTM_Q_MASK) == CTM_Q_Forward_SVN)
+ fprintf(stderr,"Svnadmin failed to close properly\n");
+ WRONG
+ }
+ if ((j & CTM_Q_MASK) == CTM_Q_Forward_SVN) {
+ snprintf(svn_command,strlen(name)+127,"svnadmin pack %s\n", name);
+ if (system(svn_command)) {
+ fprintf(stderr,"\"%s\" didn't work.", svn_command);
+ WRONG
+ }
+ }
+ break;
default: WRONG
}
}
- /* XXX This should go away. Disallow trailing '/' */
- j = strlen(name)-1;
- if(name[j] == '/') name[j] = '\0';
- /*
- * If a filter list is specified, run thru the filter list and
- * match `name' against filters. If the name matches, set the
- * required action to that specified in the filter.
- * The default action if no filterlist is given is to match
- * everything.
- */
+ if (name) {
+ /* XXX This should go away. Disallow trailing '/' */
+ j = strlen(name)-1;
+ if(name[j] == '/') name[j] = '\0';
- match = (FilterList ? !(FilterList->Action) : CTM_FILTER_ENABLE);
- for (filter = FilterList; filter; filter = filter->Next) {
- if (0 == regexec(&filter->CompiledRegex, name,
- 0, 0, 0)) {
- match = filter->Action;
+ /*
+ * If a filter list is specified, run thru the filter list and
+ * match `name' against filters. If the name matches, set the
+ * required action to that specified in the filter.
+ * The default action if no filterlist is given is to match
+ * everything.
+ */
+
+ match = (FilterList ? !(FilterList->Action) : CTM_FILTER_ENABLE);
+ for (filter = FilterList; filter; filter = filter->Next) {
+ if (0 == regexec(&filter->CompiledRegex, name,
+ 0, 0, 0)) {
+ match = filter->Action;
+ }
}
- }
- if (CTM_FILTER_DISABLE == match) /* skip file if disabled */
- continue;
+ if (CTM_FILTER_DISABLE == match) /* skip file if disabled */
+ continue;
- if (Verbose > 0)
+ if (Verbose > 0 && strcmp(sp->Key,"SV") && strcmp(sp->Key,"TR"))
fprintf(stderr,"> %s %s\n",sp->Key,name);
- if(!strcmp(sp->Key,"FM") || !strcmp(sp->Key, "FS")) {
- i = open(name,O_WRONLY|O_CREAT|O_TRUNC,0666);
- if(i < 0) {
- warn("%s", name);
- WRONG
+ if(!strcmp(sp->Key,"FM") || !strcmp(sp->Key, "FS")) {
+ i = open(name,O_WRONLY|O_CREAT|O_TRUNC,0666);
+ if(i < 0) {
+ warn("%s", name);
+ WRONG
+ }
+ if(cnt != write(i,trash,cnt)) {
+ warn("%s", name);
+ WRONG
+ }
+ close(i);
+ if(strcmp(md5,MD5File(name,md5_1))) {
+ fprintf(stderr," %s %s MD5 didn't come out right\n",
+ sp->Key,name);
+ WRONG
+ }
+ if (settime(name,times)) WRONG
+ continue;
}
- if(cnt != write(i,trash,cnt)) {
- warn("%s", name);
- WRONG
- }
- close(i);
- if(strcmp(md5,MD5File(name,md5_1))) {
- fprintf(stderr," %s %s MD5 didn't come out right\n",
- sp->Key,name);
- WRONG
- }
- if (settime(name,times)) WRONG
- continue;
}
+
if(!strcmp(sp->Key,"FE")) {
ed = popen("ed","w");
if(!ed) {
@@ -278,6 +325,8 @@ Pass3(FILE *fd)
}
continue;
}
+ if(!strcmp(sp->Key,"TR") || !strcmp(sp->Key,"SV"))
+ continue;
WRONG
}

View File

@ -0,0 +1,44 @@
--- ctm/ctm_syntax.c.orig 2018-10-27 15:56:22 UTC
+++ ctm/ctm_syntax.c
@@ -22,16 +22,21 @@
#define MD5 CTM_F_MD5
#define Count CTM_F_Count
#define Bytes CTM_F_Bytes
+#define Release CTM_F_Release
+#define Forward CTM_F_Forward
/* The qualifiers... */
#define File CTM_Q_Name_File
#define Dir CTM_Q_Name_Dir
+#define Svnbase CTM_Q_Name_Svnbase
#define New CTM_Q_Name_New
#define Subst CTM_Q_Name_Subst
#define After CTM_Q_MD5_After
#define Before CTM_Q_MD5_Before
#define Chunk CTM_Q_MD5_Chunk
#define Force CTM_Q_MD5_Force
+#define Tar CTM_Q_Forward_Tar
+#define SVN CTM_Q_Forward_SVN
static int ctmFM[] = /* File Make */
{ Name|File|New|Subst, Uid, Gid, Mode,
@@ -57,6 +62,12 @@ static int ctmDM[] = /* Directory Make */
static int ctmDR[] = /* Directory Remove */
{ Name|Dir, 0 };
+static int ctmTR[] = /* Forward to tar */
+ { Count, Forward|Tar, 0 };
+
+static int ctmSV[] = /* Forward to svnadmin load */
+ { Name|Dir|Svnbase, Release, Count, Forward|SVN, 0 };
+
struct CTM_Syntax Syntax[] = {
{ "FM", ctmFM },
{ "FS", ctmFS },
@@ -66,4 +77,6 @@ struct CTM_Syntax Syntax[] = {
{ "AS", ctmAS },
{ "DM", ctmDM },
{ "DR", ctmDR },
+ { "TR", ctmTR },
+ { "SV", ctmSV },
{ 0, 0} };

View File

@ -0,0 +1,269 @@
--- mkCTM/mkctm.c.orig 2018-10-27 15:56:22 UTC
+++ mkCTM/mkctm.c
@@ -181,12 +181,16 @@ Equ(const char *dir1, const char *dir2, const char *na
goto finish;
}
#endif
- p1=mmap(0, s1.st_size, PROT_READ, MAP_PRIVATE, fd1, 0);
- if (p1 == (u_char *)MAP_FAILED) { err(3, "%s", buf1); }
+ if (s1.st_size) {
+ p1=mmap(0, s1.st_size, PROT_READ, MAP_PRIVATE, fd1, 0);
+ if (p1 == (u_char *)MAP_FAILED) { err(3, "%s", buf1); }
+ }
close(fd1);
- p2=mmap(0, s2.st_size, PROT_READ, MAP_PRIVATE, fd2, 0);
- if (p2 == (u_char *)MAP_FAILED) { err(3, "%s", buf2); }
+ if (s2.st_size) {
+ p2=mmap(0, s2.st_size, PROT_READ, MAP_PRIVATE, fd2, 0);
+ if (p2 == (u_char *)MAP_FAILED) { err(3, "%s", buf2); }
+ }
close(fd2);
/* If identical, we're done. */
@@ -222,6 +226,9 @@ Equ(const char *dir1, const char *dir2, const char *na
int j;
FILE *F;
+ if (!s1.st_size || !s2.st_size)
+ goto subst;
+
if (s1.st_size && p1[s1.st_size-1] != '\n') {
if (verbose > 0)
fprintf(stderr,
@@ -295,8 +302,10 @@ Equ(const char *dir1, const char *dir2, const char *na
free(ob);
}
finish:
- munmap(p1, s1.st_size);
- munmap(p2, s2.st_size);
+ if (s1.st_size)
+ munmap(p1, s1.st_size);
+ if (s2.st_size)
+ munmap(p2, s2.st_size);
}
}
@@ -325,15 +334,19 @@ Add(const char *dir1, const char *dir2, const char *na
fd1 = open(buf2, O_RDONLY);
if (fd1 < 0) { err(3, "%s", buf2); }
fstat(fd1, &st);
- p1=mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd1, 0);
- if (p1 == (u_char *)MAP_FAILED) { err(3, "%s", buf2); }
+ if (st.st_size) {
+ p1=mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd1, 0);
+ if (p1 == (u_char *)MAP_FAILED) { err(3, "%s", buf2); }
+ }
close(fd1);
m2 = MD5Data(p1, st.st_size, md5_2);
name_stat("CTMFM", dir2, name, de);
printf(" %s %u\n", m2, (unsigned)st.st_size);
- fwrite(p1, 1, st.st_size, stdout);
+ if (st.st_size)
+ fwrite(p1, 1, st.st_size, stdout);
putchar('\n');
- munmap(p1, st.st_size);
+ if (st.st_size)
+ munmap(p1, st.st_size);
s_new_files++;
s_new_bytes += st.st_size;
}
@@ -493,6 +506,172 @@ DoDir(const char *dir1, const char *dir2, const char *
free(nl2);
}
+void
+SvnAdd(const char *dir1, const char *dir2, struct dirent *de)
+{
+ char current_file[] = "/db/current";
+ char *buf2 = alloca(strlen(dir2) + strlen(current_file) + strlen(de->d_name) + 4);
+ char *tmpdir = getenv("TMPDIR");
+ if (tmpdir == NULL)
+ tmpdir = strdup(_PATH_TMP);
+ char tmpfilebase[] = "/CTMserver.XXXXXXXXXX";
+ char *tmpfilename = alloca(strlen(tmpdir)+strlen(tmpfilebase)+4);
+ int command_size = strlen(dir2) + strlen(tmpdir)+strlen(tmpfilebase) + strlen(de->d_name) + 128;
+ char *command = alloca(command_size+1);
+ int ret_val;
+
+ strcpy(buf2, dir2); strcat(buf2, "/"); strcat(buf2, de->d_name); strcat(buf2, current_file);
+ strcpy(tmpfilename, tmpdir); strcat(tmpfilename, tmpfilebase);
+ mktemp(tmpfilename);
+
+ snprintf(command,command_size,"tar -C %s -cvf %s %s 2>&%d\n",dir2,tmpfilename,de->d_name,fileno(logf));
+ fflush(logf);
+ ret_val = system(command);
+ if (ret_val!=0) errx(1,"The command \"%s\" failed with return value %d",command,ret_val);
+ printf("CTMTR ");
+ change += 2; /* Make sure change is big enough .*/
+
+ StatFile(tmpfilename);
+ printf("%jd\n", st.st_size);
+ snprintf(command,command_size,"cat %s; rm -f %s\n",tmpfilename,tmpfilename);
+ ret_val = system(command);
+ if (ret_val!=0) errx(1,"The command \"%s\" failed with return value %d",command,ret_val);
+ putchar('\n');
+}
+
+void
+SvnEqu(const char *dir1, const char *dir2, struct dirent *de)
+{
+ char current_file[] = "/db/current";
+ char *buf1 = alloca(strlen(dir1) + strlen(current_file) + strlen(de->d_name) + 4);
+ char *buf2 = alloca(strlen(dir2) + strlen(current_file) + strlen(de->d_name) + 4);
+ char *tmpdir = getenv("TMPDIR");
+ if (tmpdir == NULL)
+ tmpdir = strdup(_PATH_TMP);
+ char tmpfilebase[] = "/CTMserver.XXXXXXXXXX";
+ char *tmpfilename = alloca(strlen(tmpdir)+strlen(tmpfilebase)+4);
+ int command_size = strlen(dir2) + strlen(tmpdir)+strlen(tmpfilebase) + strlen(de->d_name) + 128;
+ char *command = alloca(command_size+1);
+ long int release1, release2;
+ FILE *current1, *current2;
+ int ret_val;
+
+ strcpy(buf1, dir1); strcat(buf1, "/"); strcat(buf1, de->d_name); strcat(buf1, current_file);
+ strcpy(buf2, dir2); strcat(buf2, "/"); strcat(buf2, de->d_name); strcat(buf2, current_file);
+ strcpy(tmpfilename, tmpdir); strcat(tmpfilename, tmpfilebase);
+ mktemp(tmpfilename);
+
+ current1 = fopen(buf1,"r");
+ current2 = fopen(buf2,"r");
+
+ if (current1 != NULL) {
+ fscanf(current1,"%ld",&release1);
+ fclose(current1);
+ } else
+ errx(1,"No db/release in %s",buf1);
+ if (current2 != NULL) {
+ fscanf(current2,"%ld",&release2);
+ fclose(current2);
+ } else
+ errx(1,"No db/release in %s",buf2);
+
+ if (release2 > release1) {
+ snprintf(command,command_size,"svnadmin dump %s/%s -r %ld:%ld --incremental --deltas 2>&%d > %s\n",dir2,de->d_name,release1+1,release2,fileno(logf),tmpfilename);
+ fflush(logf);
+ ret_val = system(command);
+ if (ret_val!=0) errx(1,"The command \"%s\" failed with return value %d",command,ret_val);
+ printf("CTMSV %s %ld ", de->d_name, release1);
+ change += 2; /* Make sure change is big enough .*/
+
+ StatFile(tmpfilename);
+ printf("%jd\n", st.st_size);
+ snprintf(command,command_size,"cat %s; rm -f %s\n",tmpfilename,tmpfilename);
+ ret_val = system(command);
+ if (ret_val!=0) errx(1,"The command \"%s\" failed with return value %d",command,ret_val);
+ putchar('\n');
+ }
+}
+
+void
+DoSvn(const char *dir1, const char *dir2)
+{
+ int i1, i2, n1, n2, i;
+ struct dirent **nl1, **nl2;
+ char *buf1 = alloca(strlen(dir1) + 4);
+ char *buf2 = alloca(strlen(dir2) + 4);
+
+ strcpy(buf1, dir1); strcat(buf1, "/");
+ strcpy(buf2, dir2); strcat(buf2, "/");
+ n1 = scandir(buf1, &nl1, dirselect, alphasort);
+ n2 = scandir(buf2, &nl2, dirselect, alphasort);
+ i1 = i2 = -1;
+ GetNext(&i1, &n1, nl1, dir1, "", &s1_ignored, &s1_bogus, &s1_wrong);
+ GetNext(&i2, &n2, nl2, dir2, "", &s2_ignored, &s2_bogus, &s2_wrong);
+ for (;i1 < n1 || i2 < n2;) {
+
+ if (damage_limit && damage > damage_limit)
+ break;
+
+ /* Get next item from list 1 */
+ if (i1 < n1 && !nl1[i1])
+ GetNext(&i1, &n1, nl1, dir1, "",
+ &s1_ignored, &s1_bogus, &s1_wrong);
+
+ /* Get next item from list 2 */
+ if (i2 < n2 && !nl2[i2])
+ GetNext(&i2, &n2, nl2, dir2, "",
+ &s2_ignored, &s2_bogus, &s2_wrong);
+
+ if (i1 >= n1 && i2 >= n2) {
+ /* Done */
+ break;
+ } else if (i1 >= n1 && i2 < n2) {
+ /* end of list 1, add anything left on list 2 */
+ if (nl2[i2]->d_type == DT_REG) {
+ if (strcmp(nl2[i2]->d_name,".ctm_status")==0)
+ Add(dir1, dir2, "", nl2[i2]);
+ else
+ errx(1,"Improper file found in svn archive");
+ } else
+ SvnAdd(dir1, dir2, nl2[i2]);
+ free(nl2[i2]); nl2[i2] = 0;
+ } else if (i1 < n1 && i2 >= n2) {
+ /* end of list 2, delete anything left on list 1 */
+ Del(dir1, dir2, "", nl1[i1]);
+ free(nl1[i1]); nl1[i1] = 0;
+ } else if (!(i = strcmp(nl1[i1]->d_name, nl2[i2]->d_name))) {
+ /* Identical names */
+ if (nl2[i1]->d_type == DT_REG && nl2[i2]->d_type == DT_REG && strcmp(nl2[i2]->d_name,".ctm_status")==0)
+ Equ(dir1, dir2, "", nl1[i1]);
+ else if (nl2[i1]->d_type == DT_DIR && nl2[i2]->d_type == DT_DIR)
+ SvnEqu(dir1, dir2, nl1[i1]);
+ else
+
+ errx(1,"Improper file found in svn archive");
+ free(nl1[i1]); nl1[i1] = 0;
+ free(nl2[i2]); nl2[i2] = 0;
+ } else if (i < 0) {
+ /* Something extra in list 1, delete it */
+ Del(dir1, dir2, "", nl1[i1]);
+ free(nl1[i1]); nl1[i1] = 0;
+ } else {
+ /* Something extra in list 2, add it */
+ if (nl2[i2]->d_type == DT_REG) {
+ if (strcmp(nl2[i2]->d_name,".ctm_status")==0)
+ Add(dir1, dir2, "", nl2[i2]);
+ else
+ errx(1,"Improper file found in svn archive");
+ } else
+ SvnAdd(dir1, dir2, nl2[i2]);
+ free(nl2[i2]); nl2[i2] = 0;
+ }
+ }
+ if (n1 >= 0)
+ free(nl1);
+ if (n2 >= 0)
+ free(nl2);
+}
+
int
main(int argc, char **argv)
{
@@ -581,17 +760,22 @@ main(int argc, char **argv)
argv[0], argv[1], argv[2], argv[3]);
printf("CTM_BEGIN 2.0 %s %s %s %s\n",
argv[0], argv[1], argv[2], argv[3]);
- DoDir(argv[4], argv[5], "");
+ if (strncmp(argv[0],"svn",3) == 0)
+ DoSvn(argv[4], argv[5]);
+ else
+ DoDir(argv[4], argv[5], "");
if (damage_limit && damage > damage_limit) {
print_stat(stderr, "DAMAGE: ");
errx(1, "damage of %d would exceed %d files",
damage, damage_limit);
- } else if (change < 2) {
+/* change <= 2 means no change because of .ctm_status and .svn_revision */
+ } else if (change < 3) {
errx(4, "no changes");
} else {
printf("CTM_END ");
fprintf(logf, "CTM_END\n");
- print_stat(stderr, "END: ");
+ if (strncmp(argv[0],"svn",3) != 0)
+ print_stat(stderr, "END: ");
}
exit(0);
}