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