Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 30 May 2010 23:35:21 GMT
From:      Ivan Voras <ivoras@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 178984 for review
Message-ID:  <201005302335.o4UNZLsl028791@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://p4web.freebsd.org/@@178984?ac=10

Change 178984 by ivoras@betelgeuse on 2010/05/30 23:34:24

	Step 4: (not finished): Start creating the actual patch binary

Affected files ...

.. //depot/projects/soc2010/pkg_patch/src/patch/Makefile#8 edit
.. //depot/projects/soc2010/pkg_patch/src/patch/hashjob.c#7 edit
.. //depot/projects/soc2010/pkg_patch/src/patch/hashjob.h#7 edit
.. //depot/projects/soc2010/pkg_patch/src/patch/main.c#8 edit
.. //depot/projects/soc2010/pkg_patch/src/patch/mkpatch.c#6 edit
.. //depot/projects/soc2010/pkg_patch/src/patch/mkpatch.h#6 edit
.. //depot/projects/soc2010/pkg_patch/src/patch/pkg_patch.h#6 edit
.. //depot/projects/soc2010/pkg_patch/src/patch/support.c#5 edit

Differences ...

==== //depot/projects/soc2010/pkg_patch/src/patch/Makefile#8 (text+ko) ====


==== //depot/projects/soc2010/pkg_patch/src/patch/hashjob.c#7 (text+ko) ====


==== //depot/projects/soc2010/pkg_patch/src/patch/hashjob.h#7 (text+ko) ====


==== //depot/projects/soc2010/pkg_patch/src/patch/main.c#8 (text+ko) ====


==== //depot/projects/soc2010/pkg_patch/src/patch/mkpatch.c#6 (text+ko) ====

@@ -38,12 +38,15 @@
 perform_mkpatch()
 {
 	char fold[PATH_MAX], fnew[PATH_MAX], fpatch[PATH_MAX];
-	char dold[PATH_MAX], dnew[PATH_MAX];
+	char dold[PATH_MAX], dnew[PATH_MAX], dpatch[PATH_MAX];
+	char tmp[PATH_MAX], tmp2[PATH_MAX];
 	struct pkgxjob xold, xnew;
 	struct filelist_head flold, flnew;
 	struct filelist_head fldiff_old_new, fldiff_new_old, flintersect;
 	struct filelist_head flchanged;
 	struct filelist *fl;
+	FILE *fp;
+	time_t tm;
 	
 	if (argc < 3)
 		errx(1, "Expecting 3 arguments: old_package_file "
@@ -70,6 +73,9 @@
 	sprintf(dnew, "%s/new", my_tmp);
 	if (mkdir(dnew, 0700) != 0)
 		err(1, "Cannot create directory: %s", dnew);
+	sprintf(dpatch, "%s/patch", my_tmp);
+	if (mkdir(dpatch, 0700) != 0)
+		err(1, "Cannot create directory: %s", dpatch);
 	
 	if (pkgxjob_start(&xold, dold, fold) != 0)
 		err(1, "Cannot extract package %s to %s (start)", fold, dold);
@@ -155,4 +161,59 @@
 	}
 	if (verbose)
 		printf("Found %d changed files.\n", filelist_count(&flchanged));
+	
+	/*
+	 * XXX: Possibly reimplement with libarchive. If I finally get how it
+	 * stores directories.
+	 */
+	sprintf(tmp, "%s/%s", dpatch, PKGPATCH_FNAME);
+	fp = fopen(tmp, "w");
+	if (fp == NULL)
+		err(1, "Cannot open file for writing: %s", tmp);
+	time(&tm);
+	fprintf(fp, "# FreeBSD package patch archive created on %s\n",
+		ctime(&tm));
+	fprintf(fp, "@version %s\n", PKGPATCH_VERSION);
+	parse_package_name(fold, tmp, tmp2, NULL);
+	fprintf(fp, "@source %s-%s\n", tmp, tmp2);
+	parse_package_name(fnew, tmp, tmp2, NULL);
+	fprintf(fp, "@target %s-%s\n", tmp, tmp2);
+	SLIST_FOREACH(fl, &fldiff_new_old, linkage)
+		fprintf(fp, "@add %s\n", fl->filename);
+	SLIST_FOREACH(fl, &fldiff_old_new, linkage)
+		fprintf(fp, "@remove %s\n", fl->filename);
+	SLIST_FOREACH(fl, &flchanged, linkage)
+		fprintf(fp, "@patch [method=cp] %s\n", fl->filename);
+	if (fclose(fp) != 0)
+		err(1, "Cannot close %s", PKGPATCH_FNAME);
+	
+	/* Include all metadata files from the new package. */
+	SLIST_FOREACH(fl, &flnew, linkage) {
+		if (fl->filename[0] == '+') {
+			sprintf(tmp, "%s/%s", dnew, fl->filename);
+			sprintf(tmp2, "%s/%s", dpatch, fl->filename);
+			if (copy_file_absolute(tmp, tmp2) != 0)
+				err(1, "Cannot copy file: %s to file: %s",
+				   tmp, tmp2);
+		}
+	}
+	
+	/* Simply copy the directory hierarchy of the new package. */
+	replicate_dirtree(dnew, dpatch);
+	
+	SLIST_FOREACH(fl, &flchanged, linkage) {
+		sprintf(tmp, "%s/%s", dnew, fl->filename);
+		sprintf(tmp2, "%s/%s", dpatch, fl->filename);
+		if (copy_file_absolute(tmp, tmp2) != 0)
+			err(1, "Cannot copy file: %s to file: %s", tmp, tmp2);
+	}
+	
+	sprintf(tmp, "%s -c -j -C %s -f %s *", _PATH_TAR, dpatch, fpatch);
+	fp = popen(tmp, "r+");
+	if (fp == NULL)
+		err(1, "Final tar execution failed for: %s", fpatch);
+	rm_rf(dold);
+	rm_rf(dnew);
+	if (pclose(fp) != 0)
+		err(1, "pclose() failed");
 }

