about summary refs log tree commit diff
path: root/io/tst-fts.c
diff options
context:
space:
mode:
authorMark Wielaard <mjw@redhat.com>2015-11-06 11:22:38 +0100
committerMark Wielaard <mjw@redhat.com>2015-11-06 11:24:16 +0100
commit8b7b7f75d91f7bac323dd6a370aeb3e9c5c4a7d5 (patch)
tree1d746e27fde388945a60b17e4855a0463d7892a9 /io/tst-fts.c
parent5a28590adfc5ed898a335f7a3359a9243534eded (diff)
downloadglibc-8b7b7f75d91f7bac323dd6a370aeb3e9c5c4a7d5.tar.gz
glibc-8b7b7f75d91f7bac323dd6a370aeb3e9c5c4a7d5.tar.xz
glibc-8b7b7f75d91f7bac323dd6a370aeb3e9c5c4a7d5.zip
Add LFS support for fts functions (bug 11460)
fts didn't have large-file support yet and fts.h had an #error preventing
usage when _FILE_OFFSET_BITS was set. This required nasty workarounds for
programs using fts with LFS. This patch implements LFS support for fts by
adding FTS64 and FTENT64 variants plus fts64 functions. Which are simple
aliases for 64bit off_t arches.

Also includes a simple testcase for some of the fts functions with or
without LFS enabled.

	[BZ #11460]
	* io/Makefile (routines): Add fts64.
	(tests): Add tst-fts and tst-fts-lfs.
	(CFLAGS-fts64.c): New.
	* io/Versions (GLIBC_2.23): New.
	* io/fts.c: Replace FTS with FTSOBJ, FTSENT with FTSENTRY. Use
	function defines FTS_OPEN, FTS_CLOSE, FTS_READ, FTS_SET and
	FTS_CHILDREN. Define FTSOBJ, FTSENTRY, FTS_OPEN, FTS_CLOSE,
	FTS_READ, FTS_SET, FTS_CHILDREN, INO_T, STAT and LSTAT if necessary.
	* io/fts.h (FTS64): New if _USE_LARGEFILE64.
	(FTSENT64): Likewise.
	(fts64_children): Likewise.
	(fts64_close): Likewise.
	(fts64_open): Likewise.
	(fts64_read): Likewise.
	(fts64_set): Likewise.
	* io/fts64.c: New file.
	* io/tst-fts.c: New test.
	* io/tst-fts-lfs.c: Likewise.
	* sysdeps/unix/sysv/linux/aarch64/libc.abilist (GLIBC_2.23): Add
	GLIBC_2.23, fts64_children, fts64_close, fts64_open, fts64_read and
	fts64_set.
	* sysdeps/unix/sysv/linux/alpha/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/arm/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/hppa/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/i386/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/ia64/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/microblaze/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/nios2/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist:
	Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist:
	Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist: Likewise.
	* sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/sh/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/x86_64/64/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist: Likewise.
	* sysdeps/wordsize-64/fts.c: New file.
	* sysdeps/wordsize-64/fts64.c: Likewise.
	* sysdeps/unix/sysv/linux/mips/mips64/n64/fts.c: Likewise.
	* sysdeps/unix/sysv/linux/mips/mips64/n64/fts64.c: Likewise.
	* sysdeps/unix/sysv/linux/x86_64/x32/fts.c: likewise.
	* sysdeps/unix/sysv/linux/x86_64/x32/fts64.c: likewise.
Diffstat (limited to 'io/tst-fts.c')
-rw-r--r--io/tst-fts.c231
1 files changed, 231 insertions, 0 deletions
diff --git a/io/tst-fts.c b/io/tst-fts.c
new file mode 100644
index 0000000000..efe225d6c0
--- /dev/null
+++ b/io/tst-fts.c
@@ -0,0 +1,231 @@
+/* Simple test for some fts functions.
+   Copyright (C) 2015 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/>.  */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fts.h>
+
+#include <errno.h>
+#include <error.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+static void prepare (void);
+static int do_test (void);
+#define PREPARE(argc, argv)     prepare ()
+#define TEST_FUNCTION           do_test ()
+#include "../test-skeleton.c"
+
+static char *fts_test_dir;
+
+static void
+make_dir (const char *dirname)
+{
+  char *name;
+  if (asprintf (&name, "%s/%s", fts_test_dir, dirname) < 0)
+    {
+      puts ("out of memory");
+      exit (1);
+    }
+
+  if (mkdir (name, 0700) < 0)
+    {
+      printf ("cannot create dir \"%s\": %m\n", name);
+      exit (1);
+    }
+
+  add_temp_file (name);
+}
+
+static void
+make_file (const char *filename)
+{
+  char *name;
+  if (asprintf (&name, "%s/%s", fts_test_dir, filename) < 0)
+    {
+      puts ("out of memory");
+      exit (1);
+    }
+
+  int fd = open (name, O_WRONLY | O_CREAT | O_EXCL, 0600);
+  if (fd < 0)
+    {
+      printf ("cannot create file \"%s\": %m\n", name);
+      exit (1);
+    }
+  close (fd);
+
+  add_temp_file (name);
+}
+
+static void
+prepare (void)
+{
+  char *dirbuf;
+  char dir_name[] = "/tst-fts.XXXXXX";
+
+  if (asprintf (&dirbuf, "%s%s", test_dir, dir_name) < 0)
+    {
+      puts ("out of memory");
+      exit (1);
+    }
+
+  if (mkdtemp (dirbuf) == NULL)
+    {
+      puts ("cannot create temporary directory");
+      exit (1);
+    }
+
+  add_temp_file (dirbuf);
+  fts_test_dir = dirbuf;
+
+  make_file ("12");
+  make_file ("345");
+  make_file ("6789");
+
+  make_dir ("aaa");
+  make_file ("aaa/1234");
+  make_file ("aaa/5678");
+
+  make_dir ("bbb");
+  make_file ("bbb/1234");
+  make_file ("bbb/5678");
+  make_file ("bbb/90ab");
+}
+
+/* Largest name wins, otherwise strcmp.  */
+static int
+compare_ents (const FTSENT **ent1, const FTSENT **ent2)
+{
+  short len1 = (*ent1)->fts_namelen;
+  short len2 = (*ent2)->fts_namelen;
+  if (len1 != len2)
+    return len1 - len2;
+  else
+    {
+      const char *name1 = (*ent1)->fts_name;
+      const char *name2 = (*ent2)->fts_name;
+      return strcmp (name1, name2);
+    }
+}
+
+/* Count the number of files seen as children.  */
+static int files = 0;
+
+static void
+children (FTS *fts)
+{
+  FTSENT *child = fts_children (fts, 0);
+  if (child == NULL && errno != 0)
+    {
+      printf ("FAIL: fts_children: %m\n");
+      exit (1);
+    }
+
+  while (child != NULL)
+    {
+      short level = child->fts_level;
+      const char *name = child->fts_name;
+      if (child->fts_info == FTS_F || child->fts_info == FTS_NSOK)
+	{
+	  files++;
+	  printf ("%*s%s\n", 2 * level, "", name);
+	}
+      child = child->fts_link;
+    }
+}
+
+/* Count the number of dirs seen in the test.  */
+static int dirs = 0;
+
+static int
+do_test (void)
+{
+  char *paths[2] = { fts_test_dir, NULL };
+  FTS *fts;
+  fts = fts_open (paths, FTS_LOGICAL, &compare_ents);
+  if (fts == NULL)
+    {
+      printf ("FAIL: fts_open: %m\n");
+      exit (1);
+    }
+
+  FTSENT *ent;
+  while ((ent = fts_read (fts)) != NULL)
+    {
+      const char *name = ent->fts_name;
+      short level = ent->fts_level;
+      switch (ent->fts_info)
+	{
+	case FTS_F:
+	  /* Don't show anything, children will have on parent dir.  */
+	  break;
+
+	case FTS_D:
+	  printf ("%*s%s =>\n", 2 * level, "", name);
+	  children (fts);
+	  break;
+
+	case FTS_DP:
+	  dirs++;
+	  printf ("%*s<= %s\n", 2 * level, "", name);
+	  break;
+
+	case FTS_NS:
+	case FTS_ERR:
+	  printf ("FAIL: fts_read ent: %s\n", strerror (ent->fts_errno));
+	  exit (1);
+	  break;
+
+	default:
+	  printf ("FAIL: unexpected fts_read ent %s\n", name);
+	  exit (1);
+	  break;
+	}
+    }
+  /* fts_read returns NULL when done (and clears errno)
+     or when an error occured (with errno set).  */
+  if (errno != 0)
+    {
+      printf ("FAIL: fts_read: %m\n");
+      exit (1);
+    }
+
+  if (fts_close (fts) != 0)
+    {
+      printf ("FAIL: fts_close: %m\n");
+      exit (1);
+    }
+
+  if (files != 8)
+    {
+      printf ("FAIL: Unexpected number of files: %d\n", files);
+      return 1;
+    }
+
+  if (dirs != 3)
+    {
+      printf ("FAIL: Unexpected number of dirs: %d\n", dirs);
+      return 1;
+    }
+
+  puts ("PASS");
+  return 0;
+}