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>
44 # define dirent direct
46 # include <sys/ndir.h>
57 /* Fake a return value. */
58 # define CLOSEDIR(d) (closedir (d), 0)
60 # define CLOSEDIR(d) closedir (d)
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
75 #if !defined(USE_STRUCT_DIRENT_D_TYPE)
76 /* Not enabled, hence pretend it is absent. */
77 #undef HAVE_STRUCT_DIRENT_D_TYPE
79 #if !defined(HAVE_STRUCT_DIRENT_D_TYPE)
80 /* Not present, so cannot use it. */
81 #undef USE_STRUCT_DIRENT_D_TYPE
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.
91 type_to_mode(unsigned type
)
96 case DT_FIFO
: return S_IFIFO
;
99 case DT_CHR
: return S_IFCHR
;
102 case DT_DIR
: return S_IFDIR
;
105 case DT_BLK
: return S_IFBLK
;
108 case DT_REG
: return S_IFREG
;
111 case DT_LNK
: return S_IFLNK
;
114 case DT_SOCK
: return S_IFSOCK
;
117 return 0; /* Unknown. */
123 struct new_savedir_direntry_internal
125 int flags
; /* from SaveDirDataFlags */
127 size_t buffer_offset
;
133 savedir_cmp(const void *p1
, const void *p2
)
135 const struct savedir_direntry
*de1
, *de2
;
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
;
152 result
= xmalloc(sizeof(*result
) * info
->size
);
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
];
164 struct savedir_dirinfo
*
165 xsavedir(const char *dir
, int flags
)
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;
176 dirp
= opendir (dir
);
181 result
= xmalloc(sizeof(*result
));
182 result
->buffer
= NULL
;
184 result
->entries
= 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
;
208 internal
[result
->size
].type_info
= 0;
210 internal
[result
->size
].buffer_offset
= namebuf_used
;
212 /* Prepare for the next iteration */
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
);
227 if (flags
& SavedirSort
)
229 qsort(result
->entries
,
230 result
->size
, sizeof(*result
->entries
),
236 if (CLOSEDIR (dirp
) != 0)
240 free (result
->buffer
);
249 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 */
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. */
305 old_savedirinfo (const char *dir
, struct savedir_extrainfo
**extra
)
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
;
320 dirp
= opendir (dir
);
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. */
344 info
= extendbuf(info
,
345 (extra_used
+1) * sizeof(struct savedir_dirinfo
),
347 info
[extra_used
].type_info
= type_to_mode(dp
->d_type
);
354 name_space
= extendbuf(name_space
, namebuf_used
+1, &namebuf_allocated
);
355 name_space
[namebuf_used
] = '\0';
358 if (CLOSEDIR (dirp
) != 0)
367 #if defined(HAVE_STRUCT_DIRENT_D_TYPE) && defined(USE_STRUCT_DIRENT_D_TYPE)
378 savedirinfo (const char *dir
, struct savedir_extrainfo
**extra
)
380 return new_savedirinfo(dir
, extra
);