xref: /titanic_51/usr/src/lib/libast/common/dir/getdents.c (revision f53eecf557986dac6ededb388fedd6ca63be0350)
1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1985-2008 AT&T Intellectual Property          *
5 *                      and is licensed under the                       *
6 *                  Common Public License, Version 1.0                  *
7 *                    by AT&T Intellectual Property                     *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *            http://www.opensource.org/licenses/cpl1.0.txt             *
11 *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12 *                                                                      *
13 *              Information and Software Systems Research               *
14 *                            AT&T Research                             *
15 *                           Florham Park NJ                            *
16 *                                                                      *
17 *                 Glenn Fowler <gsf@research.att.com>                  *
18 *                  David Korn <dgk@research.att.com>                   *
19 *                   Phong Vo <kpv@research.att.com>                    *
20 *                                                                      *
21 ***********************************************************************/
22 #pragma prototyped
23 
24 #include "dirlib.h"
25 
26 #if _dir_ok || _lib_getdents
27 
28 NoN(getdents)
29 
30 #else
31 
32 /*
33  * getdents
34  *
35  * read directory entries into directory block
36  *
37  * NOTE: directory entries must fit within DIRBLKSIZ boundaries
38  */
39 
40 #ifndef MAXNAMLEN
41 #define MAXNAMLEN	255
42 #endif
43 
44 #if _lib_dirread
45 extern int		dirread(int, char*, int);
46 #endif
47 #if _lib_getdirentries
48 extern int		getdirentries(int, char*, int, long*);
49 #endif
50 
51 ssize_t
52 getdents(int fd, void* buf, size_t siz)
53 {
54 	struct stat		st;
55 
56 	if (siz < DIRBLKSIZ)
57 	{
58 		errno = EINVAL;
59 		return(-1);
60 	}
61 	if (fstat(fd, &st)) return(-1);
62 	if (!S_ISDIR(st.st_mode))
63 	{
64 #ifdef ENOTDIR
65 		errno = ENOTDIR;
66 #else
67 		errno = EBADF;
68 #endif
69 		return(-1);
70 	}
71 #if _lib_getdirentries
72 	{
73 		long		off;
74 		return(getdirentries(fd, buf, siz, &off));
75 	}
76 #else
77 #if _lib_dirread
78 	{
79 		register char*		sp;	/* system */
80 		register struct dirent*	up;	/* user */
81 		char*			u;
82 		int			n;
83 		int			m;
84 		int			i;
85 
86 		m = (siz * 6) / 10;
87 		m = roundof(m, 8);
88 		sp = (char*)buf + siz - m - 1;
89 		if (!(n = dirread(fd, sp, m))) return(0);
90 		if (n > 0)
91 		{
92 			up = (struct dirent*)buf;
93 			sp[n] = 0;
94 			while (sp < (char*)buf + siz - m + n)
95 			{
96 				i = 0;
97 				while (*sp >= '0' && *sp <= '9')
98 					i = 10 * i + *sp++ - '0';
99 				while (*sp && *sp != '\t') sp++;
100 				if (*sp++)
101 				{
102 					up->d_fileno = i;
103 					u = up->d_name;
104 					while ((*u = *sp++) && u < up->d_name + MAXNAMLEN) u++;
105 					*u = 0;
106 					up->d_reclen = sizeof(struct dirent) - sizeof(up->d_name) + (up->d_namlen = u - up->d_name) + 1;
107 					up->d_reclen = roundof(up->d_reclen, 8);
108 					up = (struct dirent*)((char*)up + up->d_reclen);
109 				}
110 			}
111 			return((char*)up - (char*)buf);
112 		}
113 	}
114 #else
115 #if _mem_d_reclen_direct
116 	return(read(fd, buf, siz));
117 #else
118 	{
119 
120 #define MAXREC	roundof(sizeof(*up)-sizeof(up->d_name)+sizeof(sp->d_name)+1,8)
121 
122 		register struct direct*	sp;	/* system */
123 		register struct dirent*	up;	/* user */
124 		register char*		s;
125 		register char*		u;
126 		int			n;
127 		int			m;
128 		char			tmp[sizeof(sp->d_name) + 1];
129 
130 		/*
131 		 * we assume sizeof(struct dirent) > sizeof(struct direct)
132 		 */
133 
134 		up = (struct dirent*)buf;
135 		n = (siz / MAXREC) * sizeof(struct direct);
136 		if ((!(m = n & ~511) || m < MAXREC) && (!(m = n & ~255) || m < MAXREC)) m = n;
137 		do
138 		{
139 			if ((n = read(fd, (char*)buf + siz - m, m)) <= 0) break;
140 			sp = (struct direct*)((char*)buf + siz - m);
141 			while (sp < (struct direct*)((char*)buf + siz - m + n))
142 			{
143 				if (sp->d_ino)
144 				{
145 					up->d_fileno = sp->d_ino;
146 					s = sp->d_name;
147 					u = tmp;
148 					while (s < sp->d_name + sizeof(sp->d_name) && *s)
149 						*u++ = *s++;
150 					*u = 0;
151 					strcpy(up->d_name, tmp);
152 					up->d_reclen = sizeof(struct dirent) - sizeof(up->d_name) + (up->d_namlen = u - tmp) + 1;
153 					up->d_reclen = roundof(up->d_reclen, 8);
154 					up = (struct dirent*)((char*)up + up->d_reclen);
155 				}
156 				sp++;
157 			}
158 		} while (up == (struct dirent*)buf);
159 		return((char*)up - (char*)buf);
160 	}
161 #endif
162 #endif
163 #endif
164 }
165 
166 #endif
167