1 /*
2 * Copyright (c) 1991, 1992 Paul Kranenburg <pk@cs.few.eur.nl>
3 * Copyright (c) 1993 Branko Lankester <branko@hacktic.nl>
4 * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
5 * Copyright (c) 1996-1999 Wichert Akkerman <wichert@cistron.nl>
6 * Copyright (c) 2005-2015 Dmitry V. Levin <ldv@strace.io>
7 * Copyright (c) 2014-2021 The strace developers.
8 * All rights reserved.
9 *
10 * SPDX-License-Identifier: LGPL-2.1-or-later
11 */
12
13 #include "defs.h"
14 #include "kernel_dirent.h"
15
16 #include DEF_MPERS_TYPE(kernel_dirent_t)
17
18 #include MPERS_DEFS
19
20 #include "xgetdents.h"
21
22 #define D_NAME_LEN_MAX 256
23
24 /* The minimum size of a valid directory entry. */
25 static const unsigned int header_size =
26 offsetof(kernel_dirent_t, d_name);
27
28 static void
29 print_dentry_head(const kernel_dirent_t *const dent)
30 {
31 tprint_struct_begin();
32 PRINT_FIELD_U(*dent, d_ino);
33 tprint_struct_next();
34 PRINT_FIELD_U(*dent, d_off);
35 tprint_struct_next();
36 PRINT_FIELD_U(*dent, d_reclen);
37 }
38
39 static unsigned int
40 decode_dentry_head(struct tcb *const tcp, const void *const arg)
41 {
42 const kernel_dirent_t *const dent = arg;
43
44 if (!abbrev(tcp))
45 print_dentry_head(dent);
46
47 return dent->d_reclen;
48 }
49
50 static int
51 decode_dentry_tail(struct tcb *const tcp, kernel_ulong_t addr,
52 const void *const arg, const unsigned int d_name_type_len)
53 {
54 int rc = 0;
55
56 /* !abbrev(tcp) */
57
58 if (d_name_type_len) {
59 unsigned int d_name_len = d_name_type_len - 1;
60 if (d_name_len) {
61 if (d_name_len > D_NAME_LEN_MAX)
62 d_name_len = D_NAME_LEN_MAX;
63 tprint_struct_next();
64 tprints_field_name("d_name");
65 rc = printpathn(tcp, addr, d_name_len - 1);
66 }
67 tprint_struct_next();
68 tprints_field_name("d_type");
69 const kernel_ulong_t d_type_addr =
70 addr + (d_name_type_len - 1);
71 unsigned char d_type;
72 if (umove_or_printaddr(tcp, d_type_addr, &d_type))
73 rc = -1;
74 else
75 printxval(dirent_types, d_type, "DT_???");
76 }
77 tprint_struct_end();
78
79 return rc;
80 }
81
82 SYS_FUNC(getdents)
83 {
84 return xgetdents(tcp, header_size,
85 decode_dentry_head, decode_dentry_tail);
86 }
87
88 static void
89 print_old_dirent(struct tcb *const tcp, const kernel_ulong_t addr)
90 {
91 kernel_dirent_t dent;
92
93 if (umove_or_printaddr(tcp, addr, &dent))
94 return;
95
96 print_dentry_head(&dent);
97 tprint_struct_next();
98 tprints_field_name("d_name");
99 printpathn(tcp, addr + header_size,
100 MIN(dent.d_reclen, D_NAME_LEN_MAX));
101 tprint_struct_end();
102 }
103
104 SYS_FUNC(readdir)
105 {
106 if (entering(tcp)) {
107 /* fd */
108 printfd(tcp, tcp->u_arg[0]);
109 #ifdef ENABLE_SECONTEXT
110 tcp->last_dirfd = (int) tcp->u_arg[0];
111 #endif
112 tprint_arg_next();
113 } else {
114 /* dirp */
115 if (tcp->u_rval == 0)
116 printaddr(tcp->u_arg[1]);
117 else
118 print_old_dirent(tcp, tcp->u_arg[1]);
119
120 /* count */
121 const unsigned int count = tcp->u_arg[2];
122 /* Not much point in printing this out, it is always 1. */
123 if (count != 1) {
124 tprint_arg_next();
125 PRINT_VAL_U(count);
126 }
127 }
128 return 0;
129 }