blob: cbebdb73314797136378cb063ac17d0e34022371 [file] [log] [blame]
Dmitry V. Levin2ed2cc72014-09-11 22:40:37 +00001#include "defs.h"
2#include <dirent.h>
3
4struct kernel_dirent {
5 unsigned long d_ino;
6 unsigned long d_off;
7 unsigned short d_reclen;
8 char d_name[1];
9};
10
11static void
12print_old_dirent(struct tcb *tcp, long addr)
13{
14#ifdef SH64
15 typedef struct kernel_dirent old_dirent_t;
16#else
17 typedef struct {
18 uint32_t d_ino;
19 uint32_t d_off;
20 unsigned short d_reclen;
21 char d_name[1];
22 } old_dirent_t;
23#endif
24 old_dirent_t d;
25
26 if (!verbose(tcp) || umove(tcp, addr, &d) < 0) {
27 tprintf("%#lx", addr);
28 return;
29 }
30
31 tprintf("{d_ino=%lu, d_off=%lu, d_reclen=%u, d_name=\"",
32 (unsigned long) d.d_ino, (unsigned long) d.d_off, d.d_reclen);
33 if (d.d_reclen > 256)
34 d.d_reclen = 256;
35 printpathn(tcp, addr + offsetof(old_dirent_t, d_name), d.d_reclen);
36 tprints("\"}");
37}
38
39int
40sys_readdir(struct tcb *tcp)
41{
42 if (entering(tcp)) {
43 printfd(tcp, tcp->u_arg[0]);
44 tprints(", ");
45 } else {
46 if (syserror(tcp) || tcp->u_rval == 0 || !verbose(tcp))
47 tprintf("%#lx", tcp->u_arg[1]);
48 else
49 print_old_dirent(tcp, tcp->u_arg[1]);
50 /* Not much point in printing this out, it is always 1. */
51 if (tcp->u_arg[2] != 1)
52 tprintf(", %lu", tcp->u_arg[2]);
53 }
54 return 0;
55}
56
57#include "xlat/direnttypes.h"
58
59int
60sys_getdents(struct tcb *tcp)
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
107 tprintf("%s{d_ino=%lu, d_off=%lu, ",
108 i ? " " : "", d->d_ino, d->d_off);
109 tprintf("d_reclen=%u, d_name=\"%.*s\", d_type=",
110 d->d_reclen, d_name_len, d->d_name);
111 if (oob)
112 tprints("?");
113 else
114 printxval(direnttypes, buf[i + d->d_reclen - 1], "DT_???");
115 tprints("}");
116 }
117 dents++;
118 if (d->d_reclen < sizeof(struct kernel_dirent)) {
119 tprints("/* d_reclen < sizeof(struct kernel_dirent) */");
120 break;
121 }
122 i += d->d_reclen;
123 }
124 if (!abbrev(tcp))
125 tprints("}");
126 else
127 tprintf("/* %u entries */", dents);
128 tprintf(", %lu", tcp->u_arg[2]);
129 free(buf);
130 return 0;
131}
132
133int
134sys_getdents64(struct tcb *tcp)
135{
136 /* the minimum size of a valid dirent64 structure */
137 const unsigned int d_name_offset = offsetof(struct dirent64, d_name);
138
139 unsigned int i, len, dents = 0;
140 char *buf;
141
142 if (entering(tcp)) {
143 printfd(tcp, tcp->u_arg[0]);
144 tprints(", ");
145 return 0;
146 }
147 if (syserror(tcp) || !verbose(tcp)) {
148 tprintf("%#lx, %lu", tcp->u_arg[1], tcp->u_arg[2]);
149 return 0;
150 }
151
152 /* Beware of insanely large or too small tcp->u_rval */
153 if (tcp->u_rval > 1024*1024)
154 len = 1024*1024;
155 else if (tcp->u_rval < (int) d_name_offset)
156 len = 0;
157 else
158 len = tcp->u_rval;
159
160 if (len) {
161 buf = malloc(len);
162 if (!buf)
163 die_out_of_memory();
164 if (umoven(tcp, tcp->u_arg[1], len, buf) < 0) {
165 tprintf("%#lx, %lu", tcp->u_arg[1], tcp->u_arg[2]);
166 free(buf);
167 return 0;
168 }
169 } else {
170 buf = NULL;
171 }
172
173 if (!abbrev(tcp))
174 tprints("{");
175 for (i = 0; len && i <= len - d_name_offset; ) {
176 struct dirent64 *d = (struct dirent64 *) &buf[i];
177 if (!abbrev(tcp)) {
178 int d_name_len;
179 if (d->d_reclen >= d_name_offset
180 && i + d->d_reclen <= len) {
181 d_name_len = d->d_reclen - d_name_offset;
182 } else {
183 d_name_len = len - i - d_name_offset;
184 }
185
186 tprintf("%s{d_ino=%" PRIu64 ", d_off=%" PRId64
187 ", d_reclen=%u, d_type=",
188 i ? " " : "",
189 d->d_ino,
190 d->d_off,
191 d->d_reclen);
192 printxval(direnttypes, d->d_type, "DT_???");
193 tprintf(", d_name=\"%.*s\"}",
194 d_name_len, d->d_name);
195 }
196 if (d->d_reclen < d_name_offset) {
197 tprints("/* d_reclen < offsetof(struct dirent64, d_name) */");
198 break;
199 }
200 i += d->d_reclen;
201 dents++;
202 }
203 if (!abbrev(tcp))
204 tprints("}");
205 else
206 tprintf("/* %u entries */", dents);
207 tprintf(", %lu", tcp->u_arg[2]);
208 free(buf);
209 return 0;
210}