Merged the d_type optimisation code; this is disabled by default, and can be enabled...
[findutils.git] / lib / savedirinfo.c
blob6e9bb279d987ef7a222b87411f3ec066030fb0f1
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)
9 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, write to the Free Software Foundation,
18 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
20 /* Written by James Youngman, <jay@gnu.org>. */
21 /* Derived from savedir.c, written by David MacKenzie <djm@gnu.org>. */
23 #if HAVE_CONFIG_H
24 # include <config.h>
25 #endif
27 #if HAVE_SYS_STAT_H
28 # include <sys/stat.h>
29 #endif
31 #if HAVE_SYS_TYPES_H
32 # include <sys/types.h>
33 #endif
35 #if HAVE_UNISTD_H
36 # include <unistd.h>
37 #endif
39 #include <errno.h>
41 #if HAVE_DIRENT_H
42 # include <dirent.h>
43 #else
44 # define dirent direct
45 # if HAVE_SYS_NDIR_H
46 # include <sys/ndir.h>
47 # endif
48 # if HAVE_SYS_DIR_H
49 # include <sys/dir.h>
50 # endif
51 # if HAVE_NDIR_H
52 # include <ndir.h>
53 # endif
54 #endif
56 #ifdef CLOSEDIR_VOID
57 /* Fake a return value. */
58 # define CLOSEDIR(d) (closedir (d), 0)
59 #else
60 # define CLOSEDIR(d) closedir (d)
61 #endif
63 #include <stddef.h>
64 #include <stdlib.h>
65 #include <string.h>
67 #include "xalloc.h"
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
73 * 'struct dirent'.
75 #if !defined(USE_STRUCT_DIRENT_D_TYPE)
76 /* Not enabled, hence pretend it is absent. */
77 #undef HAVE_STRUCT_DIRENT_D_TYPE
78 #endif
79 #if !defined(HAVE_STRUCT_DIRENT_D_TYPE)
80 /* Not present, so cannot use it. */
81 #undef USE_STRUCT_DIRENT_D_TYPE
82 #endif
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.
90 static mode_t
91 type_to_mode(unsigned type)
93 mode_t result = 0;
95 switch (type)
97 #ifdef DT_FIFO
98 case DT_FIFO: return S_IFIFO;
99 #endif
100 #ifdef DT_CHR
101 case DT_CHR: return S_IFCHR;
102 #endif
103 #ifdef DT_DIR
104 case DT_DIR: return S_IFDIR;
105 #endif
106 #ifdef DT_BLK
107 case DT_BLK: return S_IFBLK;
108 #endif
109 #ifdef DT_REG
110 case DT_REG: return S_IFREG;
111 #endif
112 #ifdef DT_LNK
113 case DT_LNK: return S_IFLNK;
114 #endif
115 #ifdef DT_SOCK
116 case DT_SOCK: return S_IFSOCK;
117 #endif
118 default:
119 return 0; /* Unknown. */
123 #endif
126 /* Return a freshly allocated string containing the filenames
127 in directory DIR, separated by '\0' characters;
128 the end is marked by two '\0' characters in a row.
129 Return NULL (setting errno) if DIR cannot be opened, read, or closed. */
131 char *
132 savedirinfo (const char *dir, struct savedir_dirinfo **extra)
134 DIR *dirp;
135 struct dirent *dp;
136 char *name_space;
137 size_t namebuf_allocated = 0u, namebuf_used = 0u;
138 #if defined(HAVE_STRUCT_DIRENT_D_TYPE) && defined(USE_STRUCT_DIRENT_D_TYPE)
139 size_t extra_allocated = 0u, extra_used = 0u;
140 struct savedir_dirinfo *info = NULL;
141 #endif
142 int save_errno;
144 if (extra)
145 *extra = NULL;
147 dirp = opendir (dir);
148 if (dirp == NULL)
149 return NULL;
151 errno = 0;
152 name_space = NULL;
153 while ((dp = readdir (dirp)) != NULL)
155 /* Skip "", ".", and "..". "" is returned by at least one buggy
156 implementation: Solaris 2.4 readdir on NFS file systems. */
157 char const *entry = dp->d_name;
158 if (entry[entry[0] != '.' ? 0 : entry[1] != '.' ? 1 : 2] != '\0')
160 /* Remember the name. */
161 size_t entry_size = strlen (entry) + 1;
162 name_space = extendbuf(name_space, namebuf_used+entry_size, &namebuf_allocated);
163 memcpy (name_space + namebuf_used, entry, entry_size);
164 namebuf_used += entry_size;
167 #if defined(HAVE_STRUCT_DIRENT_D_TYPE) && defined(USE_STRUCT_DIRENT_D_TYPE)
168 /* Remember the type. */
169 if (extra)
171 info = extendbuf(info,
172 (extra_used+1) * sizeof(struct savedir_dirinfo),
173 &extra_allocated);
174 info[extra_used].type_info = type_to_mode(dp->d_type);
175 ++extra_used;
177 #endif
181 name_space = extendbuf(name_space, namebuf_used+1, &namebuf_allocated);
182 name_space[namebuf_used] = '\0';
184 save_errno = errno;
185 if (CLOSEDIR (dirp) != 0)
186 save_errno = errno;
187 if (save_errno != 0)
189 free (name_space);
190 errno = save_errno;
191 return NULL;
194 #if defined(HAVE_STRUCT_DIRENT_D_TYPE) && defined(USE_STRUCT_DIRENT_D_TYPE)
195 if (extra && info)
196 *extra = info;
197 #endif
199 return name_space;