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 * readdir_r -- C library extension routine
32 */
33
34 #include <sys/feature_tests.h>
35
36 #if !defined(_LP64)
37 #pragma weak _readdir64_r = readdir64_r
38 #endif
39
40 #include "lint.h"
41 #include "libc.h"
42 #include <mtlib.h>
43 #include <unistd.h>
44 #include <dirent.h>
45 #include <string.h>
46 #include <limits.h>
47 #include <errno.h>
48
49 #ifdef _LP64
50
51 /*
52 * POSIX.1c standard version of the thread function readdir_r.
53 */
54
55 int
readdir_r(DIR * dirp,dirent_t * entry,dirent_t ** result)56 readdir_r(DIR *dirp, dirent_t *entry, dirent_t **result)
57 {
58 private_DIR *pdirp = (private_DIR *)dirp;
59 dirent_t *dp; /* -> directory data */
60 int saveloc = 0;
61
62 lmutex_lock(&pdirp->dd_lock);
63 if (dirp->dd_size != 0) {
64 dp = (dirent_t *)(uintptr_t)&dirp->dd_buf[dirp->dd_loc];
65 saveloc = dirp->dd_loc; /* save for possible EOF */
66 dirp->dd_loc += (int)dp->d_reclen;
67 }
68
69 if (dirp->dd_loc >= dirp->dd_size)
70 dirp->dd_loc = dirp->dd_size = 0;
71
72 if (dirp->dd_size == 0 && /* refill buffer */
73 (dirp->dd_size = getdents(dirp->dd_fd,
74 (dirent_t *)(uintptr_t)dirp->dd_buf, DIRBUF)) <= 0) {
75 if (dirp->dd_size == 0) { /* This means EOF */
76 dirp->dd_loc = saveloc; /* so save for telldir */
77 lmutex_unlock(&pdirp->dd_lock);
78 *result = NULL;
79 return (0);
80 }
81 lmutex_unlock(&pdirp->dd_lock);
82 *result = NULL;
83 return (errno); /* error */
84 }
85
86 dp = (dirent_t *)(uintptr_t)&dirp->dd_buf[dirp->dd_loc];
87 (void) memcpy(entry, dp, (size_t)dp->d_reclen);
88 lmutex_unlock(&pdirp->dd_lock);
89 *result = entry;
90 return (0);
91 }
92
93 #else /* _LP64 */
94
95 /*
96 * POSIX.1c standard version of the thr function readdir_r.
97 * Large file version.
98 */
99
100 int
readdir64_r(DIR * dirp,dirent64_t * entry,dirent64_t ** result)101 readdir64_r(DIR *dirp, dirent64_t *entry, dirent64_t **result)
102 {
103 private_DIR *pdirp = (private_DIR *)(uintptr_t)dirp;
104 dirent64_t *dp64; /* -> directory data */
105 int saveloc = 0;
106
107 lmutex_lock(&pdirp->dd_lock);
108 if (dirp->dd_size != 0) {
109 dp64 = (dirent64_t *)(uintptr_t)&dirp->dd_buf[dirp->dd_loc];
110 /* was converted by readdir and needs to be reversed */
111 if (dp64->d_ino == (ino64_t)-1) {
112 dirent_t *dp32; /* -> 32 bit directory data */
113
114 dp32 = (dirent_t *)(&dp64->d_off);
115 dp64->d_ino = (ino64_t)dp32->d_ino;
116 dp64->d_off = (off64_t)dp32->d_off;
117 dp64->d_reclen = (unsigned short)(dp32->d_reclen +
118 ((char *)&dp64->d_off - (char *)dp64));
119 }
120 saveloc = dirp->dd_loc; /* save for possible EOF */
121 dirp->dd_loc += (int)dp64->d_reclen;
122 }
123
124 if (dirp->dd_loc >= dirp->dd_size)
125 dirp->dd_loc = dirp->dd_size = 0;
126
127 if (dirp->dd_size == 0 && /* refill buffer */
128 (dirp->dd_size = getdents64(dirp->dd_fd,
129 (dirent64_t *)(uintptr_t)dirp->dd_buf, DIRBUF)) <= 0) {
130 if (dirp->dd_size == 0) { /* This means EOF */
131 dirp->dd_loc = saveloc; /* so save for telldir */
132 lmutex_unlock(&pdirp->dd_lock);
133 *result = NULL;
134 return (0);
135 }
136 lmutex_unlock(&pdirp->dd_lock);
137 *result = NULL;
138 return (errno); /* error */
139 }
140
141 dp64 = (dirent64_t *)(uintptr_t)&dirp->dd_buf[dirp->dd_loc];
142 (void) memcpy(entry, dp64, (size_t)dp64->d_reclen);
143 *result = entry;
144 lmutex_unlock(&pdirp->dd_lock);
145 return (0);
146 }
147
148 /*
149 * POSIX.1c standard version of the function readdir_r.
150 * User gets it via static readdir_r from header file.
151 */
152
153 int
__posix_readdir_r(DIR * dirp,dirent_t * entry,dirent_t ** result)154 __posix_readdir_r(DIR *dirp, dirent_t *entry, dirent_t **result)
155 {
156 int error;
157 dirent64_t *dp64;
158 struct {
159 dirent64_t dirent64;
160 char chars[MAXNAMLEN];
161 } buf;
162
163 error = readdir64_r(dirp, (dirent64_t *)&buf, &dp64);
164 if (error != 0 || dp64 == NULL) {
165 *result = NULL;
166 return (error);
167 }
168
169 if (dp64->d_ino > SIZE_MAX ||
170 (uint64_t)dp64->d_off > (uint64_t)UINT32_MAX) {
171 *result = NULL;
172 return (EOVERFLOW);
173 }
174
175 entry->d_ino = (ino_t)dp64->d_ino;
176 entry->d_off = (off_t)dp64->d_off;
177 entry->d_reclen = (unsigned short)((((char *)entry->d_name -
178 (char *)entry) + strlen(dp64->d_name) + 1 + 3) & ~3);
179 (void) strcpy(entry->d_name, dp64->d_name);
180 *result = entry;
181 return (0);
182 }
183
184 /*
185 * POSIX.1c Draft-6 version of the function readdir_r.
186 * It was implemented by Solaris 2.3.
187 */
188
189 dirent_t *
readdir_r(DIR * dirp,dirent_t * entry)190 readdir_r(DIR *dirp, dirent_t *entry)
191 {
192 int error;
193 dirent_t *result;
194
195 if ((error = __posix_readdir_r(dirp, entry, &result)) != 0)
196 errno = error;
197 return (result);
198 }
199
200 #endif /* _LP64 */
201