* Copyright (c) 1983, 1993, 1994
* The Regents of the University of California. All rights reserved.
* %sccs.include.redist.c%
#if defined(LIBC_SCCS) && !defined(lint)
static char orig_sccsid
[] = "@(#)opendir.c 8.2 (Berkeley) 2/12/94";
static char sccsid
[] = "@(#)libc.opendir.c 8.1 (Berkeley) %G%";
#endif /* LIBC_SCCS and not lint */
if ((fd
= open(name
, 0)) == -1)
if (fcntl(fd
, F_SETFD
, FD_CLOEXEC
) == -1 ||
(dirp
= (DIR *)malloc(sizeof(DIR))) == NULL
) {
* If CLBYTES is an exact multiple of DIRBLKSIZ, use a CLBYTES
* buffer that it cluster boundary aligned.
* Hopefully this can be a big win someday by allowing page
* trades trade to user space to be done by getdirentries()
if ((CLBYTES
% DIRBLKSIZ
) == 0)
* Determine whether this directory is the top of a union stack.
if (fstatfs(fd
, &sfb
) < 0) {
if (sfb
.f_type
== MOUNT_UNION
) {
* The strategy here is to read all the directory
* entries into a buffer, sort the buffer, and
* remove duplicate entries by setting the inode
* Fixup dd_loc to be non-zero to fake out readdir
dirp
->dd_loc
= sizeof(void *);
* Always make at least DIRBLKSIZ bytes
* available to getdirentries
ddptr
= buf
+ (len
- space
) + dirp
->dd_loc
;
n
= getdirentries(fd
, ddptr
, space
, &dirp
->dd_seek
);
* There is now a buffer full of (possibly) duplicate
* Go round this loop twice...
* Scan through the buffer, counting entries.
* On the second pass, save pointers to each one.
* Then sort the pointers and remove duplicate names.
ddptr
= buf
+ dirp
->dd_loc
;
while (ddptr
< buf
+ len
) {
dp
= (struct dirent
*) ddptr
;
if ((dp
->d_reclen
<= 0) ||
(dp
->d_reclen
> (buf
+ len
+ 1 - ddptr
)))
* If and when whiteouts happen,
* this sort would need to be stable.
heapsort(dpv
, n
, sizeof(*dpv
), alphasort
);
* Scan through the buffer in sort order,
* zapping the inode number of any
for (n
= 0; dpv
[n
]; n
++) {
struct dirent
*dp
= dpv
[n
];
strcmp(dp
->d_name
, xp
->d_name
))
dpv
= malloc((n
+1) * sizeof(struct dirent
*));
dirp
->dd_size
= ddptr
- dirp
->dd_buf
;
dirp
->dd_buf
= malloc(dirp
->dd_len
);
if (dirp
->dd_buf
== NULL
) {
* Set up seek point for rewinddir.
dirp
->dd_rewind
= telldir(dirp
);