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:
parent
e20bc0a239
commit
2843dcf4ff
1 changed files with 125 additions and 39 deletions
164
lib/unpack.c
164
lib/unpack.c
|
@ -131,13 +131,16 @@ set_extract_flags(int flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
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_dictionary_t forigd;
|
||||||
prop_object_iterator_t iter;
|
prop_object_t obj, obj2;
|
||||||
const char *cffile, *sha256;
|
prop_object_iterator_t iter, iter2;
|
||||||
char *buf;
|
const char *cffile, *sha256_new;
|
||||||
|
char *buf, *sha256_cur = NULL, *sha256_orig = NULL;
|
||||||
int rv = 0;
|
int rv = 0;
|
||||||
|
bool install_new = false;
|
||||||
|
|
||||||
if (d == NULL)
|
if (d == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -146,6 +149,38 @@ install_config_file(prop_dictionary_t d, struct archive_entry *entry, int flags)
|
||||||
if (iter == NULL)
|
if (iter == NULL)
|
||||||
return 0;
|
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))) {
|
while ((obj = prop_object_iterator_next(iter))) {
|
||||||
prop_dictionary_get_cstring_nocopy(obj, "file", &cffile);
|
prop_dictionary_get_cstring_nocopy(obj, "file", &cffile);
|
||||||
if (strstr(archive_entry_pathname(entry), cffile) == 0)
|
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);
|
prop_object_iterator_release(iter);
|
||||||
return errno;
|
return errno;
|
||||||
}
|
}
|
||||||
prop_dictionary_get_cstring_nocopy(obj, "sha256", &sha256);
|
prop_dictionary_get_cstring_nocopy(obj, "sha256", &sha256_new);
|
||||||
rv = xbps_check_file_hash(buf, sha256);
|
sha256_cur = xbps_get_file_hash(buf);
|
||||||
free(buf);
|
free(buf);
|
||||||
if (rv == 0 || rv == ENOENT) {
|
if (sha256_cur == NULL) {
|
||||||
/*
|
if (errno == ENOENT) {
|
||||||
* Identical files or file not installed,
|
/*
|
||||||
* install new file.
|
* File not installed, install new one.
|
||||||
*/
|
*/
|
||||||
rv = 0;
|
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;
|
break;
|
||||||
} else if (rv == ERANGE) {
|
/*
|
||||||
/*
|
* Orig = X, Curr = X, new = Y
|
||||||
* Save new file with a .new extension,
|
*
|
||||||
* preserving current installed file.
|
* 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);
|
buf = xbps_xasprintf(".%s.new", cffile);
|
||||||
if (buf == NULL) {
|
if (buf == NULL) {
|
||||||
prop_object_iterator_release(iter);
|
rv = errno;
|
||||||
return errno;
|
break;
|
||||||
}
|
}
|
||||||
printf("Installing new configuration "
|
printf("Installing new configuration "
|
||||||
"file %s to %s\n", cffile, buf);
|
"file %s.new\n", cffile);
|
||||||
|
install_new = true;
|
||||||
set_extract_flags(flags);
|
|
||||||
archive_entry_set_pathname(entry, buf);
|
archive_entry_set_pathname(entry, buf);
|
||||||
free(buf);
|
free(buf);
|
||||||
rv = 0;
|
|
||||||
break;
|
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);
|
prop_object_iterator_release(iter);
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
|
@ -206,7 +293,7 @@ unpack_archive_fini(struct archive *ar, prop_dictionary_t pkg,
|
||||||
const char *pkgname, *version, *rootdir;
|
const char *pkgname, *version, *rootdir;
|
||||||
char *buf, *buf2;
|
char *buf, *buf2;
|
||||||
int rv = 0, flags, lflags, eflags;
|
int rv = 0, flags, lflags, eflags;
|
||||||
bool actgt = false;
|
bool actgt = false, skip_entry = false;
|
||||||
|
|
||||||
assert(ar != NULL);
|
assert(ar != NULL);
|
||||||
assert(pkg != NULL);
|
assert(pkg != NULL);
|
||||||
|
@ -284,6 +371,7 @@ unpack_archive_fini(struct archive *ar, prop_dictionary_t pkg,
|
||||||
archive_entry_set_pathname(entry, buf2);
|
archive_entry_set_pathname(entry, buf2);
|
||||||
free(buf2);
|
free(buf2);
|
||||||
buf2 = NULL;
|
buf2 = NULL;
|
||||||
|
|
||||||
} else if (strcmp("./files.plist",
|
} else if (strcmp("./files.plist",
|
||||||
archive_entry_pathname(entry)) == 0) {
|
archive_entry_pathname(entry)) == 0) {
|
||||||
/*
|
/*
|
||||||
|
@ -297,6 +385,7 @@ unpack_archive_fini(struct archive *ar, prop_dictionary_t pkg,
|
||||||
|
|
||||||
/* Pass to next entry */
|
/* Pass to next entry */
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
} else if (strcmp("./props.plist",
|
} else if (strcmp("./props.plist",
|
||||||
archive_entry_pathname(entry)) == 0) {
|
archive_entry_pathname(entry)) == 0) {
|
||||||
buf2 = xbps_xasprintf(".%s/metadata/%s/props.plist",
|
buf2 = xbps_xasprintf(".%s/metadata/%s/props.plist",
|
||||||
|
@ -307,21 +396,18 @@ unpack_archive_fini(struct archive *ar, prop_dictionary_t pkg,
|
||||||
free(buf2);
|
free(buf2);
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* Check if a configuration file is currently installed
|
* Handle configuration files.
|
||||||
* 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.
|
|
||||||
*/
|
*/
|
||||||
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);
|
prop_object_release(filesd);
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
if (skip_entry) {
|
||||||
|
archive_read_data_skip(ar);
|
||||||
|
skip_entry = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* Extract entry from archive.
|
* Extract entry from archive.
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in a new issue