mirror of
https://github.com/coreutils/coreutils.git
synced 2024-12-13 11:55:02 +08:00
211b5731d7
Fix a couple of other minor bugs while we're at it. (<unistd.h>): Do not include; there's no need. (NAMLEN): Remove macro. (malloc, realloc): Remove decls. (stpcpy): Likewise. ("xalloc.h"): Include. (NAME_SIZE_DEFAULT): New macro. (savedir): Use xmalloc / xrealloc to allocate memory. Use NAME_SIZE_DEFAULT if name_size is negative or overflows to zero. Skip "" directory entries. Use strlen to calculate directory entry length, since the old method is rarely used these days and isn't worth supporting. Don't use a pointer after freeing it. Check for integer overflow when calculating allocation size. Use memcpy to copy entries, instead of stpcpy. Set errno properly when returning NULL. Check for readdir error.
138 lines
3.5 KiB
C
138 lines
3.5 KiB
C
/* savedir.c -- save the list of files in a directory in a string
|
|
Copyright (C) 1990, 1997, 1998, 1999, 2000 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 2, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
|
|
|
/* Written by David MacKenzie <djm@gnu.ai.mit.edu>. */
|
|
|
|
#if HAVE_CONFIG_H
|
|
# include <config.h>
|
|
#endif
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <errno.h>
|
|
#ifndef errno
|
|
extern int errno;
|
|
#endif
|
|
|
|
#if HAVE_DIRENT_H
|
|
# include <dirent.h>
|
|
#else
|
|
# define dirent direct
|
|
# if HAVE_SYS_NDIR_H
|
|
# include <sys/ndir.h>
|
|
# endif
|
|
# if HAVE_SYS_DIR_H
|
|
# include <sys/dir.h>
|
|
# endif
|
|
# if HAVE_NDIR_H
|
|
# include <ndir.h>
|
|
# endif
|
|
#endif
|
|
|
|
#ifdef CLOSEDIR_VOID
|
|
/* Fake a return value. */
|
|
# define CLOSEDIR(d) (closedir (d), 0)
|
|
#else
|
|
# define CLOSEDIR(d) closedir (d)
|
|
#endif
|
|
|
|
#ifdef STDC_HEADERS
|
|
# include <stdlib.h>
|
|
# include <string.h>
|
|
#endif
|
|
#ifndef NULL
|
|
# define NULL 0
|
|
#endif
|
|
|
|
#include "savedir.h"
|
|
#include "xalloc.h"
|
|
|
|
/* Return a freshly allocated string containing the filenames
|
|
in directory DIR, separated by '\0' characters;
|
|
the end is marked by two '\0' characters in a row.
|
|
NAME_SIZE is the number of bytes to initially allocate
|
|
for the string; it will be enlarged as needed.
|
|
Use NAME_SIZE == -1 if you do not know the size.
|
|
Return NULL (setting errno) if DIR cannot be opened, read, or closed. */
|
|
|
|
#ifndef NAME_SIZE_DEFAULT
|
|
# define NAME_SIZE_DEFAULT 512
|
|
#endif
|
|
|
|
char *
|
|
savedir (const char *dir, off_t name_size)
|
|
{
|
|
DIR *dirp;
|
|
struct dirent *dp;
|
|
char *name_space;
|
|
size_t allocated = name_size; /* Overflow is checked indirectly below. */
|
|
size_t used = 0;
|
|
int save_errno;
|
|
|
|
dirp = opendir (dir);
|
|
if (dirp == NULL)
|
|
return NULL;
|
|
|
|
/* Use the default if the size is not known. Be sure "allocated"
|
|
is at least `1' so there's room for the final NUL byte.
|
|
Do not simply test name_size <= 0, because the initialization
|
|
of "allocated" might have overflowed. */
|
|
if (name_size < 0 || allocated == 0)
|
|
allocated = NAME_SIZE_DEFAULT;
|
|
|
|
name_space = xmalloc (allocated);
|
|
|
|
errno = 0;
|
|
while ((dp = readdir (dirp)) != NULL)
|
|
{
|
|
/* Skip "", ".", and "..". "" is returned by at least one buggy
|
|
implementation: Solaris 2.4 readdir on NFS filesystems. */
|
|
char const *entry = dp->d_name;
|
|
if (entry[entry[0] != '.' ? 0 : entry[1] != '.' ? 1 : 2] != '\0')
|
|
{
|
|
size_t entry_size = strlen (entry) + 1;
|
|
if (used + entry_size < used)
|
|
xalloc_die ();
|
|
if (allocated <= used + entry_size)
|
|
{
|
|
do
|
|
{
|
|
if (2 * allocated < allocated)
|
|
xalloc_die ();
|
|
allocated *= 2;
|
|
}
|
|
while (allocated <= used + entry_size);
|
|
|
|
name_space = xrealloc (name_space, allocated);
|
|
}
|
|
memcpy (name_space + used, entry, entry_size);
|
|
used += entry_size;
|
|
}
|
|
}
|
|
name_space[used] = '\0';
|
|
save_errno = errno;
|
|
if (CLOSEDIR (dirp) != 0)
|
|
save_errno = errno;
|
|
if (save_errno != 0)
|
|
{
|
|
free (name_space);
|
|
errno = save_errno;
|
|
return NULL;
|
|
}
|
|
return name_space;
|
|
}
|