PERFORCE change 178984 for review
Ivan Voras
ivoras at FreeBSD.org
Sun May 30 23:35:22 UTC 2010
http://p4web.freebsd.org/@@178984?ac=10
Change 178984 by ivoras at 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);
+}
More information about the p4-projects
mailing list