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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* Copyright (c) 1988 AT&T */ 30 /* All Rights Reserved */ 31 32 33 /* 34 * readdir_r -- C library extension routine 35 */ 36 37 #include <sys/feature_tests.h> 38 39 #if !defined(_LP64) 40 #pragma weak readdir64_r = _readdir64_r 41 #endif 42 #pragma weak readdir_r = _readdir_r 43 44 #include "synonyms.h" 45 #include <mtlib.h> 46 #include <sys/types.h> 47 #include <sys/dirent.h> 48 #include <dirent.h> 49 #include <thread.h> 50 #include <string.h> 51 #include <synch.h> 52 #include <stdio.h> 53 #include <limits.h> 54 #include <errno.h> 55 #include "libc.h" 56 57 extern mutex_t _dirent_lock; 58 59 #define LBUFSIZE (sizeof (struct dirent64) + _POSIX_PATH_MAX + 1) 60 61 #ifdef _LP64 62 63 /* 64 * POSIX.1c standard version of the thread function readdir_r. 65 */ 66 67 int 68 readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result) 69 { 70 struct dirent *dp; /* -> directory data */ 71 int saveloc = 0; 72 73 lmutex_lock(&_dirent_lock); 74 if (dirp->dd_size != 0) { 75 dp = (struct dirent *)(uintptr_t)&dirp->dd_buf[dirp->dd_loc]; 76 saveloc = dirp->dd_loc; /* save for possible EOF */ 77 dirp->dd_loc += (int)dp->d_reclen; 78 } 79 80 if (dirp->dd_loc >= dirp->dd_size) 81 dirp->dd_loc = dirp->dd_size = 0; 82 83 if (dirp->dd_size == 0 && /* refill buffer */ 84 (dirp->dd_size = getdents(dirp->dd_fd, 85 (struct dirent *)(uintptr_t)dirp->dd_buf, DIRBUF)) <= 0) { 86 if (dirp->dd_size == 0) { /* This means EOF */ 87 dirp->dd_loc = saveloc; /* EOF so save for telldir */ 88 lmutex_unlock(&_dirent_lock); 89 *result = NULL; 90 return (0); /* EOF */ 91 } 92 lmutex_unlock(&_dirent_lock); 93 *result = NULL; 94 return (errno); /* error */ 95 } 96 97 dp = (struct dirent *)(uintptr_t)&dirp->dd_buf[dirp->dd_loc]; 98 (void) memcpy(entry, dp, (size_t)dp->d_reclen); 99 lmutex_unlock(&_dirent_lock); 100 *result = entry; 101 return (0); 102 } 103 104 #else /* _LP64 */ 105 106 /* 107 * POSIX.1c standard version of the thr function readdir_r. 108 * Large file version. 109 */ 110 111 int 112 readdir64_r(DIR *dirp, struct dirent64 *entry, struct dirent64 **result) 113 { 114 struct dirent64 *dp64; /* -> directory data */ 115 int saveloc = 0; 116 117 lmutex_lock(&_dirent_lock); 118 if (dirp->dd_size != 0) { 119 dp64 = (struct dirent64 *) 120 (uintptr_t)&dirp->dd_buf[dirp->dd_loc]; 121 /* was converted by readdir and needs to be reversed */ 122 if (dp64->d_ino == (ino64_t)-1) { 123 struct dirent *dp32; /* -> 32 bit directory data */ 124 125 dp32 = (struct dirent *)(&dp64->d_off); 126 dp64->d_ino = (ino64_t)dp32->d_ino; 127 dp64->d_off = (off64_t)dp32->d_off; 128 dp64->d_reclen = (unsigned short)(dp32->d_reclen + 129 ((char *)&dp64->d_off - (char *)dp64)); 130 } 131 saveloc = dirp->dd_loc; /* save for possible EOF */ 132 dirp->dd_loc += (int)dp64->d_reclen; 133 } 134 135 if (dirp->dd_loc >= dirp->dd_size) 136 dirp->dd_loc = dirp->dd_size = 0; 137 138 if (dirp->dd_size == 0 && /* refill buffer */ 139 (dirp->dd_size = getdents64(dirp->dd_fd, 140 (struct dirent64 *)(uintptr_t)dirp->dd_buf, DIRBUF)) <= 0) { 141 if (dirp->dd_size == 0) { /* This means EOF */ 142 dirp->dd_loc = saveloc; /* EOF so save for telldir */ 143 lmutex_unlock(&_dirent_lock); 144 *result = NULL; 145 return (0); /* EOF */ 146 } 147 lmutex_unlock(&_dirent_lock); 148 *result = NULL; 149 return (errno); /* error */ 150 } 151 152 dp64 = (struct dirent64 *)(uintptr_t)&dirp->dd_buf[dirp->dd_loc]; 153 (void) memcpy(entry, dp64, (size_t)dp64->d_reclen); 154 *result = entry; 155 lmutex_unlock(&_dirent_lock); 156 return (0); 157 } 158 159 /* 160 * POSIX.1c Draft-6 version of the function readdir_r. 161 * It was implemented by Solaris 2.3. 162 */ 163 164 struct dirent * 165 readdir_r(DIR *dirp, struct dirent *entry) 166 { 167 long buf[LBUFSIZE / sizeof (long) + 1]; 168 struct dirent64 *dp64; 169 170 if (readdir64_r(dirp, (struct dirent64 *)(uintptr_t)buf, &dp64) != 0 || 171 dp64 == NULL) 172 return (NULL); 173 174 if ((dp64->d_ino > SIZE_MAX) || ((uint64_t)dp64->d_off > 175 (uint64_t)UINT32_MAX)) { 176 errno = EOVERFLOW; 177 return (NULL); 178 } 179 180 entry->d_ino = (ino_t)dp64->d_ino; 181 entry->d_off = (off_t)dp64->d_off; 182 entry->d_reclen = (unsigned short)((((char *)entry->d_name - 183 (char *)entry) + strlen(dp64->d_name) + 1 + 3) & ~3); 184 (void) strcpy(entry->d_name, dp64->d_name); 185 186 return (entry); 187 } 188 189 /* 190 * POSIX.1c standard version of the thr function readdir_r. 191 * User gets it via static readdir_r from header file. 192 */ 193 194 int 195 __posix_readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result) 196 { 197 long buf[LBUFSIZE / sizeof (long) + 1]; 198 struct dirent64 *dp64; 199 int ret; 200 201 ret = readdir64_r(dirp, (struct dirent64 *)(uintptr_t)buf, &dp64); 202 if (ret != 0 || dp64 == NULL) { 203 *result = NULL; 204 return (ret); 205 } 206 207 if ((dp64->d_ino > SIZE_MAX) || ((uint64_t)dp64->d_off > 208 (uint64_t)UINT32_MAX)) { 209 *result = NULL; 210 return (EOVERFLOW); 211 } 212 213 entry->d_ino = (ino_t)dp64->d_ino; 214 entry->d_off = (off_t)dp64->d_off; 215 entry->d_reclen = (unsigned short)((((char *)entry->d_name - 216 (char *)entry) + strlen(dp64->d_name) + 1 + 3) & ~3); 217 (void) strcpy(entry->d_name, dp64->d_name); 218 *result = entry; 219 return (0); 220 } 221 222 #endif /* _LP64 */ 223