Blob Blame History Raw
From 557bb6c344247b1c4763943ec737aa6963ac5572 Mon Sep 17 00:00:00 2001
From: Mohammed Rafi KC <rkavunga@redhat.com>
Date: Wed, 3 May 2017 17:19:57 +0530
Subject: [PATCH 448/473] gfapi: fix handling of dot and double dot in path

This patch is to handle "." and ".." in file path. Which means
this special dentry names will be resolved before sending fops
on the path.

Backport of>
>Change-Id: I5e92f6d1ad1412bf432eb2488e53fb7731edb013
>BUG: 1447266
>Signed-off-by: Mohammed Rafi KC <rkavunga@redhat.com>
>Reviewed-on: https://review.gluster.org/17177
>Smoke: Gluster Build System <jenkins@build.gluster.org>
>Reviewed-by: Niels de Vos <ndevos@redhat.com>
>CentOS-regression: Gluster Build System <jenkins@build.gluster.org>
>NetBSD-regression: NetBSD Build System <jenkins@build.gluster.org>
>Reviewed-by: Jeff Darcy <jeff@pl.atyp.us>

Change-Id: I5e92f6d1ad1412bf432eb2488e53fb7731edb013
BUG: 1441280
Signed-off-by: Mohammed Rafi KC <rkavunga@redhat.com>
Reviewed-on: https://code.engineering.redhat.com/gerrit/106338
Reviewed-by: Poornima Gurusiddaiah <pgurusid@redhat.com>
Reviewed-by: Atin Mukherjee <amukherj@redhat.com>
---
 api/src/glfs-resolve.c   |  41 ++++++++----------
 libglusterfs/src/inode.c | 110 +++++++++++++++++++++++++++++++++++++++++++++++
 libglusterfs/src/inode.h |  17 ++++++++
 3 files changed, 144 insertions(+), 24 deletions(-)

diff --git a/api/src/glfs-resolve.c b/api/src/glfs-resolve.c
index d495cd2..a2be87f 100644
--- a/api/src/glfs-resolve.c
+++ b/api/src/glfs-resolve.c
@@ -25,12 +25,10 @@
 #include "syncop.h"
 #include "call-stub.h"
 #include "gfapi-messages.h"
-
+#include "inode.h"
 #include "glfs-internal.h"
 
 #define graphid_str(subvol) (uuid_utoa((unsigned char *)subvol->graph->graph_uuid))
