]> Zhao Yanbai Git Server - minix.git/commitdiff
- Return ENOENT when trying to add files to removed (but open) directories.
authorThomas Veerman <thomas@minix3.org>
Wed, 1 Sep 2010 09:07:18 +0000 (09:07 +0000)
committerThomas Veerman <thomas@minix3.org>
Wed, 1 Sep 2010 09:07:18 +0000 (09:07 +0000)
- Add test58 to test this behavior.

servers/ext2/link.c
servers/ext2/open.c
servers/mfs/link.c
servers/mfs/open.c
test/Makefile
test/run
test/test58.c [new file with mode: 0644]

index a3549422c80ac2a3287c31d8b09160fa74f0bf90..c8c793340aa267d0b48e3545b13f5d3efa80c045 100644 (file)
@@ -77,6 +77,11 @@ PUBLIC int fs_link()
   if( (ip = get_inode(fs_dev, fs_m_in.REQ_DIR_INO)) == NULL)
          return(EINVAL);
 
+  if (ip->i_links_count == NO_LINK) {  /* Dir does not actually exist */
+       put_inode(ip);
+       return(ENOENT);
+  }
+
   /* If 'name2' exists in full (even if no space) set 'r' to error. */
   if ((new_ip = advance(ip, string, IGN_PERM)) == NULL) {
        r = err_code;
@@ -349,6 +354,14 @@ PUBLIC int fs_rename()
   /* Get new dir inode */
   if( (new_dirp = get_inode(fs_dev, (ino_t) fs_m_in.REQ_REN_NEW_DIR)) == NULL)
        r = err_code;
+
+  if (new_dirp->i_links_count == NO_LINK) { /* Dir does not actually exist */
+       put_inode(old_ip);
+       put_inode(old_dirp);
+       put_inode(new_dirp);
+       return(ENOENT);
+  }
+
   new_ip = advance(new_dirp, new_name, IGN_PERM); /* not required to exist */
 
   /* However, if the check failed because the file does exist, don't continue.
index 0a6b2f27e7724731e0ffbf095186615d5781bb0a..4081e7ceef8b6253327dbbac5d2716ba155fc81e 100644 (file)
@@ -286,6 +286,11 @@ PRIVATE struct inode *new_node(struct inode *ldirp,
   register struct inode *rip;
   register int r;
 
+  if (ldirp->i_links_count == NO_LINK) { /* Dir does not actually exist */
+       err_code = ENOENT;
+       return(NULL);
+  }
+
   /* Get final component of the path. */
   rip = advance(ldirp, string, IGN_PERM);
 
index 2848345fafd8d4fbb0a5edc0ed98222e64dae076..82147a6638c8df62a5f6327c5597dbf7850d631b 100644 (file)
@@ -71,6 +71,11 @@ PUBLIC int fs_link()
   if( (ip = get_inode(fs_dev, (ino_t) fs_m_in.REQ_DIR_INO)) == NULL)
          return(EINVAL);
 
