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 /* 41 * readdir -- C library extension routine 42 */ 43 44 #include <sys/feature_tests.h> 45 46 #if !defined(_LP64) 47 #pragma weak _readdir64 = readdir64 48 #endif 49 #pragma weak _readdir = readdir 50 51 #include "lint.h" 52 #include <dirent.h> 53 #include <limits.h> 54 #include <errno.h> 55 #include "libc.h" 56 57 #ifdef _LP64 58 59 dirent_t * 60 readdir(DIR *dirp) 61 { 62 dirent_t *dp; /* -> directory data */ 63 int saveloc = 0; 64 65 if (dirp->dd_size != 0) { 66 dp = (dirent_t *)(uintptr_t)&dirp->dd_buf[dirp->dd_loc]; 67 saveloc = dirp->dd_loc; /* save for possible EOF */ 68 dirp->dd_loc += (int)dp->d_reclen; 69 } 70 if (dirp->dd_loc >= dirp->dd_size) 71 dirp->dd_loc = dirp->dd_size = 0; 72 73 if (dirp->dd_size == 0 && /* refill buffer */ 74 (dirp->dd_size = getdents(dirp->dd_fd, 75 (dirent_t *)(uintptr_t)dirp->dd_buf, DIRBUF)) <= 0) { 76 if (dirp->dd_size == 0) /* This means EOF */ 77 dirp->dd_loc = saveloc; /* so save for telldir */ 78 return (NULL); /* error or EOF */ 79 } 80 81 return ((dirent_t *)(uintptr_t)&dirp->dd_buf[dirp->dd_loc]); 82 } 83 84 #else /* _LP64 */ 85 86 /* 87 * Welcome to the complicated world of large files on a small system. 88 */ 89 90 dirent64_t * 91 readdir64(DIR *dirp) 92 { 93 dirent64_t *dp64; /* -> directory data */ 94 int saveloc = 0; 95 96 if (dirp->dd_size != 0) { 97 dp64 = (dirent64_t *)(uintptr_t)&dirp->dd_buf[dirp->dd_loc]; 98 /* was converted by readdir and needs to be reversed */ 99 if (dp64->d_ino == (ino64_t)-1) { 100 dirent_t *dp32; 101 102 dp32 = (dirent_t *)(&dp64->d_off); 103 dp64->d_ino = (ino64_t)dp32->d_ino; 104 dp64->d_off = (off64_t)dp32->d_off; 105 dp64->d_reclen = (unsigned short)(dp32->d_reclen + 106 ((char *)&dp64->d_off - (char *)dp64)); 107 } 108 saveloc = dirp->dd_loc; /* save for possible EOF */ 109 dirp->dd_loc += (int)dp64->d_reclen; 110 } 111 if (dirp->dd_loc >= dirp->dd_size) 112 dirp->dd_loc = dirp->dd_size = 0; 113 114 if (dirp->dd_size == 0 && /* refill buffer */ 115 (dirp->dd_size = getdents64(dirp->dd_fd, 116 (dirent64_t *)(uintptr_t)dirp->dd_buf, DIRBUF)) <= 0) { 117 if (dirp->dd_size == 0) /* This means EOF */ 118 dirp->dd_loc = saveloc; /* so save for telldir */ 119 return (NULL); /* error or EOF */ 120 } 121 122 dp64 = (dirent64_t *)(uintptr_t)&dirp->dd_buf[dirp->dd_loc]; 123 return (dp64); 124 } 125 126 /* 127 * readdir now does translation of dirent64 entries into dirent entries. 128 * We rely on the fact that dirents are smaller than dirent64s and we 129 * reuse the space accordingly. 130 */ 131 dirent_t * 132 readdir(DIR *dirp) 133 { 134 dirent64_t *dp64; /* -> directory data */ 135 dirent_t *dp32; /* -> directory data */ 136 137 if ((dp64 = readdir64(dirp)) == NULL) 138 return (NULL); 139 140 /* 141 * Make sure that the offset fits in 32 bits. 142 */ 143 if (((off_t)dp64->d_off != dp64->d_off && 144 (uint64_t)dp64->d_off > (uint64_t)UINT32_MAX) || 145 dp64->d_ino > SIZE_MAX) { 146 errno = EOVERFLOW; 147 return (NULL); 148 } 149 150 dp32 = (dirent_t *)(&dp64->d_off); 151 dp32->d_off = (off_t)dp64->d_off; 152 dp32->d_ino = (ino_t)dp64->d_ino; 153 dp32->d_reclen = (unsigned short)(dp64->d_reclen - 154 ((char *)&dp64->d_off - (char *)dp64)); 155 dp64->d_ino = (ino64_t)-1; /* flag as converted for readdir64 */ 156 /* d_name d_reclen should not move */ 157 return (dp32); 158 } 159 #endif /* _LP64 */ 160