]>
Commit | Line | Data |
---|---|---|
3bc05641 BF |
1 | /* |
2 | * Copyright (c) 2013 Red Hat, Inc. | |
3 | * All Rights Reserved. | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or | |
6 | * modify it under the terms of the GNU General Public License as | |
7 | * published by the Free Software Foundation. | |
8 | * | |
9 | * This program is distributed in the hope that it would be useful, | |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | * GNU General Public License for more details. | |
13 | * | |
14 | * You should have received a copy of the GNU General Public License | |
15 | * along with this program; if not, write the Free Software Foundation, | |
16 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
17 | */ | |
18 | ||
6b803e5a CH |
19 | #include "command.h" |
20 | #include "input.h" | |
3bc05641 BF |
21 | #include "init.h" |
22 | #include "io.h" | |
23 | ||
24 | #include <sys/types.h> | |
25 | #include <dirent.h> | |
26 | ||
2b86cff7 RS |
27 | #ifndef _DIRENT_HAVE_D_RECLEN |
28 | #include <string.h> | |
29 | #endif | |
30 | ||
3bc05641 BF |
31 | static struct cmdinfo readdir_cmd; |
32 | ||
33 | const char *d_type_str(unsigned int type) | |
34 | { | |
35 | const char *str; | |
36 | ||
37 | switch (type) { | |
38 | case DT_UNKNOWN: | |
39 | str = "DT_UNKNOWN"; | |
40 | break; | |
41 | case DT_FIFO: | |
42 | str = "DT_FIFO"; | |
43 | break; | |
44 | case DT_CHR: | |
45 | str = "DT_CHR"; | |
46 | break; | |
47 | case DT_DIR: | |
48 | str = "DT_DIR"; | |
49 | break; | |
50 | case DT_BLK: | |
51 | str = "DT_BLK"; | |
52 | break; | |
53 | case DT_REG: | |
54 | str = "DT_REG"; | |
55 | break; | |
56 | case DT_LNK: | |
57 | str = "DT_LNK"; | |
58 | break; | |
59 | case DT_SOCK: | |
60 | str = "DT_SOCK"; | |
61 | break; | |
62 | case DT_WHT: | |
63 | str = "DT_WHT"; | |
64 | break; | |
65 | default: | |
66 | str = "ERROR!"; | |
67 | break; | |
68 | } | |
69 | ||
70 | return str; | |
71 | } | |
72 | ||
73 | static void | |
74 | dump_dirent( | |
75 | long long offset, | |
76 | struct dirent *dirent) | |
77 | { | |
5e303e25 ES |
78 | printf("%08llx: d_ino: 0x%08llx", offset, |
79 | (unsigned long long)dirent->d_ino); | |
3bc05641 | 80 | #ifdef _DIRENT_HAVE_D_OFF |
5e303e25 | 81 | printf(" d_off: 0x%08llx", (unsigned long long)dirent->d_off); |
3bc05641 BF |
82 | #endif |
83 | #ifdef _DIRENT_HAVE_D_RECLEN | |
84 | printf(" d_reclen: 0x%x", dirent->d_reclen); | |
85 | #endif | |
86 | #ifdef _DIRENT_HAVE_D_TYPE | |
87 | printf(" d_type: %s", d_type_str(dirent->d_type)); | |
88 | #endif | |
89 | printf(" d_name: %s\n", dirent->d_name); | |
90 | } | |
91 | ||
92 | static int | |
93 | read_directory( | |
94 | DIR *dir, | |
95 | long long offset, | |
96 | unsigned long long length, | |
97 | int dump, | |
98 | unsigned long long *total) | |
99 | { | |
100 | struct dirent *dirent; | |
101 | int count = 0; | |
102 | ||
103 | seekdir(dir, offset); | |
104 | ||
105 | *total = 0; | |
106 | while (*total < length) { | |
107 | dirent = readdir(dir); | |
108 | if (!dirent) | |
109 | break; | |
110 | ||
19863f7b | 111 | #ifdef _DIRENT_HAVE_D_RECLEN |
3bc05641 | 112 | *total += dirent->d_reclen; |
19863f7b | 113 | #else |
2b86cff7 | 114 | *total += strlen(dirent->d_name) + sizeof(*dirent); |
19863f7b | 115 | #endif |
3bc05641 BF |
116 | count++; |
117 | ||
118 | if (dump) { | |
119 | dump_dirent(offset, dirent); | |
19863f7b | 120 | #ifdef _DIRENT_HAVE_D_OFF |
3bc05641 | 121 | offset = dirent->d_off; |
19863f7b JT |
122 | #else |
123 | /* Some platforms don't have dirent->d_off, but because | |
124 | * it is used only for dumping the value, it should be | |
125 | * safe to only set it to zero in such case. | |
126 | */ | |
127 | offset = 0; | |
128 | #endif | |
3bc05641 BF |
129 | } |
130 | } | |
131 | ||
132 | return count; | |
133 | } | |
134 | ||
135 | static int | |
136 | readdir_f( | |
137 | int argc, | |
138 | char **argv) | |
139 | { | |
140 | int cnt; | |
141 | unsigned long long total; | |
142 | int c; | |
143 | size_t fsblocksize, fssectsize; | |
144 | struct timeval t1, t2; | |
145 | char s1[64], s2[64], ts[64]; | |
146 | long long offset = -1; | |
147 | unsigned long long length = -1; /* max length limit */ | |
148 | int verbose = 0; | |
149 | DIR *dir; | |
150 | int dfd; | |
151 | ||
152 | init_cvtnum(&fsblocksize, &fssectsize); | |
153 | ||
154 | while ((c = getopt(argc, argv, "l:o:v")) != EOF) { | |
155 | switch (c) { | |
156 | case 'l': | |
157 | length = cvtnum(fsblocksize, fssectsize, optarg); | |
158 | break; | |
159 | case 'o': | |
160 | offset = cvtnum(fsblocksize, fssectsize, optarg); | |
161 | break; | |
162 | case 'v': | |
163 | verbose = 1; | |
164 | break; | |
165 | default: | |
166 | return command_usage(&readdir_cmd); | |
167 | } | |
168 | } | |
169 | ||
170 | dfd = dup(file->fd); | |
171 | if (dfd < 0) | |
172 | return -1; | |
173 | ||
174 | dir = fdopendir(dfd); | |
175 | if (!dir) { | |
176 | close(dfd); | |
177 | return -1; | |
178 | } | |
179 | ||
180 | if (offset == -1) { | |
181 | rewinddir(dir); | |
182 | offset = telldir(dir); | |
183 | } | |
184 | ||
185 | gettimeofday(&t1, NULL); | |
186 | cnt = read_directory(dir, offset, length, verbose, &total); | |
187 | gettimeofday(&t2, NULL); | |
188 | ||
189 | closedir(dir); | |
11e06961 | 190 | close(dfd); |
3bc05641 BF |
191 | |
192 | t2 = tsub(t2, t1); | |
193 | timestr(&t2, ts, sizeof(ts), 0); | |
194 | ||
195 | cvtstr(total, s1, sizeof(s1)); | |
196 | cvtstr(tdiv(total, t2), s2, sizeof(s2)); | |
197 | ||
198 | printf(_("read %llu bytes from offset %lld\n"), total, offset); | |
199 | printf(_("%s, %d ops, %s (%s/sec and %.4f ops/sec)\n"), | |
200 | s1, cnt, ts, s2, tdiv(cnt, t2)); | |
201 | ||
202 | return 0; | |
203 | } | |
204 | ||
205 | void | |
206 | readdir_init(void) | |
207 | { | |
208 | readdir_cmd.name = "readdir"; | |
209 | readdir_cmd.cfunc = readdir_f; | |
210 | readdir_cmd.argmax = 5; | |
211 | readdir_cmd.flags = CMD_NOMAP_OK|CMD_FOREIGN_OK; | |
212 | readdir_cmd.args = _("[-v][-o offset][-l length]"); | |
213 | readdir_cmd.oneline = _("read directory entries"); | |
214 | ||
215 | add_command(&readdir_cmd); | |
216 | } |