diff --git a/fs/vfs/main.cc b/fs/vfs/main.cc
index 7e028ffb..eca89556 100644
--- a/fs/vfs/main.cc
+++ b/fs/vfs/main.cc
@@ -825,7 +825,7 @@ mkdir(const char *pathname, mode_t mode)
mode = apply_umask(mode);
trace_vfs_mkdir(pathname, mode);
- if ((error = task_conv(t, pathname, VWRITE, path)) != 0)
+ if ((error = task_conv_remove_trailing_slash(t, pathname, VWRITE, path)) != 0)
goto out_errno;
error = sys_mkdir(path, mode);
@@ -853,7 +853,7 @@ int rmdir(const char *pathname)
error = ENOENT;
if (pathname == nullptr)
goto out_errno;
- if ((error = task_conv(t, pathname, VWRITE, path)) != 0)
+ if ((error = task_conv_remove_trailing_slash(t, pathname, VWRITE, path)) != 0)
goto out_errno;
error = sys_rmdir(path);
@@ -977,7 +977,7 @@ int chdir(const char *pathname)
if (pathname == nullptr)
goto out_errno;
- if ((error = task_conv(t, pathname, VREAD, path)) != 0)
+ if ((error = task_conv_remove_trailing_slash(t, pathname, VREAD, path)) != 0)
goto out_errno;
/* Check if directory exits */
diff --git a/fs/vfs/vfs.h b/fs/vfs/vfs.h
index d86ef957..38d2a2ab 100644
--- a/fs/vfs/vfs.h
+++ b/fs/vfs/vfs.h
@@ -135,7 +135,8 @@ int sys_fchmod(int fd, mode_t mode);
int task_alloc(struct task **pt);
int task_conv(struct task *t, const char *path, int mode, char *full);
-int path_conv(char *wd, const char *cpath, char *full);
+int task_conv_remove_trailing_slash(struct task *t, const char *path, int mode, char *full);
//int sec_file_permission(task_t task, char *path, int mode);
int sec_vnode_permission(char *path);
diff --git a/fs/vfs/vfs_lookup.cc b/fs/vfs/vfs_lookup.cc
index ad03fe25..4569061b 100644
--- a/fs/vfs/vfs_lookup.cc
+++ b/fs/vfs/vfs_lookup.cc
@@ -85,7 +85,7 @@ namei_follow_link(struct dentry *dp, char *node, char *name, char *fp, size_t mo
} else {
strlcpy(t.get(), p, PATH_MAX);
strlcpy(node, fp, mountpoint_len + c + 1);
- path_conv(node, lp, fp);
+ path_conv(node, lp, fp, false);
strlcat(fp, t.get(), PATH_MAX);
}
node[0] = 0;
diff --git a/fs/vfs/vfs_task.cc b/fs/vfs/vfs_task.cc
index 332c460d..178740a0 100644
--- a/fs/vfs/vfs_task.cc
+++ b/fs/vfs/vfs_task.cc
@@ -65,7 +65,7 @@ task_alloc(struct task **pt)
* @full: full path to be returned
*/
int
-path_conv(char *wd, const char *cpath, char *full)
+path_conv(char *wd, const char *cpath, char *full, bool truncate_trailing_slash)
{
char path[PATH_MAX];
char *src, *tgt, *p, *end;
@@ -129,6 +129,10 @@ path_conv(char *wd, const char *cpath, char *full)
}
src = p + 1;
}
+ if (truncate_trailing_slash &&
+ tgt != full && *(tgt - 1) == '/' && tgt - 1 != full) {
+ tgt--;
+ }
*tgt = '\0';
return (0);
@@ -141,8 +145,8 @@ path_conv(char *wd, const char *cpath, char *full)
* @full: full path to be returned
* @acc: access mode
*/
-int
-task_conv(struct task *t, const char *cpath, int acc, char *full)
+static int
+_task_conv(struct task *t, const char *cpath, int acc, char *full, bool truncate_trailing_slash)
{
int rc;
@@ -150,7 +154,7 @@ task_conv(struct task *t, const char *cpath, int acc, char *full)
return (EFAULT);
}
- rc = path_conv(t->t_cwd, cpath, full);
+ rc = path_conv(t->t_cwd, cpath, full, truncate_trailing_slash);
if (rc != 0) {
return (rc);
}
@@ -159,6 +163,32 @@ task_conv(struct task *t, const char *cpath, int acc, char *full)
return (0); //sec_file_permission(t->t_taskid, full, acc);
}
+/*
+ * Convert to full path from the cwd of task and path.
+ * @t: task structure
+ * @path: target path
+ * @full: full path to be returned
+ * @acc: access mode
+ */
+int
+task_conv(struct task *t, const char *cpath, int acc, char *full)
+{
+ return _task_conv(t, cpath, acc, full, false);
+}
+
+/*
+ * Convert to full path from the cwd of task and path. Remove any trailing slash.
+ * @t: task structure
+ * @path: target path
+ * @full: full path to be returned
+ * @acc: access mode
+ */
+int
+task_conv_remove_trailing_slash(struct task *t, const char *cpath, int acc, char *full)
+{
+ return _task_conv(t, cpath, acc, full, true);
+}
+
/*
* Safe copying function that checks for overflow.
*/