]> granicus.if.org Git - strace/blob - dirent.c
Mpersify parsers of utimes, futimesat, and utimensat syscalls
[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 (umove_or_printaddr(tcp, addr, &d))
29                 return;
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 > D_NAME_LEN_MAX)
34                 d.d_reclen = D_NAME_LEN_MAX;
35         printpathn(tcp, addr + offsetof(old_dirent_t, d_name), d.d_reclen);
36         tprints("}");
37 }
38
39 SYS_FUNC(readdir)
40 {
41         if (entering(tcp)) {
42                 printfd(tcp, tcp->u_arg[0]);
43                 tprints(", ");
44         } else {
45                 if (tcp->u_rval == 0)
46                         printaddr(tcp->u_arg[1]);
47                 else
48                         print_old_dirent(tcp, tcp->u_arg[1]);
49                 /* Not much point in printing this out, it is always 1. */
50                 if (tcp->u_arg[2] != 1)
51                         tprintf(", %lu", tcp->u_arg[2]);
52         }
53         return 0;
54 }
55
56 #include "xlat/direnttypes.h"
57
58 SYS_FUNC(getdents)
59 {
60         unsigned int i, len, dents = 0;
61         char *buf;
62
63         if (entering(tcp)) {
64                 printfd(tcp, tcp->u_arg[0]);
65                 tprints(", ");
66                 return 0;
67         }
68         if (syserror(tcp) || !verbose(tcp)) {
69                 printaddr(tcp->u_arg[1]);
70                 tprintf(", %lu", tcp->u_arg[2]);
71                 return 0;
72         }
73
74         /* Beware of insanely large or too small values in tcp->u_rval */
75         if (tcp->u_rval > 1024*1024)
76                 len = 1024*1024;
77         else if (tcp->u_rval < (int) sizeof(struct kernel_dirent))
78                 len = 0;
79         else
80                 len = tcp->u_rval;
81
82         if (len) {
83                 buf = malloc(len);
84                 if (!buf || umoven(tcp, tcp->u_arg[1], len, buf) < 0) {
85                         printaddr(tcp->u_arg[1]);
86                         tprintf(", %lu", 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                 printaddr(tcp->u_arg[1]);
153                 tprintf(", %lu", tcp->u_arg[2]);
154                 return 0;
155         }
156
157         /* Beware of insanely large or too small tcp->u_rval */
158         if (tcp->u_rval > 1024*1024)
159                 len = 1024*1024;
160         else if (tcp->u_rval < (int) d_name_offset)
161                 len = 0;
162         else
163                 len = tcp->u_rval;
164
165         if (len) {
166                 buf = malloc(len);
167                 if (!buf || umoven(tcp, tcp->u_arg[1], len, buf) < 0) {
168                         printaddr(tcp->u_arg[1]);
169                         tprintf(", %lu", tcp->u_arg[2]);
170                         free(buf);
171                         return 0;
172                 }
173         } else {
174                 buf = NULL;
175         }
176
177         if (!abbrev(tcp))
178                 tprints("{");
179         for (i = 0; len && i <= len - d_name_offset; ) {
180                 struct dirent64 *d = (struct dirent64 *) &buf[i];
181                 if (!abbrev(tcp)) {
182                         int d_name_len;
183                         if (d->d_reclen >= d_name_offset
184                             && i + d->d_reclen <= len) {
185                                 d_name_len = d->d_reclen - d_name_offset;
186                         } else {
187                                 d_name_len = len - i - d_name_offset;
188                         }
189                         if (d_name_len > D_NAME_LEN_MAX)
190                                 d_name_len = D_NAME_LEN_MAX;
191
192                         tprintf("%s{d_ino=%" PRIu64 ", d_off=%" PRId64
193                                 ", d_reclen=%u, d_type=",
194                                 i ? " " : "",
195                                 d->d_ino,
196                                 d->d_off,
197                                 d->d_reclen);
198                         printxval(direnttypes, d->d_type, "DT_???");
199
200                         tprints(", d_name=");
201                         if (print_quoted_string(d->d_name, d_name_len,
202                                                 QUOTE_0_TERMINATED) > 0) {
203                                 tprints("...");
204                         }
205
206                         tprints("}");
207                 }
208                 if (d->d_reclen < d_name_offset) {
209                         tprints("/* d_reclen < offsetof(struct dirent64, d_name) */");
210                         break;
211                 }
212                 i += d->d_reclen;
213                 dents++;
214         }
215         if (!abbrev(tcp))
216                 tprints("}");
217         else
218                 tprintf("/* %u entries */", dents);
219         tprintf(", %lu", tcp->u_arg[2]);
220         free(buf);
221         return 0;
222 }