]> granicus.if.org Git - strace/blob - dirent.c
getdents, getdents64: quote filenames
[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 int
42 sys_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
61 int
62 sys_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;
108                         if (d_name_len > D_NAME_LEN_MAX)
109                                 d_name_len = D_NAME_LEN_MAX;
110
111                         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=");
120                         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
142 int
143 sys_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                         }
194                         if (d_name_len > D_NAME_LEN_MAX)
195                                 d_name_len = D_NAME_LEN_MAX;
196
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_???");
204
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("}");
212                 }
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 }