From d8353810b64300810713cdf2dcd2459cef38411c Mon Sep 17 00:00:00 2001
From: Juan RP <xtraeme@gmail.com>
Date: Sat, 1 Aug 2009 11:23:41 +0200
Subject: [PATCH] Reorganize pkg metadata files.plist scheme to improve future
 changes.

This fixes an item from the TODO about 'xbps-bin -C files' not checking
configuration files.

--HG--
extra : convert_revision : bb661554a6b34a25066749844709b8cbaf5a4d6c
---
 bin/xbps-repo/util.c | 141 +++++++++++++++-------------
 doc/TODO             |   2 -
 lib/remove.c         | 215 +++++++++++++++++++++++++++----------------
 shutils/metadata.sh  |  48 ++++++----
 4 files changed, 246 insertions(+), 160 deletions(-)

diff --git a/bin/xbps-repo/util.c b/bin/xbps-repo/util.c
index eaeed0cc0a..1a720d39e5 100644
--- a/bin/xbps-repo/util.c
+++ b/bin/xbps-repo/util.c
@@ -35,13 +35,7 @@
 #include <xbps_api.h>
 #include "util.h"
 
-struct show_files_cb {
-	const char *destdir;
-	bool check_hash;
-};
-
 static void	show_pkg_info(prop_dictionary_t);
-static int	show_pkg_files(prop_object_t, void *, bool *);
 static int	show_pkg_namedesc(prop_object_t, void *, bool *);
 
 static void
@@ -206,11 +200,14 @@ int
 show_pkg_files_from_metadir(const char *pkgname, bool hash)
 {
 	prop_dictionary_t pkgd;
-	struct show_files_cb sfc;
-	const char *destdir = xbps_get_rootdir();
-	char *plist;
-	int rv = 0;
+	prop_array_t array;
+	prop_object_iterator_t iter = NULL;
+	prop_object_t obj;
+	const char *destdir, *file, *sha256;
+	char *plist, *path = NULL, *array_str = "files";
+	int i, rv = 0;
 
+	destdir = xbps_get_rootdir();
 	plist = xbps_xasprintf("%s/%s/metadata/%s/%s", destdir,
 	    XBPS_META_PATH, pkgname, XBPS_PKGFILES);
 	if (plist == NULL)
@@ -221,65 +218,81 @@ show_pkg_files_from_metadir(const char *pkgname, bool hash)
 		free(plist);
 		return errno;
 	}
-
-	sfc.destdir = destdir;
-	sfc.check_hash = hash;
-	rv = xbps_callback_array_iter_in_dict(pkgd, "filelist",
-	    show_pkg_files, (void *)&sfc);
-	prop_object_release(pkgd);
 	free(plist);
 
