2222 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2323 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2424 */
25+
26+ #define _DEFAULT_SOURCE
27+
2528#include <sys/types.h>
2629#include <sys/param.h>
2730#include <sys/stat.h>
4144#include <libgen.h>
4245#include <locale.h>
4346#include <dirent.h>
47+ #include <fnmatch.h>
4448
4549#include <xbps.h>
4650#include "queue.h"
@@ -63,9 +67,10 @@ struct xentry {
6367 TAILQ_ENTRY (xentry ) entries ;
6468 uint64_t size ;
6569 enum entry_type type ;
66- char * file , * target ;
70+ char * file , * target , * user , * group ;
6771 char sha256 [XBPS_SHA256_SIZE ];
6872 ino_t inode ;
73+ mode_t mode ;
6974};
7075
7176static TAILQ_HEAD (xentry_head , xentry ) xentry_list =
@@ -109,6 +114,9 @@ usage(bool fail)
109114 " 'vi:/usr/bin/vi:/usr/bin/vim foo:/usr/bin/foo:/usr/bin/blah'\n"
110115 " --build-options A string with the used build options\n"
111116 " --compression Compression format: none, gzip, bzip2, lz4, xz, zstd (default)\n"
117+ " --chown Set the ownership of files and directories.\n"
118+ " This expects a blank-separated list of <pattern>:<user>:<group>,\n"
119+ " where '<pattern>' is an fnmatch(3) pattern.\n"
112120 " --shlib-provides List of provided shared libraries (blank separated list,\n"
113121 " e.g 'libfoo.so.1 libblah.so.2')\n"
114122 " --shlib-requires List of required shared libraries (blank separated list,\n"
@@ -245,6 +253,63 @@ process_one_alternative(const char *altgrname, const char *val)
245253 }
246254}
247255
256+ static void
257+ process_chown_pattern (const char * key , const char * fpat , const char * user , const char * group ) {
258+ xbps_object_iterator_t iter ;
259+ xbps_object_t obj ;
260+ const char * fname ;
261+
262+ if ((iter = xbps_array_iter_from_dict (pkg_filesd , key )) != NULL ) {
263+ while ((obj = xbps_object_iterator_next (iter ))) {
264+ xbps_dictionary_get_cstring_nocopy (obj , "file" , & fname );
265+ if (fnmatch (fpat , fname , 0 ) == 0 ) {
266+ if (user != NULL )
267+ xbps_dictionary_set_cstring (obj , "user" , user );
268+ if (group != NULL )
269+ xbps_dictionary_set_cstring (obj , "group" , group );
270+ }
271+ }
272+ }
273+ }
274+
275+ static void
276+ process_chown_patterns (const char * val ) {
277+ char * raw , * itm , * fpat , * user , * group ;
278+
279+ if (val == NULL )
280+ return ;
281+
282+ raw = strdup (val );
283+
284+ while ((itm = strsep (& raw , " " ))) {
285+ fpat = strsep (& itm , ":" );
286+ if (fpat == NULL ) {
287+ xbps_warn_printf ("%s: skipping chown pattern '%s': empty pattern" , _PROGNAME , val );
288+ continue ;
289+ }
290+
291+ user = strsep (& itm , ":" );
292+ if (strcmp (user , "root" ) == 0 )
293+ user = NULL ;
294+ group = strsep (& itm , ":" );
295+ if (strcmp (group , "root" ) == 0 )
296+ group = NULL ;
297+
298+ if (itm != NULL )
299+ xbps_warn_printf ("%s: chown pattern '%s' contains extra data: %s" , _PROGNAME , val , itm );
300+
301+ if (user == NULL && group == NULL ) {
302+ xbps_warn_printf ("%s: skipping chown pattern '%s': user and group empty or root" , _PROGNAME , val );
303+ continue ;
304+ }
305+
306+ process_chown_pattern ("dirs" , fpat , user , group );
307+ process_chown_pattern ("files" , fpat , user , group );
308+ process_chown_pattern ("links" , fpat , user , group );
309+ }
310+
311+ free (raw );
312+ }
248313
249314static void
250315process_dict_of_arrays (const char * key UNUSED , const char * val )
@@ -396,6 +461,10 @@ ftw_cb(const char *fpath, const struct stat *sb, const struct dirent *dir UNUSED
396461 goto out ;
397462 }
398463
464+ // symlinks don't have a mode on linux
465+ if (!S_ISLNK (sb -> st_mode ))
466+ xe -> mode = sb -> st_mode ;
467+
399468 if (S_ISLNK (sb -> st_mode )) {
400469 char buf [PATH_MAX ];
401470 ssize_t len ;
@@ -530,7 +599,6 @@ ftw_cb(const char *fpath, const struct stat *sb, const struct dirent *dir UNUSED
530599 xbps_dictionary_set_uint64 (fileinfo , "inode" , sb -> st_ino );
531600 xe -> inode = sb -> st_ino ;
532601 xe -> size = (uint64_t )sb -> st_size ;
533-
534602 } else if (S_ISDIR (sb -> st_mode )) {
535603 /* directory */
536604 xbps_dictionary_set_cstring_nocopy (fileinfo , "type" , "dirs" );
@@ -650,6 +718,12 @@ process_xentry(enum entry_type type, const char *mutable_files)
650718 xbps_dictionary_set_cstring (d , "sha256" , xe -> sha256 );
651719 if (xe -> size )
652720 xbps_dictionary_set_uint64 (d , "size" , xe -> size );
721+ if (xe -> user )
722+ xbps_dictionary_set_cstring (d , "user" , xe -> user );
723+ if (xe -> group )
724+ xbps_dictionary_set_cstring (d , "group" , xe -> group );
725+ if (xe -> mode )
726+ xbps_dictionary_set_uint32 (d , "mode" , xe -> mode );
653727
654728 xbps_array_add (a , d );
655729 xbps_object_release (d );
@@ -832,6 +906,7 @@ main(int argc, char **argv)
832906 { "build-options" , required_argument , NULL , '2' },
833907 { "built-with" , required_argument , NULL , 'B' },
834908 { "changelog" , required_argument , NULL , 'c' },
909+ { "chown" , required_argument , NULL , '6' },
835910 { "compression" , required_argument , NULL , '3' },
836911 { "config-files" , required_argument , NULL , 'F' },
837912 { "conflicts" , required_argument , NULL , 'C' },
@@ -865,7 +940,7 @@ main(int argc, char **argv)
865940 const char * provides , * pkgver , * replaces , * reverts , * desc , * ldesc ;
866941 const char * arch , * config_files , * mutable_files , * version , * changelog ;
867942 const char * buildopts , * shlib_provides , * shlib_requires , * alternatives ;
868- const char * compression , * tags = NULL , * srcrevs = NULL , * sourcepkg = NULL ;
943+ const char * compression , * tags = NULL , * srcrevs = NULL , * sourcepkg = NULL , * chownlst ;
869944 char pkgname [XBPS_NAME_SIZE ], * binpkg , * tname , * p , cwd [PATH_MAX - 1 ];
870945 bool quiet = false, preserve = false;
871946 int c , pkg_fd ;
@@ -874,7 +949,7 @@ main(int argc, char **argv)
874949 arch = conflicts = deps = homepage = license = maint = compression = NULL ;
875950 provides = pkgver = replaces = reverts = desc = ldesc = bwith = NULL ;
876951 buildopts = config_files = mutable_files = shlib_provides = NULL ;
877- alternatives = shlib_requires = changelog = NULL ;
952+ alternatives = shlib_requires = changelog = chownlst = NULL ;
878953
879954 while ((c = getopt_long (argc , argv , shortopts , longopts , NULL )) != -1 ) {
880955 if (optarg && strcmp (optarg , "" ) == 0 )
@@ -965,6 +1040,9 @@ main(int argc, char **argv)
9651040 case '5' :
9661041 sourcepkg = optarg ;
9671042 break ;
1043+ case '6' :
1044+ chownlst = optarg ;
1045+ break ;
9681046 case '?' :
9691047 default :
9701048 usage (true);
@@ -1081,6 +1159,7 @@ main(int argc, char **argv)
10811159 die ("xbps_dictionary_create" );
10821160
10831161 process_destdir (mutable_files );
1162+ process_chown_patterns (chownlst );
10841163
10851164 /* Back to original cwd after file tree walk processing */
10861165 if (chdir (p ) == -1 )
0 commit comments