- Return ENOENT when trying to add files to removed (but open) directories.
- Add test58 to test this behavior.
This commit is contained in:
parent
bf6f0216d5
commit
0b00cf70b6
7 changed files with 221 additions and 4 deletions
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
2
test/run
2
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`
|
||||
|
||||
|
|
180
test/test58.c
Normal file
180
test/test58.c
Normal file
|
@ -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();
|
||||
}
|
||||
|
||||
|
Loading…
Reference in a new issue