-	return rv;
-}
-
-static int
-show_pkg_files(prop_object_t obj, void *arg, bool *loop_done)
-{
-	struct show_files_cb *sfc = arg;
-	const char *file = NULL, *sha256, *type;
-	char *path = NULL;
-	int rv = 0;
-
-	(void)loop_done;
-
-	prop_dictionary_get_cstring_nocopy(obj, "file", &file);
-	prop_dictionary_get_cstring_nocopy(obj, "type", &type);
-	if (strcmp(type, "dir") == 0)
-		return 0;
-
-	if (sfc->check_hash == false && file != NULL) {
-		printf("%s\n", file);
-		return 0;
-	}
-
-	if (strcmp(type, "link") == 0)
-		return 0;
-
-	if (sfc->check_hash && file != NULL) {
-		printf("%s", file);
-		if (sfc->destdir) {
-			path = xbps_xasprintf("%s/%s", sfc->destdir, file);
-			if (path == NULL)
-				return EINVAL;
+	/* Links. */
+	array = prop_dictionary_get(pkgd, "links");
+	if (array && prop_array_count(array) > 0) {
+		iter = xbps_get_array_iter_from_dict(pkgd, "links");
+		if (iter == NULL) {
+			rv = EINVAL;
+			goto out;
 		}
-
-		prop_dictionary_get_cstring_nocopy(obj, "sha256", &sha256);
-		if (sfc->destdir)
-			rv = xbps_check_file_hash(path, sha256);
-		else
-			rv = xbps_check_file_hash(file, sha256);
-
-		if (rv != 0 && rv != ERANGE)
-			printf(" (can't check: %s)", strerror(rv));
-		else if (rv == ERANGE)
-			printf("  WARNING! SHA256 HASH MISMATCH!");
-
-		printf("\n");
-		if (sfc->destdir)
-			free(path);
+		while ((obj = prop_object_iterator_next(iter))) {
+			prop_dictionary_get_cstring_nocopy(obj, "file", &file);
+			printf("%s\n", file);
+		}
+		prop_object_iterator_release(iter);
+		iter = NULL;
 	}
 
-	return 0;
+	/* Files and configuration files. */
+	for (i = 0; i < 2; i++) {
+		if (i == 0)
+			array_str = "conf_files";
+		else
+			array_str = "files";
+
+		array = prop_dictionary_get(pkgd, array_str);
+		if (array == NULL || prop_array_count(array) == 0)
+			continue;
+
+		iter = xbps_get_array_iter_from_dict(pkgd, array_str);
+		if (iter == NULL) {
+			rv = EINVAL;
+			goto out;
+		}
+		while ((obj = prop_object_iterator_next(iter))) {
+			prop_dictionary_get_cstring_nocopy(obj, "file", &file);
+			if (hash == false) {
+				printf("%s\n", file);
+				continue;
+			}
+
+			printf("%s", file);
+			if (destdir) {
+				path = xbps_xasprintf("%s/%s", destdir, file);
+				if (path == NULL) {
+					rv = EINVAL;
+					goto out2;
+				}
+			}
+			prop_dictionary_get_cstring_nocopy(obj,
+			    "sha256", &sha256);
+			if (destdir)
+				rv = xbps_check_file_hash(path, sha256);
+			else
+				rv = xbps_check_file_hash(file, sha256);
+
+			if (rv != 0 && rv != ERANGE)
+				printf(" (can't check: %s)", strerror(rv));
+			else if (rv == ERANGE)
+				printf("  WARNING! SHA256 HASH MISMATCH!");
+
+			printf("\n");
+			if (destdir)
+				free(path);
+		}
+		prop_object_iterator_release(iter);
+		iter = NULL;
+	}
+out2:
+	if (iter != NULL)
+		prop_object_iterator_release(iter);
+out:
+	prop_object_release(pkgd);
+
+	return rv;
 }
 
 int
diff --git a/doc/TODO b/doc/TODO
index a8d37a8392..557e6d8ba1 100644
--- a/doc/TODO
+++ b/doc/TODO
@@ -26,8 +26,6 @@ xbps-bin:
    overwritting files on disk and updating required_by if required.
    Perhaps change the automatic-install object to false, like pkg_install
    from NetBSD do.
- * When checking file hash integrity (with -C files), it doesn't take
-   into account configuration files.
  * Implement shell style match patterns with fnmatch().
  * Make -f flag to overwrite files when installing, and to ignore
    files with wrong checksum or unexistent when removing.
diff --git a/lib/remove.c b/lib/remove.c
index 93f1da0149..efa1d7b1ba 100644
--- a/lib/remove.c
+++ b/lib/remove.c
@@ -36,7 +36,7 @@
 
 #include <xbps_api.h>
 
-static int	remove_pkg_files(prop_object_t, void *, bool *);
+static int	remove_pkg_files(prop_dictionary_t);
 
 int
 xbps_unregister_pkg(const char *pkgname)
@@ -111,99 +111,161 @@ xbps_remove_binary_pkg_meta(const char *pkgname)
 }
 
 static int
-remove_pkg_files(prop_object_t obj, void *arg, bool *loop_done)
+remove_pkg_files(prop_dictionary_t dict)
 {
+	prop_array_t array;
+	prop_object_iterator_t iter;
+	prop_object_t obj;
 	prop_bool_t bobj;
-	const char *file, *rootdir, *sha256, *type;
+	const char *file, *rootdir, *sha256, *array_str, *curftype;
 	char *path = NULL;
-	int flags = 0, rv = 0;
-
-	(void)arg;
-	(void)loop_done;
+	int i, flags = 0, rv = 0;
 
 	rootdir = xbps_get_rootdir();
 	flags = xbps_get_flags();
 
-	if (!prop_dictionary_get_cstring_nocopy(obj, "file", &file))
+	/* Links */
+	array = prop_dictionary_get(dict, "links");
+	if (array == NULL || prop_array_count(array) == 0)
+		goto files;
+
+	iter = xbps_get_array_iter_from_dict(dict, "links");
+	if (iter == NULL)
 		return EINVAL;
 
-	path = xbps_xasprintf("%s/%s", rootdir, file);
-	if (path == NULL)
-		return EINVAL;
-
-	if (!prop_dictionary_get_cstring_nocopy(obj, "type", &type)) {
-		free(path);
-		return EINVAL;
-	}
-
-	if (strcmp(type, "file") == 0) {
-		prop_dictionary_get_cstring_nocopy(obj, "sha256", &sha256);
-		rv = xbps_check_file_hash(path, sha256);
-		if (rv != 0 && rv != ERANGE) {
-			free(path);
-			return rv;
+	while ((obj = prop_object_iterator_next(iter))) {
+		if (!prop_dictionary_get_cstring_nocopy(obj, "file", &file)) {
+			prop_object_iterator_release(iter);
+			return EINVAL;
 		}
-
-		bobj = prop_dictionary_get(obj, "conf_file");
-		if (bobj != NULL) {
-			/*
-			 * If hash is the same than the one provided by
-			 * package, that means the file hasn't been changed
-			 * and therefore can be removed. Otherwise keep it.
-			 */
-			if (rv == ERANGE)
-				goto out;
+		path = xbps_xasprintf("%s/%s", rootdir, file);
+		if (path == NULL) {
+			prop_object_iterator_release(iter);
+			return EINVAL;
 		}
-
-		if (rv == ERANGE) {
-			if (flags & XBPS_VERBOSE)
-				printf("WARNING: SHA256 doesn't match for "
-				    "file %s, ignoring...\n", file);
-			goto out;
-		}
-
-		if ((rv = remove(path)) == -1) {
-			if (flags & XBPS_VERBOSE)
-				printf("WARNING: can't remove file %s (%s)\n",
-				    file, strerror(errno));
-			goto out;
-		}
-		if (flags & XBPS_VERBOSE)
-			printf("Removed file: %s\n", file);
-
-		goto out;
-	} else if (strcmp(type, "dir") == 0) {
-		if ((bobj = prop_dictionary_get(obj, "keep")) != NULL) {
-			/* Skip permanent directory. */
-			return 0;
-		}
-
-		if ((rv = rmdir(path)) == -1) {
-			if (errno == ENOTEMPTY)
-				goto out;
-
-			if (flags & XBPS_VERBOSE) {
-				printf("WARNING: can't remove "
-				    "directory %s (%s)\n", file,
-				    strerror(errno));
-				goto out;
-			}
-			if (flags & XBPS_VERBOSE)
-				printf("Removed directory: %s\n", file);
-		}
-	} else if (strcmp(type, "link") == 0) {
 		if ((rv = remove(path)) == -1) {
 			if (flags & XBPS_VERBOSE)
 				printf("WARNING: can't remove link %s (%s)\n",
 				    file, strerror(errno));
-			goto out;
+			free(path);
+			continue;
 		}
 		if (flags & XBPS_VERBOSE)
 			printf("Removed link: %s\n", file);
+
+		free(path);
+	}
+	prop_object_iterator_release(iter);
+	path = NULL;
+
+files:
+	/* Regular files and configuration files */
+	for (i = 0; i < 2; i++) {
+		if (i == 0) {
+			array_str = "conf_files";
+			curftype = "config file";
+		} else {
+			array_str = "files";
+			curftype = "file";
+		}
+		array = prop_dictionary_get(dict, array_str);
+		if (array == NULL || prop_array_count(array) == 0) {
+			if (i == 0)
+				continue;
+			else
+				goto dirs;
+		}
+		iter = xbps_get_array_iter_from_dict(dict, array_str);
+		if (iter == NULL)
+			return EINVAL;
+
+		while ((obj = prop_object_iterator_next(iter))) {
+			if (!prop_dictionary_get_cstring_nocopy(obj,
+			    "file", &file)) {
+				prop_object_iterator_release(iter);
+				return EINVAL;
+			}
+			path = xbps_xasprintf("%s/%s", rootdir, file);
+			if (path == NULL) {
+				prop_object_iterator_release(iter);
+				return EINVAL;
+			}
+			prop_dictionary_get_cstring_nocopy(obj,
+			    "sha256", &sha256);
+			rv = xbps_check_file_hash(path, sha256);
+			if (rv != 0 && rv != ERANGE) {
+				free(path);
+				prop_object_iterator_release(iter);
+				return rv;
+			}
+			if (rv == ERANGE) {
+				if (flags & XBPS_VERBOSE)
+					printf("WARNING: SHA256 doesn't match "
+					    "for %s %s, ignoring...\n",
+					    curftype, file);
+				free(path);
+				continue;
+			}
+			if ((rv = remove(path)) == -1) {
+				if (flags & XBPS_VERBOSE)
+					printf("WARNING: can't remove "
+					    "%s %s (%s)\n", curftype, file,
+					    strerror(errno));
+				free(path);
+				continue;
+			}
+			if (flags & XBPS_VERBOSE)
+				printf("Removed %s: %s\n", curftype, file);
+
+			free(path);
+		}
+		prop_object_iterator_release(iter);
+		path = NULL;
 	}
 
-out:
-	free(path);
+dirs:
+	/* Directories */
+	array = prop_dictionary_get(dict, "dirs");
+	if (array == NULL || prop_array_count(array) == 0)
+		return 0;
+
+	iter = xbps_get_array_iter_from_dict(dict, "dirs");
+	if (iter == NULL)
+		return EINVAL;
+
+	while ((obj = prop_object_iterator_next(iter))) {
+		if ((bobj = prop_dictionary_get(obj, "keep")) != NULL) {
+			/* Skip permanent directory. */
+			continue;
+		}
+		if (!prop_dictionary_get_cstring_nocopy(obj, "file", &file)) {
+			prop_object_iterator_release(iter);
+			return EINVAL;
+		}
+		path = xbps_xasprintf("%s/%s", rootdir, file);
+		if (path == NULL) {
+			prop_object_iterator_release(iter);
+			return EINVAL;
+		}
+		if ((rv = rmdir(path)) == -1) {
+			if (errno == ENOTEMPTY) {
+				free(path);
+				continue;
+			}
+			if (flags & XBPS_VERBOSE) {
+				printf("WARNING: can't remove "
+				    "directory %s (%s)\n", file,
+				    strerror(errno));
+				free(path);
+				continue;
+			}
+		}
+		if (flags & XBPS_VERBOSE)
+			printf("Removed directory: %s\n", file);
+
+		free(path);
+	}
+	prop_object_iterator_release(iter);
 
 	return 0;
 }
@@ -244,8 +306,6 @@ xbps_remove_binary_pkg(const char *pkgname, bool update)
 		 * Run the pre remove action.
 		 */
 		prepostf = true;
-		(void)printf("\n");
-		(void)fflush(stdout);
 		rv = xbps_file_chdir_exec(rootdir, buf, "pre", pkgname, NULL);
 		if (rv != 0) {
 			printf("%s: prerm action target error (%s)\n", pkgname,
@@ -274,8 +334,7 @@ xbps_remove_binary_pkg(const char *pkgname, bool update)
 	}
 	free(path);
 
-	rv = xbps_callback_array_iter_in_dict(dict, "filelist",
-	    remove_pkg_files, NULL);
+	rv = remove_pkg_files(dict);
 	if (rv != 0) {
 		free(buf);
 		prop_object_release(dict);
diff --git a/shutils/metadata.sh b/shutils/metadata.sh
index f08fbd0a99..7158074fb1 100644
--- a/shutils/metadata.sh
+++ b/shutils/metadata.sh
@@ -32,8 +32,6 @@ write_metadata_flist_header()
 <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 <plist version="1.0">
 <dict>
-<key>filelist</key>
-<array>
 _EOF
 
 }
@@ -92,7 +90,7 @@ xbps_write_metadata_pkg()
 xbps_write_metadata_pkg_real()
 {
 	local metadir=${DESTDIR}/var/db/xbps/metadata/$pkgname
-	local f i j arch dirat lnkat newlnk lver TMPFLIST TMPFPLIST
+	local f i j found arch dirat lnkat newlnk lver TMPFLIST TMPFPLIST
 	local fpattern="s|${DESTDIR}||g;s|^\./$||g;/^$/d"
 
 	if [ ! -d "${DESTDIR}" ]; then
@@ -186,6 +184,8 @@ xbps_write_metadata_pkg_real()
 	write_metadata_flist_header $TMPFPLIST
 
 	# Pass 1: add links.
+	echo "<key>links</key>" >> $TMPFPLIST
+	echo "<array>" >> $TMPFPLIST
 	for f in $(find ${DESTDIR} -type l); do
 		j=$(echo $f|sed -e "$fpattern")
 		[ "$j" = "" ] && continue
@@ -193,34 +193,34 @@ xbps_write_metadata_pkg_real()
 		echo "<dict>" >> $TMPFPLIST
 		echo "<key>file</key>" >> $TMPFPLIST
 		echo "<string>$j</string>" >> $TMPFPLIST
-		echo "<key>type</key>" >> $TMPFPLIST
-		echo "<string>link</string>" >> $TMPFPLIST
 		echo "</dict>" >> $TMPFPLIST
 	done
+	echo "</array>" >> $TMPFPLIST
 
 	# Pass 2: add regular files.
+	echo "<key>files</key>" >> $TMPFPLIST
+	echo "<array>" >> $TMPFPLIST
 	for f in $(find ${DESTDIR} -type f); do
 		j=$(echo $f|sed -e "$fpattern")
 		[ "$j" = "" ] && continue
 		echo "$j" >> $TMPFLIST
+		# Skip configuration files.
+		for i in ${conf_files}; do
+			[ "$j" = "$i" ] && found=1 && break
+		done
+		[ -n "$found" ] && unset found && continue
 		echo "<dict>" >> $TMPFPLIST
 		echo "<key>file</key>" >> $TMPFPLIST
 		echo "<string>$j</string>" >> $TMPFPLIST
-		echo "<key>type</key>" >> $TMPFPLIST
-		echo "<string>file</string>" >> $TMPFPLIST
 		echo "<key>sha256</key>" >> $TMPFPLIST
 		echo "<string>$(xbps-digest $f)</string>"  >> $TMPFPLIST
-		for i in ${conf_files}; do
-			if [ "$j" = "$i" ]; then
-				echo "<key>conf_file</key>"  >> $TMPFPLIST
-				echo "<true/>" >> $TMPFPLIST
-				break
-			fi
-		done
 		echo "</dict>" >> $TMPFPLIST
 	done
+	echo "</array>" >> $TMPFPLIST
 
 	# Pass 3: add directories.
+	echo "<key>dirs</key>" >> $TMPFPLIST
+	echo "<array>" >> $TMPFPLIST
 	for f in $(find ${DESTDIR} -type d|sort -ur); do
 		j=$(echo $f|sed -e "$fpattern")
 		[ "$j" = "" ] && continue
@@ -228,8 +228,6 @@ xbps_write_metadata_pkg_real()
 		echo "<dict>" >> $TMPFPLIST
 		echo "<key>file</key>" >> $TMPFPLIST
 		echo "<string>$j</string>" >> $TMPFPLIST
-		echo "<key>type</key>" >> $TMPFPLIST
-		echo "<string>dir</string>" >> $TMPFPLIST
 		for i in ${keep_dirs}; do
 			if [ "$j" = "$i" ]; then
 				echo "<key>keep</key>" >> $TMPFPLIST
@@ -240,6 +238,24 @@ xbps_write_metadata_pkg_real()
 		echo "</dict>" >> $TMPFPLIST
 	done
 	echo "</array>" >> $TMPFPLIST
+
+	# Add configuration files into its own array.
+	if [ -n "${conf_files}" ]; then
+		echo "<key>conf_files</key>" >> $TMPFPLIST
+		echo "<array>" >> $TMPFPLIST
+		for f in ${conf_files}; do
+			i=${DESTDIR}/${f}
+			[ ! -f ${i} ] && continue
+			echo "<dict>" >> $TMPFPLIST
+			echo "<key>file</key>" >> $TMPFPLIST
+			echo "<string>$f</string>" >> $TMPFPLIST
+			echo "<key>sha256</key>" >> $TMPFPLIST
+			echo "<string>$(xbps-digest ${i})</string>" >> $TMPFPLIST
+			echo "</dict>" >> $TMPFPLIST
+		done
+		echo "</array>" >> $TMPFPLIST
+	fi
+
 	echo "</dict>" >> $TMPFPLIST
 	echo "</plist>" >> $TMPFPLIST
 	sed -i -e /^$/d $TMPFLIST