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