+  if (ip->i_nlinks == NO_LINK) {       /* Dir does not actually exist */
+       put_inode(ip);
+       return(ENOENT);
+  }
+
   /* If 'name2' exists in full (even if no space) set 'r' to error. */
   if((new_ip = advance(ip, string, IGN_PERM)) == NULL) {
          r = err_code;
@@ -317,6 +322,14 @@ PUBLIC int fs_rename()
   /* Get new dir inode */ 
   if( (new_dirp = get_inode(fs_dev, (ino_t) fs_m_in.REQ_REN_NEW_DIR)) == NULL) 
        r = err_code;
+
+  if (new_dirp->i_nlinks == NO_LINK) { /* Dir does not actually exist */
+       put_inode(old_ip);
+       put_inode(old_dirp);
+       put_inode(new_dirp);
+       return(ENOENT);
+  }
+  
   new_ip = advance(new_dirp, new_name, IGN_PERM); /* not required to exist */
 
   /* However, if the check failed because the file does exist, don't continue.
index 0e1d62525bfb4ac713b39eaf6cb9edd00e32db53..982b18130bacee570cc7cccc299dee483574c9af 100644 (file)
@@ -90,7 +90,7 @@ PUBLIC int fs_mknod()
   /* Get last directory inode */
   if((ldirp = get_inode(fs_dev, (ino_t) fs_m_in.REQ_INODE_NR)) == NULL)
          return(ENOENT);
-  
+
   /* Try to create the new node */
   ip = new_node(ldirp, lastc, (mode_t) fs_m_in.REQ_MODE,
                (zone_t) fs_m_in.REQ_DEV);
@@ -192,7 +192,7 @@ PUBLIC int fs_slink()
   /* Temporarily open the dir. */
   if( (ldirp = get_inode(fs_dev, (ino_t) fs_m_in.REQ_INODE_NR)) == NULL)
          return(EINVAL);
-  
+
   /* Create the inode for the symlink. */
   sip = new_node(ldirp, string, (mode_t) (I_SYMBOLIC_LINK | RWX_MODES),
                   (zone_t) 0);
@@ -261,6 +261,11 @@ PRIVATE struct inode *new_node(struct inode *ldirp,
   register struct inode *rip;
   register int r;
 
+  if (ldirp->i_nlinks == NO_LINK) {    /* Dir does not actually exist */
+       err_code = ENOENT;
+       return(NULL);
+  }
+
   /* Get final component of the path. */
   rip = advance(ldirp, string, IGN_PERM);
 
index a028938725f7a30e32d62f299115b7e41fa81a1d..5abb5df3e06eccb3f638e9cdeb0f70c66d6662ed 100644 (file)
@@ -12,7 +12,7 @@ OBJ=  test1  test2  test3  test4  test5  test6  test7  test8  test9  \
        test30 test31 test32        test34 test35 test36 test37 test38 \
        test39 t10a t11a t11b test40 t40a t40b t40c t40d t40e t40f test41 \
        test42 test45 test47 test48 test49 test50 test51 test52 test53 \
-       test54 test55 test56 
+       test54 test55 test56 test58
 
 BIGOBJ=  test20 test24
 ROOTOBJ= test11 test33 test43 test44 test46
@@ -114,3 +114,4 @@ test55: test55.c
 test56: test56.c
 test57: test57.c test57loop.S
        if which $(GCC) >/dev/null 2>&1; then $(GCC) $(CFLAGS-GCC) -o $@ test57.c test57loop.S; fi
+test58: test58.c
index 1470c523e0137bf5c044919908733409dfb1780e..48af18ae5fe69c59b3a8ee6e008588ca9e4150d2 100755 (executable)
--- a/test/run
+++ b/test/run
@@ -14,7 +14,7 @@ badones=                      # list of tests that failed
 tests="   1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 \
          21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 \
          41 42 43 44 45 45-gcc 46 47 48 49 49-gcc 50 \
-         51 51-gcc 52 52-gcc 53 54 55 56 57 \
+         51 51-gcc 52 52-gcc 53 54 55 56 57 58\
         sh1.sh sh2.sh"
 tests_no=`expr 0`
 
diff --git a/test/test58.c b/test/test58.c
new file mode 100644 (file)
index 0000000..f26713e
--- /dev/null
@@ -0,0 +1,180 @@
+/* This tests the behavior of Minix when the current working dir (cwd) doesn't
+ * actually exist and we either:
+ *   - create a new file
+ *   - make a new directory
+ *   - make a special file (mknod)
+ *   - create a hard link
+ *   - create a symbolic link, or
+ *   - rename a file
+ * In each case, `a component of the path does not name an existing file', and
+ * the operation should fail with ENOENT. These tests should actually be 
+ * distributed over the other tests that actually test the specific system 
+ * calls.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+
+int subtest = -1;
+#define MAX_ERROR 999  /* Effectively no limit. This is necessary as this
+                        * test tries to undo errors and should therefore not
+                        * preemptively exit, as that would leave the FS
+                        * in a corrupted state. */
+#include "common.c"
+
+#define TEST_PATH "a/b/c"
+#define INTEGR_MSG "You might want to check fs integrity\n"
+
+_PROTOTYPE( void do_test, (void)                                       );
+
+void do_test(void)
+{
+  int r, fd;
+  int s[2];
+  char buf[1], testroot[PATH_MAX+1], renamebuf[PATH_MAX+1];
+
+  subtest = 1;
+  if (socketpair(PF_UNIX, SOCK_STREAM, 0, s) == -1) e(1);
+  if (system("mkdir -p " TEST_PATH) == -1) e(2);
+  if (realpath(".", testroot) == NULL) e(3);
+
+  r = fork();
+  if (r == -1) e(4);
+  else if (r == 0) { /* Child */
+       /* Change child's cwd to TEST_PATH */
+       if (chdir(TEST_PATH) == -1) e(5);
+
+       /* Signal parent we're ready for the test */
+       buf[0] = 'a';
+       if (write(s[0], buf, sizeof(buf)) != sizeof(buf)) e(6);
+
+       /* Wait for parent to remove my cwd */
+       if (read(s[0], buf, sizeof(buf)) != sizeof(buf)) e(7);
+
+       /* Try to create a file */
+       if ((fd = open("testfile", O_RDWR | O_CREAT)) != -1) {
+               e(8);
+               /* Uh oh. We created a file?! Try to remove it. */
+               (void) close(fd);
+               if (unlink("testfile") != 0) {
+                       /* This is not good. We created a file, but we can
+                        * never access it; we have a spurious inode.
+                        */
+                       e(9);
+                       printf(INTEGR_MSG);
+                       exit(errct);
+               }
+       }
+       if (errno != ENOENT) e(10);
+
+       /* Try to create a dir */
+       errno = 0;
+       if (mkdir("testdir", 0777) == 0) {
+               e(11);
+               /* Uh oh. This shouldn't have been possible. Try to undo. */
+               if (rmdir("testdir") != 0) {
+                       /* Not good. */
+                       e(12);
+                       printf(INTEGR_MSG);
+                       exit(errct);
+               }
+       }
+       if (errno != ENOENT) e(13);
+
+       /* Try to create a special file */
+       errno = 0;
+       if (mknod("testnode", 0777 | S_IFIFO, 0) == 0) {
+               e(14);
+               /* Impossible. Try to make it unhappen. */
+               if (unlink("testnode") != 0) {
+                       /* Not good. */
+                       e(15);
+                       printf(INTEGR_MSG);
+                       exit(errct);
+               }
+       }
+       if (errno != ENOENT) e(16);
+
+       /* Try to rename a file */
+       errno = 0;
+       /* First create a file in the test dir */
+       snprintf(renamebuf, PATH_MAX, "%s/oldname", testroot);
+       if ((fd = open(renamebuf, O_RDWR | O_CREAT)) == -1) e(17);
+       if (close(fd) != 0) e(18);
+
+       /* Now try to rename that file to an entry in the current, non-existing
+        * working directory.
+        */
+       if (rename(renamebuf, "testrename") == 0) {
+               e(19);
+               /* This shouldn't have been possible. Revert the name change.
+                */
+               if (rename("testrename", renamebuf) != 0) {
+                       /* Failed */
+                       e(20);
+                       printf(INTEGR_MSG);
+                       exit(errct);
+               }
+       }
+
+       /* Try to create a hard link to that file */
+       errno = 0;
+       if (link(renamebuf, "testhlink") == 0) {
+               e(21);
+               /* Try to undo the hard link to prevent fs corruption. */
+               if (unlink("testhlink") != 0) {
+                       /* Failed. */
+                       e(22);
+                       printf(INTEGR_MSG);
+                       exit(errct);
+               }
+       }
+       if (errno != ENOENT) e(23);
+
+       /* Try to create a symlink */
+       errno = 0;
+       if (symlink(testroot, "testslink") == 0) {
+               e(24);
+               /* Try to remove the symlink to prevent fs corruption. */
+               if (unlink("testslink") != 0) {
+                       /* Failed. */
+                       e(25);
+                       printf(INTEGR_MSG);
+                       exit(errct);
+               }
+       }
+       if (errno != ENOENT) e(26);
+
+       exit(errct);
+  } else { /* Parent */
+       int status;
+
+       /* Wait for the child to enter the TEST_PATH dir */
+       if (read(s[1], buf, sizeof(buf)) != sizeof(buf)) e(27);
+
+       /* Delete TEST_PATH */
+       if (rmdir(TEST_PATH) != 0) e(28);
+
+       /* Tell child we removed its cwd */
+       buf[0] = 'b';
+       if (write(s[1], buf, sizeof(buf)) != sizeof(buf)) e(29);
+
+       wait(&status);
+       errct += WEXITSTATUS(status);   /* Count errors */
+  }
+}
+
+int main(int argc, void* argv[])
+{
+  start(58);
+  do_test();
+  quit();
+}
+
+