]> granicus.if.org Git - strace/blob - dirent.c
Move dirent related parsers to a separate file
[strace] / dirent.c
1 #include "defs.h"
2 #include <dirent.h>
3
4 struct kernel_dirent {
5         unsigned long   d_ino;
6         unsigned long   d_off;
7         unsigned short  d_reclen;
8         char            d_name[1];
9 };
10
11 static void
12 print_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
39 int
40 sys_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
59 int
60 sys_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
133 int
134 sys_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 }