Blob Blame History Raw
From 46f5da05629638d9ea67782d4afc0b0f5154e7b9 Mon Sep 17 00:00:00 2001
From: Gleb Fotengauer-Malinovskiy <glebfm@altlinux.org>
Date: Wed, 16 Aug 2017 19:20:03 +0300
Subject: [PATCH] Add support of LFS-compatible fts functions

Since glibc 2.23, fts has LFS support.
---
 configure.ac    |  15 ++++--
 src/Makefile.am |   1 +
 src/fts.c       | 147 +++++++++++++++++++++++++++++++++-----------------------
 src/fts64.c     |  33 +++++++++++++
 4 files changed, 132 insertions(+), 64 deletions(-)
 create mode 100644 src/fts64.c

diff --git a/configure.ac b/configure.ac
index 30557a4..e87ce94 100644
--- a/configure.ac
+++ b/configure.ac
@@ -190,6 +190,7 @@ AC_CHECK_FUNCS(m4_normalize([
     fts_children
     fts_open
     fts_read
+    fts64_open
     ftw
     ftw64
     futimesat
@@ -315,11 +316,19 @@ m4_foreach_w([function], [getpeername getsockname],
 
 ACX_CHECK_FUNC_ARGTYPES([fts_open],
     [], [sys/types.h sys/stat.h fts.h],
-    [[FTS *], [char * const *_], [int], [int (*_)(const FTSENT **, const FTSENT **)]],
-    [[FTS *]],
+    [[FTSOBJ *], [char * const *_], [int], [int (*_)(const FTSENTRY **, const FTSENTRY **)]],
+    [[FTSOBJ *]],
     [[char * const *_]],
     [[int _]],
-    [[int (*_)(const FTSENT * const *, const FTSENT * const *)], [int (*_)(const FTSENT **, const FTSENT **)]])
+    [[int (*_)(const FTSENTRY * const *, const FTSENTRY * const *)], [int (*_)(const FTSENTRY **, const FTSENTRY **)]])
+
+ACX_CHECK_FUNC_ARGTYPES([fts64_open],
+    [], [sys/types.h sys/stat.h fts.h],
+    [[FTSOBJ *], [char * const *_], [int], [int (*_)(const FTSENTRY **, const FTSENTRY **)]],
+    [[FTSOBJ *]],
+    [[char * const *_]],
+    [[int _]],
+    [[int (*_)(const FTSENTRY * const *, const FTSENTRY * const *)], [int (*_)(const FTSENTRY **, const FTSENTRY **)]])
 
 ACX_CHECK_FUNC_ARGTYPES([readlink],
     [
diff --git a/src/Makefile.am b/src/Makefile.am
index 01fc652..8af41eb 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -62,6 +62,7 @@ libfakechroot_la_SOURCES = \
     freopen.c \
     freopen64.c \
     fts.c \
+    fts64.c \
     ftw.c \
     ftw64.c \
     futimesat.c \
diff --git a/src/fts.c b/src/fts.c
index 61ac032..e69e1b7 100644
--- a/src/fts.c
+++ b/src/fts.c
@@ -32,10 +32,13 @@
 
 #include <config.h>
 
+#if !defined FTS64_C__ || (defined FTS64_C__ && HAVE_FTS64_OPEN)
+
 #define _ATFILE_SOURCE
 #define _BSD_SOURCE
 #define _XOPEN_SOURCE 500
 #define _DEFAULT_SOURCE
+#define _LARGEFILE64_SOURCE
 #include <sys/param.h>
 #include <sys/stat.h>
 
@@ -80,16 +83,34 @@
 # endif
 #endif
 
-static FTSENT   *fts_alloc(FTS *, char *, size_t);
-static FTSENT   *fts_build(FTS *, int);
-static void      fts_lfree(FTSENT *);
-static void      fts_load(FTS *, FTSENT *);
+/* Support for the LFS API version.  */
+#ifndef FTS_OPEN
+/* functions */
+# define FTS_OPEN fts_open
+# define FTS_CLOSE fts_close
+# define FTS_READ fts_read
+# define FTS_SET fts_set
+# define FTS_CHILDREN fts_children
+/* types */
+# define FTSOBJ FTS
+# define _FTSENT _ftsent
+# define FTSENTRY FTSENT
+# define INO_T ino_t
+# define STAT stat
+# define FSTAT fstat
+# define LSTAT lstat
+#endif
+
+static FTSENTRY   *fts_alloc(FTSOBJ *, char *, size_t);
+static FTSENTRY   *fts_build(FTSOBJ *, int);
+static void      fts_lfree(FTSENTRY *);
+static void      fts_load(FTSOBJ *, FTSENTRY *);
 static size_t    fts_maxarglen(char * const *);
-static void      fts_padjust(FTS *, FTSENT *);
-static int       fts_palloc(FTS *, size_t);
-static FTSENT   *fts_sort(FTS *, FTSENT *, int);
-static u_short   fts_stat(FTS *, FTSENT *, int);
-static int       fts_safe_changedir(FTS *, FTSENT *, int, char *);
+static void      fts_padjust(FTSOBJ *, FTSENTRY *);
+static int       fts_palloc(FTSOBJ *, size_t);
+static FTSENTRY   *fts_sort(FTSOBJ *, FTSENTRY *, int);
+static u_short   fts_stat(FTSOBJ *, FTSENTRY *, int);
+static int       fts_safe_changedir(FTSOBJ *, FTSENTRY *, int, char *);
 
 #define ISDOT(a)        (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2])))
 
@@ -104,14 +125,14 @@ static int       fts_safe_changedir(FTS *, FTSENT *, int, char *);
 #define BNAMES          2               /* fts_children, names only */
 #define BREAD           3               /* fts_read */
 
-FTS *
-fts_open(char * const *argv, int options,
+FTSOBJ *
+FTS_OPEN(char * const *argv, int options,
     FTS_OPEN_TYPE_ARG3(compar))
 {
-        FTS *sp;
-        FTSENT *p, *root;
+        FTSOBJ *sp;
+        FTSENTRY *p, *root;
         int nitems;
-        FTSENT *parent, *tmp = NULL;
+        FTSENTRY *parent, *tmp = NULL;
         size_t len;
 
         debug("fts_open({\"%s\", ...}, %d, &compar)", **argv, options);
@@ -123,7 +144,7 @@ fts_open(char * const *argv, int options,
         }
 
         /* Allocate/initialize the stream */
-        if ((sp = calloc(1, sizeof(FTS))) == NULL)
+        if ((sp = calloc(1, sizeof(FTSOBJ))) == NULL)
                 return (NULL);
         sp->fts_compar = (void *)compar;
         sp->fts_options = options;
@@ -216,7 +237,7 @@ mem1:   free(sp);
 }
 
 static void
-fts_load(FTS *sp, FTSENT *p)
+fts_load(FTSOBJ *sp, FTSENTRY *p)
 {
         size_t len;
         char *cp;
@@ -240,9 +261,9 @@ fts_load(FTS *sp, FTSENT *p)
 }
 
 int
-fts_close(FTS *sp)
+FTS_CLOSE(FTSOBJ *sp)
 {
-        FTSENT *freep, *p;
+        FTSENTRY *freep, *p;
         int rfd, error = 0;
 
         debug("fts_close(&sp)");
@@ -292,10 +313,10 @@ fts_close(FTS *sp)
         (p->fts_path[p->fts_pathlen - 1] == '/'                         \
             ? p->fts_pathlen - 1 : p->fts_pathlen)
 
-FTSENT *
-fts_read(FTS *sp)
+FTSENTRY *
+FTS_READ(FTSOBJ *sp)
 {
-        FTSENT *p, *tmp;
+        FTSENTRY *p, *tmp;
         int instr;
         char *t;
         int saved_errno;
@@ -490,7 +511,7 @@ name:           t = sp->fts_path + NAPPEND(p->fts_parent);
  */
 /* ARGSUSED */
 int
-fts_set(FTS *sp, FTSENT *p, int instr)
+FTS_SET(FTSOBJ *sp, FTSENTRY *p, int instr)
 {
         debug("fts_set(&sp, &p, %d)", instr);
         if (instr && instr != FTS_AGAIN && instr != FTS_FOLLOW &&
@@ -502,10 +523,10 @@ fts_set(FTS *sp, FTSENT *p, int instr)
         return (0);
 }
 
-FTSENT *
-fts_children(FTS *sp, int instr)
+FTSENTRY *
+FTS_CHILDREN(FTSOBJ *sp, int instr)
 {
-        FTSENT *p;
+        FTSENTRY *p;
         int fd;
 
         debug("fts_children(&sp, %d)", instr);
@@ -586,12 +607,12 @@ fts_children(FTS *sp, int instr)
  * directories and for any files after the subdirectories in the directory have
  * been found, cutting the stat calls by about 2/3.
  */
-static FTSENT *
-fts_build(FTS *sp, int type)
+static FTSENTRY *
+fts_build(FTSOBJ *sp, int type)
 {
         struct dirent *dp;
-        FTSENT *p, *head;
-        FTSENT *cur, *tail;
+        FTSENTRY *p, *head;
+        FTSENTRY *cur, *tail;
         DIR *dirp;
         void *oldaddr;
         size_t len, maxlen;
@@ -834,12 +855,12 @@ mem1:                           saved_errno = errno;
 }
 
 static u_short
-fts_stat(FTS *sp, FTSENT *p, int follow)
+fts_stat(FTSOBJ *sp, FTSENTRY *p, int follow)
 {
-        FTSENT *t;
+        FTSENTRY *t;
         dev_t dev;
-        ino_t ino;
-        struct stat *sbp, sb;
+        INO_T ino;
+        struct STAT *sbp, sb;
         int saved_errno;
 
         /* If user needs stat info, stat buffer already allocated. */
@@ -851,18 +872,18 @@ fts_stat(FTS *sp, FTSENT *p, int follow)
          * fail, set the errno from the stat call.
          */
         if (ISSET(FTS_LOGICAL) || follow) {
-                if (stat(p->fts_accpath, sbp)) {
+                if (STAT(p->fts_accpath, sbp)) {
                         saved_errno = errno;
-                        if (!lstat(p->fts_accpath, sbp)) {
+                        if (!LSTAT(p->fts_accpath, sbp)) {
                                 errno = 0;
                                 return (FTS_SLNONE);
                         }
                         p->fts_errno = saved_errno;
                         goto err;
                 }
-        } else if (lstat(p->fts_accpath, sbp)) {
+        } else if (LSTAT(p->fts_accpath, sbp)) {
                 p->fts_errno = errno;
-err:            memset(sbp, 0, sizeof(struct stat));
+err:            memset(sbp, 0, sizeof(struct STAT));
                 return (FTS_NS);
         }
 
@@ -902,10 +923,10 @@ err:            memset(sbp, 0, sizeof(struct stat));
         return (FTS_DEFAULT);
 }
 
-static FTSENT *
-fts_sort(FTS *sp, FTSENT *head, int nitems)
+static FTSENTRY *
+fts_sort(FTSOBJ *sp, FTSENTRY *head, int nitems)
 {
-        FTSENT **ap, *p;
+        FTSENTRY **ap, *p;
 
         /*
          * Construct an array of pointers to the structures and call qsort(3).
@@ -915,11 +936,11 @@ fts_sort(FTS *sp, FTSENT *head, int nitems)
          * 40 so don't realloc one entry at a time.
          */
         if (nitems > sp->fts_nitems) {
-                struct _ftsent **a;
+                struct _FTSENT **a;
 
                 sp->fts_nitems = nitems + 40;
                 if ((a = realloc(sp->fts_array,
-                    sp->fts_nitems * sizeof(FTSENT *))) == NULL) {
+                    sp->fts_nitems * sizeof(FTSENTRY *))) == NULL) {
                         if (sp->fts_array)
                                 free(sp->fts_array);
                         sp->fts_array = NULL;
@@ -930,33 +951,33 @@ fts_sort(FTS *sp, FTSENT *head, int nitems)
         }
         for (ap = sp->fts_array, p = head; p; p = p->fts_link)
                 *ap++ = p;
-        qsort((void *)sp->fts_array, nitems, sizeof(FTSENT *), (void *)sp->fts_compar);
+        qsort((void *)sp->fts_array, nitems, sizeof(FTSENTRY *), (void *)sp->fts_compar);
         for (head = *(ap = sp->fts_array); --nitems; ++ap)
                 ap[0]->fts_link = ap[1];
         ap[0]->fts_link = NULL;
         return (head);
 }
 
-static FTSENT *
-fts_alloc(FTS *sp, char *name, size_t namelen)
+static FTSENTRY *
+fts_alloc(FTSOBJ *sp, char *name, size_t namelen)
 {
-        FTSENT *p;
+        FTSENTRY *p;
         size_t len;
 
 #ifdef HAVE_STRUCT__FTSENT_FTS_NAME_TYPE_CHAR_P
         struct ftsent_withstat {
-                FTSENT  ent;
+                FTSENTRY  ent;
                 struct  stat statbuf;
         };
 
         /*
          * The file name is a variable length array and no stat structure is
-         * necessary if the user has set the nostat bit.  Allocate the FTSENT
+         * necessary if the user has set the nostat bit.  Allocate the FTSENTRY
          * structure, the file name and the stat structure in one chunk, but
          * be careful that the stat structure is reasonably aligned.
          */
         if (ISSET(FTS_NOSTAT))
-                len = sizeof(FTSENT) + namelen + 1;
+                len = sizeof(FTSENTRY) + namelen + 1;
         else
                 len = sizeof(struct ftsent_withstat) + namelen + 1;
 
@@ -985,15 +1006,15 @@ fts_alloc(FTS *sp, char *name, size_t namelen)
 #else
         /*
          * The file name is a variable length array and no stat structure is
-         * necessary if the user has set the nostat bit.  Allocate the FTSENT
+         * necessary if the user has set the nostat bit.  Allocate the FTSENTRY
          * structure, the file name and the stat structure in one chunk, but
          * be careful that the stat structure is reasonably aligned.  Since the
          * fts_name field is declared to be of size 1, the fts_name pointer is
          * namelen + 2 before the first possible address of the stat structure.
          */
-        len = sizeof(FTSENT) + namelen;
+        len = sizeof(FTSENTRY) + namelen;
         if (!ISSET(FTS_NOSTAT))
-                len += sizeof(struct stat) + ALIGNBYTES;
+                len += sizeof(struct STAT) + ALIGNBYTES;
         if ((p = malloc(len)) == NULL)
                 return (NULL);
 
@@ -1002,7 +1023,7 @@ fts_alloc(FTS *sp, char *name, size_t namelen)
         p->fts_namelen = namelen;
         p->fts_instr = FTS_NOINSTR;
         if (!ISSET(FTS_NOSTAT))
-                p->fts_statp = (struct stat *)ALIGN(p->fts_name + namelen + 2);
+                p->fts_statp = (struct STAT *)ALIGN(p->fts_name + namelen + 2);
         memcpy(p->fts_name, name, namelen);
 #endif
 
@@ -1010,9 +1031,9 @@ fts_alloc(FTS *sp, char *name, size_t namelen)
 }
 
 static void
-fts_lfree(FTSENT *head)
+fts_lfree(FTSENTRY *head)
 {
-        FTSENT *p;
+        FTSENTRY *p;
 
         /* Free a linked list of structures. */
         while ((p = head)) {
@@ -1028,7 +1049,7 @@ fts_lfree(FTSENT *head)
  * plus 256 bytes so don't realloc the path 2 bytes at a time.
  */
 static int
-fts_palloc(FTS *sp, size_t more)
+fts_palloc(FTSOBJ *sp, size_t more)
 {
         char *p;
 
@@ -1060,9 +1081,9 @@ fts_palloc(FTS *sp, size_t more)
  * already returned.
  */
 static void
-fts_padjust(FTS *sp, FTSENT *head)
+fts_padjust(FTSOBJ *sp, FTSENTRY *head)
 {
-        FTSENT *p;
+        FTSENTRY *p;
         char *addr = sp->fts_path;
 
 #define ADJUST(p) {                                                     \
@@ -1100,17 +1121,17 @@ fts_maxarglen(char * const *argv)
  * Assumes p->fts_dev and p->fts_ino are filled in.
  */
 static int
-fts_safe_changedir(FTS *sp, FTSENT *p, int fd, char *path)
+fts_safe_changedir(FTSOBJ *sp, FTSENTRY *p, int fd, char *path)
 {
         int ret, oerrno, newfd;
-        struct stat sb;
+        struct STAT sb;
 
         newfd = fd;
         if (ISSET(FTS_NOCHDIR))
                 return (0);
         if (fd < 0 && (newfd = open(path, O_RDONLY, 0)) < 0)
                 return (-1);
-        if (fstat(newfd, &sb)) {
+        if (FSTAT(newfd, &sb)) {
                 ret = -1;
                 goto bail;
         }
@@ -1127,3 +1148,7 @@ bail:
         errno = oerrno;
         return (ret);
 }
+
+#else
+typedef int empty_translation_unit;
+#endif
diff --git a/src/fts64.c b/src/fts64.c
new file mode 100644
index 0000000..ba98805
--- /dev/null
+++ b/src/fts64.c
@@ -0,0 +1,33 @@
+/* File tree traversal functions LFS version.
+   Copyright (C) 2015-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#define FTS64_C__
+#define FTS_OPEN fts64_open
+#define FTS_CLOSE fts64_close
+#define FTS_READ fts64_read
+#define FTS_SET fts64_set
+#define FTS_CHILDREN fts64_children
+#define FTSOBJ FTS64
+#define FTSENTRY FTSENT64
+#define _FTSENT _ftsent64
+#define INO_T ino64_t
+#define STAT stat64
+#define FSTAT fstat64
+#define LSTAT lstat64
+
+#include "fts.c"
-- 
2.14.1