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>. */
26 # include <sys/stat.h>
30 # include <sys/types.h>
33 /* The presence of unistd.h is assumed by gnulib these days, so we
34 * might as well assume it too.
43 # define dirent direct
45 # include <sys/ndir.h>
56 /* Fake a return value. */
57 # define CLOSEDIR(d) (closedir (d), 0)
59 # define CLOSEDIR(d) closedir (d)
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
74 #if !defined(USE_STRUCT_DIRENT_D_TYPE)
75 /* Not enabled, hence pretend it is absent. */
76 #undef HAVE_STRUCT_DIRENT_D_TYPE
78 #if !defined(HAVE_STRUCT_DIRENT_D_TYPE)
79 /* Not present, so cannot use it. */
80 #undef USE_STRUCT_DIRENT_D_TYPE
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.
90 type_to_mode(unsigned type
)
95 case DT_FIFO
: return S_IFIFO
;
98 case DT_CHR
: return S_IFCHR
;
101 case DT_DIR
: return S_IFDIR
;
104 case DT_BLK
: return S_IFBLK
;
107 case DT_REG
: return S_IFREG
;
110 case DT_LNK
: return S_IFLNK
;
113 case DT_SOCK
: return S_IFSOCK
;
116 return 0; /* Unknown. */
122 struct new_savedir_direntry_internal
124 int flags
; /* from SaveDirDataFlags */
126 size_t buffer_offset
;
132 savedir_cmp(const void *p1
, const void *p2
)
134 const struct savedir_direntry
*de1
, *de2
;
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
;
151 result
= xmalloc(sizeof(*result
) * info
->size
);
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
];
163 struct savedir_dirinfo
*
164 xsavedir(const char *dir
, int flags
)
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;
175 dirp
= opendir (dir
);
180 result
= xmalloc(sizeof(*result
));
181 result
->buffer
= NULL
;
183 result
->entries
= 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
;
207 internal
[result
->size
].type_info
= 0;
209 internal
[result
->size
].buffer_offset
= namebuf_used
;
211 /* Prepare for the next iteration */
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
);
226 if (flags
& SavedirSort
)
228 qsort(result
->entries
,
229 result
->size
, sizeof(*result
->entries
),
235 if (CLOSEDIR (dirp
) != 0)
239 free (result
->buffer
);
248 void free_dirinfo(struct savedir_dirinfo
*p
)
260 new_savedirinfo (const char *dir
, struct savedir_extrainfo
**extra
)
262 struct savedir_dirinfo
*p
= xsavedir(dir
, SavedirSort
);
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
);
284 *s
= 0; /* Place a NUL */
285 ++s
; /* Skip the NUL. */
287 *s
= 0; /* final (doubled) terminating NUL */
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. */
309 old_savedirinfo (const char *dir
, struct savedir_extrainfo
**extra
)
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
;
324 dirp
= opendir (dir
);
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. */
348 info
= extendbuf(info
,
349 (extra_used
+1) * sizeof(struct savedir_dirinfo
),
351 info
[extra_used
].type_info
= type_to_mode(dp
->d_type
);
358 name_space
= extendbuf(name_space
, namebuf_used
+1, &namebuf_allocated
);
359 name_space
[namebuf_used
] = '\0';
362 if (CLOSEDIR (dirp
) != 0)
371 #if defined HAVE_STRUCT_DIRENT_D_TYPE && defined USE_STRUCT_DIRENT_D_TYPE
382 savedirinfo (const char *dir
, struct savedir_extrainfo
**extra
)
384 return new_savedirinfo(dir
, extra
);