1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1988 AT&T */ 28 /* All Rights Reserved */ 29 30 /* 31 * University Copyright- Copyright (c) 1982, 1986, 1988 32 * The Regents of the University of California 33 * All Rights Reserved 34 * 35 * University Acknowledgment- Portions of this document are derived from 36 * software developed by the University of California, Berkeley, and its 37 * contributors. 38 */ 39 40 #pragma ident "%Z%%M% %I% %E% SMI" 41 42 /* 43 * readdir -- C library extension routine 44 */ 45 46 #include <sys/feature_tests.h> 47 48 #if !defined(_LP64) 49 #pragma weak _readdir64 = readdir64 50 #endif 51 #pragma weak _readdir = readdir 52 53 #include "lint.h" 54 #include <dirent.h> 55 #include <limits.h> 56 #include <errno.h> 57 #include "libc.h" 58 59 #ifdef _LP64 60 61 dirent_t * 62 readdir(DIR *dirp) 63 { 64 dirent_t *dp; /* -> directory data */ 65 int saveloc = 0; 66 67 if (dirp->dd_size != 0) { 68 dp = (dirent_t *)(uintptr_t)&dirp->dd_buf[dirp->dd_loc]; 69 saveloc = dirp->dd_loc; /* save for possible EOF */ 70 dirp->dd_loc += (int)dp->d_reclen; 71 } 72 if (dirp->dd_loc >= dirp->dd_size) 73 dirp->dd_loc = dirp->dd_size = 0; 74 75 if (dirp->dd_size == 0 && /* refill buffer */ 76 (dirp->dd_size = getdents(dirp->dd_fd, 77 (dirent_t *)(uintptr_t)dirp->dd_buf, DIRBUF)) <= 0) { 78 if (dirp->dd_size == 0) /* This means EOF */ 79 dirp->dd_loc = saveloc; /* so save for telldir */ 80 return (NULL); /* error or EOF */ 81 } 82 83 return ((dirent_t *)(uintptr_t)&dirp->dd_buf[dirp->dd_loc]); 84 } 85 86 #else /* _LP64 */ 87 88 /* 89 * Welcome to the complicated world of large files on a small system. 90 */ 91 92 dirent64_t * 93 readdir64(DIR *dirp) 94 { 95 dirent64_t *dp64; /* -> directory data */ 96 int saveloc = 0; 97 98 if (dirp->dd_size != 0) { 99 dp64 = (dirent64_t *)(uintptr_t)&dirp->dd_buf[dirp->dd_loc]; 100 /* was converted by readdir and needs to be reversed */ 101 if (dp64->d_ino == (ino64_t)-1) { 102 dirent_t *dp32; 103 104 dp32 = (dirent_t *)(&dp64->d_off); 105 dp64->d_ino = (ino64_t)dp32->d_ino; 106 dp64->d_off = (off64_t)dp32->d_off; 107 dp64->d_reclen = (unsigned short)(dp32->d_reclen + 108 ((char *)&dp64->d_off - (char *)dp64)); 109 } 110 saveloc = dirp->dd_loc; /* save for possible EOF */ 111 dirp->dd_loc += (int)dp64->d_reclen; 112 } 113 if (dirp->dd_loc >= dirp->dd_size) 114 dirp->dd_loc = dirp->dd_size = 0; 115 116 if (dirp->dd_size == 0 && /* refill buffer */ 117 (dirp->dd_size = getdents64(dirp->dd_fd, 118 (dirent64_t *)(uintptr_t)dirp->dd_buf, DIRBUF)) <= 0) { 119 if (dirp->dd_size == 0) /* This means EOF */ 120 dirp->dd_loc = saveloc; /* so save for telldir */ 121 return (NULL); /* error or EOF */ 122 } 123 124 dp64 = (dirent64_t *)(uintptr_t)&dirp->dd_buf[dirp->dd_loc]; 125 return (dp64); 126 } 127 128 /* 129 * readdir now does translation of dirent64 entries into dirent entries. 130 * We rely on the fact that dirents are smaller than dirent64s and we 131 * reuse the space accordingly. 132 */ 133 dirent_t * 134 readdir(DIR *dirp) 135 { 136 dirent64_t *dp64; /* -> directory data */ 137 dirent_t *dp32; /* -> directory data */ 138 139 if ((dp64 = readdir64(dirp)) == NULL) 140 return (NULL); 141 142 /* 143 * Make sure that the offset fits in 32 bits. 144 */ 145 if (((off_t)dp64->d_off != dp64->d_off && 146 (uint64_t)dp64->d_off > (uint64_t)UINT32_MAX) || 147 dp64->d_ino > SIZE_MAX) { 148 errno = EOVERFLOW; 149 return (NULL); 150 } 151 152 dp32 = (dirent_t *)(&dp64->d_off); 153 dp32->d_off = (off_t)dp64->d_off; 154 dp32->d_ino = (ino_t)dp64->d_ino; 155 dp32->d_reclen = (unsigned short)(dp64->d_reclen - 156 ((char *)&dp64->d_off - (char *)dp64)); 157 dp64->d_ino = (ino64_t)-1; /* flag as converted for readdir64 */ 158 /* d_name d_reclen should not move */ 159 return (dp32); 160 } 161 #endif /* _LP64 */ 162