Lines 33-40
Link Here
|
33 |
#include <sys/cdefs.h> |
33 |
#include <sys/cdefs.h> |
34 |
__FBSDID("$FreeBSD: src/lib/libc/gen/rewinddir.c,v 1.6 2007/01/09 00:27:55 imp Exp $"); |
34 |
__FBSDID("$FreeBSD: src/lib/libc/gen/rewinddir.c,v 1.6 2007/01/09 00:27:55 imp Exp $"); |
|
|
35 |
#include "namespace.h" |
35 |
#include <sys/types.h> |
36 |
#include <sys/types.h> |
|
|
37 |
#include <sys/param.h> |
38 |
#include <sys/mount.h> |
39 |
#include <errno.h> |
40 |
#include <fcntl.h> |
41 |
#include <unistd.h> |
36 |
#include <dirent.h> |
42 |
#include <dirent.h> |
|
|
43 |
#include <stdlib.h> |
44 |
#include <string.h> |
45 |
#include "un-namespace.h" |
37 |
#include "telldir.h" |
46 |
#include "telldir.h" |
Lines 42-48
Link Here
|
42 |
rewinddir(dirp) |
51 |
rewinddir(dirp) |
43 |
DIR *dirp; |
52 |
DIR *dirp; |
44 |
{ |
53 |
{ |
45 |
|
|
|
46 |
_seekdir(dirp, dirp->dd_rewind); |
54 |
_seekdir(dirp, dirp->dd_rewind); |
|
|
55 |
|
56 |
int incr; |
57 |
int unionstack; |
58 |
|
59 |
/* |
60 |
* Use the system page size if that is a multiple of DIRBLKSIZ. |
61 |
* Hopefully this can be a big win someday by allowing page |
62 |
* trades to user space to be done by _getdirentries(). |
63 |
*/ |
64 |
incr = getpagesize(); |
65 |
if ((incr % DIRBLKSIZ) != 0) |
66 |
incr = DIRBLKSIZ; |
67 |
|
68 |
/* |
69 |
* Determine whether this directory is the top of a union stack. |
70 |
*/ |
71 |
if (dirp->dd_flags & DTF_NODUP) { |
72 |
struct statfs sfb; |
73 |
|
74 |
if (_fstatfs(dirp->dd_fd, &sfb) < 0) |
75 |
goto fail; |
76 |
unionstack = !strcmp(sfb.f_fstypename, "unionfs") |
77 |
|| (sfb.f_flags & MNT_UNION); |
78 |
} else { |
79 |
unionstack = 0; |
80 |
} |
81 |
|
82 |
if (unionstack) { |
83 |
int len = dirp->dd_len; |
84 |
int space = dirp->dd_len; |
85 |
char *buf = dirp->dd_buf; |
86 |
char *ddptr = dirp->dd_buf; |
87 |
char *ddeptr; |
88 |
int n; |
89 |
struct dirent **dpv; |
90 |
|
91 |
if (lseek(dirp->dd_fd, 0, SEEK_SET) == -1) |
92 |
goto fail; |
93 |
dirp->dd_seek = 0; |
94 |
|
95 |
/* |
96 |
* The strategy here is to read all the directory |
97 |
* entries into a buffer, sort the buffer, and |
98 |
* remove duplicate entries by setting the inode |
99 |
* number to zero. |
100 |
*/ |
101 |
|
102 |
do { |
103 |
/* |
104 |
* Always make at least DIRBLKSIZ bytes |
105 |
* available to _getdirentries |
106 |
*/ |
107 |
if (space < DIRBLKSIZ) { |
108 |
space += incr; |
109 |
len += incr; |
110 |
buf = reallocf(buf, len); |
111 |
if (buf == NULL) |
112 |
goto fail; |
113 |
ddptr = buf + (len - space); |
114 |
} |
115 |
|
116 |
n = _getdirentries(dirp->dd_fd, ddptr, space, &dirp->dd_seek); |
117 |
if (n > 0) { |
118 |
ddptr += n; |
119 |
space -= n; |
120 |
} |
121 |
} while (n > 0); |
122 |
|
123 |
ddeptr = ddptr; |
124 |
dirp->dd_flags |= __DTF_READALL; |
125 |
|
126 |
/* |
127 |
* There is now a buffer full of (possibly) duplicate |
128 |
* names. |
129 |
*/ |
130 |
dirp->dd_buf = buf; |
131 |
|
132 |
/* |
133 |
* Go round this loop twice... |
134 |
* |
135 |
* Scan through the buffer, counting entries. |
136 |
* On the second pass, save pointers to each one. |
137 |
* Then sort the pointers and remove duplicate names. |
138 |
*/ |
139 |
for (dpv = 0;;) { |
140 |
n = 0; |
141 |
ddptr = buf; |
142 |
while (ddptr < ddeptr) { |
143 |
struct dirent *dp; |
144 |
|
145 |
dp = (struct dirent *) ddptr; |
146 |
if ((long)dp & 03L) |
147 |
break; |
148 |
if ((dp->d_reclen <= 0) || |
149 |
(dp->d_reclen > (ddeptr + 1 - ddptr))) |
150 |
break; |
151 |
ddptr += dp->d_reclen; |
152 |
if (dp->d_fileno) { |
153 |
if (dpv) |
154 |
dpv[n] = dp; |
155 |
n++; |
156 |
} |
157 |
} |
158 |
|
159 |
if (dpv) { |
160 |
struct dirent *xp; |
161 |
|
162 |
/* |
163 |
* This sort must be stable. |
164 |
*/ |
165 |
mergesort(dpv, n, sizeof(*dpv), alphasort); |
166 |
|
167 |
dpv[n] = NULL; |
168 |
xp = NULL; |
169 |
|
170 |
/* |
171 |
* Scan through the buffer in sort order, |
172 |
* zapping the inode number of any |
173 |
* duplicate names. |
174 |
*/ |
175 |
for (n = 0; dpv[n]; n++) { |
176 |
struct dirent *dp = dpv[n]; |
177 |
|
178 |
if ((xp == NULL) || |
179 |
strcmp(dp->d_name, xp->d_name)) { |
180 |
xp = dp; |
181 |
} else { |
182 |
dp->d_fileno = 0; |
183 |
} |
184 |
if (dp->d_type == DT_WHT && |
185 |
(dirp->dd_flags & DTF_HIDEW)) |
186 |
dp->d_fileno = 0; |
187 |
} |
188 |
|
189 |
free(dpv); |
190 |
break; |
191 |
} else { |
192 |
dpv = malloc((n+1) * sizeof(struct dirent *)); |
193 |
if (dpv == NULL) |
194 |
break; |
195 |
} |
196 |
} |
197 |
|
198 |
dirp->dd_len = len; |
199 |
dirp->dd_loc = 0; |
200 |
dirp->dd_size = ddptr - dirp->dd_buf; |
201 |
} |
202 |
|
203 |
/* |
204 |
* Silently ignore any errors |
205 |
*/ |
206 |
fail: |
47 |
dirp->dd_rewind = telldir(dirp); |
207 |
dirp->dd_rewind = telldir(dirp); |
48 |
} |
208 |
} |