glibc/io/tst-fts.c
Mark Wielaard 8b7b7f75d9 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.
2015-11-06 11:24:16 +01:00

232 lines
4.8 KiB
C

/* 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;
}