]> granicus.if.org Git - strace/blob - dirent.c
io.c: use printaddr and umove_or_printaddr
[strace] / dirent.c
1 #include "defs.h"
2 #include <dirent.h>
3
4 #define D_NAME_LEN_MAX 256
5
6 struct kernel_dirent {
7         unsigned long   d_ino;
8         unsigned long   d_off;
9         unsigned short  d_reclen;
10         char            d_name[1];
11 };
12
13 static void
14 print_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
41 SYS_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
60 SYS_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 = xmalloc(len);
85                 if (umoven(tcp, tcp->u_arg[1], len, buf) < 0) {
86                         tprintf("%#lx, %lu", tcp->u_arg[1], tcp->u_arg[2]);
87                         free(buf);
88                         return 0;
89                 }
90         } else {
91                 buf = NULL;
92         }
93
94         if (!abbrev(tcp))
95                 tprints("{");
96         for (i = 0; len && i <= len - sizeof(struct kernel_dirent); ) {
97                 struct kernel_dirent *d = (struct kernel_dirent *) &buf[i];
98
99                 if (!abbrev(tcp)) {
100                         int oob = d->d_reclen < sizeof(struct kernel_dirent) ||
101                                   i + d->d_reclen - 1 >= len;
102                         int d_name_len = oob ? len - i : d->d_reclen;
103                         d_name_len -= offsetof(struct kernel_dirent, d_name) + 1;
104                         if (d_name_len > D_NAME_LEN_MAX)
105                                 d_name_len = D_NAME_LEN_MAX;
106
107                         tprintf("%s{d_ino=%lu, d_off=%lu, d_reclen=%u, d_name=",
108                                 i ? " " : "", d->d_ino, d->d_off, d->d_reclen);
109
110                         if (print_quoted_string(d->d_name, d_name_len,
111                                                 QUOTE_0_TERMINATED) > 0) {
112                                 tprints("...");
113                         }
114
115                         tprints(", d_type=");
116                         if (oob)
117                                 tprints("?");
118                         else
119                                 printxval(direnttypes, buf[i + d->d_reclen - 1], "DT_???");
120                         tprints("}");
121                 }
122                 dents++;
123                 if (d->d_reclen < sizeof(struct kernel_dirent)) {
124                         tprints("/* d_reclen < sizeof(struct kernel_dirent) */");
125                         break;
126                 }
127                 i += d->d_reclen;
128         }
129         if (!abbrev(tcp))
130                 tprints("}");
131         else
132                 tprintf("/* %u entries */", dents);
133         tprintf(", %lu", tcp->u_arg[2]);
134         free(buf);
135         return 0;
136 }
137
138 SYS_FUNC(getdents64)
139 {
140         /* the minimum size of a valid dirent64 structure */
141         const unsigned int d_name_offset = offsetof(struct dirent64, d_name);
142
143         unsigned int i, len, dents = 0;
144         char *buf;
145
146         if (entering(tcp)) {
147                 printfd(tcp, tcp->u_arg[0]);
148                 tprints(", ");
149                 return 0;
150         }
151         if (syserror(tcp) || !verbose(tcp)) {
152                 tprintf("%#lx, %lu", tcp->u_arg[1], tcp->u_arg[2]);
153                 return 0;
154         }
155
156         /* Beware of insanely large or too small tcp->u_rval */
157         if (tcp->u_rval > 1024*1024)
158                 len = 1024*1024;
159         else if (tcp->u_rval < (int) d_name_offset)
160                 len = 0;
161         else
162                 len = tcp->u_rval;
163
164         if (len) {
165                 buf = xmalloc(len);
166                 if (umoven(tcp, tcp->u_arg[1], len, buf) < 0) {
167                         tprintf("%#lx, %lu", tcp->u_arg[1], tcp->u_arg[2]);
168                         free(buf);
169                         return 0;
170                 }
171         } else {
172                 buf = NULL;
173         }
174
175         if (!abbrev(tcp))
176                 tprints("{");
177         for (i = 0; len && i <= len - d_name_offset; ) {
178                 struct dirent64 *d = (struct dirent64 *) &buf[i];
179                 if (!abbrev(tcp)) {
180                         int d_name_len;
181                         if (d->d_reclen >= d_name_offset
182                             && i + d->d_reclen <= len) {
183                                 d_name_len = d->d_reclen - d_name_offset;
184                         } else {
185                                 d_name_len = len - i - d_name_offset;
186                         }
187                         if (d_name_len > D_NAME_LEN_MAX)
188                                 d_name_len = D_NAME_LEN_MAX;
189
190                         tprintf("%s{d_ino=%" PRIu64 ", d_off=%" PRId64
191                                 ", d_reclen=%u, d_type=",
192                                 i ? " " : "",
193                                 d->d_ino,
194                                 d->d_off,
195                                 d->d_reclen);
196                         printxval(direnttypes, d->d_type, "DT_???");
197
198                         tprints(", d_name=");
199                         if (print_quoted_string(d->d_name, d_name_len,
200                                                 QUOTE_0_TERMINATED) > 0) {
201                                 tprints("...");
202                         }
203
204                         tprints("}");
205                 }
206                 if (d->d_reclen < d_name_offset) {
207                         tprints("/* d_reclen < offsetof(struct dirent64, d_name) */");
208                         break;
209                 }
210                 i += d->d_reclen;
211                 dents++;
212         }
213         if (!abbrev(tcp))
214                 tprints("}");
215         else
216                 tprintf("/* %u entries */", dents);
217         tprintf(", %lu", tcp->u_arg[2]);
218         free(buf);
219         return 0;
220 }