From 706873142ee93ed135f448daa4826e6a4cdea6b5 Mon Sep 17 00:00:00 2001 From: Thomas Veerman Date: Thu, 8 Dec 2011 15:01:47 +0000 Subject: [PATCH] Fix dangling symlink resolving for AVFS and add test61 --- servers/avfs/open.c | 11 +++--- test/Makefile | 3 +- test/run | 2 +- test/test61.c | 87 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 97 insertions(+), 6 deletions(-) create mode 100644 test/test61.c diff --git a/servers/avfs/open.c b/servers/avfs/open.c index 2b301dae7..5358c3171 100644 --- a/servers/avfs/open.c +++ b/servers/avfs/open.c @@ -326,7 +326,6 @@ PRIVATE struct vnode *new_node(struct lookup *resolve, int oflags, mode_t bits) /* The combination of a symlink with absolute path followed by a danglink * symlink results in a new path that needs to be re-resolved entirely. */ if (path[0] == '/') { -printf("XXX: dangling symlink needs re-resolving\n"); unlock_vnode(dirp); unlock_vmnt(dir_vmp); put_vnode(dirp); @@ -391,15 +390,19 @@ printf("XXX: dangling symlink needs re-resolving\n"); /* Try to create the inode the dangling symlink was * pointing to. We have to use dirp as starting point * as there might be multiple successive symlinks - * crossing multiple mountpoints. */ + * crossing multiple mountpoints. + * Unlock vnodes and vmnts as we're going to recurse. + */ + unlock_vnode(dirp); + unlock_vnode(vp); + unlock_vmnt(dir_vmp); + old_wd = fp->fp_wd; /* Save orig. working dirp */ fp->fp_wd = dirp; vp = new_node(resolve, oflags, bits); fp->fp_wd = old_wd; /* Restore */ if (vp != NULL) { - unlock_vnode(dirp); - unlock_vmnt(dir_vmp); put_vnode(dirp); *(resolve->l_vnode) = vp; return(vp); diff --git a/test/Makefile b/test/Makefile index 485c6fb90..e02032497 100644 --- a/test/Makefile +++ b/test/Makefile @@ -19,7 +19,7 @@ OBJ= test1 test2 test3 test4 test5 test6 test7 test8 test9 \ test54 test56 test58 t60a t60b BIGOBJ= test20 test24 -ROOTOBJ= test11 test33 test43 test44 test46 test60 +ROOTOBJ= test11 test33 test43 test44 test46 test60 test61 GCCOBJ= test45-gcc test48 test49-gcc test55 GCCFPUOBJ= test51-gcc test52-gcc OTHEROBJ= test57 test59 @@ -133,3 +133,4 @@ test59: test59.c test60: test60.c t60a: t60a.c t60b: t60b.c +test61: test61.c diff --git a/test/run b/test/run index fdf893be4..eed3970ca 100755 --- a/test/run +++ b/test/run @@ -15,7 +15,7 @@ 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 58 59\ - 60 \ + 60 61 \ sh1.sh sh2.sh" tests_no=`expr 0` diff --git a/test/test61.c b/test/test61.c new file mode 100644 index 000000000..42c3746e4 --- /dev/null +++ b/test/test61.c @@ -0,0 +1,87 @@ +#include +#include +#include +#include +#include +#include + +#define MAX_ERROR 5 +#include "common.c" + +void dangling_slink(int sub_test, char const slink_to[PATH_MAX]); + +void dangling_slink(int sub_test, char const slink_to[PATH_MAX]) +{ + pid_t child; + + subtest = sub_test; + + child = fork(); + if (child == (pid_t) -1) { + e(1); + return; + } else if (child == (pid_t) 0) { + /* I'm the child. Create a dangling symlink with an absolute path */ + int fd; + char buf[4]; + + + /* We don't want to actually write to '/', so instead we pretend */ + if (chroot(".") != 0) e(2); + + /* Create file 'slink_to' with contents "bar" */ + if ((fd = open(slink_to, O_CREAT|O_WRONLY)) == -1) e(3); + if (write(fd, "bar", strlen("bar")) != strlen("bar")) e(4); + close(fd); + + if (symlink(slink_to, "a") == -1) e(5); /* Create the symlink */ + if (rename(slink_to, "c") == -1) e(6); /* Make it a dangling symlink */ + + /* Write "foo" to symlink; this should recreate file 'slink_to' with + * contents "foo" */ + if ((fd = open("a", O_CREAT|O_WRONLY)) == -1) e(7); + if (write(fd, "foo", strlen("foo")) != strlen("foo")) e(8); + close(fd); + + /* Verify 'a' and 'slink_to' contain "foo" */ + memset(buf, '\0', sizeof(buf)); + if ((fd = open("a", O_RDONLY)) == -1) e(9); + if (read(fd, buf, 3) != 3) e(10); + if (strncmp(buf, "foo", strlen("foo"))) e(11); + close(fd); + memset(buf, '\0', sizeof(buf)); + if ((fd = open(slink_to, O_RDONLY)) == -1) e(12); + if (read(fd, buf, 3) != 3) e(13); + if (strncmp(buf, "foo", strlen("foo"))) e(14); + close(fd); + + /* Verify 'c' contains 'bar' */ + memset(buf, '\0', sizeof(buf)); + if ((fd = open("c", O_RDONLY)) == -1) e(15); + if (read(fd, buf, 3) != 3) e(16); + if (strncmp(buf, "bar", strlen("bar"))) e(17); + close(fd); + + /* Cleanup created files */ + if (unlink(slink_to) == -1) e(18); + if (unlink("a") == -1) e(19); + if (unlink("c") == -1) e(20); + + exit(EXIT_SUCCESS); + } else { + int status; + if (wait(&status) == -1) e(7); + } + + +} + +int main(int argc, char *argv[]) +{ + start(61); + dangling_slink(1, "/abs"); /* Create dangling symlink with absolute path */ + dangling_slink(2, "rel"); /* Create dangling symlink with relative path */ + quit(); + return(-1); /* Unreachable */ +} +