Whamcloud - gitweb
b=10466
[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 filldirents(struct file *fil,
89             char *buf, size_t nbytes,
90             _SYSIO_OFF_T *__restrict basep)
91 {
92         _SYSIO_OFF_T opos;
93         ssize_t cc;
94
95         if (!S_ISDIR(fil->f_ino->i_stbuf.st_mode))
96                 return -ENOTDIR;
97
98         opos = fil->f_pos;
99         cc =
100             (*fil->f_ino->i_ops.inop_filldirentries)(fil->f_ino,
101                                                      &fil->f_pos,
102                                                      buf, nbytes);
103         if (cc < 0)
104                 return cc;
105         *basep = opos;
106         return cc;
107 }
108
109 static ssize_t
110 PREPEND(_, SYSIO_INTERFACE_NAME(getdirentries64))(int fd,
111                                                   char *buf,
112                                                   size_t nbytes,
113                                                   _SYSIO_OFF_T * __restrict
114                                                    basep)
115 {
116         struct file *fil;
117         ssize_t cc;
118         SYSIO_INTERFACE_DISPLAY_BLOCK;
119
120         SYSIO_INTERFACE_ENTER;
121
122         fil = _sysio_fd_find(fd);
123         if (!(fil && fil->f_ino))
124                 return -EBADF;
125
126         cc = filldirents(fil, buf, nbytes, basep);
127         SYSIO_INTERFACE_RETURN(cc < 0 ? -1 : cc, cc < 0 ? (int )cc : 0);
128 }
129
130 #if _LARGEFILE64_SOURCE
131 #undef getdirentries64
132 sysio_sym_strong_alias(PREPEND(_, SYSIO_INTERFACE_NAME(getdirentries64)),
133                        SYSIO_INTERFACE_NAME(getdirentries64))
134 #endif
135
136 #undef getdirentries
137
138 #ifndef DIRENT64_IS_NATURAL
139
140 #ifndef EOVERFLOW
141 #define EOVERFLOW       ERANGE
142 #endif
143
144 #ifdef _DIRENT_HAVE_D_NAMLEN
145 #define _namlen(dp)     ((dp)->d_namlen)
146 #else
147 #define _namlen(dp)     (strlen((dp)->d_name))
148 #endif
149
150 #ifndef _rndup
151 #define _rndup(n, boundary) \
152         ((((n) + (boundary) - 1 ) / (boundary)) * (boundary))
153 #endif
154
155 #define _dbaselen       ((size_t )&((struct dirent *)0)->d_name[0])
156
157 #ifdef __GLIBC__
158 #define _dreclen(namlen) \
159         ((_dbaselen + (namlen) + __alignof__ (struct dirent)) & \
160          ~(__alignof__ (struct dirent) - 1))
161 #else /* !defined(__GLIBC__) */
162 #define _dreclen(namlen) \
163         _rndup(_dbaselen + (namlen) + 1, sizeof(int))
164 #endif
165
166 #ifndef BSD
167 ssize_t
168 SYSIO_INTERFACE_NAME(getdirentries)(int fd,
169                                     char *buf,
170                                     size_t nbytes,
171                                     off_t * __restrict basep)
172 #else
173 int
174 SYSIO_INTERFACE_NAME(getdirentries)(int fd,
175                                     char *buf,
176                                     int nbytes,
177                                     long * __restrict basep)
178 #endif
179 {
180         struct file *fil;
181         _SYSIO_OFF_T b;
182         ssize_t cc, count;
183         struct dirent64 *d64p, d64;
184         struct dirent *dp;
185         size_t  n, reclen;
186         void    *p;
187         char    *cp;
188         SYSIO_INTERFACE_DISPLAY_BLOCK;
189
190         SYSIO_INTERFACE_ENTER;
191
192         fil = _sysio_fd_find(fd);
193         if (!(fil && fil->f_ino))
194                 return -EBADF;
195
196         count = cc = filldirents(fil, buf, nbytes, &b);
197         d64p = (void *)buf;
198         dp = (void *)buf;
199         reclen = 0;
200         while (cc > 0) {
201                 n = _namlen(d64p);
202                 reclen = _dreclen(n);
203                 d64.d_ino = d64p->d_ino;
204                 d64.d_off = d64p->d_off;
205                 d64.d_type = d64p->d_type;
206                 d64.d_reclen = d64p->d_reclen;
207                 /*
208                  * Copy name first.
209                  */
210                 (void )memcpy(dp->d_name, d64p->d_name, n);
211                 /*
212                  * Then, the rest.
213                  */
214                 dp->d_ino = d64.d_ino;
215                 dp->d_off = d64.d_off;
216                 if (dp->d_ino != d64.d_ino ||
217                     dp->d_off != d64.d_off) {
218                         /*
219                          * If conversion failure then we are done.
220                          */
221                         if (cc == count) {
222                                 /*
223                                  * Couldn't process any entries. We return
224                                  * the error now.
225                                  */
226                                 cc = - EOVERFLOW;
227                         }
228                         break;
229                 }
230                 fil->f_pos = dp->d_off;
231                 dp->d_type = d64.d_type;
232                 dp->d_reclen = reclen;
233                 /*
234                  * Fill the remainder with zeros.
235                  */
236                 p = (char *)dp + dp->d_reclen;
237 #ifdef HAVE_D_NAMLEN
238                 dp->d_namlen = n;
239 #endif
240                 cp = dp->d_name + n;
241                 do {
242                         *cp++ = 0;
243                 } while (cp < (char *)p);
244                 /*
245                  * Advance.
246                  */
247                 dp = p;
248                 cc -= d64.d_reclen;
249                 d64p = (struct dirent64 *)((char *)d64p + d64.d_reclen);
250         }
251
252         if (cc < 0)
253                 SYSIO_INTERFACE_RETURN(-1, cc);
254         cc = (char *)dp - buf;
255         *basep = b;
256         SYSIO_INTERFACE_RETURN(cc, 0);
257 }
258 #else /* !defined(DIRENT64_IS_NATURAL) */
259 sysio_sym_strong_alias(PREPEND(_, SYSIO_INTERFACE_NAME(getdirentries64),
260                        SYSIO_INTERFACE_NAME(getdirentries)))
261 #endif
262
263 #ifdef REDSTORM
264 #undef __getdirentries
265 sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(getdirentries),
266                      PREPEND(__, SYSIO_INTERFACE_NAME(getdirentries)))
267 #endif
268 #if defined(BSD) || defined(REDSTORM)
269 #undef _getdirentries
270 sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(getdirentries),
271                      PREPEND(_, SYSIO_INTERFACE_NAME(getdirentries)))
272 #endif