]> Zhao Yanbai Git Server - minix.git/commitdiff
VFS: fix last_dir not returning last directory
authorThomas Veerman <thomas@minix3.org>
Tue, 21 Feb 2012 10:16:42 +0000 (10:16 +0000)
committerThomas Veerman <thomas@minix3.org>
Tue, 21 Feb 2012 10:21:05 +0000 (10:21 +0000)
If the provided path was only a single component (i.e., without
slashes), then last_dir would return early and skip the symlink
detection (i.e., check whether the path ends in a symlink and resolve
that first before returning). This bug triggered an assert in open
which expects that an advance after an last_dir (with VMNT_WRITE lock)
does not yield another vmnt lock.

servers/vfs/path.c

index 8fb047dc1aa3938046538e8faf47d839823eed23..562f7c968ec89480d86a93d04354c1359ab8f34c 100644 (file)
@@ -206,30 +206,13 @@ struct fproc *rfp;
 
        cp = strrchr(resolve->l_path, '/');
        if (cp == NULL) {
-               /* Just an entry in the current working directory */
-               struct vmnt *vmp;
-
-               vmp = find_vmnt(start_dir->v_fs_e);
-               if (vmp == NULL) {
-                       r = EIO;
-                       res_vp = NULL;
-                       break;
-               }
-               r = lock_vmnt(vmp, resolve->l_vmnt_lock);
-               if (r == EDEADLK) {
-                       res_vp = NULL;
-                       break;
-               } else if (r == OK)
-                       *resolve->l_vmp = vmp;
-
-               lock_vnode(start_dir, resolve->l_vnode_lock);
-               *resolve->l_vnode = start_dir;
-               dup_vnode(start_dir);
-               if (loop_start != NULL) {
-                       unlock_vnode(loop_start);
-                       put_vnode(loop_start);
-               }
-               return(start_dir);
+               /* Just an entry in the current working directory. Prepend
+                * "./" in front of the path and resolve it.
+                */
+               strncpy(dir_entry, resolve->l_path, NAME_MAX);
+               dir_entry[NAME_MAX] = '\0';
+               resolve->l_path[0] = '.';
+               resolve->l_path[1] = '\0';
        } else if (cp[1] == '\0') {
                /* Path ends in a slash. The directory entry is '.' */
                strcpy(dir_entry, ".");
@@ -341,6 +324,10 @@ struct fproc *rfp;
 
   /* Copy the directory entry back to user_fullpath */
   strncpy(resolve->l_path, dir_entry, NAME_MAX + 1);
+
+  /* Turn PATH_RET_SYMLINK flag back on if it was on */
+  if (ret_on_symlink) resolve->l_flags |= PATH_RET_SYMLINK;
+
   return(res_vp);
 }