==== //depot/projects/soc2010/pkg_patch/src/patch/mkpatch.h#6 (text+ko) ====


==== //depot/projects/soc2010/pkg_patch/src/patch/pkg_patch.h#6 (text+ko) ====

@@ -24,6 +24,9 @@
 #define _PATH_TAR "/usr/bin/tar"
 #endif
 
+#define PKGPATCH_FNAME		"+PKGPATCH"
+#define PKGPATCH_VERSION 	"1.0"
+
 enum PP_OP { PP_NONE, PP_MKPATCH };
 
 struct pkgxjob {
@@ -57,5 +60,9 @@
 int filelist_intersect(struct filelist_head *fl1, struct filelist_head *fl2,
     struct filelist_head *flisect);
 unsigned int filelist_count(struct filelist_head *flist);
+void parse_package_name(char *pkgfile, char *basename, char *version,
+    char *suffix);
+int copy_file_absolute(char *from, char *to);
+int replicate_dirtree(char *from, char *to);
 
 #endif

==== //depot/projects/soc2010/pkg_patch/src/patch/support.c#5 (text+ko) ====

@@ -26,9 +26,12 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <unistd.h>
+#include <fcntl.h>
 #include <paths.h>
+#include <errno.h>
 #include <err.h>
 #include <fts.h>
+#include <regex.h>
 
 #include <pkg.h>
 #include "pkg_patch.h"
@@ -163,3 +166,109 @@
 		count++;
 	return (count);
 }
+
+
+/*
+ * For a given binary package archive filename, extract its base package name
+ * (e.g. "apache-ant"), its version (e.g. "1.7.1") and its suffix (e.g. ".tbz").
+ * Any of the component pointers / arguments can be NULL. The package filname
+ * might contain path information (slashes), which will be discarded.
+ */
+void
+parse_package_name(char *pkgfile, char *basename, char *version, char *suff)
+{
+	char *tmp, *p;
+	
+	/* Strip directory path, if any */
+	p = strrchr(pkgfile, '/');
+	if (p != NULL)
+		tmp = strdup(p + 1);
+	else
+		tmp = strdup(pkgfile);
+	p = strrchr(tmp, '.');
+	if (suff != NULL)
+		strcpy(suff, p);
+	*p = '\0';
+	p = strrchr(tmp, '-');
+	if (version != NULL)
+		strcpy(version, p + 1);
+	*p = '\0';
+	if (basename != NULL)
+		strcpy(basename, tmp);
+	free(tmp);
+}
+
+
+/*
+ * File copy, preserving attributes: ownership, mtime, mode. Knows how to handle
+ * (re-create) symlinks.
+ */
+int
+copy_file_absolute(char *from, char *to)
+{
+	char *buf;
+	const ssize_t bufsize = 256*1024;
+	ssize_t bs;
+	int fdfrom, fdto;
+	struct stat st;
+	struct timeval tv;
+	
+	if (lstat(from, &st) != 0)
+		return (errno);
+	
+	if (S_ISLNK(st.st_mode)) {
+		char tmp[PATH_MAX];
+		
+		if (readlink(from, tmp, PATH_MAX) < 0)
+			return (errno);
+		if (symlink(tmp, to) < 0)
+			return (errno);
+		return (0);
+	}
+	
+	fdfrom = open(from, O_RDONLY);
+	if (fdfrom < 0)
+		return (errno);
+	fdto = open(to, O_CREAT | O_WRONLY | O_TRUNC);
+	if (fdto < 0)
+		return (errno);
+	buf = malloc(bufsize);
+	if (buf == NULL)
+		return (ENOMEM);
+	while (1) {
+		bs = read(fdfrom, buf, bufsize);
+		if (bs < 0)
+			err(1, "read() failure");
+		else if (bs > 0)
+			if (write(fdto, buf, bs) != bs)
+				err(1, "write() failure");
+		if (bs == 0)
+			break;
+	}
+	free(buf);
+	close(fdto);
+	close(fdfrom);
+	
+	if (chown(to, st.st_uid, st.st_gid) < 0)
+		return (errno);
+	tv.tv_usec = 0;
+	tv.tv_sec = st.st_mtime;
+	if (lutimes(to, &tv) < 0)
+		return (errno);
+	if (lchmod(to, st.st_mode) < 0)
+		return (errno);
+	return (0);
+}
+
+
+/*
+ * Replicates / re-creates a directory tree in the destination to contain
+ * all directories from the source, including their properties: ownership,
+ * mode, mtime.
+ */
+int
+replicate_dirtree(char __unused *from, char __unused *to)
+{
+	/* XXX: todo */
+	return (0);
+}



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201005302335.o4UNZLsl028791>