- 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
					
				| @ -77,6 +77,11 @@ PUBLIC int fs_link() | |||||||
|   if( (ip = get_inode(fs_dev, fs_m_in.REQ_DIR_INO)) == NULL) |   if( (ip = get_inode(fs_dev, fs_m_in.REQ_DIR_INO)) == NULL) | ||||||
| 	  return(EINVAL); | 	  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 'name2' exists in full (even if no space) set 'r' to error. */ | ||||||
|   if ((new_ip = advance(ip, string, IGN_PERM)) == NULL) { |   if ((new_ip = advance(ip, string, IGN_PERM)) == NULL) { | ||||||
| 	r = err_code; | 	r = err_code; | ||||||
| @ -349,6 +354,14 @@ PUBLIC int fs_rename() | |||||||
|   /* Get new dir inode */ |   /* Get new dir inode */ | ||||||
|   if( (new_dirp = get_inode(fs_dev, (ino_t) fs_m_in.REQ_REN_NEW_DIR)) == NULL) |   if( (new_dirp = get_inode(fs_dev, (ino_t) fs_m_in.REQ_REN_NEW_DIR)) == NULL) | ||||||
| 	r = err_code; | 	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 */ |   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.
 |   /* 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 struct inode *rip; | ||||||
|   register int r; |   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. */ |   /* Get final component of the path. */ | ||||||
|   rip = advance(ldirp, string, IGN_PERM); |   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) |   if( (ip = get_inode(fs_dev, (ino_t) fs_m_in.REQ_DIR_INO)) == NULL) | ||||||
| 	  return(EINVAL); | 	  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 'name2' exists in full (even if no space) set 'r' to error. */ | ||||||
|   if((new_ip = advance(ip, string, IGN_PERM)) == NULL) { |   if((new_ip = advance(ip, string, IGN_PERM)) == NULL) { | ||||||
| 	  r = err_code; | 	  r = err_code; | ||||||
| @ -317,6 +322,14 @@ PUBLIC int fs_rename() | |||||||
|   /* Get new dir inode */  |   /* Get new dir inode */  | ||||||
|   if( (new_dirp = get_inode(fs_dev, (ino_t) fs_m_in.REQ_REN_NEW_DIR)) == NULL)  |   if( (new_dirp = get_inode(fs_dev, (ino_t) fs_m_in.REQ_REN_NEW_DIR)) == NULL)  | ||||||
| 	r = err_code; | 	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 */ |   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.
 |   /* 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 */ |   /* Get last directory inode */ | ||||||
|   if((ldirp = get_inode(fs_dev, (ino_t) fs_m_in.REQ_INODE_NR)) == NULL) |   if((ldirp = get_inode(fs_dev, (ino_t) fs_m_in.REQ_INODE_NR)) == NULL) | ||||||
| 	  return(ENOENT); | 	  return(ENOENT); | ||||||
|    | 
 | ||||||
|   /* Try to create the new node */ |   /* Try to create the new node */ | ||||||
|   ip = new_node(ldirp, lastc, (mode_t) fs_m_in.REQ_MODE, |   ip = new_node(ldirp, lastc, (mode_t) fs_m_in.REQ_MODE, | ||||||
|   		(zone_t) fs_m_in.REQ_DEV); |   		(zone_t) fs_m_in.REQ_DEV); | ||||||
| @ -192,7 +192,7 @@ PUBLIC int fs_slink() | |||||||
|   /* Temporarily open the dir. */ |   /* Temporarily open the dir. */ | ||||||
|   if( (ldirp = get_inode(fs_dev, (ino_t) fs_m_in.REQ_INODE_NR)) == NULL) |   if( (ldirp = get_inode(fs_dev, (ino_t) fs_m_in.REQ_INODE_NR)) == NULL) | ||||||
| 	  return(EINVAL); | 	  return(EINVAL); | ||||||
|    | 
 | ||||||
|   /* Create the inode for the symlink. */ |   /* Create the inode for the symlink. */ | ||||||
|   sip = new_node(ldirp, string, (mode_t) (I_SYMBOLIC_LINK | RWX_MODES), |   sip = new_node(ldirp, string, (mode_t) (I_SYMBOLIC_LINK | RWX_MODES), | ||||||
| 		   (zone_t) 0); | 		   (zone_t) 0); | ||||||
| @ -261,6 +261,11 @@ PRIVATE struct inode *new_node(struct inode *ldirp, | |||||||
|   register struct inode *rip; |   register struct inode *rip; | ||||||
|   register int r; |   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. */ |   /* Get final component of the path. */ | ||||||
|   rip = advance(ldirp, string, IGN_PERM); |   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 \
 | 	test30 test31 test32        test34 test35 test36 test37 test38 \
 | ||||||
| 	test39 t10a t11a t11b test40 t40a t40b t40c t40d t40e t40f test41 \
 | 	test39 t10a t11a t11b test40 t40a t40b t40c t40d t40e t40f test41 \
 | ||||||
| 	test42 test45 test47 test48 test49 test50 test51 test52 test53 \
 | 	test42 test45 test47 test48 test49 test50 test51 test52 test53 \
 | ||||||
| 	test54 test55 test56  | 	test54 test55 test56 test58 | ||||||
| 
 | 
 | ||||||
| BIGOBJ=  test20 test24 | BIGOBJ=  test20 test24 | ||||||
| ROOTOBJ= test11 test33 test43 test44 test46 | ROOTOBJ= test11 test33 test43 test44 test46 | ||||||
| @ -114,3 +114,4 @@ test55: test55.c | |||||||
| test56: test56.c | test56: test56.c | ||||||
| test57: test57.c test57loop.S | test57: test57.c test57loop.S | ||||||
| 	if which $(GCC) >/dev/null 2>&1; then $(GCC) $(CFLAGS-GCC) -o $@ test57.c test57loop.S; fi | 	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 \ | 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 \ |          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 \ |          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" | 	 sh1.sh sh2.sh" | ||||||
| tests_no=`expr 0` | 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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Thomas Veerman
						Thomas Veerman