Applied patch from Dmitry V. Levin fixing two compilation warnings.
[findutils.git] / lib / savedirinfo.c
blob8e800d1f27c4d354a2e80823ca3d5ecc1c1ff51a
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 #if HAVE_UNISTD_H
36 # include <unistd.h>
37 #endif
39 #include <errno.h>
41 #if HAVE_DIRENT_H
42 # include <dirent.h>
43 #else
44 # define dirent direct
45 # if HAVE_SYS_NDIR_H
46 # include <sys/ndir.h>
47 # endif
48 # if HAVE_SYS_DIR_H
49 # include <sys/dir.h>
50 # endif
51 # if HAVE_NDIR_H
52 # include <ndir.h>
53 # endif
54 #endif
56 #ifdef CLOSEDIR_VOID
57 /* Fake a return value. */
58 # define CLOSEDIR(d) (closedir (d), 0)
59 #else
60 # define CLOSEDIR(d) closedir (d)
61 #endif
63 #include <stddef.h>
64 #include <stdlib.h>
65 #include <string.h>
67 #include "xalloc.h"
68 #include "extendbuf.h"
69 #include "savedirinfo.h"
71 /* In order to use struct dirent.d_type, it has to be enabled on the
72 * configure command line, and we have to have a d_type member in
73 * 'struct dirent'.
75 #if !defined(USE_STRUCT_DIRENT_D_TYPE)
76 /* Not enabled, hence pretend it is absent. */
77 #undef HAVE_STRUCT_DIRENT_D_TYPE
78 #endif
79 #if !defined(HAVE_STRUCT_DIRENT_D_TYPE)
80 /* Not present, so cannot use it. */
81 #undef USE_STRUCT_DIRENT_D_TYPE
82 #endif
85 #if defined(HAVE_STRUCT_DIRENT_D_TYPE) && defined(USE_STRUCT_DIRENT_D_TYPE)
86 /* Convert the value of struct dirent.d_type into a value for
87 * struct stat.st_mode (at least the file type bits), or zero
88 * if the type is DT_UNKNOWN or is a value we don't know about.
90 static mode_t
91 type_to_mode(unsigned type)
93 switch (type)
95 #ifdef DT_FIFO
96 case DT_FIFO: return S_IFIFO;
97 #endif
98 #ifdef DT_CHR
99 case DT_CHR: return S_IFCHR;
100 #endif
101 #ifdef DT_DIR
102 case DT_DIR: return S_IFDIR;
103 #endif
104 #ifdef DT_BLK
105 case DT_BLK: return S_IFBLK;
106 #endif
107 #ifdef DT_REG
108 case DT_REG: return S_IFREG;
109 #endif
110 #ifdef DT_LNK
111 case DT_LNK: return S_IFLNK;
112 #endif
113 #ifdef DT_SOCK
114 case DT_SOCK: return S_IFSOCK;
115 #endif
116 default:
117 return 0; /* Unknown. */
121 #endif
123 struct new_savedir_direntry_internal
125 int flags; /* from SaveDirDataFlags */
126 mode_t type_info;
127 size_t buffer_offset;
132 static int
133 savedir_cmp(const void *p1, const void *p2)
135 const struct savedir_direntry *de1, *de2;
136 de1 = p1;
137 de2 = p2;
138 return strcmp(de1->name, de2->name); /* POSIX order, not locale order. */
142 static struct savedir_direntry*
143 convertentries(const struct savedir_dirinfo *info,
144 struct new_savedir_direntry_internal *internal)
146 char *p = info->buffer;
147 struct savedir_direntry *result;
148 int n =info->size;
149 int i;
152 result = xmalloc(sizeof(*result) * info->size);
154 for (i=0; i<n; ++i)
156 result[i].flags = internal[i].flags;
157 result[i].type_info = internal[i].type_info;
158 result[i].name = &p[internal[i].buffer_offset];
160 return result;
164 struct savedir_dirinfo *
165 xsavedir(const char *dir, int flags)
167 DIR *dirp;
168 struct dirent *dp;
169 struct savedir_dirinfo *result = NULL;
170 struct new_savedir_direntry_internal *internal;
172 size_t namebuf_allocated = 0u, namebuf_used = 0u;
173 size_t entrybuf_allocated = 0u;
174 int save_errno;
176 dirp = opendir (dir);
177 if (dirp == NULL)
178 return NULL;
180 errno = 0;
181 result = xmalloc(sizeof(*result));
182 result->buffer = NULL;
183 result->size = 0u;
184 result->entries = NULL;
185 internal = NULL;
187 while ((dp = readdir (dirp)) != NULL)
189 /* Skip "", ".", and "..". "" is returned by at least one buggy
190 implementation: Solaris 2.4 readdir on NFS file systems. */
191 char const *entry = dp->d_name;
192 if (entry[entry[0] != '.' ? 0 : entry[1] != '.' ? 1 : 2] != '\0')
194 /* Remember the name. */
195 size_t entry_size = strlen (entry) + 1;
196 result->buffer = extendbuf(result->buffer, namebuf_used+entry_size, &namebuf_allocated);
197 memcpy ((result->buffer) + namebuf_used, entry, entry_size);
199 /* Remember the other stuff. */
200 internal = extendbuf(internal, (1+result->size)*sizeof(*internal), &entrybuf_allocated);
201 internal[result->size].flags = 0;
203 #if defined(HAVE_STRUCT_DIRENT_D_TYPE) && defined(USE_STRUCT_DIRENT_D_TYPE)
204 internal[result->size].type_info = type_to_mode(dp->d_type);
205 if (dp->d_type != DT_UNKNOWN)
206 internal[result->size].flags |= SavedirHaveFileType;
207 #else
208 internal[result->size].type_info = 0;
209 #endif
210 internal[result->size].buffer_offset = namebuf_used;
212 /* Prepare for the next iteration */
213 ++(result->size);
214 namebuf_used += entry_size;
218 result->buffer = extendbuf(result->buffer, namebuf_used+1, &namebuf_allocated);
219 result->buffer[namebuf_used] = '\0';
221 /* convert the result to its externally-usable form. */
222 result->entries = convertentries(result, internal);
223 free(internal);
224 internal = NULL;
227 if (flags & SavedirSort)
229 qsort(result->entries,
230 result->size, sizeof(*result->entries),
231 savedir_cmp);
235 save_errno = errno;
236 if (CLOSEDIR (dirp) != 0)
237 save_errno = errno;
238 if (save_errno != 0)
240 free (result->buffer);
241 free (result);
242 errno = save_errno;
243 return NULL;
246 return result;
249 void free_dirinfo(struct savedir_dirinfo *p)
251 free(p->entries);
252 p->entries = NULL;
253 free(p->buffer);
254 p->buffer = NULL;
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 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;
298 #if 0
299 /* Return a freshly allocated string containing the filenames
300 in directory DIR, separated by '\0' characters;
301 the end is marked by two '\0' characters in a row.
302 Return NULL (setting errno) if DIR cannot be opened, read, or closed. */
304 static char *
305 old_savedirinfo (const char *dir, struct savedir_extrainfo **extra)
307 DIR *dirp;
308 struct dirent *dp;
309 char *name_space;
310 size_t namebuf_allocated = 0u, namebuf_used = 0u;
311 #if defined(HAVE_STRUCT_DIRENT_D_TYPE) && defined(USE_STRUCT_DIRENT_D_TYPE)
312 size_t extra_allocated = 0u, extra_used = 0u;
313 struct savedir_extrainfo *info = NULL;
314 #endif
315 int save_errno;
317 if (extra)
318 *extra = NULL;
320 dirp = opendir (dir);
321 if (dirp == NULL)
322 return NULL;
324 errno = 0;
325 name_space = NULL;
326 while ((dp = readdir (dirp)) != NULL)
328 /* Skip "", ".", and "..". "" is returned by at least one buggy
329 implementation: Solaris 2.4 readdir on NFS file systems. */
330 char const *entry = dp->d_name;
331 if (entry[entry[0] != '.' ? 0 : entry[1] != '.' ? 1 : 2] != '\0')
333 /* Remember the name. */
334 size_t entry_size = strlen (entry) + 1;
335 name_space = extendbuf(name_space, namebuf_used+entry_size, &namebuf_allocated);
336 memcpy (name_space + namebuf_used, entry, entry_size);
337 namebuf_used += entry_size;
340 #if defined(HAVE_STRUCT_DIRENT_D_TYPE) && defined(USE_STRUCT_DIRENT_D_TYPE)
341 /* Remember the type. */
342 if (extra)
344 info = extendbuf(info,
345 (extra_used+1) * sizeof(struct savedir_dirinfo),
346 &extra_allocated);
347 info[extra_used].type_info = type_to_mode(dp->d_type);
348 ++extra_used;
350 #endif
354 name_space = extendbuf(name_space, namebuf_used+1, &namebuf_allocated);
355 name_space[namebuf_used] = '\0';
357 save_errno = errno;
358 if (CLOSEDIR (dirp) != 0)
359 save_errno = errno;
360 if (save_errno != 0)
362 free (name_space);
363 errno = save_errno;
364 return NULL;
367 #if defined(HAVE_STRUCT_DIRENT_D_TYPE) && defined(USE_STRUCT_DIRENT_D_TYPE)
368 if (extra && info)
369 *extra = info;
370 #endif
372 return name_space;
374 #endif
377 char *
378 savedirinfo (const char *dir, struct savedir_extrainfo **extra)
380 return new_savedirinfo(dir, extra);