1/*	$Id: getdents.c,v 1.9 2006/12/30 23:19:11 yamt Exp $	*/
2
3/*-
4 * Copyright (c)2004, 2006 YAMAMOTO Takashi,
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <err.h>
30#include <errno.h>
31#include <dirent.h>
32#include <fcntl.h>
33#include <inttypes.h>
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37#include <unistd.h>
38
39void print_dents(FILE *, const void *, int);
40int main(int, char *[]);
41
42void
43print_dents(FILE *fp, const void *vp, int sz)
44{
45	const char *cp = vp;
46	const char *ep = cp + sz;
47	const struct dirent *d;
48
49	while (cp < ep) {
50		d = (const void *)cp;
51		fprintf(fp, "fileno=%" PRIu64
52		    ", type=%d, reclen=%d, len=%d, %s\n",
53		    (uint64_t)d->d_fileno, (int)d->d_type, (int)d->d_reclen,
54		    (int)d->d_namlen, d->d_name);
55		cp += d->d_reclen;
56	}
57#if 1
58	{
59		int i;
60
61		for (cp = vp, i = 0; cp < ep; cp++, i++) {
62			if ((i % 16) == 0)
63				fprintf(fp, "%08tx:", cp - (const char *)vp);
64			fprintf(fp, "%02x ", (int)(unsigned char)*cp);
65			if ((i % 16) == 15)
66				fprintf(fp, "\n");
67		}
68	}
69#endif
70}
71
72struct ent {
73	off_t off;
74	int sz;
75	union {
76		struct dirent u_d;
77		char u_buf[DIRBLKSIZ];
78	} u;
79};
80
81int
82main(int argc, char *argv[])
83{
84	int fd;
85	off_t off;
86	int ret;
87	const char *path;
88	int nblks = 0;
89	struct ent *blks = NULL;
90	int i;
91	int count;
92
93	if (argc < 2)
94		errx(EXIT_FAILURE, "arg");
95	path = argv[1];
96	if (argc > 2)
97		off = strtoull(argv[2], 0, 0);
98	else
99		off = 0;
100
101	printf("dir=%s\n", path);
102	fd = open(path, O_RDONLY);
103	if (fd == -1)
104		err(EXIT_FAILURE, "open");
105	printf("seek: off=%" PRIx64 "(%" PRIu64 ")\n",
106	    (uint64_t)off, (uint64_t)off);
107	if (off != lseek(fd, off, SEEK_SET))
108		err(EXIT_FAILURE, "lseek");
109
110#if defined(DENSE_DIRECTORY)
111	printf("searching valid offsets..\n");
112	for (off = 0; ; off++) {
113		struct ent *p;
114		blks = realloc(blks, sizeof(*blks) * (nblks + 1));
115		if (blks == NULL)
116			err(EXIT_FAILURE, "realloc");
117		p = &blks[nblks];
118		memset(p, 0, sizeof(*p));
119		p->off = off = lseek(fd, off, SEEK_SET);
120		if (off == (off_t)-1)
121			err(EXIT_FAILURE, "lseek");
122		printf("off=%" PRIx64 "(%" PRIu64 ")\n",
123		    (uint64_t)off, (uint64_t)off);
124		p->sz = ret = getdents(fd, p->u.u_buf, DIRBLKSIZ);
125		printf("getdents: %d\n", ret);
126		if (ret == -1) {
127			if (errno == EINVAL) {
128				continue;
129			}
130			errx(EXIT_FAILURE, "getdents");
131		}
132		if (ret == 0) {
133			break;
134		}
135		nblks++;
136		print_dents(stdout, p->u.u_buf, ret);
137	}
138	printf("%d valid offsets found\n", nblks);
139#else /* defined(DENSE_DIRECTORY) */
140	printf("start reading..\n");
141	do {
142		struct ent *p;
143		blks = realloc(blks, sizeof(*blks) * (nblks + 1));
144		if (blks == NULL)
145			err(EXIT_FAILURE, "realloc");
146		p = &blks[nblks];
147		memset(p, 0, sizeof(*p));
148		p->off = off = lseek(fd, (off_t)0, SEEK_CUR);
149		if (off == (off_t)-1)
150			err(EXIT_FAILURE, "lseek");
151		printf("off=%" PRIx64 "(%" PRIu64 ")\n",
152		    (uint64_t)off, (uint64_t)off);
153		p->sz = ret = getdents(fd, p->u.u_buf, DIRBLKSIZ);
154		printf("getdents: %d\n", ret);
155		if (ret == -1)
156			err(EXIT_FAILURE, "getdents");
157		nblks++;
158		print_dents(stdout, p->u.u_buf, ret);
159	} while (ret > 0);
160	printf("%d blks read\n", nblks);
161#endif /* defined(DENSE_DIRECTORY) */
162
163#if 1
164	printf("re-open the file\n");
165	if (close(fd))
166		err(EXIT_FAILURE, "close");
167	fd = open(path, O_RDONLY);
168	if (fd == -1)
169		err(EXIT_FAILURE, "open");
170#endif
171
172	printf("starting random read...\n");
173	for (count = nblks * 4 + 10; count; count--) {
174		char buf[DIRBLKSIZ];
175		struct ent *p;
176		int differ = 0;
177
178		i = rand() % nblks;
179		p = &blks[i];
180		off = lseek(fd, p->off, SEEK_SET);
181		if (off == (off_t)-1)
182			err(1, "seek");
183		printf("off=%" PRIx64 "(%" PRIu64 ")\n",
184		    (uint64_t)off, (uint64_t)off);
185		ret = getdents(fd, buf, DIRBLKSIZ);
186		printf("getdents: %d\n", ret);
187		if (ret == -1)
188			err(EXIT_FAILURE, "getdents");
189		if (p->sz != ret) {
190			fflush(NULL);
191			fprintf(stderr, "off=%" PRIx64
192			    ": different sz %d != %d\n",
193			    (uint64_t)off, p->sz, ret);
194			differ = 1;
195		} else if (memcmp(p->u.u_buf, buf, (size_t)ret)) {
196			fflush(NULL);
197			fprintf(stderr, "off=%" PRIx64 ": different data\n",
198			    (uint64_t)off);
199			fprintf(stderr, "previous:\n");
200			print_dents(stderr, p->u.u_buf, p->sz);
201			fprintf(stderr, "now:\n");
202			print_dents(stderr, buf, ret);
203			differ = 1;
204		}
205		if (differ) {
206			const struct dirent *d1 = (void *)p->u.u_buf;
207			const struct dirent *d2 = (void *)buf;
208
209			if (p->sz == 0 || ret == 0 ||
210			    d1->d_fileno != d2->d_fileno ||
211#if defined(DT_UNKNOWN)
212			    (d1->d_type != DT_UNKNOWN &&
213			     d2->d_type != DT_UNKNOWN &&
214			     d1->d_type != d2->d_type) ||
215#endif /* defined(DT_UNKNOWN) */
216			    d1->d_namlen != d2->d_namlen ||
217			    memcmp(d1->d_name, d2->d_name, d1->d_namlen)) {
218				fprintf(stderr, "fatal difference\n");
219				exit(EXIT_FAILURE);
220			}
221		}
222	}
223
224	exit(EXIT_SUCCESS);
225	/* NOTREACHED */
226}
227