Hello I've played around with the code in order to fix the trailing slash issue. When we do a file name lookup with a trailing '/' and the final component is a translator, the '/' is not sent to the translator since glibc strips the '/' before calling dir_lookup on the translator. This patches fixes this by changing glibc, libnetfs and libdiskfs. The change in glibc is not a big issue since must translators already remove leading slashes. In libdiskfs and libnetfs's dir_lookup, 'mustbedir' must be checked (it indicates that there is a trailing slash) and is used to add a '/' to retry_name whenever needed. At the end of the day, this patch makes things like 'ls /dev/null/' to return 'invalid directory'.
I've been able to boot the system using this patch and everything looks good so far, however, I'm asking you for initial comments and for anything else I might be missing. Best Flavio --- diff --git a/libdiskfs/dir-lookup.c b/libdiskfs/dir-lookup.c index 75df9b8..be0f88c 100644 --- a/libdiskfs/dir-lookup.c +++ b/libdiskfs/dir-lookup.c @@ -161,7 +161,9 @@ diskfs_S_dir_lookup (struct protid *dircred, *retry = FS_RETRY_REAUTH; *returned_port = dircred->po->shadow_root_parent; *returned_port_poly = MACH_MSG_TYPE_COPY_SEND; - if (! lastcomp) + if (lastcomp && mustbedir) /* Trailing slash. */ + strcpy (retryname, "/"); + else if (!lastcomp) strcpy (retryname, nextname); err = 0; goto out; @@ -175,7 +177,9 @@ diskfs_S_dir_lookup (struct protid *dircred, *retry = FS_RETRY_REAUTH; *returned_port = dircred->po->root_parent; *returned_port_poly = MACH_MSG_TYPE_COPY_SEND; - if (!lastcomp) + if (lastcomp && mustbedir) /* Trailing slash. */ + strcpy (retryname, "/"); + else if (!lastcomp) strcpy (retryname, nextname); err = 0; goto out; @@ -213,7 +217,7 @@ diskfs_S_dir_lookup (struct protid *dircred, /* If this is translated, start the translator (if necessary) and return. */ - if ((((flags & O_NOTRANS) == 0) || !lastcomp) + if ((((flags & O_NOTRANS) == 0) || !lastcomp || mustbedir) && ((np->dn_stat.st_mode & S_IPTRANS) || S_ISFIFO (np->dn_stat.st_mode) || S_ISCHR (np->dn_stat.st_mode) @@ -290,7 +294,7 @@ diskfs_S_dir_lookup (struct protid *dircred, err = fshelp_fetch_root (&np->transbox, dircred->po, dirport, dircred->user, - lastcomp ? flags : 0, + (lastcomp && !mustbedir) ? flags : 0, ((np->dn_stat.st_mode & S_IPTRANS) ? _diskfs_translator_callback1 : short_circuited_callback1), @@ -304,11 +308,16 @@ diskfs_S_dir_lookup (struct protid *dircred, if (err != ENOENT) { *returned_port_poly = MACH_MSG_TYPE_MOVE_SEND; - if (!lastcomp && !err) - { + if (!err) + { char *end = strchr (retryname, '\0'); - *end++ = '/'; - strcpy (end, nextname); + if (mustbedir) + *end++ = '/'; /* Trailing slash. */ + else if (!lastcomp) { + if (end != retryname) + *end++ = '/'; + strcpy (end, nextname); + } } if (register_translator) diff --git a/libnetfs/dir-lookup.c b/libnetfs/dir-lookup.c index 8b8cd6e..4b68144 100644 --- a/libnetfs/dir-lookup.c +++ b/libnetfs/dir-lookup.c @@ -128,7 +128,9 @@ netfs_S_dir_lookup (struct protid *diruser, *do_retry = FS_RETRY_REAUTH; *retry_port = diruser->po->shadow_root_parent; *retry_port_type = MACH_MSG_TYPE_COPY_SEND; - if (! lastcomp) + if (lastcomp && mustbedir) /* Trailing slash. */ + strcpy (retry_name, "/"); + else if (!lastcomp) strcpy (retry_name, nextname); error = 0; pthread_mutex_unlock (&dnp->lock); @@ -142,7 +144,9 @@ netfs_S_dir_lookup (struct protid *diruser, *do_retry = FS_RETRY_REAUTH; *retry_port = diruser->po->root_parent; *retry_port_type = MACH_MSG_TYPE_COPY_SEND; - if (!lastcomp) + if (lastcomp && mustbedir) /* Trailing slash. */ + strcpy (retry_name, "/"); + else if (!lastcomp) strcpy (retry_name, nextname); error = 0; pthread_mutex_unlock (&dnp->lock); @@ -194,7 +198,7 @@ netfs_S_dir_lookup (struct protid *diruser, if (error) goto out; - if ((((flags & O_NOTRANS) == 0) || !lastcomp) + if ((((flags & O_NOTRANS) == 0) || !lastcomp || mustbedir) && ((np->nn_translated & S_IPTRANS) || S_ISFIFO (np->nn_translated) || S_ISCHR (np->nn_translated) @@ -290,8 +294,14 @@ netfs_S_dir_lookup (struct protid *diruser, *retry_port_type = MACH_MSG_TYPE_MOVE_SEND; if (!lastcomp && !error) { - strcat (retry_name, "/"); - strcat (retry_name, nextname); + char *end = strchr (retry_name, '\0'); + if (mustbedir) + *end++ = '/'; /* Trailing slash. */ + else if (!lastcomp) { + if (end != retry_name) + *end++ = '/'; + strcpy (end, nextname); + } } if (register_translator) diff --git a/hurd/lookup-retry.c b/hurd/lookup-retry.c index f633e57..b221db8 100644 --- a/hurd/lookup-retry.c +++ b/hurd/lookup-retry.c @@ -62,7 +62,7 @@ __hurd_file_name_lookup_retry (error_t (*use_init_port) error_t lookup_op (file_t startdir) { - while (file_name[0] == '/') + while (file_name[0] == '/' && file_name[1] == '/') file_name++; return lookup_error ((*lookup) (startdir, file_name, flags, mode,