1 /* savedirinfo.c -- Save the list of files in a directory, with additional information.
3 Copyright 1990, 1997, 1998, 1999, 2000, 2001, 2003, 2004,
4 2005, 2010 Free 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>. */
27 # include <sys/types.h>
30 /* The presence of unistd.h is assumed by gnulib these days, so we
31 * might as well assume it too.
40 # define dirent direct
42 # include <sys/ndir.h>
53 /* Fake a return value. */
54 # define CLOSEDIR(d) (closedir (d), 0)
56 # define CLOSEDIR(d) closedir (d)
64 #include "extendbuf.h"
65 #include "dirent-safer.h"
66 #include "savedirinfo.h"
68 #if defined HAVE_STRUCT_DIRENT_D_TYPE
69 /* Convert the value of struct dirent.d_type into a value for
70 * struct stat.st_mode (at least the file type bits), or zero
71 * if the type is DT_UNKNOWN or is a value we don't know about.
74 type_to_mode (unsigned type)
79 case DT_FIFO: return S_IFIFO;
82 case DT_CHR: return S_IFCHR;
85 case DT_DIR: return S_IFDIR;
88 case DT_BLK: return S_IFBLK;
91 case DT_REG: return S_IFREG;
94 case DT_LNK: return S_IFLNK;
97 case DT_SOCK: return S_IFSOCK;
100 return 0; /* Unknown. */
105 struct new_savedir_direntry_internal
107 int flags; /* from SaveDirDataFlags */
109 size_t buffer_offset;
115 savedir_cmp (const void *p1, const void *p2)
117 const struct savedir_direntry *de1, *de2;
120 return strcmp (de1->name, de2->name); /* POSIX order, not locale order. */
124 static struct savedir_direntry*
125 convertentries (const struct savedir_dirinfo *info,
126 struct new_savedir_direntry_internal *internal)
128 char *p = info->buffer;
129 struct savedir_direntry *result;
134 result = xmalloc (sizeof (*result) * info->size);
138 result[i].flags = internal[i].flags;
139 result[i].type_info = internal[i].type_info;
140 result[i].name = &p[internal[i].buffer_offset];
146 struct savedir_dirinfo *
147 xsavedir (const char *dir, int flags)
151 struct savedir_dirinfo *result = NULL;
152 struct new_savedir_direntry_internal *internal;
154 size_t namebuf_allocated = 0u, namebuf_used = 0u;
155 size_t entrybuf_allocated = 0u;
158 dirp = opendir_safer (dir);
163 result = xmalloc (sizeof (*result));
164 result->buffer = NULL;
166 result->entries = NULL;
169 while ((dp = readdir (dirp)) != NULL)
171 /* Skip "", ".", and "..". "" is returned by at least one buggy
172 implementation: Solaris 2.4 readdir on NFS file systems. */
173 char const *entry = dp->d_name;
174 if (entry[entry[0] != '.' ? 0 : entry[1] != '.' ? 1 : 2] != '\0')
176 /* Remember the name. */
177 size_t entry_size = strlen (entry) + 1;
178 result->buffer = xextendbuf (result->buffer, namebuf_used+entry_size, &namebuf_allocated);
179 memcpy ((result->buffer) + namebuf_used, entry, entry_size);
181 /* Remember the other stuff. */
182 internal = xextendbuf (internal, (1+result->size)*sizeof (*internal), &entrybuf_allocated);
183 internal[result->size].flags = 0;
185 internal[result->size].type_info = 0;
186 #if defined HAVE_STRUCT_DIRENT_D_TYPE
187 internal[result->size].type_info = type_to_mode (dp->d_type);
188 if (dp->d_type != DT_UNKNOWN)
189 internal[result->size].flags |= SavedirHaveFileType;
191 internal[result->size].buffer_offset = namebuf_used;
193 /* Prepare for the next iteration */
195 namebuf_used += entry_size;
199 result->buffer = xextendbuf (result->buffer, namebuf_used+1, &namebuf_allocated);
200 result->buffer[namebuf_used] = '\0';
202 /* convert the result to its externally-usable form. */
203 result->entries = convertentries (result, internal);
208 if (flags & SavedirSort)
210 qsort (result->entries,
211 result->size, sizeof (*result->entries),
217 if (CLOSEDIR (dirp) != 0)
221 free (result->buffer);
230 void free_dirinfo (struct savedir_dirinfo *p)
242 savedirinfo (const char *dir, struct savedir_extrainfo **extra)
244 struct savedir_dirinfo *p = xsavedir (dir, SavedirSort);
251 struct savedir_extrainfo *pex = xmalloc (p->size * sizeof (*extra));
252 for (i=0; i<p->size; ++i)
254 bufbytes += strlen (p->entries[i].name);
255 ++bufbytes; /* the \0 */
257 pex[i].type_info = p->entries[i].type_info;
260 s = buf = xmalloc (bufbytes+1);
261 for (i=0; i<p->size; ++i)
263 size_t len = strlen (p->entries[i].name);
264 memcpy (s, p->entries[i].name, len);
266 *s = 0; /* Place a NUL */
267 ++s; /* Skip the NUL. */
269 *s = 0; /* final (doubled) terminating NUL */