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#include "system.h" 75 76char *path; 77size_t pathlen; 78 79static int 80isdir1 (const char *dir, const char *file) 81{ 82 int status; 83 int slash; 84 size_t dirlen = strlen (dir); 85 size_t filelen = strlen (file); 86 if ((dirlen + filelen + 2) > pathlen) 87 { 88 path = calloc (dirlen + 1 + filelen + 1, sizeof (*path)); 89 pathlen = dirlen + filelen + 2; 90 } 91 strcpy (path, dir); 92 slash = (path[dirlen] != '/'); 93 path[dirlen] = '/'; 94 strcpy (path + dirlen + slash , file); 95 status = isdir (path); 96 return status; 97} 98 99/* Return a freshly allocated string containing the filenames 100 in directory DIR, separated by '\0' characters; 101 the end is marked by two '\0' characters in a row. 102 NAME_SIZE is the number of bytes to initially allocate 103 for the string; it will be enlarged as needed. 104 Return NULL if DIR cannot be opened or if out of memory. */ 105char * 106savedir (const char *dir, off_t name_size, struct exclude *included_patterns, 107 struct exclude *excluded_patterns) 108{ 109 DIR *dirp; 110 struct dirent *dp; 111 char *name_space; 112 char *namep; 113 114 dirp = opendir (dir); 115 if (dirp == NULL) 116 return NULL; 117 118 /* Be sure name_size is at least `1' so there's room for 119 the final NUL byte. */ 120 if (name_size <= 0) 121 name_size = 1; 122 123 name_space = (char *) malloc (name_size); 124 if (name_space == NULL) 125 { 126 closedir (dirp); 127 return NULL; 128 } 129 namep = name_space; 130 131 while ((dp = readdir (dirp)) != NULL) 132 { 133 /* Skip "." and ".." (some NFS filesystems' directories lack them). */ 134 if (dp->d_name[0] != '.' 135 || (dp->d_name[1] != '\0' 136 && (dp->d_name[1] != '.' || dp->d_name[2] != '\0'))) 137 { 138 off_t size_needed = (namep - name_space) + NAMLEN (dp) + 2; 139 140 if ((included_patterns || excluded_patterns) 141 && !isdir1 (dir, dp->d_name)) 142 { 143 if (included_patterns 144 && !excluded_filename (included_patterns, path, 0)) 145 continue; 146 if (excluded_patterns 147 && excluded_filename (excluded_patterns, path, 0)) 148 continue; 149 } 150 151 if (size_needed > name_size) 152 { 153 char *new_name_space; 154 155 while (size_needed > name_size) 156 name_size += 1024; 157 158 new_name_space = realloc (name_space, name_size); 159 if (new_name_space == NULL) 160 { 161 closedir (dirp); 162 return NULL; 163 } 164 namep += new_name_space - name_space; 165 name_space = new_name_space; 166 } 167 namep = stpcpy (namep, dp->d_name) + 1; 168 } 169 } 170 *namep = '\0'; 171 if (CLOSEDIR (dirp)) 172 { 173 free (name_space); 174 return NULL; 175 } 176 if (path) 177 { 178 free (path); 179 path = NULL; 180 pathlen = 0; 181 } 182 return name_space; 183} 184