/* Check multiple telldir and seekdir.
Copyright (C) 2020 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
. */
#include
#include
#include
#include
#include
#include
#include
#include
/* Some filesystems returns a arbitrary value for d_off direnty entry (ext4
for instance, where the value is an internal hash key). The idea of
create a large number of file is to try trigger a overflow d_off value
in a entry to check if telldir/seekdir does work corretly in such
case. */
static const char *dirname;
static const size_t nfiles = 10240;
static void
do_prepare (int argc, char *argv[])
{
dirname = support_create_temp_directory ("tst-seekdir2-");
for (size_t i = 0; i < nfiles; i++)
{
int fd = create_temp_file_in_dir ("tempfile.", dirname, NULL);
TEST_VERIFY_EXIT (fd > 0);
close (fd);
}
}
#define PREPARE do_prepare
/* Check for old non Large File Support (LFS). */
static int
do_test_not_lfs (void)
{
DIR *dirp = opendir (dirname);
TEST_VERIFY_EXIT (dirp != NULL);
size_t dirp_count = 0;
for (struct dirent *dp = readdir (dirp);
dp != NULL;
dp = readdir (dirp))
dirp_count++;
/* The 2 extra files are '.' and '..'. */
TEST_COMPARE (dirp_count, nfiles + 2);
rewinddir (dirp);
long *tdirp = xmalloc (dirp_count * sizeof (long));
struct dirent **ddirp = xmalloc (dirp_count * sizeof (struct dirent *));
size_t i = 0;
do
{
tdirp[i] = telldir (dirp);
struct dirent *dp = readdir (dirp);
TEST_VERIFY_EXIT (dp != NULL);
ddirp[i] = xmalloc (dp->d_reclen);
memcpy (ddirp[i], dp, dp->d_reclen);
} while (++i < dirp_count);
for (i = 0; i < dirp_count - 1; i++)
{
seekdir (dirp, tdirp[i]);
struct dirent *dp = readdir (dirp);
TEST_COMPARE (strcmp (dp->d_name, ddirp[i]->d_name), 0);
TEST_COMPARE (dp->d_ino, ddirp[i]->d_ino);
TEST_COMPARE (dp->d_off, ddirp[i]->d_off);
}
closedir (dirp);
free (tdirp);
for (i = 0; i < dirp_count; i++)
free (ddirp[i]);
free (ddirp);
return 0;
}
/* Same as before but with LFS support. */
static int
do_test_lfs (void)
{
DIR *dirp = opendir (dirname);
TEST_VERIFY_EXIT (dirp != NULL);
size_t dirp_count = 0;
for (struct dirent64 * dp = readdir64 (dirp);
dp != NULL;
dp = readdir64 (dirp))
dirp_count++;
/* The 2 extra files are '.' and '..'. */
TEST_COMPARE (dirp_count, nfiles + 2);
rewinddir (dirp);
long *tdirp = xmalloc (dirp_count * sizeof (long));
struct dirent64 **ddirp = xmalloc (dirp_count * sizeof (struct dirent64 *));
size_t i = 0;
do
{
tdirp[i] = telldir (dirp);
struct dirent64 *dp = readdir64 (dirp);
TEST_VERIFY_EXIT (dp != NULL);
ddirp[i] = xmalloc (dp->d_reclen);
memcpy (ddirp[i], dp, dp->d_reclen);
} while (++i < dirp_count);
for (i = 0; i < dirp_count - 1; i++)
{
seekdir (dirp, tdirp[i]);
struct dirent64 *dp = readdir64 (dirp);
TEST_COMPARE (strcmp (dp->d_name, ddirp[i]->d_name), 0);
TEST_COMPARE (dp->d_ino, ddirp[i]->d_ino);
TEST_COMPARE (dp->d_off, ddirp[i]->d_off);
}
closedir (dirp);
free (tdirp);
for (i = 0; i < dirp_count; i++)
free (ddirp[i]);
free (ddirp);
return 0;
}
static int
do_test (void)
{
do_test_not_lfs ();
do_test_lfs ();
return 0;
}
#include