Whamcloud - gitweb
b=3359
[fs/lustre-release.git] / libsysio / src / getdirentries.c
1 /*
2  *    This Cplant(TM) source code is the property of Sandia National
3  *    Laboratories.
4  *
5  *    This Cplant(TM) source code is copyrighted by Sandia National
6  *    Laboratories.
7  *
8  *    The redistribution of this Cplant(TM) source code is subject to the
9  *    terms of the GNU Lesser General Public License
10  *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
11  *
12  *    Cplant(TM) Copyright 1998-2004 Sandia Corporation. 
13  *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
14  *    license for use of this work by or on behalf of the US Government.
15  *    Export of this program may require a license from the United States
16  *    Government.
17  */
18
19 /*
20  * #############################################################################
21  * #
22  * #     This Cplant(TM) source code is the property of Sandia National
23  * #     Laboratories.
24  * #
25  * #     This Cplant(TM) source code is copyrighted by Sandia National
26  * #     Laboratories.
27  * #
28  * #     The redistribution of this Cplant(TM) source code is subject to the
29  * #     terms of the GNU Lesser General Public License
30  * #     (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
31  * #
32  * #     Cplant(TM) Copyright 1998-2004 Sandia Corporation. 
33  * #     Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
34  * #     license for use of this work by or on behalf of the US Government.
35  * #     Export of this program may require a license from the United States
36  * #     Government.
37  * #
38  * #############################################################################
39  */
40
41 /*
42  * This library is free software; you can redistribute it and/or
43  * modify it under the terms of the GNU Lesser General Public
44  * License as published by the Free Software Foundation; either
45  * version 2.1 of the License, or (at your option) any later version.
46  * 
47  * This library is distributed in the hope that it will be useful,
48  * but WITHOUT ANY WARRANTY; without even the implied warranty of
49  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
50  * Lesser General Public License for more details.
51  * 
52  * You should have received a copy of the GNU Lesser General Public
53  * License along with this library; if not, write to the Free Software
54  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
55  *
56  * Questions or comments about this library should be sent to:
57  *
58  * Lee Ward
59  * Sandia National Laboratories, New Mexico
60  * P.O. Box 5800
61  * Albuquerque, NM 87185-1110
62  *
63  * lee@sandia.gov
64  */
65
66 #include <unistd.h>
67 #include <stdlib.h>
68 #ifdef __GLIBC__
69 #include <alloca.h>
70 #endif
71 #include <string.h>
72 #include <errno.h>
73 #include <sys/types.h>
74 #include <sys/stat.h>
75 #include <dirent.h>
76 #include <sys/queue.h>
77
78 #include "sysio.h"
79 #include "inode.h"
80 #include "file.h"
81 #include "sysio-symbols.h"
82
83 #ifndef __GNUC__
84 #define __restrict
85 #endif
86
87 static ssize_t
88 PREPEND(_, SYSIO_INTERFACE_NAME(getdirentries64))(int fd,
89                                                   char *buf,
90                                                   size_t nbytes,
91                                                   _SYSIO_OFF_T * __restrict
92                                                    basep)
93 {
94         struct file *fil;
95         ssize_t cc;
96         SYSIO_INTERFACE_DISPLAY_BLOCK;
97
98         SYSIO_INTERFACE_ENTER;
99
100         fil = _sysio_fd_find(fd);
101         if (!(fil && fil->f_ino))
102                 SYSIO_INTERFACE_RETURN(-1, -EBADF);
103
104         if (!S_ISDIR(fil->f_ino->i_stbuf.st_mode))
105                 SYSIO_INTERFACE_RETURN(-1, -ENOTDIR);
106
107         cc =
108             (*fil->f_ino->i_ops.inop_getdirentries)(fil->f_ino,
109                                                     buf,
110                                                     nbytes,
111                                                     basep);
112         SYSIO_INTERFACE_RETURN(cc < 0 ? -1 : cc, cc < 0 ? (int )cc : 0);
113 }
114
115 #if _LARGEFILE64_SOURCE
116 #undef getdirentries64
117 sysio_sym_strong_alias(PREPEND(_, SYSIO_INTERFACE_NAME(getdirentries64)),
118                        SYSIO_INTERFACE_NAME(getdirentries64))
119 #endif
120
121 #undef getdirentries
122
123 #ifndef DIRENT64_IS_NATURAL
124
125 #ifndef EOVERFLOW
126 #define EOVERFLOW       ERANGE
127 #endif
128
129 #ifdef _DIRENT_HAVE_D_NAMLEN
130 #define _namlen(dp)     ((dp)->d_namlen)
131 #else
132 #define _namlen(dp)     (strlen((dp)->d_name))
133 #endif
134
135 #ifndef _rndup
136 #define _rndup(n, boundary) \
137         ((((n) + (boundary) - 1 ) / (boundary)) * (boundary))
138 #endif
139
140 #ifndef BSD
141 ssize_t
142 SYSIO_INTERFACE_NAME(getdirentries)(int fd,
143                                     char *buf,
144                                     size_t nbytes,
145                                     off_t * __restrict basep)
146 #else
147 int
148 SYSIO_INTERFACE_NAME(getdirentries)(int fd,
149                                     char *buf,
150                                     int nbytes,
151                                     long * __restrict basep)
152 #endif
153 {
154         size_t inbytes;
155         void    *ibuf;
156         _SYSIO_OFF_T ibase;
157         ssize_t cc;
158         struct dirent *dp, *nxtdp;
159 #if defined(BSD)
160         int     off;
161 #endif
162         struct intnl_dirent *od64p, *d64p;
163         size_t  n;
164         size_t  reclen;
165         char    *cp;
166         SYSIO_INTERFACE_DISPLAY_BLOCK;
167
168 #define _dbaselen       ((size_t )&((struct dirent *)0)->d_name[0])
169
170 #ifdef __GLIBC__
171 #define _dreclen(namlen) \
172         ((_dbaselen + (namlen) + __alignof__ (struct dirent)) & \
173          ~(__alignof__ (struct dirent) - 1))
174 #else /* !defined(__GLIBC__) */
175 #define _dreclen(namlen) \
176         _rndup(_dbaselen + (namlen) + 1, sizeof(int))
177 #endif
178
179 #if defined(__GLIBC__)
180 #define _fast_alloc(n)  alloca(n)
181 #define _fast_free(p)
182 #else /* !defined(__GLIBC__) */
183 #define _fast_alloc(n)  malloc(n)
184 #define _fast_free(p)   free(p)
185 #endif
186
187         SYSIO_INTERFACE_ENTER;
188 #if defined(BSD)
189         if (nbytes < 0)
190                 SYSIO_INTERFACE_RETURN(-1, -EINVAL);
191 #endif
192
193         inbytes = nbytes;
194         if (inbytes > 8 * 1024) {
195                 /*
196                  * Limit stack use.
197                  */
198                 inbytes = 8 * 1024;
199         }
200         ibuf = _fast_alloc(inbytes);
201         if (!ibuf)
202                 SYSIO_INTERFACE_RETURN(-1, -ENOMEM);
203
204         dp = (struct dirent *)buf;
205
206         ibase = *basep;
207         cc =
208             PREPEND(_, SYSIO_INTERFACE_NAME(getdirentries64))(fd,
209                                             ibuf,
210                                             inbytes,
211                                             &ibase);
212         if (cc < 0) {
213                 cc = -errno;
214                 goto out;
215         }
216         *basep = (off_t )ibase;
217         if (sizeof(*basep) != sizeof(ibase) && *basep != ibase) {
218                 cc = -EOVERFLOW;
219                 goto out;
220         }
221
222 #if defined(BSD)
223         off = *basep;
224 #endif
225         od64p = NULL;
226         d64p = ibuf;
227         for (;;) {
228                 if (!cc)
229                         break;
230 #ifdef HAVE_D_NAMLEN
231                 n = d64p->d_namlen;
232 #else
233                 n = strlen(d64p->d_name);
234 #endif
235                 reclen = _dreclen(n);
236                 if (reclen >= (unsigned )nbytes)
237                         break;
238                 dp->d_ino = (ino_t )d64p->d_ino;
239 #if !(defined(BSD))
240                 dp->d_off = (off_t )d64p->d_off;
241 #endif
242                 if ((sizeof(dp->d_ino) != sizeof(d64p->d_ino) &&
243                      dp->d_ino != d64p->d_ino)
244                                 ||
245 #if !(defined(BSD))
246                     (sizeof(dp->d_off) != sizeof(d64p->d_off) &&
247                      dp->d_off != d64p->d_off)
248 #else
249                     (off + (int )reclen < off)
250 #endif
251                     ) {
252                         cc = -EOVERFLOW;
253                         break;
254                 }
255                 dp->d_type = d64p->d_type;
256                 dp->d_reclen = reclen;
257                 nxtdp = (struct dirent *)((char *)dp + dp->d_reclen);
258                 (void )memcpy(dp->d_name, d64p->d_name, n);
259                 for (cp = dp->d_name + n; cp < (char *)nxtdp; *cp++ = '\0')
260                         ;
261                 cc -= d64p->d_reclen;
262                 od64p = d64p;
263                 d64p = (struct dirent64 *)((char *)d64p + d64p->d_reclen);
264                 nbytes -= reclen;
265 #if defined(BSD)
266                 off += reclen;
267 #endif
268                 dp = nxtdp;
269         }
270
271 out:
272         _fast_free(ibuf);
273
274         if (dp == (struct dirent *)buf && cc < 0)
275                 SYSIO_INTERFACE_RETURN(-1, (int )cc);
276         cc = (char *)dp - buf;
277         if (cc)
278                 *basep =
279 #if !(defined(BSD))
280                     od64p->d_off;
281 #else
282                     off;
283 #endif
284         SYSIO_INTERFACE_RETURN(cc, 0);
285
286 #ifdef __GLIBC__
287 #undef _fast_alloc
288 #undef _fast_free
289 #endif
290 #undef _dreclen
291 #undef _dbaselen
292 }
293 #else /* !defined(DIRENT64_IS_NATURAL) */
294 sysio_sym_strong_alias(PREPEND(_, SYSIO_INTERFACE_NAME(getdirentries64),
295                        SYSIO_INTERFACE_NAME(getdirentries)))
296 #endif
297
298 #ifdef REDSTORM
299 #undef __getdirentries
300 sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(getdirentries),
301                      PREPEND(__, SYSIO_INTERFACE_NAME(getdirentries)))
302 #endif
303 #if defined(BSD) || defined(REDSTORM)
304 #undef _getdirentries
305 sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(getdirentries),
306                      PREPEND(_, SYSIO_INTERFACE_NAME(getdirentries)))
307 #endif