-
-
 int
 glfs_first_lookup_safe (xlator_t *subvol)
 {
@@ -251,33 +249,26 @@ glfs_resolve_component (struct glfs *fs, xlator_t *subvol, inode_t *parent,
 	loc.parent = inode_ref (parent);
 	gf_uuid_copy (loc.pargfid, parent->gfid);
 
-        /* /.. and /. should point back to /
-           we lookup using inode and gfid of root
-           Fill loc.name so that we make use md-cache.
-           md-cache is not valid for nameless lookups.
-        */
+        /* At this point we should never have '.' or ".." in path */
         if (__is_root_gfid (parent->gfid) &&
-            (strcmp (component, "..") == 0)) {
-                loc.inode = inode_ref (parent);
-                loc.name = ".";
-        } else {
-                if (strcmp (component, ".") == 0)
-                        loc.inode = inode_ref (parent);
-                else if (strcmp (component, "..") == 0)
-                        loc.inode = inode_parent (parent, 0, 0);
-                else
-                        loc.inode = inode_grep (parent->table, parent,
-                                                component);
+            (strcmp (component, "/") == 0)) {
+                if (!force_lookup) {
+                        inode = inode_ref (parent);
+                } else {
+                        ret = glfs_resolve_base (fs, subvol, parent, &ciatt);
+                        if (!ret)
+                                inode = inode_ref (parent);
+                }
+                goto found;
         }
 
-
+        loc.inode = inode_grep (parent->table, parent, component);
 	if (loc.inode) {
 		gf_uuid_copy (loc.gfid, loc.inode->gfid);
 		reval = 1;
 
                 if (!(force_lookup || inode_needs_lookup (loc.inode, THIS))) {
 			inode = inode_ref (loc.inode);
-			ciatt.ia_type = inode->ia_type;
 			goto found;
 		}
 	} else {
@@ -357,8 +348,10 @@ glfs_resolve_component (struct glfs *fs, xlator_t *subvol, inode_t *parent,
         } else if (inode == loc.inode)
                 inode_ctx_set (inode, THIS, &ctx_value);
 found:
-	if (inode)
+	if (inode) {
+                ciatt.ia_type = inode->ia_type;
 		inode_lookup (inode);
+        }
 	if (iatt)
 		*iatt = ciatt;
 out:
@@ -384,6 +377,7 @@ priv_glfs_resolve_at (struct glfs *fs, xlator_t *subvol, inode_t *at,
 	char       *next_component = NULL;
 	int         ret = -1;
 	struct iatt ciatt = {0, };
+        char        dentry_name[PATH_MAX]  = {0, };
 
 	DECLARE_OLD_THIS;
 	__GLFS_ENTRY_VALIDATE_FS(fs, invalid_fs);
@@ -414,9 +408,8 @@ priv_glfs_resolve_at (struct glfs *fs, xlator_t *subvol, inode_t *at,
 
 		if (parent)
 			inode_unref (parent);
-
 		parent = inode;
-
+                glusterfs_normalize_dentry (&parent, &component, dentry_name);
 		inode = glfs_resolve_component (fs, subvol, parent,
 						component, &ciatt,
 						/* force hard lookup on the last
diff --git a/libglusterfs/src/inode.c b/libglusterfs/src/inode.c
index 747c1f1..90a5608 100644
--- a/libglusterfs/src/inode.c
+++ b/libglusterfs/src/inode.c
@@ -2548,3 +2548,113 @@ inode_ctx_size (inode_t *inode)
 out:
         return size;
 }
+
+static void
+inode_parent_null_check(inode_t **parent, inode_t *inode, char **component)
+{
+        GF_VALIDATE_OR_GOTO ("inode", inode, out);
+        GF_VALIDATE_OR_GOTO ("inode", (*component), out);
+
+        if (!(*parent) && __is_root_gfid (inode->gfid)) {
+                *parent = inode_ref (inode);
+                *component = "/";
+        }
+out:
+        return;
+}
+
+/*
+ * This function changes component name and parent inode
+ * if the component name is either "." or ".."
+ *
+ * @Paramas:
+ * Parent : Parent inode of current dentry
+ * component : component name that we need to test
+ * dentry_name : Address for memory if need to change component.
+ *               The caller has to preallocate this memory with
+ *               PATH_MAX as the size.
+ *
+ * We return the updated parent inode and component in the
+ * respective structures.
+ *
+ * Basic Idea of the function:
+ *
+ * Example 1 :
+ * Path /out_dir/dir/in_dir/.
+ *     In put values :
+ *         parent = in_dir
+ *         component : "."
+ *
+ *     Out put values:
+ *         parent : dir
+ *         component : "in_dir"
+ *
+ * Example 2 :
+ * Path /out_dir/dir/in_dir/..
+ *     In put values :
+ *         parent = in_dir
+ *         component : ".."
+ *
+ *     Out put values:
+ *         parent : output_dir
+ *         component : "dir"
+ */
+void
+glusterfs_normalize_dentry (inode_t **parent, char **component,
+                          char *dentry_name)
+{
+        inode_t         *temp_inode             = NULL;
+        dentry_t        *dentry                 = NULL;
+
+        GF_VALIDATE_OR_GOTO ("inode", (*parent), out);
+        GF_VALIDATE_OR_GOTO ("inode", (*component), out);
+        GF_VALIDATE_OR_GOTO ("inode", (dentry_name), out);
+
+        /* After this point, there should not be "." or ".."
+         * in the path. Dot and double dots are replaced with
+         * appropriate base name and parent inode.
+         */
+
+        /* During the resolving, if it goes beyond the mount point
+         * we do lookup on the mount itself like "/.. " will be
+         * converted as "/"
+         */
+        if (strcmp (*component, ".") == 0) {
+                temp_inode = *parent;
+                *parent = inode_parent (*parent, 0, 0);
+                inode_parent_null_check (parent, temp_inode, component);
+                pthread_mutex_lock (&temp_inode->table->lock);
+                {
+                        dentry = __dentry_search_arbit (temp_inode);
+                        if (dentry) {
+                                snprintf (dentry_name, PATH_MAX, "%s",
+                                          dentry->name);
+                                *component = dentry_name;
+                        }
+                }
+                pthread_mutex_unlock (&temp_inode->table->lock);
+                inode_unref (temp_inode);
+        } else if (strcmp (*component, "..") == 0) {
+                temp_inode = *parent;
+                *parent = inode_parent (*parent, 0, 0);
+                inode_parent_null_check (parent, temp_inode, component);
+                inode_unref (temp_inode);
+
+                temp_inode = *parent;
+                *parent = inode_parent (*parent, 0, 0);
+                inode_parent_null_check (parent, temp_inode, component);
+                pthread_mutex_lock (&temp_inode->table->lock);
+                {
+                        dentry = __dentry_search_arbit (temp_inode);
+                        if (dentry) {
+                                snprintf (dentry_name, PATH_MAX, "%s",
+                                          dentry->name);
+                                *component = dentry_name;
+                        }
+                }
+                pthread_mutex_unlock (&temp_inode->table->lock);
+                inode_unref (temp_inode);
+        }
+out:
+        return;
+}
diff --git a/libglusterfs/src/inode.h b/libglusterfs/src/inode.h
index 5289b15..e3c38bb 100644
--- a/libglusterfs/src/inode.h
+++ b/libglusterfs/src/inode.h
@@ -282,4 +282,21 @@ inode_has_dentry (inode_t *inode);
 size_t
 inode_ctx_size (inode_t *inode);
 
+/*
+ * This function is used to change the dentry from a path
+ * if it contains any "." or ".." .
+ *
+ * It replaces "." and ".." to proper bname after resolving
+ * and will change the component accordingly.
+ *
+ * This fucntion also replaces the parent inode based on the
+ * bname.
+ *
+ * We should give a allocated memory as a third argument to store
+ * the component in case if we are modifying it.
+ */
+
+void
+glusterfs_normalize_dentry (inode_t **parent, char **component,
+                            char *dentry_name);
 #endif /* _INODE_H */
-- 
1.8.3.1