ports/misc/ctm/files/patch-mkCTM_mkctm.c
Stefan Eßer 4d6c49aae2 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)
2018-12-23 07:19:01 +00:00

269 lines
8.7 KiB
C

--- 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);
}