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)
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>. */
28 # include <sys/stat.h>
32 # include <sys/types.h>
35 /* The presence of unistd.h is assumed by gnulib these days, so we
36 * might as well assume it too.
45 # define dirent direct
47 # include <sys/ndir.h>
58 /* Fake a return value. */
59 # define CLOSEDIR(d) (closedir (d), 0)
61 # define CLOSEDIR(d) closedir (d)
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
76 #if !defined(USE_STRUCT_DIRENT_D_TYPE)
77 /* Not enabled, hence pretend it is absent. */
78 #undef HAVE_STRUCT_DIRENT_D_TYPE
80 #if !defined(HAVE_STRUCT_DIRENT_D_TYPE)
81 /* Not present, so cannot use it. */
82 #undef USE_STRUCT_DIRENT_D_TYPE
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.
92 type_to_mode(unsigned type
)
97 case DT_FIFO
: return S_IFIFO
;
100 case DT_CHR
: return S_IFCHR
;
103 case DT_DIR
: return S_IFDIR
;
106 case DT_BLK
: return S_IFBLK
;
109 case DT_REG
: return S_IFREG
;
112 case DT_LNK
: return S_IFLNK
;
115 case DT_SOCK
: return S_IFSOCK
;
118 return 0; /* Unknown. */
124 struct new_savedir_direntry_internal
126 int flags
; /* from SaveDirDataFlags */
128 size_t buffer_offset
;
134 savedir_cmp(const void *p1
, const void *p2
)
136 const struct savedir_direntry
*de1
, *de2
;
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
;
153 result
= xmalloc(sizeof(*result
) * info
->size
);
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
];
165 struct savedir_dirinfo
*
166 xsavedir(const char *dir
, int flags
)
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;
177 dirp
= opendir (dir
);
182 result
= xmalloc(sizeof(*result
));
183 result
->buffer
= NULL
;
185 result
->entries
= 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
;
209 internal
[result
->size
].type_info
= 0;
211 internal
[result
->size
].buffer_offset
= namebuf_used
;
213 /* Prepare for the next iteration */
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
);
228 if (flags
& SavedirSort
)
230 qsort(result
->entries
,
231 result
->size
, sizeof(*result
->entries
),
237 if (CLOSEDIR (dirp
) != 0)
241 free (result
->buffer
);
250 void free_dirinfo(struct savedir_dirinfo
*p
)
262 new_savedirinfo (const char *dir
, struct savedir_extrainfo
**extra
)
264 struct savedir_dirinfo
*p
= xsavedir(dir
, SavedirSort
);
271 struct savedir_extrainfo
*pex
= xmalloc(p
->size
* sizeof(*extra
));
272 for (i
=0; i
<p
->size
; ++i
)
274 bufbytes
+= strlen(p
->entries
[i
].name
);
275 ++bufbytes
; /* the \0 */
277 pex
[i
].type_info
= p
->entries
[i
].type_info
;
280 s
= buf
= xmalloc(bufbytes
+1);
281 for (i
=0; i
<p
->size
; ++i
)
283 size_t len
= strlen(p
->entries
[i
].name
);
284 memcpy(s
, p
->entries
[i
].name
, len
);
286 *s
= 0; /* Place a NUL */
287 ++s
; /* Skip the NUL. */
289 *s
= 0; /* final (doubled) terminating NUL */
305 /* Return a freshly allocated string containing the filenames
306 in directory DIR, separated by '\0' characters;
307 the end is marked by two '\0' characters in a row.
308 Return NULL (setting errno) if DIR cannot be opened, read, or closed. */
311 old_savedirinfo (const char *dir
, struct savedir_extrainfo
**extra
)
316 size_t namebuf_allocated
= 0u, namebuf_used
= 0u;
317 #if defined(HAVE_STRUCT_DIRENT_D_TYPE) && defined(USE_STRUCT_DIRENT_D_TYPE)
318 size_t extra_allocated
= 0u, extra_used
= 0u;
319 struct savedir_extrainfo
*info
= NULL
;
326 dirp
= opendir (dir
);
332 while ((dp
= readdir (dirp
)) != NULL
)
334 /* Skip "", ".", and "..". "" is returned by at least one buggy
335 implementation: Solaris 2.4 readdir on NFS file systems. */
336 char const *entry
= dp
->d_name
;
337 if (entry
[entry
[0] != '.' ? 0 : entry
[1] != '.' ? 1 : 2] != '\0')
339 /* Remember the name. */
340 size_t entry_size
= strlen (entry
) + 1;
341 name_space
= extendbuf(name_space
, namebuf_used
+entry_size
, &namebuf_allocated
);
342 memcpy (name_space
+ namebuf_used
, entry
, entry_size
);
343 namebuf_used
+= entry_size
;
346 #if defined(HAVE_STRUCT_DIRENT_D_TYPE) && defined(USE_STRUCT_DIRENT_D_TYPE)
347 /* Remember the type. */
350 info
= extendbuf(info
,
351 (extra_used
+1) * sizeof(struct savedir_dirinfo
),
353 info
[extra_used
].type_info
= type_to_mode(dp
->d_type
);
360 name_space
= extendbuf(name_space
, namebuf_used
+1, &namebuf_allocated
);
361 name_space
[namebuf_used
] = '\0';
364 if (CLOSEDIR (dirp
) != 0)
373 #if defined(HAVE_STRUCT_DIRENT_D_TYPE) && defined(USE_STRUCT_DIRENT_D_TYPE)
384 savedirinfo (const char *dir
, struct savedir_extrainfo
**extra
)
386 return new_savedirinfo(dir
, extra
);