Hi,

I noticed many files in cpio are older versions of those in Gnulib. Here
are a few patches to just import them.

Patch 1 fixes a function pointer that doesn't work when using 'gcc
-std=c23'. There 'int func ()' == 'int func (void)' so using arguments
throws an error.

Patch 2 makes 'make' return success when running 'make clean' before
'make check'.

Patch 3, 4, 5 removes filemode.c, idcache.c, and userspec.c instead
opting for updated versions in Gnulib.

I'd like to pull in Paul's recent changes to paxutils but that needs a
bit more work. So work-in-progress for now.

Collin

>From 3643eb52fb84c99f8d9fa7ac2a0c36aa38b1cd08 Mon Sep 17 00:00:00 2001
From: Collin Funk <[email protected]>
Date: Mon, 5 Aug 2024 21:55:33 -0700
Subject: [PATCH 1/5] maint: Allow compilation with C23 compilers.

* src/extern.h (xstat): Add parameters to function signature.
* src/global.c (xstat): Likewise.
---
 src/extern.h | 2 +-
 src/global.c | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/extern.h b/src/extern.h
index 9431729..fb83b1e 100644
--- a/src/extern.h
+++ b/src/extern.h
@@ -97,7 +97,7 @@ extern char input_is_special;
 extern char output_is_special;
 extern char input_is_seekable;
 extern char output_is_seekable;
-extern int (*xstat) ();
+extern int (*xstat) (const char *pathname, struct stat *buf);
 extern void (*copy_function) ();
 extern char *change_directory_option;
 
diff --git a/src/global.c b/src/global.c
index 085d41a..3a4a41a 100644
--- a/src/global.c
+++ b/src/global.c
@@ -185,7 +185,7 @@ bool to_stdout_option = false;
 
 /* A pointer to either lstat or stat, depending on whether
    dereferencing of symlinks is done for input files.  */
-int (*xstat) ();
+int (*xstat) (const char *pathname, struct stat *buf);
 
 /* Which copy operation to perform. (-i, -o, -p) */
 void (*copy_function) () = 0;
-- 
2.45.2

>From 591ac98e606d11eb70cc8e5b83f60f50468c896d Mon Sep 17 00:00:00 2001
From: Collin Funk <[email protected]>
Date: Mon, 5 Aug 2024 22:09:22 -0700
Subject: [PATCH 2/5] build: Don't fail on 'make clean' before 'make check'.

* tests/Makefile.am (clean-local): Check for the $(TESTSUITE) before
trying to run it.
---
 tests/Makefile.am | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/tests/Makefile.am b/tests/Makefile.am
index a2894a7..43b5fae 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -72,7 +72,9 @@ atconfig: $(top_builddir)/config.status
 	cd $(top_builddir) && ./config.status tests/$@
 
 clean-local:
-	$(SHELL) $(TESTSUITE) --clean
+	if test -x $(TESTSUITE); then    \
+	  $(SHELL) $(TESTSUITE) --clean; \
+	fi
 
 check-local: atconfig atlocal $(TESTSUITE)
 	$(SHELL) $(TESTSUITE) $(TESTSUITEFLAGS)
-- 
2.45.2

>From de69c5474ec016d405f3d98a71724b88f853c61c Mon Sep 17 00:00:00 2001
From: Collin Funk <[email protected]>
Date: Tue, 6 Aug 2024 20:31:11 -0700
Subject: [PATCH 3/5] maint: Use filemode from Gnulib.

* gnulib.modules: Add filemode.
* src/Makefile.am (cpio_SOURCES): Remove filemode.c.
* src/copyin.c: Include filemode.h.
(long_format): Use strmode instead of mode_string.
* src/extern.h (mode_string): Remove declaration.
* src/filemode.c: Remove file.
---
 gnulib.modules  |   1 +
 src/Makefile.am |   1 -
 src/copyin.c    |   8 +-
 src/extern.h    |   3 -
 src/filemode.c  | 242 ------------------------------------------------
 5 files changed, 5 insertions(+), 250 deletions(-)
 delete mode 100644 src/filemode.c

diff --git a/gnulib.modules b/gnulib.modules
index 701abf9..40e8087 100644
--- a/gnulib.modules
+++ b/gnulib.modules
@@ -9,6 +9,7 @@ dirname
 error
 fdutimensat
 fileblocks
+filemode
 fnmatch-gnu
 full-write
 getline
diff --git a/src/Makefile.am b/src/Makefile.am
index 739cb83..b469aa5 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -36,7 +36,6 @@ cpio_SOURCES = \
  main.c\
  tar.c\
  util.c\
- filemode.c\
  idcache.c\
  makepath.c\
  userspec.c
diff --git a/src/copyin.c b/src/copyin.c
index ace0a02..467d86d 100644
--- a/src/copyin.c
+++ b/src/copyin.c
@@ -31,6 +31,7 @@
 # include <fnmatch.h>
 #endif
 #include <hash.h>
+#include <filemode.h>
 
 #ifndef HAVE_LCHOWN
 # define lchown(f,u,g) 0
@@ -873,7 +874,7 @@ static struct timespec current_time;
 void
 long_format (struct cpio_file_stat *file_hdr, char const *link_name)
 {
-  char mbuf[11];
+  char mbuf[12];
   time_t when;
   char *tbuf;
   struct timespec when_timespec;
@@ -885,10 +886,9 @@ long_format (struct cpio_file_stat *file_hdr, char const *link_name)
     .tv_nsec = current_time.tv_nsec
   };
 
-  mode_string (file_hdr->c_mode, mbuf);
-  mbuf[10] = '\0';
+  strmode (file_hdr->c_mode, mbuf);
 
