os161-1.99
 All Data Structures
dirseek.c
00001 /*
00002  * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
00003  *      The President and Fellows of Harvard College.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the University nor the names of its contributors
00014  *    may be used to endorse or promote products derived from this software
00015  *    without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
00018  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
00021  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00023  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00024  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00025  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00026  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00027  * SUCH DAMAGE.
00028  */
00029 
00030 /*
00031  * dirseek.c
00032  *
00033  *      Tests seeking on directories (both legally and illegally).
00034  *
00035  *      Makes a test subdirectory in the current directory.
00036  *
00037  *      Intended for the file system assignment. Should run (on SFS)
00038  *      when that assignment is complete.
00039  *
00040  *      Note: checks a few things that are not _strictly_ guaranteed
00041  *      by the official semantics of getdirentry() but that are more
00042  *      or less necessary in a sane implementation, like that the
00043  *      current seek position returned after seeking is the same
00044  *      position that was requested. If you believe your
00045  *      implementation is legal and the the test is rejecting it
00046  *      gratuitously, please contact the course staff.
00047  */
00048 
00049 #include <sys/types.h>
00050 #include <sys/stat.h>
00051 #include <unistd.h>
00052 #include <string.h>
00053 #include <stdio.h>
00054 #include <stdlib.h>
00055 #include <err.h>
00056 
00057 #define TESTDIR "seektestdir"
00058 
00059 static struct {
00060         const char *name;
00061         int make_it;
00062         off_t pos;
00063 } testfiles[] = {
00064         { ".",          0, -1 },
00065         { "..",         0, -1 },
00066         { "ridcully",   1, -1 },
00067         { "weatherwax", 1, -1 },
00068         { "ogg",        1, -1 },
00069         { "vorbis",     1, -1 },
00070         { "verence",    1, -1 },
00071         { "magrat",     1, -1 },
00072         { "agnes",      1, -1 },
00073         { "rincewind",  1, -1 },
00074         { "angua",      1, -1 },
00075         { "cherry",     1, -1 },
00076         { "dorfl",      1, -1 },
00077         { "nobby",      1, -1 },
00078         { "carrot",     1, -1 },
00079         { "vimes",      1, -1 },
00080         { "detritus",   1, -1 },
00081         { "twoflower",  1, -1 },
00082         { "teatime",    1, -1 },
00083         { "qu",         1, -1 },
00084         { NULL, 0, 0 }
00085 };
00086 
00087 /************************************************************/
00088 /* Test code                                                */
00089 /************************************************************/
00090 
00091 static int dirfd;
00092 
00093 static
00094 int
00095 findentry(const char *name)
00096 {
00097         int i;
00098 
00099         for (i=0; testfiles[i].name; i++) {
00100                 if (!strcmp(testfiles[i].name, name)) {
00101                         return i;
00102                 }
00103         }
00104         return -1;
00105 }
00106 
00107 static
00108 void
00109 openit(void)
00110 {
00111         dirfd = open(".", O_RDONLY);
00112         if (dirfd < 0) {
00113                 err(1, ".: open");
00114         }
00115 }
00116 
00117 static
00118 void
00119 closeit(void)
00120 {
00121         if (close(dirfd)<0) {
00122                 err(1, ".: close");
00123         }
00124         dirfd = -1;
00125 }
00126 
00127 static
00128 void
00129 readit(void)
00130 {
00131         char buf[4096];
00132         off_t pos;
00133         int len;
00134         int n, i, ix;
00135 
00136         for (i=0; testfiles[i].name; i++) {
00137                 testfiles[i].pos = -1;
00138         }
00139 
00140         pos = lseek(dirfd, 0, SEEK_CUR);
00141         if (pos < 0) {
00142                 err(1, ".: lseek(0, SEEK_CUR)");
00143         }
00144         n = 0;
00145 
00146         while ((len = getdirentry(dirfd, buf, sizeof(buf)-1)) > 0) {
00147 
00148                 if ((unsigned)len >= sizeof(buf)-1) {
00149                         errx(1, ".: entry %d: getdirentry returned "
00150                              "invalid length %d", n, len);
00151                 }
00152                 buf[len] = 0;
00153                 ix = findentry(buf);
00154                 if (ix < 0) {
00155                         errx(1, ".: entry %d: getdirentry returned "
00156                              "unexpected name %s", n, buf);
00157                 }
00158 
00159                 if (testfiles[ix].pos >= 0) {
00160                         errx(1, ".: entry %d: getdirentry returned "
00161                              "%s a second time", n, buf);
00162                 }
00163 
00164                 testfiles[ix].pos = pos;
00165                 
00166                 pos = lseek(dirfd, 0, SEEK_CUR);
00167                 if (pos < 0) {
00168                         err(1, ".: lseek(0, SEEK_CUR)");
00169                 }
00170                 n++;
00171         }
00172         if (len<0) {
00173                 err(1, ".: entry %d: getdirentry", n);
00174         }
00175 
00176         for (i=0; testfiles[i].name; i++) {
00177                 if (testfiles[i].pos < 0) {
00178                         errx(1, ".: getdirentry failed to return %s",
00179                              testfiles[i].name);
00180                 }
00181         }
00182         if (i!=n) {
00183                 /*
00184                  * If all of the other checks have passed, this should not
00185                  * be able to fail. But... just in case I forgot something
00186                  * or there's a bug...
00187                  */
00188 
00189                 errx(1, ".: getdirentry returned %d names, not %d (huh...?)",
00190                      n, i);
00191         }
00192 }
00193         
00194 static
00195 void
00196 firstread(void)
00197 {
00198         off_t pos;
00199 
00200         pos = lseek(dirfd, 0, SEEK_CUR);
00201         if (pos < 0) {
00202                 err(1, ".: lseek(0, SEEK_CUR)");
00203         }
00204         if (pos != 0) {
00205                 errx(1, ".: File position after open not 0");
00206         }
00207 
00208         printf("Scanning directory...\n");
00209 
00210         readit();
00211 }
00212 
00213 static
00214 void
00215 doreadat0(void)
00216 {
00217         off_t pos;
00218 
00219         printf("Rewinding directory and reading it again...\n");
00220 
00221         pos = lseek(dirfd, 0, SEEK_SET);
00222         if (pos < 0) {
00223                 err(1, ".: lseek(0, SEEK_SET)");
00224         }
00225         if (pos != 0) {
00226                 errx(1, ".: lseek(0, SEEK_SET) returned %ld", (long) pos);
00227         }
00228 
00229         readit();
00230 }
00231 
00232 static
00233 void
00234 readone(const char *shouldbe)
00235 {
00236         char buf[4096];
00237         int len;
00238 
00239         len = getdirentry(dirfd, buf, sizeof(buf)-1);
00240         if (len < 0) {
00241                 err(1, ".: getdirentry");
00242         }
00243         if ((unsigned)len >= sizeof(buf)-1) {
00244                 errx(1, ".: getdirentry returned invalid length %d", len);
00245         }
00246         buf[len] = 0;
00247 
00248         if (strcmp(buf, shouldbe)) {
00249                 errx(1, ".: getdirentry returned %s (expected %s)",
00250                      buf, shouldbe);
00251         }
00252 }
00253 
00254 static
00255 void
00256 doreadone(int which)
00257 {
00258         off_t pos;
00259         pos = lseek(dirfd, testfiles[which].pos, SEEK_SET);
00260         if (pos<0) {
00261                 err(1, ".: lseek(%ld, SEEK_SET)", (long) testfiles[which].pos);
00262         }
00263         if (pos != testfiles[which].pos) {
00264                 errx(1, ".: lseek(%ld, SEEK_SET) returned %ld",
00265                      (long) testfiles[which].pos, (long) pos);
00266         }
00267 
00268         readone(testfiles[which].name);
00269 }
00270 
00271 static
00272 void
00273 readallonebyone(void)
00274 {
00275         int i;
00276 
00277         printf("Trying to read each entry again...\n");
00278         for (i=0; testfiles[i].name; i++) {
00279                 doreadone(i);
00280         }
00281 }
00282 
00283 static
00284 void
00285 readallrandomly(void)
00286 {
00287         int n, i, x;
00288 
00289         printf("Trying to read a bunch of entries randomly...\n");
00290 
00291         for (i=0; testfiles[i].name; i++);
00292         n = i;
00293 
00294         srandom(39584);
00295         for (i=0; i<512; i++) {
00296                 x = (int)(random()%n);
00297                 doreadone(x);
00298         }
00299 }
00300 
00301 static
00302 void
00303 readateof(void)
00304 {
00305         char buf[4096];
00306         int len;
00307 
00308         len = getdirentry(dirfd, buf, sizeof(buf)-1);
00309         if (len < 0) {
00310                 err(1, ".: at EOF: getdirentry");
00311         }
00312         if (len==0) {
00313                 return;
00314         }
00315         if ((unsigned)len >= sizeof(buf)-1) {
00316                 errx(1, ".: at EOF: getdirentry returned "
00317                      "invalid length %d", len);
00318         }
00319         buf[len] = 0;
00320         errx(1, ".: at EOF: got unexpected name %s", buf);
00321 }
00322 
00323 static
00324 void
00325 doreadateof(void)
00326 {
00327         off_t pos;
00328         int i;
00329 
00330         printf("Trying to read after going to EOF...\n");
00331 
00332         pos = lseek(dirfd, 0, SEEK_END);
00333         if (pos<0) {
00334                 err(1, ".: lseek(0, SEEK_END)");
00335         }
00336 
00337         for (i=0; testfiles[i].name; i++) {
00338                 if (pos <= testfiles[i].pos) {
00339                         errx(1, ".: EOF position %ld below position %ld of %s",
00340                              pos, testfiles[i].pos, testfiles[i].name);
00341                 }
00342         }
00343 
00344         readateof();
00345 }
00346 
00347 static
00348 void
00349 inval_read(void)
00350 {
00351         char buf[4096];
00352         int len;
00353 
00354         len = getdirentry(dirfd, buf, sizeof(buf)-1);
00355 
00356         /* Any result is ok, as long as the system doesn't crash */
00357         (void)len;
00358 }
00359 
00360 static
00361 void
00362 dobadreads(void)
00363 {
00364         off_t pos, pos2, eof;
00365         int valid, i, k=0;
00366 
00367         printf("Trying some possibly invalid reads...\n");
00368 
00369         eof = lseek(dirfd, 0, SEEK_END);
00370         if (eof < 0) {
00371                 err(1, ".: lseek(0, SEEK_END)");
00372         }
00373 
00374         for (pos=0; pos < eof; pos++) {
00375                 valid = 0;
00376                 for (i=0; testfiles[i].name; i++) {
00377                         if (pos==testfiles[i].pos) {
00378                                 valid = 1;
00379                         }
00380                 }
00381                 if (valid) {
00382                         /* don't try offsets that are known to be valid */
00383                         continue;
00384                 }
00385 
00386                 pos2 = lseek(dirfd, pos, SEEK_SET);
00387                 if (pos2 < 0) {
00388                         /* this is ok */
00389                 }
00390                 else {
00391                         inval_read();
00392                         k++;
00393                 }
00394         }
00395 
00396         if (k>0) {
00397                 printf("Survived %d invalid reads...\n", k);
00398         }
00399         else {
00400                 printf("Couldn't find any invalid offsets to try...\n");
00401         }
00402 
00403         printf("Trying to read beyond EOF...\n");
00404         pos2 = lseek(dirfd, eof + 1000, SEEK_SET);
00405         if (pos2 < 0) {
00406                 /* this is ok */
00407         }
00408         else {
00409                 inval_read();
00410         }
00411 }
00412 
00413 static
00414 void
00415 dotest(void)
00416 {
00417         printf("Opening directory...\n");
00418         openit();
00419 
00420         printf("Running tests...\n");
00421 
00422         /* read the whole directory */
00423         firstread();
00424 
00425         /* make sure eof behaves right */
00426         readateof();
00427 
00428         /* read all the filenames again by seeking */
00429         readallonebyone();
00430 
00431         /* try reading at eof */
00432         doreadateof();
00433 
00434         /* read a bunch of the filenames over and over again */
00435         readallrandomly();
00436 
00437         /* rewind and read the whole thing again, to make sure that works */
00438         doreadat0();
00439 
00440         /* do invalid reads */
00441         dobadreads();
00442 
00443         /* rewind again to make sure the invalid attempts didn't break it */
00444         doreadat0();
00445 
00446         printf("Closing directory...\n");
00447         closeit();
00448 }
00449 
00450 /************************************************************/
00451 /* Setup code                                               */
00452 /************************************************************/
00453 
00454 static
00455 void
00456 mkfile(const char *name)
00457 {
00458         int fd, i, r;
00459         static const char message[] = "The turtle moves!\n";
00460         char buf[32*sizeof(message)+1];
00461 
00462         buf[0]=0;
00463         for (i=0; i<32; i++) {
00464                 strcat(buf, message);
00465         }
00466 
00467         /* Use O_EXCL, because we know the file shouldn't already be there */
00468         fd = open(name, O_WRONLY|O_CREAT|O_EXCL, 0664);
00469         if (fd<0) {
00470                 err(1, "%s: create", name);
00471         }
00472 
00473         r = write(fd, buf, strlen(buf));
00474         if (r<0) {
00475                 err(1, "%s: write", name);
00476         }
00477         if ((unsigned)r != strlen(buf)) {
00478                 errx(1, "%s: short write (%d bytes)", name, r);
00479         }
00480 
00481         if (close(fd)<0) {
00482                 err(1, "%s: close", name);
00483         }
00484 }
00485 
00486 static
00487 void
00488 setup(void)
00489 {
00490         int i;
00491 
00492         printf("Making directory %s...\n", TESTDIR);
00493 
00494         /* Create a directory */
00495         if (mkdir(TESTDIR, 0775)<0) {
00496                 err(1, "%s: mkdir", TESTDIR);
00497         }
00498 
00499         /* Switch to it */
00500         if (chdir(TESTDIR)<0) {
00501                 err(1, "%s: chdir", TESTDIR);
00502         }
00503 
00504         printf("Making some files...\n");
00505 
00506         /* Populate it */
00507         for (i=0; testfiles[i].name; i++) {
00508                 if (testfiles[i].make_it) {
00509                         mkfile(testfiles[i].name);
00510                 }
00511                 testfiles[i].pos = -1;
00512         }
00513 }
00514 
00515 static
00516 void
00517 cleanup(void)
00518 {
00519         int i;
00520 
00521         printf("Cleaning up...\n");
00522 
00523         /* Remove the files */
00524         for (i=0; testfiles[i].name; i++) {
00525                 if (testfiles[i].make_it) {
00526                         if (remove(testfiles[i].name)<0) {
00527                                 err(1, "%s: remove", testfiles[i].name);
00528                         }
00529                 }
00530         }
00531 
00532         /* Leave the dir */
00533         if (chdir("..")<0) {
00534                 err(1, "..: chdir");
00535         }
00536 
00537         /* Remove the dir */
00538         if (rmdir(TESTDIR)<0) {
00539                 err(1, "%s: rmdir", TESTDIR);
00540         }
00541 }
00542 
00543 
00544 int
00545 main()
00546 {
00547         setup();
00548 
00549         /* Do the whole thing twice */
00550         dotest();
00551         dotest();
00552 
00553         cleanup();
00554         return 0;
00555 }
 All Data Structures