Whamcloud - gitweb
Branch b1_4
[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  * This library is free software; you can redistribute it and/or
21  * modify it under the terms of the GNU Lesser General Public
22  * License as published by the Free Software Foundation; either
23  * version 2.1 of the License, or (at your option) any later version.
24  * 
25  * This library is distributed in the hope that it will be useful,
26  * but WITHOUT ANY WARRANTY; without even the implied warranty of
27  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
28  * Lesser General Public License for more details.
29  * 
30  * You should have received a copy of the GNU Lesser General Public
31  * License along with this library; if not, write to the Free Software
32  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
33  *
34  * Questions or comments about this library should be sent to:
35  *
36  * Lee Ward
37  * Sandia National Laboratories, New Mexico
38  * P.O. Box 5800
39  * Albuquerque, NM 87185-1110
40  *
41  * lee@sandia.gov
42  */
43
44 #include <unistd.h>
45 #include <stdlib.h>
46 #ifdef __GLIBC__
47 #include <alloca.h>
48 #endif
49 #include <string.h>
50 #include <errno.h>
51 #include <sys/types.h>
52 #include <sys/stat.h>
53 #include <dirent.h>
54 #include <sys/queue.h>
55
56 #include "sysio.h"
57 #include "inode.h"
58 #include "file.h"
59 #include "sysio-symbols.h"
60
61 #ifndef __GNUC__
62 #define __restrict
63 #endif
64
65 static ssize_t
66 filldirents(struct file *fil,
67             char *buf, size_t nbytes,
68             _SYSIO_OFF_T *__restrict basep)
69 {
70         _SYSIO_OFF_T opos;
71         ssize_t cc;
72
73         if (!S_ISDIR(fil->f_ino->i_stbuf.st_mode))
74                 return -ENOTDIR;
75
76         opos = fil->f_pos;
77         cc =
78             (*fil->f_ino->i_ops.inop_filldirentries)(fil->f_ino,
79                                                      &fil->f_pos,
80                                                      buf, nbytes);
81         if (cc < 0)
82                 return cc;
83         *basep = opos;
84         return cc;
85 }
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
105         cc = filldirents(fil, buf, nbytes, basep);
106         SYSIO_INTERFACE_RETURN(cc < 0 ? -1 : cc, cc < 0 ? (int )cc : 0);
107 }
108
109 #ifdef _LARGEFILE64_SOURCE
110 #undef getdirentries64
111 sysio_sym_strong_alias(PREPEND(_, SYSIO_INTERFACE_NAME(getdirentries64)),
112                        SYSIO_INTERFACE_NAME(getdirentries64))
113 #endif
114
115 #undef getdirentries
116
117 #ifndef DIRENT64_IS_NATURAL
118
119 #ifndef EOVERFLOW
120 #define EOVERFLOW       ERANGE
121 #endif
122
123 #ifdef _DIRENT_HAVE_D_NAMLEN
124 #define _namlen(dp)     ((dp)->d_namlen)
125 #else
126 #define _namlen(dp)     (strlen((dp)->d_name))
127 #endif
128
129 #ifndef _rndup
130 #define _rndup(n, boundary) \
131         ((((n) + (boundary) - 1 ) / (boundary)) * (boundary))
132 #endif
133
134 #define _dbaselen       ((size_t )&((struct dirent *)0)->d_name[0])
135
136 #ifdef __GLIBC__
137 #define _dreclen(namlen) \
138         ((_dbaselen + (namlen) + __alignof__ (struct dirent)) & \
139          ~(__alignof__ (struct dirent) - 1))
140 #else /* !defined(__GLIBC__) */
141 #define _dreclen(namlen) \
142         _rndup(_dbaselen + (namlen) + 1, sizeof(int))
143 #endif
144
145 #ifndef BSD
146 ssize_t
147 SYSIO_INTERFACE_NAME(getdirentries)(int fd,
148                                     char *buf,
149                                     size_t nbytes,
150                                     off_t * __restrict basep)
151 #else
152 int
153 SYSIO_INTERFACE_NAME(getdirentries)(int fd,
154                                     char *buf,
155                                     int nbytes,
156                                     long * __restrict basep)
157 #endif
158 {
159         struct file *fil;
160         _SYSIO_OFF_T b;
161         ssize_t cc, count;
162         struct dirent64 *d64p, d64;
163         struct dirent *dp;
164         size_t  n, reclen;
165         void    *p;
166         char    *cp;
167         SYSIO_INTERFACE_DISPLAY_BLOCK;
168
169         SYSIO_INTERFACE_ENTER;
170
171         fil = _sysio_fd_find(fd);
172         if (!(fil && fil->f_ino)) {
173                 SYSIO_INTERFACE_RETURN(-1, -EBADF);
174         }
175
176         count = cc = filldirents(fil, buf, nbytes, &b);
177         d64p = (void *)buf;
178         dp = (void *)buf;
179         reclen = 0;
180         while (cc > 0) {
181                 n = _namlen(d64p);
182                 reclen = _dreclen(n);
183                 d64.d_ino = d64p->d_ino;
184                 d64.d_off = d64p->d_off;
185                 d64.d_type = d64p->d_type;
186                 d64.d_reclen = d64p->d_reclen;
187                 /*
188                  * Copy name first.
189                  */
190                 (void )memcpy(dp->d_name, d64p->d_name, n);
191                 /*
192                  * Then, the rest.
193                  */
194                 dp->d_ino = d64.d_ino;
195                 dp->d_off = d64.d_off;
196                 if (dp->d_ino != d64.d_ino ||
197                     dp->d_off != d64.d_off) {
198                         /*
199                          * If conversion failure then we are done.
200                          */
201                         if (cc == count) {
202                                 /*
203                                  * Couldn't process any entries. We return
204                                  * the error now.
205                                  */
206                                 cc = - EOVERFLOW;
207                         }
208                         break;
209                 }
210                 fil->f_pos = dp->d_off;
211                 dp->d_type = d64.d_type;
212                 dp->d_reclen = reclen;
213                 /*
214                  * Fill the remainder with zeros.
215                  */
216                 p = (char *)dp + dp->d_reclen;
217 #ifdef HAVE_D_NAMLEN
218                 dp->d_namlen = n;
219 #endif
220                 cp = dp->d_name + n;
221                 do {
222                         *cp++ = 0;
223                 } while (cp < (char *)p);
224                 /*
225                  * Advance.
226                  */
227                 dp = p;
228                 cc -= d64.d_reclen;
229                 d64p = (struct dirent64 *)((char *)d64p + d64.d_reclen);
230         }
231
232         if (cc < 0)
233                 SYSIO_INTERFACE_RETURN(-1, cc);
234         cc = (char *)dp - buf;
235         *basep = b;
236         SYSIO_INTERFACE_RETURN(cc, 0);
237 }
238 #else /* !defined(DIRENT64_IS_NATURAL) */
239 sysio_sym_strong_alias(PREPEND(_, SYSIO_INTERFACE_NAME(getdirentries64),
240                        SYSIO_INTERFACE_NAME(getdirentries)))
241 #endif
242
243 #ifdef REDSTORM
244 #undef __getdirentries
245 sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(getdirentries),
246                      PREPEND(__, SYSIO_INTERFACE_NAME(getdirentries)))
247 #endif
248 #if defined(BSD) || defined(REDSTORM)
249 #undef _getdirentries
250 sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(getdirentries),
251                      PREPEND(_, SYSIO_INTERFACE_NAME(getdirentries)))
252 #endif