/* 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);
/* 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);
--- /dev/null
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#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 */
+}
+