Hi, I'm attaching the patch we use at the moment. We try to keep our patches as small as possible, so it is a bit Solaris specific. If you think that this could be merged into gzip tree, I'm happy to work on more generic approach - configure testing availability of new headers and functions used.
Thank you -- Vlad
--- gzip-1.5/gzip.c Tue Apr 24 16:25:28 2012 +++ gzip-1.5/gzip.c Mon Oct 21 09:32:07 2013 @@ -83,6 +83,10 @@ #include <stdlib.h> #include <errno.h> +#ifdef __sun +# include <priv.h> +#endif + #ifndef NO_DIR # define NO_DIR 0 #endif @@ -1694,6 +1698,10 @@ { mode_t mode = ifstat->st_mode & S_IRWXUGO; int r; +#ifdef __sun + int swap_chmod_chown; + priv_set_t *priv_set; +#endif /* __sun */ #ifndef NO_UTIME struct timespec timespec[2]; @@ -1722,6 +1730,40 @@ } #endif +#ifdef __sun + /* If the user is able to change ownership of his file to someone else, + * the chmod executed just after that may fail. In such case we need to + * swap chown and chmod operation. On Solaris there are two + * ways how to achieve this situation + * + * a) norstchown mount option + * b) file_chown_self user privilege. + * + * If one of the two options is met, we need to change the order of chmod + * and chown operation. Otherwise we first chown the file to second user + * and might not have permissions to chmod it afterwards. + * + * We detect whether the filesystem in question is mounted with norstchown + * option by checking that pathconf returns -1 but errno is 0. + * + * We detect whether current user has file_chown_self by priv_ismember + * function. + */ + swap_chmod_chown = pathconf(ifname, _PC_CHOWN_RESTRICTED) == -1 && errno == 0; + if (!swap_chmod_chown) { + priv_set = priv_allocset(); + if (priv_set == NULL) { + WARN((stderr, "priv_allocset can't allocate memory")); + } else { + getppriv(PRIV_EFFECTIVE, priv_set); + swap_chmod_chown = priv_ismember(priv_set, PRIV_FILE_CHOWN_SELF); + priv_freeset(priv_set); + } + } + + if (!swap_chmod_chown) { +#endif /* __sun */ + #ifndef NO_CHOWN /* Copy ownership */ # if HAVE_FCHOWN @@ -1731,6 +1773,10 @@ # endif #endif +#ifdef __sun + } +#endif /* __sun */ + /* Copy the protection modes */ #if HAVE_FCHMOD r = fchmod (ofd, mode); @@ -1745,6 +1791,19 @@ perror(ofname); } } + +#ifdef __sun + if (swap_chmod_chown) { +#ifndef NO_CHOWN + /* Copy ownership */ +# if HAVE_FCHOWN + ignore_value (fchown (ofd, ifstat->st_uid, ifstat->st_gid)); +# elif HAVE_CHOWN + ignore_value (chown (ofname, ifstat->st_uid, ifstat->st_gid)); +# endif +#endif + } +#endif /* __sun */ } #if ! NO_DIR