1/* savedir.c -- save the list of files in a directory in a string 2 Copyright (C) 1990, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. 3 4 This program is free software; you can redistribute it and/or modify 5 it under the terms of the GNU General Public License as published by 6 the Free Software Foundation; either version 2, or (at your option) 7 any later version. 8 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 GNU General Public License for more details. 13 14 You should have received a copy of the GNU General Public License 15 along with this program; if not, write to the Free Software Foundation, 16 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 17 18/* Written by David MacKenzie <djm@gnu.ai.mit.edu>. */ 19 20#include <sys/cdefs.h> 21__FBSDID("$FreeBSD$"); 22 23#if HAVE_CONFIG_H 24# include <config.h> 25#endif 26 27#include <sys/types.h> 28 29#if HAVE_UNISTD_H 30# include <unistd.h> 31#endif 32 33#if HAVE_DIRENT_H 34# include <dirent.h> 35# define NAMLEN(dirent) strlen((dirent)->d_name) 36#else 37# define dirent direct 38# define NAMLEN(dirent) (dirent)->d_namlen 39# if HAVE_SYS_NDIR_H 40# include <sys/ndir.h> 41# endif 42# if HAVE_SYS_DIR_H 43# include <sys/dir.h> 44# endif 45# if HAVE_NDIR_H 46# include <ndir.h> 47# endif 48#endif 49 50#ifdef CLOSEDIR_VOID 51/* Fake a return value. */ 52# define CLOSEDIR(d) (closedir (d), 0) 53#else 54# define CLOSEDIR(d) closedir (d) 55#endif 56 57#ifdef STDC_HEADERS 58# include <stdlib.h> 59# include <string.h> 60#else 61char *malloc (); 62char *realloc (); 63#endif 64#ifndef NULL 65# define NULL 0 66#endif 67 68#ifndef stpcpy 69char *stpcpy (); 70#endif 71 72#include <fnmatch.h> 73#include "savedir.h" 74 75char *path; 76size_t pathlen; 77 78static int 79isdir1 (const char *dir, const char *file) 80{ 81 int status; 82 int slash; 83 size_t dirlen = strlen (dir); 84 size_t filelen = strlen (file); 85 if ((dirlen + filelen + 2) > pathlen) 86 { 87 path = calloc (dirlen + 1 + filelen + 1, sizeof (*path)); 88 pathlen = dirlen + filelen + 2; 89 } 90 strcpy (path, dir); 91 slash = (path[dirlen] != '/'); 92 path[dirlen] = '/'; 93 strcpy (path + dirlen + slash , file); 94 status = isdir (path); 95 return status; 96} 97 98/* Return a freshly allocated string containing the filenames 99 in directory DIR, separated by '\0' characters; 100 the end is marked by two '\0' characters in a row. 101 NAME_SIZE is the number of bytes to initially allocate 102 for the string; it will be enlarged as needed. 103 Return NULL if DIR cannot be opened or if out of memory. */ 104char * 105savedir (const char *dir, off_t name_size, struct exclude *included_patterns, 106 struct exclude *excluded_patterns) 107{ 108 DIR *dirp; 109 struct dirent *dp; 110 char *name_space; 111 char *namep; 112 113 dirp = opendir (dir); 114 if (dirp == NULL) 115 return NULL; 116 117 /* Be sure name_size is at least `1' so there's room for 118 the final NUL byte. */ 119 if (name_size <= 0) 120 name_size = 1; 121 122 name_space = (char *) malloc (name_size); 123 if (name_space == NULL) 124 { 125 closedir (dirp); 126 return NULL; 127 } 128 namep = name_space; 129 130 while ((dp = readdir (dirp)) != NULL) 131 { 132 /* Skip "." and ".." (some NFS filesystems' directories lack them). */ 133 if (dp->d_name[0] != '.' 134 || (dp->d_name[1] != '\0' 135 && (dp->d_name[1] != '.' || dp->d_name[2] != '\0'))) 136 { 137 off_t size_needed = (namep - name_space) + NAMLEN (dp) + 2; 138 139 if ((included_patterns || excluded_patterns) 140 && !isdir1 (dir, dp->d_name)) 141 { 142 if (included_patterns 143 && !excluded_filename (included_patterns, path, 0)) 144 continue; 145 if (excluded_patterns 146 && excluded_filename (excluded_patterns, path, 0)) 147 continue; 148 } 149 150 if (size_needed > name_size) 151 { 152 char *new_name_space; 153 154 while (size_needed > name_size) 155 name_size += 1024; 156 157 new_name_space = realloc (name_space, name_size); 158 if (new_name_space == NULL) 159 { 160 closedir (dirp); 161 return NULL; 162 } 163 namep += new_name_space - name_space; 164 name_space = new_name_space; 165 } 166 namep = stpcpy (namep, dp->d_name) + 1; 167 } 168 } 169 *namep = '\0'; 170 if (CLOSEDIR (dirp)) 171 { 172 free (name_space); 173 return NULL; 174 } 175 if (path) 176 { 177 free (path); 178 path = NULL; 179 pathlen = 0; 180 } 181 return name_space; 182} 183