Prefer the word 'Invalid' or the phrase 'not allowed' over 'Illegal', as per the...
[findutils.git] / lib / savedirinfo.c
blob1d2f9967c34701eb9e9dac75bfb140dcd51a9ce7
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 #if HAVE_CONFIG_H
24 # include <config.h>
25 #endif
27 #if HAVE_SYS_STAT_H
28 # include <sys/stat.h>
29 #endif
31 #if HAVE_SYS_TYPES_H
32 # include <sys/types.h>
33 #endif
35 /* The presence of unistd.h is assumed by gnulib these days, so we
36 * might as well assume it too.
38 #include <unistd.h>
40 #include <errno.h>
42 #if HAVE_DIRENT_H
43 # include <dirent.h>
44 #else
45 # define dirent direct
46 # if HAVE_SYS_NDIR_H
47 # include <sys/ndir.h>
48 # endif
49 # if HAVE_SYS_DIR_H
50 # include <sys/dir.h>
51 # endif
52 # if HAVE_NDIR_H
53 # include <ndir.h>
54 # endif
55 #endif
57 #ifdef CLOSEDIR_VOID
58 /* Fake a return value. */
59 # define CLOSEDIR(d) (closedir (d), 0)
60 #else
61 # define CLOSEDIR(d) closedir (d)
62 #endif
64 #include <stddef.h>
65 #include <stdlib.h>
66 #include <string.h>
68 #include "xalloc.h"
69 #include "extendbuf.h"
70 #include "savedirinfo.h"
72 /* In order to use struct dirent.d_type, it has to be enabled on the
73 * configure command line, and we have to have a d_type member in
74 * 'struct dirent'.
76 #if !defined(USE_STRUCT_DIRENT_D_TYPE)
77 /* Not enabled, hence pretend it is absent. */
78 #undef HAVE_STRUCT_DIRENT_D_TYPE
79 #endif
80 #if !defined(HAVE_STRUCT_DIRENT_D_TYPE)
81 /* Not present, so cannot use it. */
82 #undef USE_STRUCT_DIRENT_D_TYPE
83 #endif
86 #if defined(HAVE_STRUCT_DIRENT_D_TYPE) && defined(USE_STRUCT_DIRENT_D_TYPE)
87 /* Convert the value of struct dirent.d_type into a value for
88 * struct stat.st_mode (at least the file type bits), or zero
89 * if the type is DT_UNKNOWN or is a value we don't know about.
91 static mode_t
92 type_to_mode(unsigned type)
94 switch (type)
96 #ifdef DT_FIFO
97 case DT_FIFO: return S_IFIFO;
98 #endif
99 #ifdef DT_CHR
100 case DT_CHR: return S_IFCHR;
101 #endif
102 #ifdef DT_DIR
103 case DT_DIR: return S_IFDIR;
104 #endif
105 #ifdef DT_BLK
106 case DT_BLK: return S_IFBLK;
107 #endif
108 #ifdef DT_REG
109 case DT_REG: return S_IFREG;
110 #endif
111 #ifdef DT_LNK
112 case DT_LNK: return S_IFLNK;
113 #endif
114 #ifdef DT_SOCK
115 case DT_SOCK: return S_IFSOCK;
116 #endif
117 default:
118 return 0; /* Unknown. */
122 #endif
124 struct new_savedir_direntry_internal
126 int flags; /* from SaveDirDataFlags */
127 mode_t type_info;
128 size_t buffer_offset;
133 static int
134 savedir_cmp(const void *p1, const void *p2)
136 const struct savedir_direntry *de1, *de2;
137 de1 = p1;
138 de2 = p2;
139 return strcmp(de1->name, de2->name); /* POSIX order, not locale order. */
143 static struct savedir_direntry*
144 convertentries(const struct savedir_dirinfo *info,
145 struct new_savedir_direntry_internal *internal)
147 char *p = info->buffer;
148 struct savedir_direntry *result;
149 int n =info->size;
150 int i;
153 result = xmalloc(sizeof(*result) * info->size);
155 for (i=0; i<n; ++i)
157 result[i].flags = internal[i].flags;
158 result[i].type_info = internal[i].type_info;
159 result[i].name = &p[internal[i].buffer_offset];
161 return result;
165 struct savedir_dirinfo *
166 xsavedir(const char *dir, int flags)
168 DIR *dirp;
169 struct dirent *dp;
170 struct savedir_dirinfo *result = NULL;
171 struct new_savedir_direntry_internal *internal;
173 size_t namebuf_allocated = 0u, namebuf_used = 0u;
174 size_t entrybuf_allocated = 0u;
175 int save_errno;
177 dirp = opendir (dir);
178 if (dirp == NULL)
179 return NULL;
181 errno = 0;
182 result = xmalloc(sizeof(*result));
183 result->buffer = NULL;
184 result->size = 0u;
185 result->entries = NULL;
186 internal = NULL;
188 while ((dp = readdir (dirp)) != NULL)
190 /* Skip "", ".", and "..". "" is returned by at least one buggy
191 implementation: Solaris 2.4 readdir on NFS file systems. */
192 char const *entry = dp->d_name;
193 if (entry[entry[0] != '.' ? 0 : entry[1] != '.' ? 1 : 2] != '\0')
195 /* Remember the name. */
196 size_t entry_size = strlen (entry) + 1;
197 result->buffer = extendbuf(result->buffer, namebuf_used+entry_size, &namebuf_allocated);
198 memcpy ((result->buffer) + namebuf_used, entry, entry_size);
200 /* Remember the other stuff. */
201 internal = extendbuf(internal, (1+result->size)*sizeof(*internal), &entrybuf_allocated);
202 internal[result->size].flags = 0;
204 #if defined(HAVE_STRUCT_DIRENT_D_TYPE) && defined(USE_STRUCT_DIRENT_D_TYPE)
205 internal[result->size].type_info = type_to_mode(dp->d_type);
206 if (dp->d_type != DT_UNKNOWN)
207 internal[result->size].flags |= SavedirHaveFileType;
208 #else
209 internal[result->size].type_info = 0;
210 #endif
211 internal[result->size].buffer_offset = namebuf_used;
213 /* Prepare for the next iteration */
214 ++(result->size);
215 namebuf_used += entry_size;
219 result->buffer = extendbuf(result->buffer, namebuf_used+1, &namebuf_allocated);
220 result->buffer[namebuf_used] = '\0';
222 /* convert the result to its externally-usable form. */
223 result->entries = convertentries(result, internal);
224 free(internal);
225 internal = NULL;
228 if (flags & SavedirSort)
230 qsort(result->entries,
231 result->size, sizeof(*result->entries),
232 savedir_cmp);
236 save_errno = errno;
237 if (CLOSEDIR (dirp) != 0)
238 save_errno = errno;
239 if (save_errno != 0)
241 free (result->buffer);
242 free (result);
243 errno = save_errno;
244 return NULL;
247 return result;
250 void free_dirinfo(struct savedir_dirinfo *p)
252 free(p->entries);
253 p->entries = NULL;
254 free(p->buffer);
255 p->buffer = NULL;
260 static char *
261 new_savedirinfo (const char *dir, struct savedir_extrainfo **extra)
263 struct savedir_dirinfo *p = xsavedir(dir, SavedirSort);
264 char *buf, *s;
265 size_t bufbytes = 0;
266 int i;
268 if (p)
270 struct savedir_extrainfo *pex = xmalloc(p->size * sizeof(*extra));
271 for (i=0; i<p->size; ++i)
273 bufbytes += strlen(p->entries[i].name);
274 ++bufbytes; /* the \0 */
276 pex[i].type_info = p->entries[i].type_info;
279 s = buf = xmalloc(bufbytes+1);
280 for (i=0; i<p->size; ++i)
282 size_t len = strlen(p->entries[i].name);
283 memcpy(s, p->entries[i].name, len);
284 s += len;
285 *s = 0; /* Place a NUL */
286 ++s; /* Skip the NUL. */
288 *s = 0; /* final (doubled) terminating NUL */
290 if (extra)
291 *extra = pex;
292 else
293 free (pex);
294 return buf;
296 else
298 return NULL;
303 #if 0
304 /* Return a freshly allocated string containing the filenames
305 in directory DIR, separated by '\0' characters;
306 the end is marked by two '\0' characters in a row.
307 Return NULL (setting errno) if DIR cannot be opened, read, or closed. */
309 static char *
310 old_savedirinfo (const char *dir, struct savedir_extrainfo **extra)
312 DIR *dirp;
313 struct dirent *dp;
314 char *name_space;
315 size_t namebuf_allocated = 0u, namebuf_used = 0u;
316 #if defined(HAVE_STRUCT_DIRENT_D_TYPE) && defined(USE_STRUCT_DIRENT_D_TYPE)
317 size_t extra_allocated = 0u, extra_used = 0u;
318 struct savedir_extrainfo *info = NULL;
319 #endif
320 int save_errno;
322 if (extra)
323 *extra = NULL;
325 dirp = opendir (dir);
326 if (dirp == NULL)
327 return NULL;
329 errno = 0;
330 name_space = NULL;
331 while ((dp = readdir (dirp)) != NULL)
333 /* Skip "", ".", and "..". "" is returned by at least one buggy
334 implementation: Solaris 2.4 readdir on NFS file systems. */
335 char const *entry = dp->d_name;
336 if (entry[entry[0] != '.' ? 0 : entry[1] != '.' ? 1 : 2] != '\0')
338 /* Remember the name. */
339 size_t entry_size = strlen (entry) + 1;
340 name_space = extendbuf(name_space, namebuf_used+entry_size, &namebuf_allocated);
341 memcpy (name_space + namebuf_used, entry, entry_size);
342 namebuf_used += entry_size;
345 #if defined(HAVE_STRUCT_DIRENT_D_TYPE) && defined(USE_STRUCT_DIRENT_D_TYPE)
346 /* Remember the type. */
347 if (extra)
349 info = extendbuf(info,
350 (extra_used+1) * sizeof(struct savedir_dirinfo),
351 &extra_allocated);
352 info[extra_used].type_info = type_to_mode(dp->d_type);
353 ++extra_used;
355 #endif
359 name_space = extendbuf(name_space, namebuf_used+1, &namebuf_allocated);
360 name_space[namebuf_used] = '\0';
362 save_errno = errno;
363 if (CLOSEDIR (dirp) != 0)
364 save_errno = errno;
365 if (save_errno != 0)
367 free (name_space);
368 errno = save_errno;
369 return NULL;
372 #if defined(HAVE_STRUCT_DIRENT_D_TYPE) && defined(USE_STRUCT_DIRENT_D_TYPE)
373 if (extra && info)
374 *extra = info;
375 #endif
377 return name_space;
379 #endif
382 char *
383 savedirinfo (const char *dir, struct savedir_extrainfo **extra)
385 return new_savedirinfo(dir, extra);