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"
@@ -66,6 +70,7 @@ struct xentry {
6670 char * file , * target ;
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,7 +253,6 @@ process_one_alternative(const char *altgrname, const char *val)
245253 }
246254}
247255
248-
249256static void
250257process_dict_of_arrays (const char * key UNUSED , const char * val )
251258{
@@ -281,6 +288,69 @@ process_dict_of_arrays(const char *key UNUSED, const char *val)
281288 free (args );
282289}
283290
291+ static bool
292+ process_chown_pattern (const char * key , const char * fpat , const char * user , const char * group ) {
293+ xbps_object_iterator_t iter ;
294+ xbps_object_t obj ;
295+ const char * fname ;
296+ bool match = false;
297+
298+ if ((iter = xbps_array_iter_from_dict (pkg_filesd , key )) != NULL ) {
299+ while ((obj = xbps_object_iterator_next (iter ))) {
300+ xbps_dictionary_get_cstring_nocopy (obj , "file" , & fname );
301+ if (fnmatch (fpat , fname , 0 ) == 0 ) {
302+ match = true;
303+ if (user != NULL )
304+ xbps_dictionary_set_cstring (obj , "user" , user );
305+ if (group != NULL )
306+ xbps_dictionary_set_cstring (obj , "group" , group );
307+ }
308+ }
309+ }
310+ return match ;
311+ }
312+
313+ static void
314+ process_chown_patterns (const char * val ) {
315+ char * raw , * itm , * fpat , * user , * group ;
316+
317+ if (val == NULL )
318+ return ;
319+
320+ raw = strdup (val );
321+
322+ while ((itm = strsep (& raw , " " ))) {
323+ fpat = strsep (& itm , ":" );
324+ if (fpat == NULL || strlen (fpat ) == 0 ) {
325+ xbps_warn_printf ("%s: skipping chown pattern `:%s': empty pattern\n" , _PROGNAME , itm );
326+ continue ;
327+ }
328+
329+ user = strsep (& itm , ":" );
330+ if (strlen (user ) == 0 || strcmp (user , "root" ) == 0 )
331+ user = NULL ;
332+ group = strsep (& itm , ":" );
333+ if (strlen (group ) == 0 || strcmp (group , "root" ) == 0 )
334+ group = NULL ;
335+
336+ if (itm != NULL )
337+ xbps_warn_printf ("%s: chown pattern contains extra data: %s\n" , _PROGNAME , itm );
338+
339+ if (user == NULL && group == NULL ) {
340+ xbps_warn_printf ("%s: skipping chown pattern `%s': user and group empty or root\n" , _PROGNAME , fpat );
341+ continue ;
342+ }
343+
344+ if (!(process_chown_pattern ("dirs" , fpat , user , group ) ||
345+ process_chown_pattern ("files" , fpat , user , group ) ||
346+ process_chown_pattern ("links" , fpat , user , group ))) {
347+ xbps_warn_printf ("%s: chown pattern %s matched nothing\n" , _PROGNAME , fpat );
348+ }
349+ }
350+
351+ free (raw );
352+ }
353+
284354static void
285355process_file (const char * file , const char * key )
286356{
@@ -396,6 +466,10 @@ ftw_cb(const char *fpath, const struct stat *sb, const struct dirent *dir UNUSED
396466 goto out ;
397467 }
398468
469+ // symlinks don't have a mode on linux
470+ if (!S_ISLNK (sb -> st_mode ))
471+ xe -> mode = sb -> st_mode ;
472+
399473 if (S_ISLNK (sb -> st_mode )) {
400474 char buf [PATH_MAX ];
401475 ssize_t len ;
@@ -530,7 +604,6 @@ ftw_cb(const char *fpath, const struct stat *sb, const struct dirent *dir UNUSED
530604 xbps_dictionary_set_uint64 (fileinfo , "inode" , sb -> st_ino );
531605 xe -> inode = sb -> st_ino ;
532606 xe -> size = (uint64_t )sb -> st_size ;
533-
534607 } else if (S_ISDIR (sb -> st_mode )) {
535608 /* directory */
536609 xbps_dictionary_set_cstring_nocopy (fileinfo , "type" , "dirs" );
@@ -650,6 +723,8 @@ process_xentry(enum entry_type type, const char *mutable_files)
650723 xbps_dictionary_set_cstring (d , "sha256" , xe -> sha256 );
651724 if (xe -> size )
652725 xbps_dictionary_set_uint64 (d , "size" , xe -> size );
726+ if (xe -> mode )
727+ xbps_dictionary_set_uint32 (d , "mode" , xe -> mode );
653728
654729 xbps_array_add (a , d );
655730 xbps_object_release (d );
@@ -832,6 +907,7 @@ main(int argc, char **argv)
832907 { "build-options" , required_argument , NULL , '2' },
833908 { "built-with" , required_argument , NULL , 'B' },
834909 { "changelog" , required_argument , NULL , 'c' },
910+ { "chown" , required_argument , NULL , '6' },
835911 { "compression" , required_argument , NULL , '3' },
836912 { "config-files" , required_argument , NULL , 'F' },
837913 { "conflicts" , required_argument , NULL , 'C' },
@@ -865,7 +941,7 @@ main(int argc, char **argv)
865941 const char * provides , * pkgver , * replaces , * reverts , * desc , * ldesc ;
866942 const char * arch , * config_files , * mutable_files , * version , * changelog ;
867943 const char * buildopts , * shlib_provides , * shlib_requires , * alternatives ;
868- const char * compression , * tags = NULL , * srcrevs = NULL , * sourcepkg = NULL ;
944+ const char * compression , * tags = NULL , * srcrevs = NULL , * sourcepkg = NULL , * chownlst ;
869945 char pkgname [XBPS_NAME_SIZE ], * binpkg , * tname , * p , cwd [PATH_MAX - 1 ];
870946 bool quiet = false, preserve = false;
871947 int c , pkg_fd ;
@@ -874,7 +950,7 @@ main(int argc, char **argv)
874950 arch = conflicts = deps = homepage = license = maint = compression = NULL ;
875951 provides = pkgver = replaces = reverts = desc = ldesc = bwith = NULL ;
876952 buildopts = config_files = mutable_files = shlib_provides = NULL ;
877- alternatives = shlib_requires = changelog = NULL ;
953+ alternatives = shlib_requires = changelog = chownlst = NULL ;
878954
879955 while ((c = getopt_long (argc , argv , shortopts , longopts , NULL )) != -1 ) {
880956 if (optarg && strcmp (optarg , "" ) == 0 )
@@ -965,6 +1041,9 @@ main(int argc, char **argv)
9651041 case '5' :
9661042 sourcepkg = optarg ;
9671043 break ;
1044+ case '6' :
1045+ chownlst = optarg ;
1046+ break ;
9681047 case '?' :
9691048 default :
9701049 usage (true);
@@ -1081,6 +1160,7 @@ main(int argc, char **argv)
10811160 die ("xbps_dictionary_create" );
10821161
10831162 process_destdir (mutable_files );
1163+ process_chown_patterns (chownlst );
10841164
10851165 /* Back to original cwd after file tree walk processing */
10861166 if (chdir (p ) == -1 )
0 commit comments