source: trunk/essentials/sys-apps/findutils/lib/savedirinfo.c

Last change on this file was 3170, checked in by bird, 18 years ago

findutils 4.3.2

File size: 9.1 KB
Line 
1/* savedirinfo.c -- Save the list of files in a directory, with additional information.
2
3 Copyright 1990, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005 Free
4 Software Foundation, Inc.
5
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.
10
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.
15
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. */
19
20/* Written by James Youngman, <jay@gnu.org>. */
21/* Derived from savedir.c, written by David MacKenzie <djm@gnu.org>. */
22
23#if HAVE_CONFIG_H
24# include <config.h>
25#endif
26
27#if HAVE_SYS_STAT_H
28# include <sys/stat.h>
29#endif
30
31#if HAVE_SYS_TYPES_H
32# include <sys/types.h>
33#endif
34
35/* The presence of unistd.h is assumed by gnulib these days, so we
36 * might as well assume it too.
37 */
38#include <unistd.h>
39
40#include <errno.h>
41
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
56
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
63
64#include <stddef.h>
65#include <stdlib.h>
66#include <string.h>
67
68#include "xalloc.h"
69#include "extendbuf.h"
70#include "savedirinfo.h"
71
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'.
75 */
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
84
85
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.
90 */
91static mode_t
92type_to_mode(unsigned type)
93{
94 switch (type)
95 {
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. */
119 }
120}
121
122#endif
123
124struct new_savedir_direntry_internal
125{
126 int flags; /* from SaveDirDataFlags */
127 mode_t type_info;
128 size_t buffer_offset;
129};
130
131
132
133static int
134savedir_cmp(const void *p1, const void *p2)
135{
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. */
140}
141
142
143static struct savedir_direntry*
144convertentries(const struct savedir_dirinfo *info,
145 struct new_savedir_direntry_internal *internal)
146{
147 char *p = info->buffer;
148 struct savedir_direntry *result;
149 int n =info->size;
150 int i;
151
152
153 result = xmalloc(sizeof(*result) * info->size);
154
155 for (i=0; i<n; ++i)
156 {
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];
160 }
161 return result;
162}
163
164
165struct savedir_dirinfo *
166xsavedir(const char *dir, int flags)
167{
168 DIR *dirp;
169 struct dirent *dp;
170 struct savedir_dirinfo *result = NULL;
171 struct new_savedir_direntry_internal *internal;
172
173 size_t namebuf_allocated = 0u, namebuf_used = 0u;
174 size_t entrybuf_allocated = 0u;
175 int save_errno;
176
177 dirp = opendir (dir);
178 if (dirp == NULL)
179 return NULL;
180
181 errno = 0;
182 result = xmalloc(sizeof(*result));
183 result->buffer = NULL;
184 result->size = 0u;
185 result->entries = NULL;
186 internal = NULL;
187
188 while ((dp = readdir (dirp)) != NULL)
189 {
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')
194 {
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);
199
200 /* Remember the other stuff. */
201 internal = extendbuf(internal, (1+result->size)*sizeof(*internal), &entrybuf_allocated);
202 internal[result->size].flags = 0;
203
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;
212
213 /* Prepare for the next iteration */
214 ++(result->size);
215 namebuf_used += entry_size;
216 }
217 }
218
219 result->buffer = extendbuf(result->buffer, namebuf_used+1, &namebuf_allocated);
220 result->buffer[namebuf_used] = '\0';
221
222 /* convert the result to its externally-usable form. */
223 result->entries = convertentries(result, internal);
224 free(internal);
225 internal = NULL;
226
227
228 if (flags & SavedirSort)
229 {
230 qsort(result->entries,
231 result->size, sizeof(*result->entries),
232 savedir_cmp);
233 }
234
235
236 save_errno = errno;
237 if (CLOSEDIR (dirp) != 0)
238 save_errno = errno;
239 if (save_errno != 0)
240 {
241 free (result->buffer);
242 free (result);
243 errno = save_errno;
244 return NULL;
245 }
246
247 return result;
248}
249
250void free_dirinfo(struct savedir_dirinfo *p)
251{
252 free(p->entries);
253 p->entries = NULL;
254 free(p->buffer);
255 p->buffer = NULL;
256}
257
258
259
260static char *
261new_savedirinfo (const char *dir, struct savedir_extrainfo **extra)
262{
263 struct savedir_dirinfo *p = xsavedir(dir, SavedirSort);
264 char *buf, *s;
265 size_t bufbytes = 0;
266 unsigned int i;
267
268 if (p)
269 {
270 struct savedir_extrainfo *pex = xmalloc(p->size * sizeof(*extra));
271 for (i=0; i<p->size; ++i)
272 {
273 bufbytes += strlen(p->entries[i].name);
274 ++bufbytes; /* the \0 */
275
276 pex[i].type_info = p->entries[i].type_info;
277 }
278
279 s = buf = xmalloc(bufbytes+1);
280 for (i=0; i<p->size; ++i)
281 {
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. */
287 }
288 *s = 0; /* final (doubled) terminating NUL */
289
290 if (extra)
291 *extra = pex;
292 else
293 free (pex);
294 return buf;
295 }
296 else
297 {
298 return NULL;
299 }
300}
301
302
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. */
308
309static char *
310old_savedirinfo (const char *dir, struct savedir_extrainfo **extra)
311{
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;
321
322 if (extra)
323 *extra = NULL;
324
325 dirp = opendir (dir);
326 if (dirp == NULL)
327 return NULL;
328
329 errno = 0;
330 name_space = NULL;
331 while ((dp = readdir (dirp)) != NULL)
332 {
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')
337 {
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;
343
344
345#if defined(HAVE_STRUCT_DIRENT_D_TYPE) && defined(USE_STRUCT_DIRENT_D_TYPE)
346 /* Remember the type. */
347 if (extra)
348 {
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;
354 }
355#endif
356 }
357 }
358
359 name_space = extendbuf(name_space, namebuf_used+1, &namebuf_allocated);
360 name_space[namebuf_used] = '\0';
361
362 save_errno = errno;
363 if (CLOSEDIR (dirp) != 0)
364 save_errno = errno;
365 if (save_errno != 0)
366 {
367 free (name_space);
368 errno = save_errno;
369 return NULL;
370 }
371
372#if defined(HAVE_STRUCT_DIRENT_D_TYPE) && defined(USE_STRUCT_DIRENT_D_TYPE)
373 if (extra && info)
374 *extra = info;
375#endif
376
377 return name_space;
378}
379#endif
380
381
382char *
383savedirinfo (const char *dir, struct savedir_extrainfo **extra)
384{
385 return new_savedirinfo(dir, extra);
386}
Note: See TracBrowser for help on using the repository browser.