11/*-
22 * Copyright (c) 2008-2015 Juan Romero Pardines.
3+ * Copyright (c) 2024 Duncan Overbruck <[email protected] >. 34 * All rights reserved.
45 *
56 * Redistribution and use in source and binary forms, with or without
@@ -79,15 +80,97 @@ match_preserved_file(struct xbps_handle *xhp, const char *entry)
7980 return xbps_match_string_in_array (xhp -> preserved_files , file );
8081}
8182
83+ enum {
84+ CONFFILE_SKIP = 0 ,
85+ CONFFILE_UPDATE = 1 ,
86+ CONFFILE_NEW = 2 ,
87+ };
88+
89+ static int
90+ handle_conffile (struct xbps_handle * xhp ,
91+ const char * path ,
92+ const struct xbps_file * old ,
93+ const struct xbps_file * new ,
94+ const struct stat * st )
95+ {
96+ char sha256_cur [XBPS_SHA256_SIZE ];
97+ enum {
98+ MATCH_SAME = 1 << 0 ,
99+ MATCH_OLD = 1 << 1 ,
100+ MATCH_NEW = 1 << 2 ,
101+ } match = 0 ;
102+
103+ (void ) xhp ;
104+
105+ /* 1. File exist on disk, but was untracked, extract as new. */
106+ if (!old )
107+ return CONFFILE_NEW ;
108+
109+ /* 2. File exists as link, extract as new. */
110+ if (S_ISLNK (st -> st_mode ))
111+ return CONFFILE_NEW ;
112+
113+ if (!xbps_file_sha256 (sha256_cur , sizeof (sha256_cur ), path )) {
114+ if (errno == ENOENT )
115+ return 0 ;
116+ return - errno ;
117+ }
118+
119+ if (old && strcmp (old -> sha256 , new -> sha256 ) == 0 )
120+ match |= MATCH_SAME ;
121+ if (old && strcmp (sha256_cur , old -> sha256 ) == 0 )
122+ match |= MATCH_OLD ;
123+ if (strcmp (sha256_cur , new -> sha256 ) == 0 )
124+ match |= MATCH_NEW ;
125+
126+ if (match == (MATCH_SAME |MATCH_OLD |MATCH_NEW )) {
127+ /*
128+ * All files are the same, do nothing.
129+ */
130+ return CONFFILE_SKIP ;
131+ } else if (match == MATCH_SAME ) {
132+ /*
133+ * Old and new package files are the same,
134+ * but on disk differs, extract as new.
135+ */
136+ return CONFFILE_NEW ;
137+ } else if (match == MATCH_NEW ) {
138+ /*
139+ * File matches the new config file, do nothing.
140+ */
141+ return CONFFILE_SKIP ;
142+ } else if (match == MATCH_OLD ) {
143+ /*
144+ * File matches the old config file:
145+ * If keep_conf is on, extract as new, otherwise
146+ * update the file.
147+ */
148+ if (xhp -> flags & XBPS_FLAG_KEEP_CONFIG )
149+ return CONFFILE_NEW ;
150+ return CONFFILE_UPDATE ;
151+ } else if (match == 0 ) {
152+ /*
153+ * Old and new file changes and on disk is also differnt,
154+ * extract as new.
155+ */
156+ return CONFFILE_NEW ;
157+ } else {
158+ return - EINVAL ;
159+ }
160+
161+ return 0 ;
162+ }
163+
82164static int
83165unpack_archive (struct xbps_handle * xhp ,
84166 xbps_dictionary_t pkg_repod ,
85167 const char * pkgver ,
86168 const char * fname ,
87169 struct archive * ar )
88170{
171+ char buf [PATH_MAX ];
89172 const struct xbps_file * old = NULL , * new = NULL ;
90- xbps_dictionary_t binpkg_filesd , pkg_filesd , obsd ;
173+ xbps_dictionary_t binpkg_filesd , obsd ;
91174 xbps_array_t array , obsoletes ;
92175 xbps_trans_type_t ttype ;
93176 const struct stat * entry_statp ;
@@ -96,13 +179,12 @@ unpack_archive(struct xbps_handle *xhp,
96179 struct archive_entry * entry ;
97180 ssize_t entry_size ;
98181 const char * entry_pname , * pkgname ;
99- char * buf = NULL ;
100182 int ar_rv , rv , error , entry_type , flags ;
101183 bool preserve , update , file_exists , keep_conf_file ;
102184 bool skip_extract , force , xucd_stats ;
103185 uid_t euid ;
104186
105- binpkg_filesd = pkg_filesd = NULL ;
187+ binpkg_filesd = NULL ;
106188 force = preserve = update = file_exists = false;
107189 xucd_stats = false;
108190 ar_rv = rv = error = entry_type = flags = 0 ;
@@ -207,11 +289,6 @@ unpack_archive(struct xbps_handle *xhp,
207289 goto out ;
208290 }
209291
210- /*
211- * Internalize current pkg metadata files plist.
212- */
213- pkg_filesd = xbps_pkgdb_get_pkg_files (xhp , pkgname );
214-
215292 /*
216293 * Unpack all files on archive now.
217294 */
@@ -327,17 +404,32 @@ unpack_archive(struct xbps_handle *xhp,
327404 if (xhp -> unpack_cb != NULL )
328405 xucd .entry_is_conf = true;
329406
330- rv = xbps_entry_install_conf_file (xhp ,
331- binpkg_filesd , pkg_filesd , entry ,
332- entry_pname , pkgver , S_ISLNK (st .st_mode ));
333- if (rv == -1 ) {
407+ rv = handle_conffile (xhp , entry_pname , old , new , & st );
408+ if (rv < 0 ) {
334409 /* error */
410+ rv = - rv ;
335411 goto out ;
336- } else if (rv == 0 ) {
412+ } else if (rv == CONFFILE_SKIP ) {
337413 /*
338414 * Keep curfile as is.
339415 */
340416 skip_extract = true;
417+ } else if (rv == CONFFILE_UPDATE ) {
418+ /*
419+ * Update file.
420+ */
421+ } else if (rv == CONFFILE_NEW ) {
422+ /*
423+ * Extract as .new-$version.
424+ */
425+ const char * version = xbps_pkg_version (pkgver );
426+ snprintf (buf , sizeof (buf ), "%s.new-%s" ,
427+ entry_pname , version );
428+ xbps_set_cb_state (xhp , XBPS_STATE_CONFIG_FILE ,
429+ 0 , pkgver , "File `%s' exists,"
430+ " installing configuration file"
431+ " to `%s'." , entry_pname + 1 , buf + 1 );
432+ archive_entry_copy_pathname (entry , buf );
341433 }
342434 rv = 0 ;
343435 } else {
@@ -460,27 +552,24 @@ unpack_archive(struct xbps_handle *xhp,
460552 if (xbps_dictionary_count (binpkg_filesd )) {
461553 mode_t prev_umask ;
462554 prev_umask = umask (022 );
463- buf = xbps_xasprintf ( "%s/.%s-files.plist" , xhp -> metadir , pkgname );
555+ snprintf ( buf , sizeof ( buf ), "%s/.%s-files.plist" , xhp -> metadir , pkgname );
464556 if (!xbps_dictionary_externalize_to_file (binpkg_filesd , buf )) {
465557 rv = errno ;
466558 umask (prev_umask );
467- free (buf );
468559 xbps_set_cb_state (xhp , XBPS_STATE_UNPACK_FAIL ,
469560 rv , pkgver , "%s: [unpack] failed to externalize pkg "
470561 "pkg metadata files: %s" , pkgver , strerror (rv ));
471562 goto out ;
472563 }
473564 umask (prev_umask );
474- free (buf );
475565 }
476566out :
477567 /*
478568 * If unpacked pkg has no files, remove its files metadata plist.
479569 */
480570 if (!xbps_dictionary_count (binpkg_filesd )) {
481- buf = xbps_xasprintf ( "%s/.%s-files.plist" , xhp -> metadir , pkgname );
571+ snprintf ( buf , sizeof ( buf ), "%s/.%s-files.plist" , xhp -> metadir , pkgname );
482572 unlink (buf );
483- free (buf );
484573 }
485574 xbps_object_release (binpkg_filesd );
486575
0 commit comments