2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright (c) 1988, 2011, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A/* Copyright (c) 1988 AT&T */
2N/A/* All Rights Reserved */
2N/A
2N/A/*
2N/A * University Copyright- Copyright (c) 1982, 1986, 1988
2N/A * The Regents of the University of California
2N/A * All Rights Reserved
2N/A *
2N/A * University Acknowledgment- Portions of this document are derived from
2N/A * software developed by the University of California, Berkeley, and its
2N/A * contributors.
2N/A */
2N/A
2N/A/*
2N/A * readdir -- C library extension routine
2N/A */
2N/A
2N/A#include <sys/feature_tests.h>
2N/A
2N/A#if !defined(_LP64)
2N/A#pragma weak _readdir64 = readdir64
2N/A#endif
2N/A#pragma weak _readdir = readdir
2N/A
2N/A#include "lint.h"
2N/A#include <dirent.h>
2N/A#include <limits.h>
2N/A#include <errno.h>
2N/A#include "libc.h"
2N/A
2N/A#ifdef _LP64
2N/A
2N/Adirent_t *
2N/Areaddir(DIR *dirp)
2N/A{
2N/A dirent_t *dp; /* -> directory data */
2N/A int saveloc = 0;
2N/A
2N/A if (dirp->d_size != 0) {
2N/A dp = (dirent_t *)(uintptr_t)&dirp->d_buf[dirp->d_loc];
2N/A saveloc = dirp->d_loc; /* save for possible EOF */
2N/A dirp->d_loc += (int)dp->d_reclen;
2N/A }
2N/A if (dirp->d_loc >= dirp->d_size)
2N/A dirp->d_loc = dirp->d_size = 0;
2N/A
2N/A if (dirp->d_size == 0 && /* refill buffer */
2N/A (dirp->d_size = getdents(dirp->d_fd,
2N/A (dirent_t *)(uintptr_t)dirp->d_buf, DIRBUF)) <= 0) {
2N/A if (dirp->d_size == 0) /* This means EOF */
2N/A dirp->d_loc = saveloc; /* so save for telldir */
2N/A return (NULL); /* error or EOF */
2N/A }
2N/A
2N/A return ((dirent_t *)(uintptr_t)&dirp->d_buf[dirp->d_loc]);
2N/A}
2N/A
2N/A#else /* _LP64 */
2N/A
2N/A/*
2N/A * Welcome to the complicated world of large files on a small system.
2N/A */
2N/A
2N/Adirent64_t *
2N/Areaddir64(DIR *dirp)
2N/A{
2N/A dirent64_t *dp64; /* -> directory data */
2N/A int saveloc = 0;
2N/A
2N/A if (dirp->d_size != 0) {
2N/A dp64 = (dirent64_t *)(uintptr_t)&dirp->d_buf[dirp->d_loc];
2N/A /* was converted by readdir and needs to be reversed */
2N/A if (dp64->d_ino == (ino64_t)-1) {
2N/A dirent_t *dp32;
2N/A
2N/A dp32 = (dirent_t *)(&dp64->d_off);
2N/A dp64->d_ino = (ino64_t)dp32->d_ino;
2N/A dp64->d_off = (off64_t)dp32->d_off;
2N/A dp64->d_reclen = (unsigned short)(dp32->d_reclen +
2N/A ((char *)&dp64->d_off - (char *)dp64));
2N/A }
2N/A saveloc = dirp->d_loc; /* save for possible EOF */
2N/A dirp->d_loc += (int)dp64->d_reclen;
2N/A }
2N/A if (dirp->d_loc >= dirp->d_size)
2N/A dirp->d_loc = dirp->d_size = 0;
2N/A
2N/A if (dirp->d_size == 0 && /* refill buffer */
2N/A (dirp->d_size = getdents64(dirp->d_fd,
2N/A (dirent64_t *)(uintptr_t)dirp->d_buf, DIRBUF)) <= 0) {
2N/A if (dirp->d_size == 0) /* This means EOF */
2N/A dirp->d_loc = saveloc; /* so save for telldir */
2N/A return (NULL); /* error or EOF */
2N/A }
2N/A
2N/A dp64 = (dirent64_t *)(uintptr_t)&dirp->d_buf[dirp->d_loc];
2N/A return (dp64);
2N/A}
2N/A
2N/A/*
2N/A * readdir now does translation of dirent64 entries into dirent entries.
2N/A * We rely on the fact that dirents are smaller than dirent64s and we
2N/A * reuse the space accordingly.
2N/A */
2N/Adirent_t *
2N/Areaddir(DIR *dirp)
2N/A{
2N/A dirent64_t *dp64; /* -> directory data */
2N/A dirent_t *dp32; /* -> directory data */
2N/A
2N/A if ((dp64 = readdir64(dirp)) == NULL)
2N/A return (NULL);
2N/A
2N/A /*
2N/A * Make sure that the offset fits in 32 bits.
2N/A */
2N/A if (((off_t)dp64->d_off != dp64->d_off &&
2N/A (uint64_t)dp64->d_off > (uint64_t)UINT32_MAX) ||
2N/A dp64->d_ino > SIZE_MAX) {
2N/A errno = EOVERFLOW;
2N/A return (NULL);
2N/A }
2N/A
2N/A dp32 = (dirent_t *)(&dp64->d_off);
2N/A dp32->d_off = (off_t)dp64->d_off;
2N/A dp32->d_ino = (ino_t)dp64->d_ino;
2N/A dp32->d_reclen = (unsigned short)(dp64->d_reclen -
2N/A ((char *)&dp64->d_off - (char *)dp64));
2N/A dp64->d_ino = (ino64_t)-1; /* flag as converted for readdir64 */
2N/A /* d_name d_reclen should not move */
2N/A return (dp32);
2N/A}
2N/A#endif /* _LP64 */