blob: d30e0d2af7f133f1e4464fe92b2e41935d277ae6 [file] [log] [blame]
Dmitry V. Levin2ed2cc72014-09-11 22:40:37 +00001#include "defs.h"
2#include <dirent.h>
3
Dmitry V. Levinc9297712015-01-25 00:04:20 +00004#define D_NAME_LEN_MAX 256
5
Dmitry V. Levin2ed2cc72014-09-11 22:40:37 +00006struct 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
Dmitry V. Levinc9297712015-01-25 00:04:20 +000033 tprintf("{d_ino=%lu, d_off=%lu, d_reclen=%u, d_name=",
Dmitry V. Levin2ed2cc72014-09-11 22:40:37 +000034 (unsigned long) d.d_ino, (unsigned long) d.d_off, d.d_reclen);
Dmitry V. Levinc9297712015-01-25 00:04:20 +000035 if (d.d_reclen > D_NAME_LEN_MAX)
36 d.d_reclen = D_NAME_LEN_MAX;
Dmitry V. Levin2ed2cc72014-09-11 22:40:37 +000037 printpathn(tcp, addr + offsetof(old_dirent_t, d_name), d.d_reclen);
Dmitry V. Levinc9297712015-01-25 00:04:20 +000038 tprints("}");
Dmitry V. Levin2ed2cc72014-09-11 22:40:37 +000039}
40
41int
42sys_readdir(struct tcb *tcp)
43{
44 if (entering(tcp)) {
45 printfd(tcp, tcp->u_arg[0]);
46 tprints(", ");
47 } else {
48 if (syserror(tcp) || tcp->u_rval == 0 || !verbose(tcp))
49 tprintf("%#lx", tcp->u_arg[1]);
50 else
51 print_old_dirent(tcp, tcp->u_arg[1]);
52 /* Not much point in printing this out, it is always 1. */
53 if (tcp->u_arg[2] != 1)
54 tprintf(", %lu", tcp->u_arg[2]);
55 }
56 return 0;
57}
58
59#include "xlat/direnttypes.h"
60
61int
62sys_getdents(struct tcb *tcp)
63{
64 unsigned int i, len, dents = 0;
65 char *buf;
66
67 if (entering(tcp)) {
68 printfd(tcp, tcp->u_arg[0]);
69 tprints(", ");
70 return 0;
71 }
72 if (syserror(tcp) || !verbose(tcp)) {
73 tprintf("%#lx, %lu", tcp->u_arg[1], tcp->u_arg[2]);
74 return 0;
75 }
76
77 /* Beware of insanely large or too small values in tcp->u_rval */
78 if (tcp->u_rval > 1024*1024)
79 len = 1024*1024;
80 else if (tcp->u_rval < (int) sizeof(struct kernel_dirent))
81 len = 0;
82 else
83 len = tcp->u_rval;
84
85 if (len) {
86 buf = malloc(len);
87 if (!buf)
88 die_out_of_memory();
89 if (umoven(tcp, tcp->u_arg[1], len, buf) < 0) {
90 tprintf("%#lx, %lu", tcp->u_arg[1], tcp->u_arg[2]);
91 free(buf);
92 return 0;
93 }
94 } else {
95 buf = NULL;
96 }
97
98 if (!abbrev(tcp))
99 tprints("{");
100 for (i = 0; len && i <= len - sizeof(struct kernel_dirent); ) {
101 struct kernel_dirent *d = (struct kernel_dirent *) &buf[i];
102
103 if (!abbrev(tcp)) {
104 int oob = d->d_reclen < sizeof(struct kernel_dirent) ||
105 i + d->d_reclen - 1 >= len;
106 int d_name_len = oob ? len - i : d->d_reclen;
107 d_name_len -= offsetof(struct kernel_dirent, d_name) + 1;
Dmitry V. Levinc9297712015-01-25 00:04:20 +0000108 if (d_name_len > D_NAME_LEN_MAX)
109 d_name_len = D_NAME_LEN_MAX;
Dmitry V. Levin2ed2cc72014-09-11 22:40:37 +0000110
Dmitry V. Levinc9297712015-01-25 00:04:20 +0000111 tprintf("%s{d_ino=%lu, d_off=%lu, d_reclen=%u, d_name=",
112 i ? " " : "", d->d_ino, d->d_off, d->d_reclen);
113
114 if (print_quoted_string(d->d_name, d_name_len,
115 QUOTE_0_TERMINATED) > 0) {
116 tprints("...");
117 }
118
119 tprints(", d_type=");
Dmitry V. Levin2ed2cc72014-09-11 22:40:37 +0000120 if (oob)
121 tprints("?");
122 else
123 printxval(direnttypes, buf[i + d->d_reclen - 1], "DT_???");
124 tprints("}");
125 }
126 dents++;
127 if (d->d_reclen < sizeof(struct kernel_dirent)) {
128 tprints("/* d_reclen < sizeof(struct kernel_dirent) */");
129 break;
130 }
131 i += d->d_reclen;
132 }
133 if (!abbrev(tcp))
134 tprints("}");
135 else
136 tprintf("/* %u entries */", dents);
137 tprintf(", %lu", tcp->u_arg[2]);
138 free(buf);
139 return 0;
140}
141
142int
143sys_getdents64(struct tcb *tcp)
144{
145 /* the minimum size of a valid dirent64 structure */
146 const unsigned int d_name_offset = offsetof(struct dirent64, d_name);
147
148 unsigned int i, len, dents = 0;
149 char *buf;
150
151 if (entering(tcp)) {
152 printfd(tcp, tcp->u_arg[0]);
153 tprints(", ");
154 return 0;
155 }
156 if (syserror(tcp) || !verbose(tcp)) {
157 tprintf("%#lx, %lu", tcp->u_arg[1], tcp->u_arg[2]);
158 return 0;
159 }
160
161 /* Beware of insanely large or too small tcp->u_rval */
162 if (tcp->u_rval > 1024*1024)
163 len = 1024*1024;
164 else if (tcp->u_rval < (int) d_name_offset)
165 len = 0;
166 else
167 len = tcp->u_rval;
168
169 if (len) {
170 buf = malloc(len);
171 if (!buf)
172 die_out_of_memory();
173 if (umoven(tcp, tcp->u_arg[1], len, buf) < 0) {
174 tprintf("%#lx, %lu", tcp->u_arg[1], tcp->u_arg[2]);
175 free(buf);
176 return 0;
177 }
178 } else {
179 buf = NULL;
180 }
181
182 if (!abbrev(tcp))
183 tprints("{");
184 for (i = 0; len && i <= len - d_name_offset; ) {
185 struct dirent64 *d = (struct dirent64 *) &buf[i];
186 if (!abbrev(tcp)) {
187 int d_name_len;
188 if (d->d_reclen >= d_name_offset
189 && i + d->d_reclen <= len) {
190 d_name_len = d->d_reclen - d_name_offset;
191 } else {
192 d_name_len = len - i - d_name_offset;
193 }
Dmitry V. Levinc9297712015-01-25 00:04:20 +0000194 if (d_name_len > D_NAME_LEN_MAX)
195 d_name_len = D_NAME_LEN_MAX;
Dmitry V. Levin2ed2cc72014-09-11 22:40:37 +0000196
197 tprintf("%s{d_ino=%" PRIu64 ", d_off=%" PRId64
198 ", d_reclen=%u, d_type=",
199 i ? " " : "",
200 d->d_ino,
201 d->d_off,
202 d->d_reclen);
203 printxval(direnttypes, d->d_type, "DT_???");
Dmitry V. Levinc9297712015-01-25 00:04:20 +0000204
205 tprints(", d_name=");
206 if (print_quoted_string(d->d_name, d_name_len,
207 QUOTE_0_TERMINATED) > 0) {
208 tprints("...");
209 }
210
211 tprints("}");
Dmitry V. Levin2ed2cc72014-09-11 22:40:37 +0000212 }
213 if (d->d_reclen < d_name_offset) {
214 tprints("/* d_reclen < offsetof(struct dirent64, d_name) */");
215 break;
216 }
217 i += d->d_reclen;
218 dents++;
219 }
220 if (!abbrev(tcp))
221 tprints("}");
222 else
223 tprintf("/* %u entries */", dents);
224 tprintf(", %lu", tcp->u_arg[2]);
225 free(buf);
226 return 0;
227}