Use the same approach than RPM and pacman to handle config files.

It's explained in the pacman manpage.

--HG--
extra : convert_revision : 96f780d9f50f99162dcd40f5ae6eae70c0b89cd9
This commit is contained in:
Juan RP 2009-08-14 07:12:05 +02:00
parent e20bc0a239
commit 2843dcf4ff

View file

@ -131,13 +131,16 @@ set_extract_flags(int flags)
}
static int
install_config_file(prop_dictionary_t d, struct archive_entry *entry, int flags)
install_config_file(prop_dictionary_t d, struct archive_entry *entry,
const char *pkgname, int flags, bool skip)
{
prop_object_t obj;
prop_object_iterator_t iter;
const char *cffile, *sha256;
char *buf;
prop_dictionary_t forigd;
prop_object_t obj, obj2;
prop_object_iterator_t iter, iter2;
const char *cffile, *sha256_new;
char *buf, *sha256_cur = NULL, *sha256_orig = NULL;
int rv = 0;
bool install_new = false;
if (d == NULL)
return 0;
@ -146,6 +149,38 @@ install_config_file(prop_dictionary_t d, struct archive_entry *entry, int flags)
if (iter == NULL)
return 0;
/*
* Get original hash for the file from current
* installed package.
*/
buf = xbps_xasprintf(".%s/metadata/%s/%s", XBPS_META_PATH,
pkgname, XBPS_PKGFILES);
if (buf == NULL)
return errno;
forigd = prop_dictionary_internalize_from_file(buf);
free(buf);
if (forigd != NULL) {
iter2 = xbps_get_array_iter_from_dict(forigd, "conf_files");
if (iter2 != NULL) {
while ((obj2 = prop_object_iterator_next(iter2))) {
prop_dictionary_get_cstring_nocopy(obj2,
"file", &cffile);
if (strstr(archive_entry_pathname(entry),
cffile)) {
prop_dictionary_get_cstring(obj2,
"sha256", &sha256_orig);
break;
}
}
prop_object_iterator_release(iter2);
}
prop_object_release(forigd);
}
/*
* Compare original, installed and new hash for current file.
*/
while ((obj = prop_object_iterator_next(iter))) {
prop_dictionary_get_cstring_nocopy(obj, "file", &cffile);
if (strstr(archive_entry_pathname(entry), cffile) == 0)
@ -155,39 +190,91 @@ install_config_file(prop_dictionary_t d, struct archive_entry *entry, int flags)
prop_object_iterator_release(iter);
return errno;
}
prop_dictionary_get_cstring_nocopy(obj, "sha256", &sha256);
rv = xbps_check_file_hash(buf, sha256);
prop_dictionary_get_cstring_nocopy(obj, "sha256", &sha256_new);
sha256_cur = xbps_get_file_hash(buf);
free(buf);
if (rv == 0 || rv == ENOENT) {
/*
* Identical files or file not installed,
* install new file.
*/
rv = 0;
if (sha256_cur == NULL) {
if (errno == ENOENT) {
/*
* File not installed, install new one.
*/
install_new = true;
break;
} else {
rv = errno;
break;
}
}
/*
* Orig = X, Curr = X, new = X
*
* Install new file.
*/
if ((strcmp(sha256_orig, sha256_cur) == 0) &&
(strcmp(sha256_cur, sha256_new) == 0) &&
(strcmp(sha256_orig, sha256_new) == 0)) {
install_new = true;
break;
} else if (rv == ERANGE) {
/*
* Save new file with a .new extension,
* preserving current installed file.
*/
/*
* Orig = X, Curr = X, new = Y
*
* Install new file.
*/
} else if ((strcmp(sha256_orig, sha256_cur) == 0) &&
(strcmp(sha256_cur, sha256_new)) &&
(strcmp(sha256_orig, sha256_new))) {
install_new = true;
break;
/*
* Orig = X, Curr = Y, new = X
*
* Keep current file as is.
*/
} else if ((strcmp(sha256_orig, sha256_cur)) &&
(strcmp(sha256_orig, sha256_new) == 0) &&
(strcmp(sha256_cur, sha256_new))) {
skip = true;
break;
/*
* Orig = X, Curr = Y, New = Y
*
* Install new file.
*/
} else if ((strcmp(sha256_orig, sha256_cur)) &&
(strcmp(sha256_cur, sha256_new) == 0) &&
(strcmp(sha256_orig, sha256_new))) {
install_new = true;
break;
/*
* Orig = X, Curr = Y, New = Z
*
* Install new file as file.new.
*/
} else if ((strcmp(sha256_orig, sha256_cur)) &&
(strcmp(sha256_cur, sha256_new)) &&
(strcmp(sha256_orig, sha256_new))) {
buf = xbps_xasprintf(".%s.new", cffile);
if (buf == NULL) {
prop_object_iterator_release(iter);
return errno;
rv = errno;
break;
}
printf("Installing new configuration "
"file %s to %s\n", cffile, buf);
set_extract_flags(flags);
"file %s.new\n", cffile);
install_new = true;
archive_entry_set_pathname(entry, buf);
free(buf);
rv = 0;
break;
} else {
prop_object_iterator_release(iter);
return rv;
}
}
if (install_new)
set_extract_flags(flags);
if (sha256_orig)
free(sha256_orig);
if (sha256_cur)
free(sha256_cur);
prop_object_iterator_release(iter);
return rv;
@ -206,7 +293,7 @@ unpack_archive_fini(struct archive *ar, prop_dictionary_t pkg,
const char *pkgname, *version, *rootdir;
char *buf, *buf2;
int rv = 0, flags, lflags, eflags;
bool actgt = false;
bool actgt = false, skip_entry = false;
assert(ar != NULL);
assert(pkg != NULL);
@ -284,6 +371,7 @@ unpack_archive_fini(struct archive *ar, prop_dictionary_t pkg,
archive_entry_set_pathname(entry, buf2);
free(buf2);
buf2 = NULL;
} else if (strcmp("./files.plist",
archive_entry_pathname(entry)) == 0) {
/*
@ -297,6 +385,7 @@ unpack_archive_fini(struct archive *ar, prop_dictionary_t pkg,
/* Pass to next entry */
continue;
} else if (strcmp("./props.plist",
archive_entry_pathname(entry)) == 0) {
buf2 = xbps_xasprintf(".%s/metadata/%s/props.plist",
@ -307,21 +396,18 @@ unpack_archive_fini(struct archive *ar, prop_dictionary_t pkg,
free(buf2);
}
/*
* Check if a configuration file is currently installed
* and take action. The following actions are executed:
*
* - if file doesn't exist or new/current are identical:
* install new one.
*
* - if file exists and new/current do have differences,
* install new file with extension ".new" and preserve
* current file.
* Handle configuration files.
*/
if ((rv = install_config_file(filesd, entry, eflags)) != 0) {
if ((rv = install_config_file(filesd, entry, pkgname,
eflags, skip_entry)) != 0) {
prop_object_release(filesd);
return rv;
}
if (skip_entry) {
archive_read_data_skip(ar);
skip_entry = false;
continue;
}
/*
* Extract entry from archive.
*/