os161-1.99
 All Data Structures
rmdirtest.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  * rmdirtest.c
00032  *
00033  *      Tests file system synchronization and directory implementation by
00034  *      removing the current directory under itself and then trying to do
00035  *      things. It's ok for most of those things to fail, but the system
00036  *      shouldn't crash.
00037  */
00038 
00039 #include <sys/types.h>
00040 #include <sys/stat.h>
00041 #include <stdio.h>
00042 #include <string.h>
00043 #include <unistd.h>
00044 #include <fcntl.h>
00045 #include <errno.h>
00046 #include <limits.h>
00047 #include <err.h>
00048 
00049 
00050 static const char testdir[] = "testdir";
00051 static char startpoint[PATH_MAX - sizeof(testdir)];
00052 
00053 /*
00054  * Create the test directory, and change into it, remembering
00055  * where we came from.
00056  */
00057 
00058 static
00059 void
00060 startup(void)
00061 {
00062         if (getcwd(startpoint, sizeof(startpoint))==NULL) {
00063                 err(1, "getcwd (not in test dir)");
00064         }
00065 
00066         if (mkdir(testdir, 0775) < 0) {
00067                 err(1, "%s: mkdir", testdir);
00068         }
00069 
00070         if (chdir(testdir) < 0) {
00071                 err(1, "%s: chdir", testdir);
00072         }
00073 }
00074 
00075 /*
00076  * Remove the test directory.
00077  *
00078  * Note that even though it's the current directory, we can't do it
00079  * with rmdir(".") - what that would try to do is remove the "." entry
00080  * from the current directory, which is justifiably prohibited.
00081  */
00082 
00083 static
00084 void
00085 killdir(void)
00086 {
00087         char tmp[PATH_MAX];
00088 
00089         snprintf(tmp, sizeof(tmp), "%s/%s", startpoint, testdir);
00090         if (rmdir(tmp)<0) {
00091                 err(1, "%s: rmdir", tmp);
00092         }
00093 }
00094 
00095 /*
00096  * Leave the test directory and go back to where we came from, so we
00097  * can try again.
00098  */
00099 
00100 static
00101 void
00102 finish(void)
00103 {
00104         if (chdir(startpoint)<0) {
00105                 err(1, "%s: chdir", startpoint);
00106         }
00107 }
00108 
00109 /*************************************************************/
00110 
00111 /*
00112  * Basic test - just try removing the directory without doing anything
00113  * evil.
00114  */
00115 static
00116 void
00117 test1(void)
00118 {
00119         printf("Making %s\n", testdir);
00120         startup();
00121 
00122         printf("Removing %s while in it\n", testdir);
00123         killdir();
00124 
00125         printf("Leaving the test directory\n");
00126         finish();
00127 }
00128 
00129 /*
00130  * Now do it while we also have the directory open.
00131  */
00132 
00133 static
00134 void
00135 test2(void)
00136 {
00137         int fd;
00138 
00139         printf("Now trying with the directory open...\n");
00140         startup();
00141         fd = open(".", O_RDONLY);
00142         if (fd<0) {
00143                 err(1, ".: open");
00144         }
00145         killdir();
00146         finish();
00147 
00148         /* close *after* leaving, just for excitement */
00149         if (close(fd)<0) {
00150                 err(1, "removed %s: close", testdir);
00151         }
00152 }
00153 
00154 /*
00155  * Now see if . and .. work after rmdir.
00156  */
00157 
00158 static
00159 void
00160 test3(void)
00161 {
00162         char buf[PATH_MAX];
00163         int fd;
00164 
00165         printf("Checking if . exists after rmdir\n");
00166         startup();
00167         killdir();
00168 
00169         fd = open(".", O_RDONLY);
00170         if (fd<0) {
00171                 switch (errno) {
00172                     case EINVAL:
00173                     case EIO:
00174                     case ENOENT:
00175                         break;
00176                     default:
00177                         err(1, ".");
00178                         break;
00179                 }
00180         }
00181         else {
00182                 close(fd);
00183         }
00184 
00185         fd = open("..", O_RDONLY);
00186         if (fd<0) {
00187                 switch (errno) {
00188                     case EINVAL:
00189                     case EIO:
00190                     case ENOENT:
00191                         break;
00192                     default:
00193                         err(1, "..");
00194                         break;
00195                 }
00196         }
00197         else {
00198                 warnx("..: openable after rmdir - might be bad");
00199                 close(fd);
00200         }
00201 
00202         snprintf(buf, sizeof(buf), "../%s", testdir);
00203         fd = open(buf, O_RDONLY);
00204         if (fd<0) {
00205                 switch (errno) {
00206                     case EINVAL:
00207                     case EIO:
00208                     case ENOENT:
00209                         break;
00210                     default:
00211                         err(1, "%s", buf);
00212                         break;
00213                 }
00214         }
00215         else {
00216                 errx(1, "%s: works after rmdir", buf);
00217         }
00218 
00219         finish();
00220 }
00221 
00222 /*
00223  * Now try to create files.
00224  */
00225 
00226 static
00227 void
00228 test4(void)
00229 {
00230         char buf[4096];
00231         int fd;
00232 
00233         printf("Checking if creating files works after rmdir...\n");
00234         startup();
00235         killdir();
00236 
00237         fd = open("newfile", O_WRONLY|O_CREAT|O_TRUNC, 0664);
00238         if (fd<0) {
00239                 switch (errno) {
00240                     case EINVAL:
00241                     case EIO:
00242                     case ENOENT:
00243                         break;
00244                     default:
00245                         err(1, "%s", buf);
00246                         break;
00247                 }
00248         }
00249         else {
00250                 warnx("newfile: creating files after rmdir works");
00251                 warnx("(this is only ok if the space gets reclaimed)");
00252 
00253                 /*
00254                  * Waste a bunch of space so we'll be able to tell
00255                  */
00256                 memset(buf, 'J', sizeof(buf));
00257                 write(fd, buf, sizeof(buf));
00258                 write(fd, buf, sizeof(buf));
00259                 write(fd, buf, sizeof(buf));
00260                 write(fd, buf, sizeof(buf));
00261                 close(fd);
00262         }
00263 
00264         finish();
00265 }
00266 
00267 /*
00268  * Now try to create directories.
00269  */
00270 
00271 static
00272 void
00273 test5(void)
00274 {
00275         printf("Checking if creating subdirs works after rmdir...\n");
00276         startup();
00277         killdir();
00278 
00279         if (mkdir("newdir", 0775)<0) {
00280                 switch (errno) {
00281                     case EINVAL:
00282                     case EIO:
00283                     case ENOENT:
00284                         break;
00285                     default:
00286                         err(1, "mkdir in removed dir");
00287                         break;
00288                 }
00289         }
00290         else {
00291                 warnx("newfile: creating directories after rmdir works");
00292                 warnx("(this is only ok if the space gets reclaimed)");
00293 
00294                 /*
00295                  * Waste a bunch of space so we'll be able to tell
00296                  */
00297                 mkdir("newdir/t0", 0775);
00298                 mkdir("newdir/t1", 0775);
00299                 mkdir("newdir/t2", 0775);
00300                 mkdir("newdir/t3", 0775);
00301                 mkdir("newdir/t4", 0775);
00302                 mkdir("newdir/t5", 0775);
00303         }
00304 
00305         finish();
00306 }
00307 
00308 /*
00309  * Now try listing the directory.
00310  */
00311 static
00312 void
00313 test6(void)
00314 {
00315         char buf[PATH_MAX];
00316         int fd, len;
00317 
00318         printf("Now trying to list the directory...\n");
00319         startup();
00320         fd = open(".", O_RDONLY);
00321         if (fd<0) {
00322                 err(1, ".: open");
00323         }
00324         killdir();
00325 
00326         while ((len = getdirentry(fd, buf, sizeof(buf)-1))>0) {
00327                 if ((unsigned)len >= sizeof(buf)-1) {
00328                         errx(1, ".: getdirentry: returned invalid length");
00329                 }
00330                 buf[len] = 0;
00331                 if (!strcmp(buf, ".") || !strcmp(buf, "..")) {
00332                         /* these are allowed to appear */
00333                         continue;
00334                 }
00335                 errx(1, ".: getdirentry: returned unexpected name %s", buf);
00336         }
00337         if (len==0) {
00338                 /* EOF - ok */
00339         }
00340         else { /* len < 0 */
00341                 switch (errno) {
00342                     case EINVAL:
00343                     case EIO:
00344                         break;
00345                     default:
00346                         err(1, ".: getdirentry");
00347                         break;
00348                 }
00349         }
00350 
00351         finish();
00352 
00353         /* close *after* leaving, just for excitement */
00354         if (close(fd)<0) {
00355                 err(1, "removed %s: close", testdir);
00356         }
00357 }
00358 
00359 /*
00360  * Try getcwd.
00361  */
00362 static
00363 void
00364 test7(void)
00365 {
00366         char buf[PATH_MAX];
00367 
00368         startup();
00369         killdir();
00370         if (getcwd(buf, sizeof(buf))==NULL) {
00371                 switch (errno) {
00372                     case EINVAL:
00373                     case EIO:
00374                     case ENOENT:
00375                         break;
00376                     default:
00377                         err(1, "getcwd after removing %s", testdir);
00378                         break;
00379                 }
00380         }
00381         else {
00382                 errx(1, "getcwd after removing %s: succeeded (got %s)",
00383                      testdir, buf);
00384         }
00385 
00386         finish();
00387 }
00388 
00389 /**************************************************************/
00390 
00391 int
00392 main(void)
00393 {
00394         test1();
00395         test2();
00396         test3();
00397         test4();
00398         test5();
00399         test6();
00400         test7();
00401 
00402         printf("Whew... survived.\n");
00403         return 0;
00404 }
 All Data Structures