1 /*
2 * Copyright (c) 2003 Gunnar Ritter
3 *
4 * This software is provided 'as-is', without any express or implied
5 * warranty. In no event will the authors be held liable for any damages
6 * arising from the use of this software.
7 *
8 * Permission is granted to anyone to use this software for any purpose,
9 * including commercial applications, and to alter it and redistribute
10 * it freely, subject to the following restrictions:
11 *
12 * 1. The origin of this software must not be misrepresented; you must not
13 * claim that you wrote the original software. If you use this software
14 * in a product, an acknowledgment in the product documentation would be
15 * appreciated but is not required.
16 *
17 * 2. Altered source versions must be plainly marked as such, and must not be
18 * misrepresented as being the original software.
19 *
20 * 3. This notice may not be removed or altered from any source distribution.
21 */
22 /* Sccsid @(#)getdir.c 1.20 (gritter) 5/14/06 */
23
24 #ifndef __linux__
25 /*
26 * 32-bit Solaris and Open UNIX do not have 64-bit getdents(); but
27 * having _FILE_OFFSET_BITS=64 will make it use a dirent64 struct
28 * on Open UNIX -> SEGV.
29 */
30 #undef _FILE_OFFSET_BITS
31 #endif /* !__linux__ */
32
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <stdlib.h>
36 #include <errno.h>
37 #include <string.h>
38
39 #if defined (__UCLIBC__)
40 #include <linux/types.h>
41 #include <linux/dirent.h>
42 #define getdents(a, b, c) __getdents64(a, b, c)
43 #define dirent dirent64
44 extern int getdents(int, struct dirent *, size_t);
45 #elif defined (__GLIBC__) || defined (__FreeBSD__) || defined (_AIX) || \
46 defined (__NetBSD__) || defined (__OpenBSD__) || \
47 defined (__DragonFly__) || defined (__APPLE__)
48 #include <dirent.h>
49 #define getdents(a, b, c) getdirentries((a), (char *)(b), (c), &(db->g_offs))
50 #if defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) || \
51 defined (__DragonFly__) || defined (__APPLE__)
52 #undef d_ino
53 #endif /* __FreeBSD__ || __NetBSD__ || __OpenBSD__ || __DragonFly__
54 || __APPLE__ */
55 #elif defined (__dietlibc__)
56 #include <dirent.h>
57 #include <unistd.h>
58 #else /* !__GLIBC__, !__dietlibc__ */
59 #ifdef __hpux
60 #define _KERNEL
61 #endif /* __hpux */
62 #include <sys/dirent.h>
63 #ifdef __hpux
64 #ifndef _INO64_T
65 typedef unsigned long long uint64_t;
66 typedef uint64_t ino64_t;
67 #endif /* !_INO64_T */
68 #ifdef __LP64__
69 #define dirent __dirent64
70 #else /* !__LP64__ */
71 #define dirent __dirent32
72 #endif /* !__LP64__ */
73 #define d_reclen __d_reclen
74 #define d_name __d_name
75 #define d_ino __d_ino
76 #endif /* __hpux */
77 #endif /* !__GLIBC__, !__dietlibc__ */
78
79 #include "getdir.h"
80
81 #define DIBSIZE 5120
82
83 struct getdb {
84 #if !defined (__FreeBSD__) && !defined (__NetBSD__) && !defined (__OpenBSD__) \
85 && !defined (__DragonFly__) && !defined (__APPLE__)
86 off_t g_offs;
87 #else /* __FreeBSD__, __NetBSD__, __OpenBSD__, __DragonFly__, __APPLE__ */
88 long g_offs;
89 #endif /* __FreeBSD__, __NetBSD__, __OpenBSD__, __DragonFly__, __APPLE__ */
90 struct dirent *g_dirp;
91 const char *g_path;
92 struct direc g_dic;
93 union {
94 char g_dirbuf[DIBSIZE+1];
95 struct dirent g_dummy[1];
96 } g_u;
97 int g_num;
98 int g_fd;
99 };
100
101 struct getdb *
getdb_alloc(const char * path,int fd)102 getdb_alloc(const char *path, int fd)
103 {
104 struct getdb *db;
105
106 if ((db = malloc(sizeof *db)) == NULL)
107 return NULL;
108 db->g_dirp = NULL;
109 db->g_offs = 0;
110 db->g_fd = fd;
111 db->g_path = path;
112 return db;
113 }
114
115 void
getdb_free(struct getdb * db)116 getdb_free(struct getdb *db)
117 {
118 free(db);
119 }
120
121 struct direc *
getdir(struct getdb * db,int * err)122 getdir(struct getdb *db, int *err)
123 {
124 int reclen;
125
126 *err = 0;
127 while (db->g_dirp == NULL)
128 {
129 /*LINTED*/
130 db->g_num = getdents(db->g_fd,
131 (struct dirent *)db->g_u.g_dirbuf,
132 DIBSIZE);
133 if (db->g_num <= 0) {
134 if (db->g_num < 0)
135 *err = errno;
136 db->g_offs = 0;
137 return NULL;
138 }
139 /*LINTED*/
140 db->g_dirp = (struct dirent *)db->g_u.g_dirbuf;
141 while (db->g_dirp &&
142 #if !defined (__FreeBSD__) && !defined (__NetBSD__) && !defined (__OpenBSD__) \
143 && !defined (__DragonFly__) && !defined (__APPLE__)
144 db->g_dirp->d_ino == 0
145 #else /* __FreeBSD__, __NetBSD__, __OpenBSD__, __DragonFly__, __APPLE__ */
146 (db->g_dirp->d_fileno == 0
147 #ifdef DT_WHT
148 || db->g_dirp->d_type == DT_WHT
149 #endif
150 )
151 #endif /* __FreeBSD__, __NetBSD__, __OpenBSD__, __DragonFly__, __APPLE__ */
152 )
153 {
154 next:
155 #ifndef __DragonFly__
156 reclen = db->g_dirp->d_reclen;
157 #else
158 reclen = _DIRENT_DIRSIZ(db->g_dirp);
159 #endif
160 if ((db->g_num -= reclen) == 0 || reclen == 0)
161 db->g_dirp = NULL;
162 else
163 db->g_dirp =
164 /*LINTED*/
165 (struct dirent *)((char *)db->g_dirp
166 + reclen);
167 }
168 }
169 #if !defined (__FreeBSD__) && !defined (__NetBSD__) && !defined (__OpenBSD__) \
170 && !defined (__DragonFly__) && !defined (__APPLE__)
171 if (db->g_dirp->d_ino == 0)
172 goto next;
173 db->g_dic.d_ino = db->g_dirp->d_ino;
174 #else /* __FreeBSD__, __NetBSD__, __OpenBSD__, __DragonFly__, __APPLE__ */
175 if (db->g_dirp->d_fileno == 0
176 #ifdef DT_WHT
177 || db->g_dirp->d_type == DT_WHT
178 #endif
179 )
180 {
181 goto next;
182 }
183 db->g_dic.d_ino = db->g_dirp->d_fileno;
184 #endif /* __FreeBSD__, __NetBSD__, __OpenBSD__, __DragonFly__, __APPLE__ */
185 db->g_dic.d_name = db->g_dirp->d_name;
186 #ifndef __DragonFly__
187 reclen = db->g_dirp->d_reclen;
188 #else
189 reclen = _DIRENT_DIRSIZ(db->g_dirp);
190 #endif
191 if ((db->g_num -= reclen) == 0 || reclen == 0)
192 db->g_dirp = NULL;
193 else
194 /*LINTED*/
195 db->g_dirp = (struct dirent *)((char *)db->g_dirp + reclen);
196 return &(db->g_dic);
197 }
198