1#include "defs.h"
2#include <dirent.h>
3
4#define D_NAME_LEN_MAX 256
5
6struct kernel_dirent {
7	unsigned long   d_ino;
8	unsigned long   d_off;
9	unsigned short  d_reclen;
10	char            d_name[1];
11};
12
13static void
14print_old_dirent(struct tcb *tcp, long addr)
15{
16#ifdef SH64
17	typedef struct kernel_dirent old_dirent_t;
18#else
19	typedef struct {
20		uint32_t	d_ino;
21		uint32_t	d_off;
22		unsigned short  d_reclen;
23		char            d_name[1];
24	} old_dirent_t;
25#endif
26	old_dirent_t d;
27
28	if (!verbose(tcp) || umove(tcp, addr, &d) < 0) {
29		tprintf("%#lx", addr);
30		return;
31	}
32
33	tprintf("{d_ino=%lu, d_off=%lu, d_reclen=%u, d_name=",
34		(unsigned long) d.d_ino, (unsigned long) d.d_off, d.d_reclen);
35	if (d.d_reclen > D_NAME_LEN_MAX)
36		d.d_reclen = D_NAME_LEN_MAX;
37	printpathn(tcp, addr + offsetof(old_dirent_t, d_name), d.d_reclen);
38	tprints("}");
39}
40
41SYS_FUNC(readdir)
42{
43	if (entering(tcp)) {
44		printfd(tcp, tcp->u_arg[0]);
45		tprints(", ");
46	} else {
47		if (syserror(tcp) || tcp->u_rval == 0 || !verbose(tcp))
48			tprintf("%#lx", tcp->u_arg[1]);
49		else
50			print_old_dirent(tcp, tcp->u_arg[1]);
51		/* Not much point in printing this out, it is always 1. */
52		if (tcp->u_arg[2] != 1)
53			tprintf(", %lu", tcp->u_arg[2]);
54	}
55	return 0;
56}
57
58#include "xlat/direnttypes.h"
59
60SYS_FUNC(getdents)
61{
62	unsigned int i, len, dents = 0;
63	char *buf;
64
65	if (entering(tcp)) {
66		printfd(tcp, tcp->u_arg[0]);
67		tprints(", ");
68		return 0;
69	}
70	if (syserror(tcp) || !verbose(tcp)) {
71		tprintf("%#lx, %lu", tcp->u_arg[1], tcp->u_arg[2]);
72		return 0;
73	}
74
75	/* Beware of insanely large or too small values in tcp->u_rval */
76	if (tcp->u_rval > 1024*1024)
77		len = 1024*1024;
78	else if (tcp->u_rval < (int) sizeof(struct kernel_dirent))
79		len = 0;
80	else
81		len = tcp->u_rval;
82
83	if (len) {
84		buf = malloc(len);
85		if (!buf)
86			die_out_of_memory();
87		if (umoven(tcp, tcp->u_arg[1], len, buf) < 0) {
88			tprintf("%#lx, %lu", tcp->u_arg[1], tcp->u_arg[2]);
89			free(buf);
90			return 0;
91		}
92	} else {
93		buf = NULL;
94	}
95
96	if (!abbrev(tcp))
97		tprints("{");
98	for (i = 0; len && i <= len - sizeof(struct kernel_dirent); ) {
99		struct kernel_dirent *d = (struct kernel_dirent *) &buf[i];
100
101		if (!abbrev(tcp)) {
102			int oob = d->d_reclen < sizeof(struct kernel_dirent) ||
103				  i + d->d_reclen - 1 >= len;
104			int d_name_len = oob ? len - i : d->d_reclen;
105			d_name_len -= offsetof(struct kernel_dirent, d_name) + 1;
106			if (d_name_len > D_NAME_LEN_MAX)
107				d_name_len = D_NAME_LEN_MAX;
108
109			tprintf("%s{d_ino=%lu, d_off=%lu, d_reclen=%u, d_name=",
110				i ? " " : "", d->d_ino, d->d_off, d->d_reclen);
111
112			if (print_quoted_string(d->d_name, d_name_len,
113					        QUOTE_0_TERMINATED) > 0) {
114				tprints("...");
115			}
116
117			tprints(", d_type=");
118			if (oob)
119				tprints("?");
120			else
121				printxval(direnttypes, buf[i + d->d_reclen - 1], "DT_???");
122			tprints("}");
123		}
124		dents++;
125		if (d->d_reclen < sizeof(struct kernel_dirent)) {
126			tprints("/* d_reclen < sizeof(struct kernel_dirent) */");
127			break;
128		}
129		i += d->d_reclen;
130	}
131	if (!abbrev(tcp))
132		tprints("}");
133	else
134		tprintf("/* %u entries */", dents);
135	tprintf(", %lu", tcp->u_arg[2]);
136	free(buf);
137	return 0;
138}
139
140SYS_FUNC(getdents64)
141{
142	/* the minimum size of a valid dirent64 structure */
143	const unsigned int d_name_offset = offsetof(struct dirent64, d_name);
144
145	unsigned int i, len, dents = 0;
146	char *buf;
147
148	if (entering(tcp)) {
149		printfd(tcp, tcp->u_arg[0]);
150		tprints(", ");
151		return 0;
152	}
153	if (syserror(tcp) || !verbose(tcp)) {
154		tprintf("%#lx, %lu", tcp->u_arg[1], tcp->u_arg[2]);
155		return 0;
156	}
157
158	/* Beware of insanely large or too small tcp->u_rval */
159	if (tcp->u_rval > 1024*1024)
160		len = 1024*1024;
161	else if (tcp->u_rval < (int) d_name_offset)
162		len = 0;
163	else
164		len = tcp->u_rval;
165
166	if (len) {
167		buf = malloc(len);
168		if (!buf)
169			die_out_of_memory();
170		if (umoven(tcp, tcp->u_arg[1], len, buf) < 0) {
171			tprintf("%#lx, %lu", tcp->u_arg[1], tcp->u_arg[2]);
172			free(buf);
173			return 0;
174		}
175	} else {
176		buf = NULL;
177	}
178
179	if (!abbrev(tcp))
180		tprints("{");
181	for (i = 0; len && i <= len - d_name_offset; ) {
182		struct dirent64 *d = (struct dirent64 *) &buf[i];
183		if (!abbrev(tcp)) {
184			int d_name_len;
185			if (d->d_reclen >= d_name_offset
186			    && i + d->d_reclen <= len) {
187				d_name_len = d->d_reclen - d_name_offset;
188			} else {
189				d_name_len = len - i - d_name_offset;
190			}
191			if (d_name_len > D_NAME_LEN_MAX)
192				d_name_len = D_NAME_LEN_MAX;
193
194			tprintf("%s{d_ino=%" PRIu64 ", d_off=%" PRId64
195				", d_reclen=%u, d_type=",
196				i ? " " : "",
197				d->d_ino,
198				d->d_off,
199				d->d_reclen);
200			printxval(direnttypes, d->d_type, "DT_???");
201
202			tprints(", d_name=");
203			if (print_quoted_string(d->d_name, d_name_len,
204					        QUOTE_0_TERMINATED) > 0) {
205				tprints("...");
206			}
207
208			tprints("}");
209		}
210		if (d->d_reclen < d_name_offset) {
211			tprints("/* d_reclen < offsetof(struct dirent64, d_name) */");
212			break;
213		}
214		i += d->d_reclen;
215		dents++;
216	}
217	if (!abbrev(tcp))
218		tprints("}");
219	else
220		tprintf("/* %u entries */", dents);
221	tprintf(", %lu", tcp->u_arg[2]);
222	free(buf);
223	return 0;
224}
225