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>