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 3 of the License, or
9 (at your option) 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, see <http://www.gnu.org/licenses/>.
19 /* Written by James Youngman, <jay@gnu.org>. */
20 /* Derived from savedir.c, written by David MacKenzie <djm@gnu.org>. */
25 # include <sys/stat.h>
29 # include <sys/types.h>
32 /* The presence of unistd.h is assumed by gnulib these days, so we
33 * might as well assume it too.
42 # define dirent direct
44 # include <sys/ndir.h>
55 /* Fake a return value. */
56 # define CLOSEDIR(d) (closedir (d), 0)
58 # define CLOSEDIR(d) closedir (d)
66 #include "extendbuf.h"
67 #include "savedirinfo.h"
69 /* In order to use struct dirent.d_type, it has to be enabled on the
70 * configure command line, and we have to have a d_type member in
73 #if !defined(USE_STRUCT_DIRENT_D_TYPE)
74 /* Not enabled, hence pretend it is absent. */
75 #undef HAVE_STRUCT_DIRENT_D_TYPE
77 #if !defined(HAVE_STRUCT_DIRENT_D_TYPE)
78 /* Not present, so cannot use it. */
79 #undef USE_STRUCT_DIRENT_D_TYPE
83 #if defined HAVE_STRUCT_DIRENT_D_TYPE && defined USE_STRUCT_DIRENT_D_TYPE
84 /* Convert the value of struct dirent.d_type into a value for
85 * struct stat.st_mode (at least the file type bits), or zero
86 * if the type is DT_UNKNOWN or is a value we don't know about.
89 type_to_mode(unsigned type
)
94 case DT_FIFO
: return S_IFIFO
;
97 case DT_CHR
: return S_IFCHR
;
100 case DT_DIR
: return S_IFDIR
;
103 case DT_BLK
: return S_IFBLK
;
106 case DT_REG
: return S_IFREG
;
109 case DT_LNK
: return S_IFLNK
;
112 case DT_SOCK
: return S_IFSOCK
;
115 return 0; /* Unknown. */
121 struct new_savedir_direntry_internal
123 int flags
; /* from SaveDirDataFlags */
125 size_t buffer_offset
;
131 savedir_cmp(const void *p1
, const void *p2
)
133 const struct savedir_direntry
*de1
, *de2
;
136 return strcmp(de1
->name
, de2
->name
); /* POSIX order, not locale order. */
140 static struct savedir_direntry
*
141 convertentries(const struct savedir_dirinfo
*info
,
142 struct new_savedir_direntry_internal
*internal
)
144 char *p
= info
->buffer
;
145 struct savedir_direntry
*result
;
150 result
= xmalloc(sizeof(*result
) * info
->size
);
154 result
[i
].flags
= internal
[i
].flags
;
155 result
[i
].type_info
= internal
[i
].type_info
;
156 result
[i
].name
= &p
[internal
[i
].buffer_offset
];
162 struct savedir_dirinfo
*
163 xsavedir(const char *dir
, int flags
)
167 struct savedir_dirinfo
*result
= NULL
;
168 struct new_savedir_direntry_internal
*internal
;
170 size_t namebuf_allocated
= 0u, namebuf_used
= 0u;
171 size_t entrybuf_allocated
= 0u;
174 dirp
= opendir (dir
);
179 result
= xmalloc(sizeof(*result
));
180 result
->buffer
= NULL
;
182 result
->entries
= NULL
;
185 while ((dp
= readdir (dirp
)) != NULL
)
187 /* Skip "", ".", and "..". "" is returned by at least one buggy
188 implementation: Solaris 2.4 readdir on NFS file systems. */
189 char const *entry
= dp
->d_name
;
190 if (entry
[entry
[0] != '.' ? 0 : entry
[1] != '.' ? 1 : 2] != '\0')
192 /* Remember the name. */
193 size_t entry_size
= strlen (entry
) + 1;
194 result
->buffer
= extendbuf(result
->buffer
, namebuf_used
+entry_size
, &namebuf_allocated
);
195 memcpy ((result
->buffer
) + namebuf_used
, entry
, entry_size
);
197 /* Remember the other stuff. */
198 internal
= extendbuf(internal
, (1+result
->size
)*sizeof(*internal
), &entrybuf_allocated
);
199 internal
[result
->size
].flags
= 0;
201 #if defined HAVE_STRUCT_DIRENT_D_TYPE && defined USE_STRUCT_DIRENT_D_TYPE
202 internal
[result
->size
].type_info
= type_to_mode(dp
->d_type
);
203 if (dp
->d_type
!= DT_UNKNOWN
)
204 internal
[result
->size
].flags
|= SavedirHaveFileType
;
206 internal
[result
->size
].type_info
= 0;
208 internal
[result
->size
].buffer_offset
= namebuf_used
;
210 /* Prepare for the next iteration */
212 namebuf_used
+= entry_size
;
216 result
->buffer
= extendbuf(result
->buffer
, namebuf_used
+1, &namebuf_allocated
);
217 result
->buffer
[namebuf_used
] = '\0';
219 /* convert the result to its externally-usable form. */
220 result
->entries
= convertentries(result
, internal
);
225 if (flags
& SavedirSort
)
227 qsort(result
->entries
,
228 result
->size
, sizeof(*result
->entries
),
234 if (CLOSEDIR (dirp
) != 0)
238 free (result
->buffer
);
247 void free_dirinfo(struct savedir_dirinfo
*p
)
259 new_savedirinfo (const char *dir
, struct savedir_extrainfo
**extra
)
261 struct savedir_dirinfo
*p
= xsavedir(dir
, SavedirSort
);
268 struct savedir_extrainfo
*pex
= xmalloc(p
->size
* sizeof(*extra
));
269 for (i
=0; i
<p
->size
; ++i
)
271 bufbytes
+= strlen(p
->entries
[i
].name
);
272 ++bufbytes
; /* the \0 */
274 pex
[i
].type_info
= p
->entries
[i
].type_info
;
277 s
= buf
= xmalloc(bufbytes
+1);
278 for (i
=0; i
<p
->size
; ++i
)
280 size_t len
= strlen(p
->entries
[i
].name
);
281 memcpy(s
, p
->entries
[i
].name
, len
);
283 *s
= 0; /* Place a NUL */
284 ++s
; /* Skip the NUL. */
286 *s
= 0; /* final (doubled) terminating NUL */
302 /* Return a freshly allocated string containing the filenames
303 in directory DIR, separated by '\0' characters;
304 the end is marked by two '\0' characters in a row.
305 Return NULL (setting errno) if DIR cannot be opened, read, or closed. */
308 old_savedirinfo (const char *dir
, struct savedir_extrainfo
**extra
)
313 size_t namebuf_allocated
= 0u, namebuf_used
= 0u;
314 #if defined HAVE_STRUCT_DIRENT_D_TYPE && defined USE_STRUCT_DIRENT_D_TYPE
315 size_t extra_allocated
= 0u, extra_used
= 0u;
316 struct savedir_extrainfo
*info
= NULL
;
323 dirp
= opendir (dir
);
329 while ((dp
= readdir (dirp
)) != NULL
)
331 /* Skip "", ".", and "..". "" is returned by at least one buggy
332 implementation: Solaris 2.4 readdir on NFS file systems. */
333 char const *entry
= dp
->d_name
;
334 if (entry
[entry
[0] != '.' ? 0 : entry
[1] != '.' ? 1 : 2] != '\0')
336 /* Remember the name. */
337 size_t entry_size
= strlen (entry
) + 1;
338 name_space
= extendbuf(name_space
, namebuf_used
+entry_size
, &namebuf_allocated
);
339 memcpy (name_space
+ namebuf_used
, entry
, entry_size
);
340 namebuf_used
+= entry_size
;
343 #if defined HAVE_STRUCT_DIRENT_D_TYPE && defined USE_STRUCT_DIRENT_D_TYPE
344 /* Remember the type. */
347 info
= extendbuf(info
,
348 (extra_used
+1) * sizeof(struct savedir_dirinfo
),
350 info
[extra_used
].type_info
= type_to_mode(dp
->d_type
);
357 name_space
= extendbuf(name_space
, namebuf_used
+1, &namebuf_allocated
);
358 name_space
[namebuf_used
] = '\0';
361 if (CLOSEDIR (dirp
) != 0)
370 #if defined HAVE_STRUCT_DIRENT_D_TYPE && defined USE_STRUCT_DIRENT_D_TYPE
381 savedirinfo (const char *dir
, struct savedir_extrainfo
**extra
)
383 return new_savedirinfo(dir
, extra
);