root/user/testbin/dirseek/dirseek.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. findentry
  2. openit
  3. closeit
  4. readit
  5. firstread
  6. doreadat0
  7. readone
  8. doreadone
  9. readallonebyone
  10. readallrandomly
  11. readateof
  12. doreadateof
  13. inval_read
  14. dobadreads
  15. dotest
  16. mkfile
  17. setup
  18. cleanup
  19. main

   1 /*
   2  * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
   3  *      The President and Fellows of Harvard College.
   4  *
   5  * Redistribution and use in source and binary forms, with or without
   6  * modification, are permitted provided that the following conditions
   7  * are met:
   8  * 1. Redistributions of source code must retain the above copyright
   9  *    notice, this list of conditions and the following disclaimer.
  10  * 2. Redistributions in binary form must reproduce the above copyright
  11  *    notice, this list of conditions and the following disclaimer in the
  12  *    documentation and/or other materials provided with the distribution.
  13  * 3. Neither the name of the University nor the names of its contributors
  14  *    may be used to endorse or promote products derived from this software
  15  *    without specific prior written permission.
  16  *
  17  * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
  18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
  21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27  * SUCH DAMAGE.
  28  */
  29 
  30 /*
  31  * dirseek.c
  32  *
  33  *      Tests seeking on directories (both legally and illegally).
  34  *
  35  *      Makes a test subdirectory in the current directory.
  36  *
  37  *      Intended for the file system assignment. Should run (on SFS)
  38  *      when that assignment is complete.
  39  *
  40  *      Note: checks a few things that are not _strictly_ guaranteed
  41  *      by the official semantics of getdirentry() but that are more
  42  *      or less necessary in a sane implementation, like that the
  43  *      current seek position returned after seeking is the same
  44  *      position that was requested. If you believe your
  45  *      implementation is legal and the the test is rejecting it
  46  *      gratuitously, please contact the course staff.
  47  */
  48 
  49 #include <sys/types.h>
  50 #include <sys/stat.h>
  51 #include <unistd.h>
  52 #include <string.h>
  53 #include <stdio.h>
  54 #include <stdlib.h>
  55 #include <err.h>
  56 
  57 #define TESTDIR "seektestdir"
  58 
  59 static struct {
  60         const char *name;
  61         int make_it;
  62         off_t pos;
  63 } testfiles[] = {
  64         { ".",          0, -1 },
  65         { "..",         0, -1 },
  66         { "ridcully",   1, -1 },
  67         { "weatherwax", 1, -1 },
  68         { "ogg",        1, -1 },
  69         { "vorbis",     1, -1 },
  70         { "verence",    1, -1 },
  71         { "magrat",     1, -1 },
  72         { "agnes",      1, -1 },
  73         { "rincewind",  1, -1 },
  74         { "angua",      1, -1 },
  75         { "cherry",     1, -1 },
  76         { "dorfl",      1, -1 },
  77         { "nobby",      1, -1 },
  78         { "carrot",     1, -1 },
  79         { "vimes",      1, -1 },
  80         { "detritus",   1, -1 },
  81         { "twoflower",  1, -1 },
  82         { "teatime",    1, -1 },
  83         { "qu",         1, -1 },
  84         { NULL, 0, 0 }
  85 };
  86 
  87 /************************************************************/
  88 /* Test code                                                */
  89 /************************************************************/
  90 
  91 static int dirfd;
  92 
  93 static
  94 int
  95 findentry(const char *name)
  96 {
  97         int i;
  98 
  99         for (i=0; testfiles[i].name; i++) {
 100                 if (!strcmp(testfiles[i].name, name)) {
 101                         return i;
 102                 }
 103         }
 104         return -1;
 105 }
 106 
 107 static
 108 void
 109 openit(void)
 110 {
 111         dirfd = open(".", O_RDONLY);
 112         if (dirfd < 0) {
 113                 err(1, ".: open");
 114         }
 115 }
 116 
 117 static
 118 void
 119 closeit(void)
 120 {
 121         if (close(dirfd)<0) {
 122                 err(1, ".: close");
 123         }
 124         dirfd = -1;
 125 }
 126 
 127 static
 128 void
 129 readit(void)
 130 {
 131         char buf[4096];
 132         off_t pos;
 133         int len;
 134         int n, i, ix;
 135 
 136         for (i=0; testfiles[i].name; i++) {
 137                 testfiles[i].pos = -1;
 138         }
 139 
 140         pos = lseek(dirfd, 0, SEEK_CUR);
 141         if (pos < 0) {
 142                 err(1, ".: lseek(0, SEEK_CUR)");
 143         }
 144         n = 0;
 145 
 146         while ((len = getdirentry(dirfd, buf, sizeof(buf)-1)) > 0) {
 147 
 148                 if ((unsigned)len >= sizeof(buf)-1) {
 149                         errx(1, ".: entry %d: getdirentry returned "
 150                              "invalid length %d", n, len);
 151                 }
 152                 buf[len] = 0;
 153                 ix = findentry(buf);
 154                 if (ix < 0) {
 155                         errx(1, ".: entry %d: getdirentry returned "
 156                              "unexpected name %s", n, buf);
 157                 }
 158 
 159                 if (testfiles[ix].pos >= 0) {
 160                         errx(1, ".: entry %d: getdirentry returned "
 161                              "%s a second time", n, buf);
 162                 }
 163 
 164                 testfiles[ix].pos = pos;
 165                 
 166                 pos = lseek(dirfd, 0, SEEK_CUR);
 167                 if (pos < 0) {
 168                         err(1, ".: lseek(0, SEEK_CUR)");
 169                 }
 170                 n++;
 171         }
 172         if (len<0) {
 173                 err(1, ".: entry %d: getdirentry", n);
 174         }
 175 
 176         for (i=0; testfiles[i].name; i++) {
 177                 if (testfiles[i].pos < 0) {
 178                         errx(1, ".: getdirentry failed to return %s",
 179                              testfiles[i].name);
 180                 }
 181         }
 182         if (i!=n) {
 183                 /*
 184                  * If all of the other checks have passed, this should not
 185                  * be able to fail. But... just in case I forgot something
 186                  * or there's a bug...
 187                  */
 188 
 189                 errx(1, ".: getdirentry returned %d names, not %d (huh...?)",
 190                      n, i);
 191         }
 192 }
 193         
 194 static
 195 void
 196 firstread(void)
 197 {
 198         off_t pos;
 199 
 200         pos = lseek(dirfd, 0, SEEK_CUR);
 201         if (pos < 0) {
 202                 err(1, ".: lseek(0, SEEK_CUR)");
 203         }
 204         if (pos != 0) {
 205                 errx(1, ".: File position after open not 0");
 206         }
 207 
 208         printf("Scanning directory...\n");
 209 
 210         readit();
 211 }
 212 
 213 static
 214 void
 215 doreadat0(void)
 216 {
 217         off_t pos;
 218 
 219         printf("Rewinding directory and reading it again...\n");
 220 
 221         pos = lseek(dirfd, 0, SEEK_SET);
 222         if (pos < 0) {
 223                 err(1, ".: lseek(0, SEEK_SET)");
 224         }
 225         if (pos != 0) {
 226                 errx(1, ".: lseek(0, SEEK_SET) returned %ld", (long) pos);
 227         }
 228 
 229         readit();
 230 }
 231 
 232 static
 233 void
 234 readone(const char *shouldbe)
 235 {
 236         char buf[4096];
 237         int len;
 238 
 239         len = getdirentry(dirfd, buf, sizeof(buf)-1);
 240         if (len < 0) {
 241                 err(1, ".: getdirentry");
 242         }
 243         if ((unsigned)len >= sizeof(buf)-1) {
 244                 errx(1, ".: getdirentry returned invalid length %d", len);
 245         }
 246         buf[len] = 0;
 247 
 248         if (strcmp(buf, shouldbe)) {
 249                 errx(1, ".: getdirentry returned %s (expected %s)",
 250                      buf, shouldbe);
 251         }
 252 }
 253 
 254 static
 255 void
 256 doreadone(int which)
 257 {
 258         off_t pos;
 259         pos = lseek(dirfd, testfiles[which].pos, SEEK_SET);
 260         if (pos<0) {
 261                 err(1, ".: lseek(%ld, SEEK_SET)", (long) testfiles[which].pos);
 262         }
 263         if (pos != testfiles[which].pos) {
 264                 errx(1, ".: lseek(%ld, SEEK_SET) returned %ld",
 265                      (long) testfiles[which].pos, (long) pos);
 266         }
 267 
 268         readone(testfiles[which].name);
 269 }
 270 
 271 static
 272 void
 273 readallonebyone(void)
 274 {
 275         int i;
 276 
 277         printf("Trying to read each entry again...\n");
 278         for (i=0; testfiles[i].name; i++) {
 279                 doreadone(i);
 280         }
 281 }
 282 
 283 static
 284 void
 285 readallrandomly(void)
 286 {
 287         int n, i, x;
 288 
 289         printf("Trying to read a bunch of entries randomly...\n");
 290 
 291         for (i=0; testfiles[i].name; i++);
 292         n = i;
 293 
 294         srandom(39584);
 295         for (i=0; i<512; i++) {
 296                 x = (int)(random()%n);
 297                 doreadone(x);
 298         }
 299 }
 300 
 301 static
 302 void
 303 readateof(void)
 304 {
 305         char buf[4096];
 306         int len;
 307 
 308         len = getdirentry(dirfd, buf, sizeof(buf)-1);
 309         if (len < 0) {
 310                 err(1, ".: at EOF: getdirentry");
 311         }
 312         if (len==0) {
 313                 return;
 314         }
 315         if ((unsigned)len >= sizeof(buf)-1) {
 316                 errx(1, ".: at EOF: getdirentry returned "
 317                      "invalid length %d", len);
 318         }
 319         buf[len] = 0;
 320         errx(1, ".: at EOF: got unexpected name %s", buf);
 321 }
 322 
 323 static
 324 void
 325 doreadateof(void)
 326 {
 327         off_t pos;
 328         int i;
 329 
 330         printf("Trying to read after going to EOF...\n");
 331 
 332         pos = lseek(dirfd, 0, SEEK_END);
 333         if (pos<0) {
 334                 err(1, ".: lseek(0, SEEK_END)");
 335         }
 336 
 337         for (i=0; testfiles[i].name; i++) {
 338                 if (pos <= testfiles[i].pos) {
 339                         errx(1, ".: EOF position %ld below position %ld of %s",
 340                              pos, testfiles[i].pos, testfiles[i].name);
 341                 }
 342         }
 343 
 344         readateof();
 345 }
 346 
 347 static
 348 void
 349 inval_read(void)
 350 {
 351         char buf[4096];
 352         int len;
 353 
 354         len = getdirentry(dirfd, buf, sizeof(buf)-1);
 355 
 356         /* Any result is ok, as long as the system doesn't crash */
 357         (void)len;
 358 }
 359 
 360 static
 361 void
 362 dobadreads(void)
 363 {
 364         off_t pos, pos2, eof;
 365         int valid, i, k=0;
 366 
 367         printf("Trying some possibly invalid reads...\n");
 368 
 369         eof = lseek(dirfd, 0, SEEK_END);
 370         if (eof < 0) {
 371                 err(1, ".: lseek(0, SEEK_END)");
 372         }
 373 
 374         for (pos=0; pos < eof; pos++) {
 375                 valid = 0;
 376                 for (i=0; testfiles[i].name; i++) {
 377                         if (pos==testfiles[i].pos) {
 378                                 valid = 1;
 379                         }
 380                 }
 381                 if (valid) {
 382                         /* don't try offsets that are known to be valid */
 383                         continue;
 384                 }
 385 
 386                 pos2 = lseek(dirfd, pos, SEEK_SET);
 387                 if (pos2 < 0) {
 388                         /* this is ok */
 389                 }
 390                 else {
 391                         inval_read();
 392                         k++;
 393                 }
 394         }
 395 
 396         if (k>0) {
 397                 printf("Survived %d invalid reads...\n", k);
 398         }
 399         else {
 400                 printf("Couldn't find any invalid offsets to try...\n");
 401         }
 402 
 403         printf("Trying to read beyond EOF...\n");
 404         pos2 = lseek(dirfd, eof + 1000, SEEK_SET);
 405         if (pos2 < 0) {
 406                 /* this is ok */
 407         }
 408         else {
 409                 inval_read();
 410         }
 411 }
 412 
 413 static
 414 void
 415 dotest(void)
 416 {
 417         printf("Opening directory...\n");
 418         openit();
 419 
 420         printf("Running tests...\n");
 421 
 422         /* read the whole directory */
 423         firstread();
 424 
 425         /* make sure eof behaves right */
 426         readateof();
 427 
 428         /* read all the filenames again by seeking */
 429         readallonebyone();
 430 
 431         /* try reading at eof */
 432         doreadateof();
 433 
 434         /* read a bunch of the filenames over and over again */
 435         readallrandomly();
 436 
 437         /* rewind and read the whole thing again, to make sure that works */
 438         doreadat0();
 439 
 440         /* do invalid reads */
 441         dobadreads();
 442 
 443         /* rewind again to make sure the invalid attempts didn't break it */
 444         doreadat0();
 445 
 446         printf("Closing directory...\n");
 447         closeit();
 448 }
 449 
 450 /************************************************************/
 451 /* Setup code                                               */
 452 /************************************************************/
 453 
 454 static
 455 void
 456 mkfile(const char *name)
 457 {
 458         int fd, i, r;
 459         static const char message[] = "The turtle moves!\n";
 460         char buf[32*sizeof(message)+1];
 461 
 462         buf[0]=0;
 463         for (i=0; i<32; i++) {
 464                 strcat(buf, message);
 465         }
 466 
 467         /* Use O_EXCL, because we know the file shouldn't already be there */
 468         fd = open(name, O_WRONLY|O_CREAT|O_EXCL, 0664);
 469         if (fd<0) {
 470                 err(1, "%s: create", name);
 471         }
 472 
 473         r = write(fd, buf, strlen(buf));
 474         if (r<0) {
 475                 err(1, "%s: write", name);
 476         }
 477         if ((unsigned)r != strlen(buf)) {
 478                 errx(1, "%s: short write (%d bytes)", name, r);
 479         }
 480 
 481         if (close(fd)<0) {
 482                 err(1, "%s: close", name);
 483         }
 484 }
 485 
 486 static
 487 void
 488 setup(void)
 489 {
 490         int i;
 491 
 492         printf("Making directory %s...\n", TESTDIR);
 493 
 494         /* Create a directory */
 495         if (mkdir(TESTDIR, 0775)<0) {
 496                 err(1, "%s: mkdir", TESTDIR);
 497         }
 498 
 499         /* Switch to it */
 500         if (chdir(TESTDIR)<0) {
 501                 err(1, "%s: chdir", TESTDIR);
 502         }
 503 
 504         printf("Making some files...\n");
 505 
 506         /* Populate it */
 507         for (i=0; testfiles[i].name; i++) {
 508                 if (testfiles[i].make_it) {
 509                         mkfile(testfiles[i].name);
 510                 }
 511                 testfiles[i].pos = -1;
 512         }
 513 }
 514 
 515 static
 516 void
 517 cleanup(void)
 518 {
 519         int i;
 520 
 521         printf("Cleaning up...\n");
 522 
 523         /* Remove the files */
 524         for (i=0; testfiles[i].name; i++) {
 525                 if (testfiles[i].make_it) {
 526                         if (remove(testfiles[i].name)<0) {
 527                                 err(1, "%s: remove", testfiles[i].name);
 528                         }
 529                 }
 530         }
 531 
 532         /* Leave the dir */
 533         if (chdir("..")<0) {
 534                 err(1, "..: chdir");
 535         }
 536 
 537         /* Remove the dir */
 538         if (rmdir(TESTDIR)<0) {
 539                 err(1, "%s: rmdir", TESTDIR);
 540         }
 541 }
 542 
 543 
 544 int
 545 main()
 546 {
 547         setup();
 548 
 549         /* Do the whole thing twice */
 550         dotest();
 551         dotest();
 552 
 553         cleanup();
 554         return 0;
 555 }

/* [<][>][^][v][top][bottom][index][help] */