Ignore the usually-ignored files in git
[findutils.git] / lib / savedirinfo.c
blob8b006445bb2d5f594490def070b08a452b4dead5
1 /* savedirinfo.c -- Save the list of files in a directory, with additional information.
3 Copyright 1990, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005 Free
4 Software Foundation, Inc.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software Foundation,
18 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
20 /* Written by James Youngman, <jay@gnu.org>. */
21 /* Derived from savedir.c, written by David MacKenzie <djm@gnu.org>. */
23 #include <config.h>
25 #if HAVE_SYS_STAT_H
26 # include <sys/stat.h>
27 #endif
29 #if HAVE_SYS_TYPES_H
30 # include <sys/types.h>
31 #endif
33 /* The presence of unistd.h is assumed by gnulib these days, so we
34 * might as well assume it too.
36 #include <unistd.h>
38 #include <errno.h>
40 #if HAVE_DIRENT_H
41 # include <dirent.h>
42 #else
43 # define dirent direct
44 # if HAVE_SYS_NDIR_H
45 # include <sys/ndir.h>
46 # endif
47 # if HAVE_SYS_DIR_H
48 # include <sys/dir.h>
49 # endif
50 # if HAVE_NDIR_H
51 # include <ndir.h>
52 # endif
53 #endif
55 #ifdef CLOSEDIR_VOID
56 /* Fake a return value. */
57 # define CLOSEDIR(d) (closedir (d), 0)
58 #else
59 # define CLOSEDIR(d) closedir (d)
60 #endif
62 #include <stddef.h>
63 #include <stdlib.h>
64 #include <string.h>
66 #include "xalloc.h"
67 #include "extendbuf.h"
68 #include "savedirinfo.h"
70 /* In order to use struct dirent.d_type, it has to be enabled on the
71 * configure command line, and we have to have a d_type member in
72 * 'struct dirent'.
74 #if !defined(USE_STRUCT_DIRENT_D_TYPE)
75 /* Not enabled, hence pretend it is absent. */
76 #undef HAVE_STRUCT_DIRENT_D_TYPE
77 #endif
78 #if !defined(HAVE_STRUCT_DIRENT_D_TYPE)
79 /* Not present, so cannot use it. */
80 #undef USE_STRUCT_DIRENT_D_TYPE
81 #endif
84 #if defined HAVE_STRUCT_DIRENT_D_TYPE && defined USE_STRUCT_DIRENT_D_TYPE
85 /* Convert the value of struct dirent.d_type into a value for
86 * struct stat.st_mode (at least the file type bits), or zero
87 * if the type is DT_UNKNOWN or is a value we don't know about.
89 static mode_t
90 type_to_mode(unsigned type)
92 switch (type)
94 #ifdef DT_FIFO
95 case DT_FIFO: return S_IFIFO;
96 #endif
97 #ifdef DT_CHR
98 case DT_CHR: return S_IFCHR;
99 #endif
100 #ifdef DT_DIR
101 case DT_DIR: return S_IFDIR;
102 #endif
103 #ifdef DT_BLK
104 case DT_BLK: return S_IFBLK;
105 #endif
106 #ifdef DT_REG
107 case DT_REG: return S_IFREG;
108 #endif
109 #ifdef DT_LNK
110 case DT_LNK: return S_IFLNK;
111 #endif
112 #ifdef DT_SOCK
113 case DT_SOCK: return S_IFSOCK;
114 #endif
115 default:
116 return 0; /* Unknown. */
120 #endif
122 struct new_savedir_direntry_internal
124 int flags; /* from SaveDirDataFlags */
125 mode_t type_info;
126 size_t buffer_offset;
131 static int
132 savedir_cmp(const void *p1, const void *p2)
134 const struct savedir_direntry *de1, *de2;
135 de1 = p1;
136 de2 = p2;
137 return strcmp(de1->name, de2->name); /* POSIX order, not locale order. */
141 static struct savedir_direntry*
142 convertentries(const struct savedir_dirinfo *info,
143 struct new_savedir_direntry_internal *internal)
145 char *p = info->buffer;
146 struct savedir_direntry *result;
147 int n =info->size;
148 int i;
151 result = xmalloc(sizeof(*result) * info->size);
153 for (i=0; i<n; ++i)
155 result[i].flags = internal[i].flags;
156 result[i].type_info = internal[i].type_info;
157 result[i].name = &p[internal[i].buffer_offset];
159 return result;
163 struct savedir_dirinfo *
164 xsavedir(const char *dir, int flags)
166 DIR *dirp;
167 struct dirent *dp;
168 struct savedir_dirinfo *result = NULL;
169 struct new_savedir_direntry_internal *internal;
171 size_t namebuf_allocated = 0u, namebuf_used = 0u;
172 size_t entrybuf_allocated = 0u;
173 int save_errno;
175 dirp = opendir (dir);
176 if (dirp == NULL)
177 return NULL;
179 errno = 0;
180 result = xmalloc(sizeof(*result));
181 result->buffer = NULL;
182 result->size = 0u;
183 result->entries = NULL;
184 internal = NULL;
186 while ((dp = readdir (dirp)) != NULL)
188 /* Skip "", ".", and "..". "" is returned by at least one buggy
189 implementation: Solaris 2.4 readdir on NFS file systems. */
190 char const *entry = dp->d_name;
191 if (entry[entry[0] != '.' ? 0 : entry[1] != '.' ? 1 : 2] != '\0')
193 /* Remember the name. */
194 size_t entry_size = strlen (entry) + 1;
195 result->buffer = extendbuf(result->buffer, namebuf_used+entry_size, &namebuf_allocated);
196 memcpy ((result->buffer) + namebuf_used, entry, entry_size);
198 /* Remember the other stuff. */
199 internal = extendbuf(internal, (1+result->size)*sizeof(*internal), &entrybuf_allocated);
200 internal[result->size].flags = 0;
202 #if defined HAVE_STRUCT_DIRENT_D_TYPE && defined USE_STRUCT_DIRENT_D_TYPE
203 internal[result->size].type_info = type_to_mode(dp->d_type);
204 if (dp->d_type != DT_UNKNOWN)
205 internal[result->size].flags |= SavedirHaveFileType;
206 #else
207 internal[result->size].type_info = 0;
208 #endif
209 internal[result->size].buffer_offset = namebuf_used;
211 /* Prepare for the next iteration */
212 ++(result->size);
213 namebuf_used += entry_size;
217 result->buffer = extendbuf(result->buffer, namebuf_used+1, &namebuf_allocated);
218 result->buffer[namebuf_used] = '\0';
220 /* convert the result to its externally-usable form. */
221 result->entries = convertentries(result, internal);
222 free(internal);
223 internal = NULL;
226 if (flags & SavedirSort)
228 qsort(result->entries,
229 result->size, sizeof(*result->entries),
230 savedir_cmp);
234 save_errno = errno;
235 if (CLOSEDIR (dirp) != 0)
236 save_errno = errno;
237 if (save_errno != 0)
239 free (result->buffer);
240 free (result);
241 errno = save_errno;
242 return NULL;
245 return result;
248 void free_dirinfo(struct savedir_dirinfo *p)
250 free(p->entries);
251 p->entries = NULL;
252 free(p->buffer);
253 p->buffer = NULL;
254 free(p);
259 static char *
260 new_savedirinfo (const char *dir, struct savedir_extrainfo **extra)
262 struct savedir_dirinfo *p = xsavedir(dir, SavedirSort);
263 char *buf, *s;
264 size_t bufbytes = 0;
265 unsigned int i;
267 if (p)
269 struct savedir_extrainfo *pex = xmalloc(p->size * sizeof(*extra));
270 for (i=0; i<p->size; ++i)
272 bufbytes += strlen(p->entries[i].name);
273 ++bufbytes; /* the \0 */
275 pex[i].type_info = p->entries[i].type_info;
278 s = buf = xmalloc(bufbytes+1);
279 for (i=0; i<p->size; ++i)
281 size_t len = strlen(p->entries[i].name);
282 memcpy(s, p->entries[i].name, len);
283 s += len;
284 *s = 0; /* Place a NUL */
285 ++s; /* Skip the NUL. */
287 *s = 0; /* final (doubled) terminating NUL */
289 if (extra)
290 *extra = pex;
291 else
292 free (pex);
293 return buf;
295 else
297 return NULL;
302 #if 0
303 /* Return a freshly allocated string containing the filenames
304 in directory DIR, separated by '\0' characters;
305 the end is marked by two '\0' characters in a row.
306 Return NULL (setting errno) if DIR cannot be opened, read, or closed. */
308 static char *
309 old_savedirinfo (const char *dir, struct savedir_extrainfo **extra)
311 DIR *dirp;
312 struct dirent *dp;
313 char *name_space;
314 size_t namebuf_allocated = 0u, namebuf_used = 0u;
315 #if defined HAVE_STRUCT_DIRENT_D_TYPE && defined USE_STRUCT_DIRENT_D_TYPE
316 size_t extra_allocated = 0u, extra_used = 0u;
317 struct savedir_extrainfo *info = NULL;
318 #endif
319 int save_errno;
321 if (extra)
322 *extra = NULL;
324 dirp = opendir (dir);
325 if (dirp == NULL)
326 return NULL;
328 errno = 0;
329 name_space = NULL;
330 while ((dp = readdir (dirp)) != NULL)
332 /* Skip "", ".", and "..". "" is returned by at least one buggy
333 implementation: Solaris 2.4 readdir on NFS file systems. */
334 char const *entry = dp->d_name;
335 if (entry[entry[0] != '.' ? 0 : entry[1] != '.' ? 1 : 2] != '\0')
337 /* Remember the name. */
338 size_t entry_size = strlen (entry) + 1;
339 name_space = extendbuf(name_space, namebuf_used+entry_size, &namebuf_allocated);
340 memcpy (name_space + namebuf_used, entry, entry_size);
341 namebuf_used += entry_size;
344 #if defined HAVE_STRUCT_DIRENT_D_TYPE && defined USE_STRUCT_DIRENT_D_TYPE
345 /* Remember the type. */
346 if (extra)
348 info = extendbuf(info,
349 (extra_used+1) * sizeof(struct savedir_dirinfo),
350 &extra_allocated);
351 info[extra_used].type_info = type_to_mode(dp->d_type);
352 ++extra_used;
354 #endif
358 name_space = extendbuf(name_space, namebuf_used+1, &namebuf_allocated);
359 name_space[namebuf_used] = '\0';
361 save_errno = errno;
362 if (CLOSEDIR (dirp) != 0)
363 save_errno = errno;
364 if (save_errno != 0)
366 free (name_space);
367 errno = save_errno;
368 return NULL;
371 #if defined HAVE_STRUCT_DIRENT_D_TYPE && defined USE_STRUCT_DIRENT_D_TYPE
372 if (extra && info)
373 *extra = info;
374 #endif
376 return name_space;
378 #endif
381 char *
382 savedirinfo (const char *dir, struct savedir_extrainfo **extra)
384 return new_savedirinfo(dir, extra);