-  printf ("%s %3ju ", mbuf, (uintmax_t) file_hdr->c_nlink);
+  printf ("%s%3ju ", mbuf, (uintmax_t) file_hdr->c_nlink);
 
   if (numeric_uid)
     printf ("%-8ju %-8ju ",
diff --git a/src/extern.h b/src/extern.h
index fb83b1e..1cb99fc 100644
--- a/src/extern.h
+++ b/src/extern.h
@@ -135,9 +135,6 @@ int link_to_name (char const *link_name, char const *link_target);
 /* dirname.c */
 char *dirname (char *path);
 
-/* filemode.c */
-void mode_string (unsigned int mode, char *str);
-
 /* idcache.c */
 char *getgroup (gid_t gid);
 char *getuser (uid_t uid);
diff --git a/src/filemode.c b/src/filemode.c
deleted file mode 100644
index 13dfaaf..0000000
--- a/src/filemode.c
+++ /dev/null
@@ -1,242 +0,0 @@
-/* filemode.c -- make a string describing file modes
-   Copyright (C) 1985-2024 Free Software Foundation, Inc.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3, or (at your option)
-   any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public
-   License along with this program; if not, write to the Free
-   Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301 USA.  */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#if !S_IRUSR
-# if S_IREAD
-#  define S_IRUSR S_IREAD
-# else
-#  define S_IRUSR 00400
-# endif
-#endif
-
-#if !S_IWUSR
-# if S_IWRITE
-#  define S_IWUSR S_IWRITE
-# else
-#  define S_IWUSR 00200
-# endif
-#endif
-
-#if !S_IXUSR
-# if S_IEXEC
-#  define S_IXUSR S_IEXEC
-# else
-#  define S_IXUSR 00100
-# endif
-#endif
-
-#ifdef STAT_MACROS_BROKEN
-#undef S_ISBLK
-#undef S_ISCHR
-#undef S_ISDIR
-#undef S_ISFIFO
-#undef S_ISLNK
-#undef S_ISMPB
-#undef S_ISMPC
-#undef S_ISNWK
-#undef S_ISREG
-#undef S_ISSOCK
-#endif /* STAT_MACROS_BROKEN.  */
-
-#if !defined(S_ISBLK) && defined(S_IFBLK)
-#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
-#endif
-#if !defined(S_ISCHR) && defined(S_IFCHR)
-#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
-#endif
-#if !defined(S_ISDIR) && defined(S_IFDIR)
-#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
-#endif
-#if !defined(S_ISREG) && defined(S_IFREG)
-#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
-#endif
-#if !defined(S_ISFIFO) && defined(S_IFIFO)
-#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
-#endif
-#if !defined(S_ISLNK) && defined(S_IFLNK)
-#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
-#endif
-#if !defined(S_ISSOCK) && defined(S_IFSOCK)
-#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
-#endif
-#if !defined(S_ISMPB) && defined(S_IFMPB) /* V7 */
-#define S_ISMPB(m) (((m) & S_IFMT) == S_IFMPB)
-#define S_ISMPC(m) (((m) & S_IFMT) == S_IFMPC)
-#endif
-#if !defined(S_ISNWK) && defined(S_IFNWK) /* HP/UX */
-#define S_ISNWK(m) (((m) & S_IFMT) == S_IFNWK)
-#endif
-
-/* Return a character indicating the type of file described by
-   file mode BITS:
-   'd' for directories
-   'b' for block special files
-   'c' for character special files
-   'm' for multiplexor files
-   'l' for symbolic links
-   's' for sockets
-   'p' for fifos
-   '-' for regular files
-   '?' for any other file type.  */
-
-static char
-ftypelet (long bits)
-{
-#ifdef S_ISBLK
-  if (S_ISBLK (bits))
-    return 'b';
-#endif
-  if (S_ISCHR (bits))
-    return 'c';
-  if (S_ISDIR (bits))
-    return 'd';
-  if (S_ISREG (bits))
-    return '-';
-#ifdef S_ISFIFO
-  if (S_ISFIFO (bits))
-    return 'p';
-#endif
-#ifdef S_ISLNK
-  if (S_ISLNK (bits))
-    return 'l';
-#endif
-#ifdef S_ISSOCK
-  if (S_ISSOCK (bits))
-    return 's';
-#endif
-#ifdef S_ISMPC
-  if (S_ISMPC (bits))
-    return 'm';
-#endif
-#ifdef S_ISNWK
-  if (S_ISNWK (bits))
-    return 'n';
-#endif
-  return '?';
-}
-
-/* Look at read, write, and execute bits in BITS and set
-   flags in CHARS accordingly.  */
-
-static void
-rwx (unsigned short bits, char *chars)
-{
-  chars[0] = (bits & S_IRUSR) ? 'r' : '-';
-  chars[1] = (bits & S_IWUSR) ? 'w' : '-';
-  chars[2] = (bits & S_IXUSR) ? 'x' : '-';
-}
-
-/* Set the 's' and 't' flags in file attributes string CHARS,
-   according to the file mode BITS.  */
-
-static void
-setst (unsigned short bits, char *chars)
-{
-#ifdef S_ISUID
-  if (bits & S_ISUID)
-    {
-      if (chars[3] != 'x')
-	/* Set-uid, but not executable by owner.  */
-	chars[3] = 'S';
-      else
-	chars[3] = 's';
-    }
-#endif
-#ifdef S_ISGID
-  if (bits & S_ISGID)
-    {
-      if (chars[6] != 'x')
-	/* Set-gid, but not executable by group.  */
-	chars[6] = 'S';
-      else
-	chars[6] = 's';
-    }
-#endif
-#ifdef S_ISVTX
-  if (bits & S_ISVTX)
-    {
-      if (chars[9] != 'x')
-	/* Sticky, but not executable by others.  */
-	chars[9] = 'T';
-      else
-	chars[9] = 't';
-    }
-#endif
-}
-
-/* Like filemodestring (see below), but only the relevant part of the
-   `struct stat' is given as an argument.  */
-
-void
-mode_string (unsigned int mode, char *str)
-{
-  str[0] = ftypelet ((long) mode);
-  rwx ((mode & 0700) << 0, &str[1]);
-  rwx ((mode & 0070) << 3, &str[4]);
-  rwx ((mode & 0007) << 6, &str[7]);
-  setst (mode, str);
-}
-
-/* filemodestring - fill in string STR with an ls-style ASCII
-   representation of the st_mode field of file stats block STATP.
-   10 characters are stored in STR; no terminating null is added.
-   The characters stored in STR are:
-
-   0	File type.  'd' for directory, 'c' for character
-	special, 'b' for block special, 'm' for multiplex,
-	'l' for symbolic link, 's' for socket, 'p' for fifo,
-	'-' for regular, '?' for any other file type
-
-   1	'r' if the owner may read, '-' otherwise.
-
-   2	'w' if the owner may write, '-' otherwise.
-
-   3	'x' if the owner may execute, 's' if the file is
-	set-user-id, '-' otherwise.
-	'S' if the file is set-user-id, but the execute
-	bit isn't set.
-
-   4	'r' if group members may read, '-' otherwise.
-
-   5	'w' if group members may write, '-' otherwise.
-
-   6	'x' if group members may execute, 's' if the file is
-	set-group-id, '-' otherwise.
-	'S' if it is set-group-id but not executable.
-
-   7	'r' if any user may read, '-' otherwise.
-
-   8	'w' if any user may write, '-' otherwise.
-
-   9	'x' if any user may execute, 't' if the file is "sticky"
-	(will be retained in swap space after execution), '-'
-	otherwise.
-	'T' if the file is sticky but not executable.  */
-
-void
-filemodestring (struct stat *statp, char *str)
-{
-  mode_string (statp->st_mode, str);
-}
-- 
2.45.2

>From de69c5474ec016d405f3d98a71724b88f853c61c Mon Sep 17 00:00:00 2001
From: Collin Funk <[email protected]>
Date: Tue, 6 Aug 2024 20:31:11 -0700
Subject: [PATCH 3/5] maint: Use filemode from Gnulib.

* gnulib.modules: Add filemode.
* src/Makefile.am (cpio_SOURCES): Remove filemode.c.
* src/copyin.c: Include filemode.h.
(long_format): Use strmode instead of mode_string.
* src/extern.h (mode_string): Remove declaration.
* src/filemode.c: Remove file.
---
 gnulib.modules  |   1 +
 src/Makefile.am |   1 -
 src/copyin.c    |   8 +-
 src/extern.h    |   3 -
 src/filemode.c  | 242 ------------------------------------------------
 5 files changed, 5 insertions(+), 250 deletions(-)
 delete mode 100644 src/filemode.c

diff --git a/gnulib.modules b/gnulib.modules
index 701abf9..40e8087 100644
--- a/gnulib.modules
+++ b/gnulib.modules
@@ -9,6 +9,7 @@ dirname
 error
 fdutimensat
 fileblocks
+filemode
 fnmatch-gnu
 full-write
 getline
diff --git a/src/Makefile.am b/src/Makefile.am
index 739cb83..b469aa5 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -36,7 +36,6 @@ cpio_SOURCES = \
  main.c\
  tar.c\
  util.c\
- filemode.c\
  idcache.c\
  makepath.c\
  userspec.c
diff --git a/src/copyin.c b/src/copyin.c
index ace0a02..467d86d 100644
--- a/src/copyin.c
+++ b/src/copyin.c
@@ -31,6 +31,7 @@
 # include <fnmatch.h>
 #endif
 #include <hash.h>
+#include <filemode.h>
 
 #ifndef HAVE_LCHOWN
 # define lchown(f,u,g) 0
@@ -873,7 +874,7 @@ static struct timespec current_time;
 void
 long_format (struct cpio_file_stat *file_hdr, char const *link_name)
 {
-  char mbuf[11];
+  char mbuf[12];
   time_t when;
   char *tbuf;
   struct timespec when_timespec;
@@ -885,10 +886,9 @@ long_format (struct cpio_file_stat *file_hdr, char const *link_name)
     .tv_nsec = current_time.tv_nsec
   };
 
-  mode_string (file_hdr->c_mode, mbuf);
-  mbuf[10] = '\0';
+  strmode (file_hdr->c_mode, mbuf);
 
-  printf ("%s %3ju ", mbuf, (uintmax_t) file_hdr->c_nlink);
+  printf ("%s%3ju ", mbuf, (uintmax_t) file_hdr->c_nlink);
 
   if (numeric_uid)
     printf ("%-8ju %-8ju ",
diff --git a/src/extern.h b/src/extern.h
index fb83b1e..1cb99fc 100644
--- a/src/extern.h
+++ b/src/extern.h
@@ -135,9 +135,6 @@ int link_to_name (char const *link_name, char const *link_target);
 /* dirname.c */
 char *dirname (char *path);
 
-/* filemode.c */
-void mode_string (unsigned int mode, char *str);
-
 /* idcache.c */
 char *getgroup (gid_t gid);
 char *getuser (uid_t uid);
diff --git a/src/filemode.c b/src/filemode.c
deleted file mode 100644
index 13dfaaf..0000000
--- a/src/filemode.c
+++ /dev/null
@@ -1,242 +0,0 @@
-/* filemode.c -- make a string describing file modes
-   Copyright (C) 1985-2024 Free Software Foundation, Inc.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3, or (at your option)
-   any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public
-   License along with this program; if not, write to the Free
-   Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301 USA.  */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#if !S_IRUSR
-# if S_IREAD
-#  define S_IRUSR S_IREAD
-# else
-#  define S_IRUSR 00400
-# endif
-#endif
-
-#if !S_IWUSR
-# if S_IWRITE
-#  define S_IWUSR S_IWRITE
-# else
-#  define S_IWUSR 00200
-# endif
-#endif
-
-#if !S_IXUSR
-# if S_IEXEC
-#  define S_IXUSR S_IEXEC
-# else
-#  define S_IXUSR 00100
-# endif
-#endif
-
-#ifdef STAT_MACROS_BROKEN
-#undef S_ISBLK
-#undef S_ISCHR
-#undef S_ISDIR
-#undef S_ISFIFO
-#undef S_ISLNK
-#undef S_ISMPB
-#undef S_ISMPC
-#undef S_ISNWK
-#undef S_ISREG
-#undef S_ISSOCK
-#endif /* STAT_MACROS_BROKEN.  */
-
-#if !defined(S_ISBLK) && defined(S_IFBLK)
-#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
-#endif
-#if !defined(S_ISCHR) && defined(S_IFCHR)
-#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
-#endif
-#if !defined(S_ISDIR) && defined(S_IFDIR)
-#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
-#endif
-#if !defined(S_ISREG) && defined(S_IFREG)
-#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
-#endif
-#if !defined(S_ISFIFO) && defined(S_IFIFO)
-#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
-#endif
-#if !defined(S_ISLNK) && defined(S_IFLNK)
-#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
-#endif
-#if !defined(S_ISSOCK) && defined(S_IFSOCK)
-#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
-#endif
-#if !defined(S_ISMPB) && defined(S_IFMPB) /* V7 */
-#define S_ISMPB(m) (((m) & S_IFMT) == S_IFMPB)
-#define S_ISMPC(m) (((m) & S_IFMT) == S_IFMPC)
-#endif
-#if !defined(S_ISNWK) && defined(S_IFNWK) /* HP/UX */
-#define S_ISNWK(m) (((m) & S_IFMT) == S_IFNWK)
-#endif
-
-/* Return a character indicating the type of file described by
-   file mode BITS:
-   'd' for directories
-   'b' for block special files
-   'c' for character special files
-   'm' for multiplexor files
-   'l' for symbolic links
-   's' for sockets
-   'p' for fifos
-   '-' for regular files
-   '?' for any other file type.  */
-
-static char
-ftypelet (long bits)
-{
-#ifdef S_ISBLK
-  if (S_ISBLK (bits))
-    return 'b';
-#endif
-  if (S_ISCHR (bits))
-    return 'c';
-  if (S_ISDIR (bits))
-    return 'd';
-  if (S_ISREG (bits))
-    return '-';
-#ifdef S_ISFIFO
-  if (S_ISFIFO (bits))
-    return 'p';
-#endif
-#ifdef S_ISLNK
-  if (S_ISLNK (bits))
-    return 'l';
-#endif
-#ifdef S_ISSOCK
-  if (S_ISSOCK (bits))
-    return 's';
-#endif
-#ifdef S_ISMPC
-  if (S_ISMPC (bits))
-    return 'm';
-#endif
-#ifdef S_ISNWK
-  if (S_ISNWK (bits))
-    return 'n';
-#endif
-  return '?';
-}
-
-/* Look at read, write, and execute bits in BITS and set
-   flags in CHARS accordingly.  */
-
-static void
-rwx (unsigned short bits, char *chars)
-{
-  chars[0] = (bits & S_IRUSR) ? 'r' : '-';
-  chars[1] = (bits & S_IWUSR) ? 'w' : '-';
-  chars[2] = (bits & S_IXUSR) ? 'x' : '-';
-}
-
-/* Set the 's' and 't' flags in file attributes string CHARS,
-   according to the file mode BITS.  */
-
-static void
-setst (unsigned short bits, char *chars)
-{
-#ifdef S_ISUID
-  if (bits & S_ISUID)
-    {
-      if (chars[3] != 'x')
-	/* Set-uid, but not executable by owner.  */
-	chars[3] = 'S';
-      else
-	chars[3] = 's';
-    }
-#endif
-#ifdef S_ISGID
-  if (bits & S_ISGID)
-    {
-      if (chars[6] != 'x')
-	/* Set-gid, but not executable by group.  */
-	chars[6] = 'S';
-      else
-	chars[6] = 's';
-    }
-#endif
-#ifdef S_ISVTX
-  if (bits & S_ISVTX)
-    {
-      if (chars[9] != 'x')
-	/* Sticky, but not executable by others.  */
-	chars[9] = 'T';
-      else
-	chars[9] = 't';
-    }
-#endif
-}
-
-/* Like filemodestring (see below), but only the relevant part of the
-   `struct stat' is given as an argument.  */
-
-void
-mode_string (unsigned int mode, char *str)
-{
-  str[0] = ftypelet ((long) mode);
-  rwx ((mode & 0700) << 0, &str[1]);
-  rwx ((mode & 0070) << 3, &str[4]);
-  rwx ((mode & 0007) << 6, &str[7]);
-  setst (mode, str);
-}
-
-/* filemodestring - fill in string STR with an ls-style ASCII
-   representation of the st_mode field of file stats block STATP.
-   10 characters are stored in STR; no terminating null is added.
-   The characters stored in STR are:
-
-   0	File type.  'd' for directory, 'c' for character
-	special, 'b' for block special, 'm' for multiplex,
-	'l' for symbolic link, 's' for socket, 'p' for fifo,
-	'-' for regular, '?' for any other file type
-
-   1	'r' if the owner may read, '-' otherwise.
-
-   2	'w' if the owner may write, '-' otherwise.
-
-   3	'x' if the owner may execute, 's' if the file is
-	set-user-id, '-' otherwise.
-	'S' if the file is set-user-id, but the execute
-	bit isn't set.
-
-   4	'r' if group members may read, '-' otherwise.
-
-   5	'w' if group members may write, '-' otherwise.
-
-   6	'x' if group members may execute, 's' if the file is
-	set-group-id, '-' otherwise.
-	'S' if it is set-group-id but not executable.
-
-   7	'r' if any user may read, '-' otherwise.
-
-   8	'w' if any user may write, '-' otherwise.
-
-   9	'x' if any user may execute, 't' if the file is "sticky"
-	(will be retained in swap space after execution), '-'
-	otherwise.
-	'T' if the file is sticky but not executable.  */
-
-void
-filemodestring (struct stat *statp, char *str)
-{
-  mode_string (statp->st_mode, str);
-}
-- 
2.45.2

>From 5362f8ac33f13908b6e3656f3a7e946da83481b8 Mon Sep 17 00:00:00 2001
From: Collin Funk <[email protected]>
Date: Tue, 6 Aug 2024 21:16:15 -0700
Subject: [PATCH 4/5] maint: Use idcache from Gnulib.

* gnulib.modules: Add idcache.
* src/Makefile.am (cpio_SOURCES): Remove idcache.c
* src/copyin.c: Include idcache.h
(long_format): Adjust code to Gnulib's version which may return a null
pointer instead of uid/gid as a numeric string.
* src/tar.c (write_out_tar_header): Likewise.
* src/extern.h (getgroup, getuser, getuidbyname, getgidbyname): Remove
declarations.
* src/idcache.c: Remove file.
---
 gnulib.modules  |   1 +
 src/Makefile.am |   1 -
 src/copyin.c    |  17 +++--
 src/extern.h    |   6 --
 src/idcache.c   | 197 ------------------------------------------------
 src/tar.c       |  13 +++-
 6 files changed, 21 insertions(+), 214 deletions(-)
 delete mode 100644 src/idcache.c

diff --git a/gnulib.modules b/gnulib.modules
index 40e8087..ee54d2f 100644
--- a/gnulib.modules
+++ b/gnulib.modules
@@ -17,6 +17,7 @@ gettext-h
 gettime
 gitlog-to-changelog
 hash
+idcache
 inttostr
 inttypes
 lchown
diff --git a/src/Makefile.am b/src/Makefile.am
index b469aa5..5ee0e79 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -36,7 +36,6 @@ cpio_SOURCES = \
  main.c\
  tar.c\
  util.c\
- idcache.c\
  makepath.c\
  userspec.c
 
diff --git a/src/copyin.c b/src/copyin.c
index 467d86d..3725cab 100644
--- a/src/copyin.c
+++ b/src/copyin.c
@@ -32,6 +32,7 @@
 #endif
 #include <hash.h>
 #include <filemode.h>
+#include <idcache.h>
 
 #ifndef HAVE_LCHOWN
 # define lchown(f,u,g) 0
@@ -875,6 +876,8 @@ void
 long_format (struct cpio_file_stat *file_hdr, char const *link_name)
 {
   char mbuf[12];
+  char *user = !numeric_uid ? getuser (file_hdr->c_uid) : NULL;
+  char *group = !numeric_uid ? getgroup (file_hdr->c_gid) : NULL;
   time_t when;
   char *tbuf;
   struct timespec when_timespec;
@@ -890,13 +893,15 @@ long_format (struct cpio_file_stat *file_hdr, char const *link_name)
 
   printf ("%s%3ju ", mbuf, (uintmax_t) file_hdr->c_nlink);
 
-  if (numeric_uid)
-    printf ("%-8ju %-8ju ",
-	    (uintmax_t) file_hdr->c_uid,
-	    (uintmax_t) file_hdr->c_gid);
+  if (user != NULL)
+    printf ("%-8.8s ", user);
   else
-    printf ("%-8.8s %-8.8s ", getuser (file_hdr->c_uid),
-	    getgroup (file_hdr->c_gid));
+    printf ("%-8ju ", (uintmax_t) file_hdr->c_uid);
+
+  if (group != NULL)
+    printf ("%-8.8s ", group);
+  else
+    printf ("%-8ju ", (uintmax_t) file_hdr->c_gid);
 
   if ((file_hdr->c_mode & CP_IFMT) == CP_IFCHR
       || (file_hdr->c_mode & CP_IFMT) == CP_IFBLK)
diff --git a/src/extern.h b/src/extern.h
index 1cb99fc..0b7fb83 100644
--- a/src/extern.h
+++ b/src/extern.h
@@ -135,12 +135,6 @@ int link_to_name (char const *link_name, char const *link_target);
 /* dirname.c */
 char *dirname (char *path);
 
-/* idcache.c */
-char *getgroup (gid_t gid);
-char *getuser (uid_t uid);
-uid_t *getuidbyname (char *user);
-gid_t *getgidbyname (char *group);
-
 /* main.c */
 void process_args (int argc, char *argv[]);
 void initialize_buffers (void);
diff --git a/src/idcache.c b/src/idcache.c
deleted file mode 100644
index 7e18799..0000000
--- a/src/idcache.c
+++ /dev/null
@@ -1,197 +0,0 @@
-/* idcache.c -- map user and group IDs, cached for speed
-   Copyright (C) 1985-2024 Free Software Foundation, Inc.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3, or (at your option)
-   any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public
-   License along with this program; if not, write to the Free
-   Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301 USA.  */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <sys/types.h>
-#include <xalloc.h>
-
-#include <system.h>
-
-#if defined(STDC_HEADERS) || defined(HAVE_STRING_H)
-#include <string.h>
-#else
-#include <strings.h>
-#endif
-
-#include <unistd.h>
-#include "cpiohdr.h"
-#include "extern.h"
-
-struct userid
-{
-  union
-    {
-      uid_t u;
-      gid_t g;
-    } id;
-  char *name;
-  struct userid *next;
-};
-
-static struct userid *user_alist;
-
-/* The members of this list have names not in the local passwd file.  */
-static struct userid *nouser_alist;
-
-/* Translate UID to a login name or a stringified number,
-   with cache.  */
-
-char *
-getuser (uid_t uid)
-{
-  register struct userid *tail;
-  struct passwd *pwent;
-
-  for (tail = user_alist; tail; tail = tail->next)
-    if (tail->id.u == uid)
-      return tail->name;
-
-  pwent = getpwuid (uid);
-  tail = (struct userid *) xmalloc (sizeof (struct userid));
-  tail->id.u = uid;
-  if (pwent == 0)
-    {
-      char nbuf[UINTMAX_STRSIZE_BOUND];
-      tail->name = xstrdup (umaxtostr (uid, nbuf));
-    }
-  else
-    tail->name = xstrdup (pwent->pw_name);
-
-  /* Add to the head of the list, so most recently used is first.  */
-  tail->next = user_alist;
-  user_alist = tail;
-  return tail->name;
-}
-
-/* Translate USER to a UID, with cache.
-   Return NULL if there is no such user.
-   (We also cache which user names have no passwd entry,
-   so we don't keep looking them up.)  */
-
-uid_t *
-getuidbyname (char *user)
-{
-  register struct userid *tail;
-  struct passwd *pwent;
-
-  for (tail = user_alist; tail; tail = tail->next)
-    /* Avoid a function call for the most common case.  */
-    if (*tail->name == *user && !strcmp (tail->name, user))
-      return &tail->id.u;
-
-  for (tail = nouser_alist; tail; tail = tail->next)
-    /* Avoid a function call for the most common case.  */
-    if (*tail->name == *user && !strcmp (tail->name, user))
-      return 0;
-
-  pwent = getpwnam (user);
-
-  tail = (struct userid *) xmalloc (sizeof (struct userid));
-  tail->name = xstrdup (user);
-
-  /* Add to the head of the list, so most recently used is first.  */
-  if (pwent)
-    {
-      tail->id.u = pwent->pw_uid;
-      tail->next = user_alist;
-      user_alist = tail;
-      return &tail->id.u;
-    }
-
-  tail->next = nouser_alist;
-  nouser_alist = tail;
-  return 0;
-}
-
-/* Use the same struct as for userids.  */
-static struct userid *group_alist;
-static struct userid *nogroup_alist;
-
-/* Translate GID to a group name or a stringified number,
-   with cache.  */
-
-char *
-getgroup (gid_t gid)
-{
-  register struct userid *tail;
-  struct group *grent;
-
-  for (tail = group_alist; tail; tail = tail->next)
-    if (tail->id.g == gid)
-      return tail->name;
-
-  grent = getgrgid (gid);
-  tail = (struct userid *) xmalloc (sizeof (struct userid));
-  tail->id.g = gid;
-  if (grent == 0)
-    {
-      char nbuf[UINTMAX_STRSIZE_BOUND];
-      tail->name = xstrdup (umaxtostr (gid, nbuf));
-    }
-  else
-    tail->name = xstrdup (grent->gr_name);
-
-  /* Add to the head of the list, so most recently used is first.  */
-  tail->next = group_alist;
-  group_alist = tail;
-  return tail->name;
-}
-
-/* Translate GROUP to a UID, with cache.
-   Return NULL if there is no such group.
-   (We also cache which group names have no group entry,
-   so we don't keep looking them up.)  */
-
-gid_t *
-getgidbyname (char *group)
-{
-  register struct userid *tail;
-  struct group *grent;
-
-  for (tail = group_alist; tail; tail = tail->next)
-    /* Avoid a function call for the most common case.  */
-    if (*tail->name == *group && !strcmp (tail->name, group))
-      return &tail->id.g;
-
-  for (tail = nogroup_alist; tail; tail = tail->next)
-    /* Avoid a function call for the most common case.  */
-    if (*tail->name == *group && !strcmp (tail->name, group))
-      return 0;
-
-  grent = getgrnam (group);
-
-  tail = (struct userid *) xmalloc (sizeof (struct userid));
-  tail->name = xstrdup (group);
-
-  /* Add to the head of the list, so most recently used is first.  */
-  if (grent)
-    {
-      tail->id.g = grent->gr_gid;
-      tail->next = group_alist;
-      group_alist = tail;
-      return &tail->id.g;
-    }
-
-  tail->next = nogroup_alist;
-  nogroup_alist = tail;
-  return 0;
-}
diff --git a/src/tar.c b/src/tar.c
index 318cbbe..dc0672d 100644
--- a/src/tar.c
+++ b/src/tar.c
@@ -26,6 +26,7 @@
 #include "dstring.h"
 #include "extern.h"
 #include <rmt.h>
+#include <idcache.h>
 #include "tarhdr.h"
 
 /* Stash the tar linkname in static storage.  */
@@ -208,16 +209,20 @@ write_out_tar_header (struct cpio_file_stat *file_hdr, int out_des)
   if (archive_format == arf_ustar)
     {
       char *name;
+      char id_buffer[UINTMAX_STRSIZE_BOUND];
 
       strncpy (tar_hdr->magic, TMAGIC, TMAGLEN);
       strncpy (tar_hdr->version, TVERSION, TVERSLEN);
 
       name = getuser (file_hdr->c_uid);
-      if (name)
-	strcpy (tar_hdr->uname, name);
+      if (name == NULL)
+        name = umaxtostr (file_hdr->c_uid, id_buffer);
+      strcpy (tar_hdr->uname, name);
+
       name = getgroup (file_hdr->c_gid);
-      if (name)
-	strcpy (tar_hdr->gname, name);
+      if (name == NULL)
+        name = umaxtostr (file_hdr->c_gid, id_buffer);
+      strcpy (tar_hdr->gname, name);
 
       TO_OCT (file_hdr, c_rdev_maj, 8, tar_hdr, devmajor);
       TO_OCT (file_hdr, c_rdev_min, 8, tar_hdr, devminor);
-- 
2.45.2

>From 448e52ab8613a672b50e2a49578a07a44ed10986 Mon Sep 17 00:00:00 2001
From: Collin Funk <[email protected]>
Date: Tue, 6 Aug 2024 21:53:25 -0700
Subject: [PATCH 5/5] maint: Use userspec from Gnulib.

* gnulib.modules: Add userspec.
* po/POTFILES.in: Add gnu/userspec.c. Remove src/userspec.c.
* src/Makefile.am (cpio_SOURCES): Remove userspec.c.
* src/extern.h (parse_user_spec): Remove declaration.
* src/main.c: Include userspec.h.
* src/userspec.c: Remove file.
---
 gnulib.modules  |   1 +
 po/POTFILES.in  |   2 +-
 src/Makefile.am |   3 +-
 src/extern.h    |   4 -
 src/main.c      |   1 +
 src/userspec.c  | 243 ------------------------------------------------
 6 files changed, 4 insertions(+), 250 deletions(-)
 delete mode 100644 src/userspec.c

diff --git a/gnulib.modules b/gnulib.modules
index ee54d2f..6363887 100644
--- a/gnulib.modules
+++ b/gnulib.modules
@@ -30,6 +30,7 @@ stpcpy
 strerror
 timespec
 unlocked-io
+userspec
 xalloc
 xalloc-die
 xgetcwd
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 51d7618..0cc7a16 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -24,6 +24,7 @@ gnu/getopt.c
 gnu/obstack.c
 gnu/openat-die.c
 gnu/quotearg.c
+gnu/userspec.c
 gnu/version-etc.c
 gnu/xalloc-die.c
 
@@ -41,7 +42,6 @@ src/main.c
 src/makepath.c
 src/mt.c
 src/tar.c
-src/userspec.c
 src/util.c
 
 tests/genfile.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 5ee0e79..77df2e0 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -36,8 +36,7 @@ cpio_SOURCES = \
  main.c\
  tar.c\
  util.c\
- makepath.c\
- userspec.c
+ makepath.c
 
 noinst_HEADERS =\
  cpio.h\
diff --git a/src/extern.h b/src/extern.h
index 0b7fb83..6447359 100644
--- a/src/extern.h
+++ b/src/extern.h
@@ -151,10 +151,6 @@ int otoa (char *s, unsigned long *n);
 int is_tar_header (char *buf);
 int is_tar_filename_too_long (char *name);
 
-/* userspec.c */
-const char *parse_user_spec (const char *spec_arg, uid_t *uid, gid_t *gid,
-			     char **username_arg, char **groupname_arg);
-
 /* util.c */
 void tape_empty_output_buffer (int out_des);
 void disk_empty_output_buffer (int out_des, bool flush);
diff --git a/src/main.c b/src/main.c
index d2135c8..7c889db 100644
--- a/src/main.c
+++ b/src/main.c
@@ -36,6 +36,7 @@
 
 #include <progname.h>
 #include <closeout.h>
+#include <userspec.h>
 
 #include "filetypes.h"
 #include "cpiohdr.h"
diff --git a/src/userspec.c b/src/userspec.c
deleted file mode 100644
index 43d565c..0000000
--- a/src/userspec.c
+++ /dev/null
@@ -1,243 +0,0 @@
-/* userspec.c -- Parse a user and group string.
-   Copyright (C) 1989-2024 Free Software Foundation, Inc.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3, or (at your option)
-   any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public
-   License along with this program; if not, write to the Free
-   Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301 USA.  */
-
-/* Written by David MacKenzie <[email protected]>.  */
-
-#include <system.h>
-#include <alloca.h>
-#include <stdio.h>
-#include <ctype.h>
-#include <sys/types.h>
-#include "cpiohdr.h"
-#include "extern.h"
-
-#ifndef HAVE_ENDPWENT
-# define endpwent()
-#endif
-#ifndef HAVE_ENDGRENT
-# define endgrent()
-#endif
-
-/* Perform the equivalent of the statement `dest = strdup (src);',
-   but obtaining storage via alloca instead of from the heap.  */
-
-#define V_STRDUP(dest, src)						\
-  do									\
-    {									\
-      int _len = strlen ((src));					\
-      (dest) = (char *) alloca (_len + 1);				\
-      strcpy (dest, src);						\
-    }									\
-  while (0)
-
-/* Return nonzero if STR represents an unsigned decimal integer,
-   otherwise return 0. */
-
-static int
-isnumber_p (const char *str)
-{
-  for (; *str; str++)
-    if (!isdigit (*str))
-      return 0;
-  return 1;
-}
-
-/* Extract from NAME, which has the form "[user][:.][group]",
-   a USERNAME, UID U, GROUPNAME, and GID G.
-   Either user or group, or both, must be present.
-   If the group is omitted but the ":" or "." separator is given,
-   use the given user's login group.
-
-   USERNAME and GROUPNAME will be in newly malloc'd memory.
-   Either one might be NULL instead, indicating that it was not
-   given and the corresponding numeric ID was left unchanged.
-
-   Return NULL if successful, a static error message string if not.  */
-
-const char *
-parse_user_spec (const char *spec_arg, uid_t *uid, gid_t *gid,
-		 char **username_arg, char **groupname_arg)
-{
-  static const char *tired = "virtual memory exhausted";
-  const char *error_msg;
-  char *spec;			/* A copy we can write on.  */
-  struct passwd *pwd;
-  struct group *grp;
-  char *g, *u, *separator;
-  char *groupname;
-
-  error_msg = NULL;
-  *username_arg = *groupname_arg = NULL;
-  groupname = NULL;
-
-  V_STRDUP (spec, spec_arg);
-
-  /* Find the separator if there is one.  */
-  separator = strchr (spec, ':');
-  if (separator == NULL)
-    separator = strchr (spec, '.');
-
-  /* Replace separator with a NUL.  */
-  if (separator != NULL)
-    *separator = '\0';
-
-  /* Set U and G to non-zero length strings corresponding to user and
-     group specifiers or to NULL.  */
-  u = (*spec == '\0' ? NULL : spec);
-
-  g = (separator == NULL || *(separator + 1) == '\0'
-       ? NULL
-       : separator + 1);
-
-  if (u == NULL && g == NULL)
-    return "can not omit both user and group";
-
-  if (u != NULL)
-    {
-      if (*u == '+')
-	{
-	  pwd = NULL;
-	  ++u;
-	}
-      else
-	pwd = getpwnam (u);
-
-      if (pwd == NULL)
-	{
-	  if (!isnumber_p (u))
-	    error_msg = _("invalid user");
-	  else
-	    {
-	      int use_login_group;
-	      use_login_group = (separator != NULL && g == NULL);
-	      if (use_login_group)
-		error_msg = _("cannot get the login group of a numeric UID");
-	      else
-		*uid = atoi (u);
-	    }
-	}
-      else
-	{
-	  *uid = pwd->pw_uid;
-	  if (g == NULL && separator != NULL)
-	    {
-	      /* A separator was given, but a group was not specified,
-		 so get the login group.  */
-	      *gid = pwd->pw_gid;
-	      grp = getgrgid (pwd->pw_gid);
-	      if (grp == NULL)
-		{
-		  char nbuf[UINTMAX_STRSIZE_BOUND];
-		  V_STRDUP (groupname, umaxtostr (pwd->pw_gid, nbuf));
-		}
-	      else
-		{
-		  V_STRDUP (groupname, grp->gr_name);
-		}
-	      endgrent ();
-	    }
-	}
-      endpwent ();
-    }
-
-  if (g != NULL && error_msg == NULL)
-    {
-      /* Explicit group.  */
-      if (*g == '+')
-	{
-	  grp = NULL;
-	  ++g;
-	}
-      else
-	grp = getgrnam (g);
-
-      if (grp == NULL)
-	{
-	  if (!isnumber_p (g))
-	    error_msg = _("invalid group");
-	  else
-	    *gid = atoi (g);
-	}
-      else
-	*gid = grp->gr_gid;
-      endgrent ();		/* Save a file descriptor.  */
-
-      if (error_msg == NULL)
-	V_STRDUP (groupname, g);
-    }
-
-  if (error_msg == NULL)
-    {
-      if (u != NULL)
-	{
-	  *username_arg = strdup (u);
-	  if (*username_arg == NULL)
-	    error_msg = tired;
-	}
-
-      if (groupname != NULL && error_msg == NULL)
-	{
-	  *groupname_arg = strdup (groupname);
-	  if (*groupname_arg == NULL)
-	    {
-	      if (*username_arg != NULL)
-		{
-		  free (*username_arg);
-		  *username_arg = NULL;
-		}
-	      error_msg = tired;
-	    }
-	}
-    }
-
-  return error_msg;
-}
-
-#ifdef TEST
-
-#define NULL_CHECK(s) ((s) == NULL ? "(null)" : (s))
-
-int
-main (int argc, char **argv)
-{
-  int i;
-
-  for (i = 1; i < argc; i++)
-    {
-      const char *e;
-      char *username, *groupname;
-      uid_t uid;
-      gid_t gid;
-      char *tmp;
-
-      tmp = strdup (argv[i]);
-      e = parse_user_spec (tmp, &uid, &gid, &username, &groupname);
-      free (tmp);
-      printf ("%s: %u %u %s %s %s\n",
-	      argv[i],
-	      (unsigned int) uid,
-	      (unsigned int) gid,
-	      NULL_CHECK (username),
-	      NULL_CHECK (groupname),
-	      NULL_CHECK (e));
-    }
-
-  exit (0);
-}
-
-#endif
-- 
2.45.2

Reply via email to