]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
client: Add symlink loop checking in path_walk()
authorSam Lang <sam.lang@inktank.com>
Mon, 5 Nov 2012 23:17:22 +0000 (17:17 -0600)
committerSam Lang <sam.lang@inktank.com>
Mon, 5 Nov 2012 23:19:41 +0000 (17:19 -0600)
If a loop exists in directories due to a symlink: /a/b/c -> /a
We now return -ELOOP from path_walk() instead of looping forever.

Signed-off-by: Sam Lang <sam.lang@inktank.com>
src/client/Client.cc
src/client/Inode.h

index f2591829779412ab5aa37c131aea01e5b8cb63f5..830ab8c9c07ef48a624dd00420cffc2c209ccaf0 100644 (file)
@@ -3719,6 +3719,7 @@ int Client::path_walk(const filepath& origpath, Inode **final, bool followsym)
 
   ldout(cct, 10) << "path_walk " << path << dendl;
 
+  set<Inode*,Inode::Compare> visited;
   unsigned i=0;
   while (i < path.depth() && cur) {
     const string &dname = path[i];
@@ -3731,6 +3732,13 @@ int Client::path_walk(const filepath& origpath, Inode **final, bool followsym)
     // 'directory' symlinks.
     if (next && next->is_symlink()) {
       if (i < path.depth() - 1) {
+       // check for loops
+       if(visited.find(next) != visited.end()) {
+         // already hit this one, return error
+         return -ELOOP;
+       }
+       visited.insert(next);
+
        // dir symlink
        // replace consumed components of path with symlink dir target
        filepath resolved(next->symlink.c_str());
index ff5e96c6f9fc91d6ea96d94b1263884f0c9ca35c..6bda720d5a320bc97ba7d8451146c663fe5dddda 100644 (file)
@@ -211,6 +211,14 @@ class Inode {
 
   vinodeno_t vino() { return vinodeno_t(ino, snapid); }
 
+  struct Compare {
+    bool operator() (Inode* const & left, Inode* const & right) {
+      if (left->ino.val < right->ino.val) {
+       return (left->snapid.val < right->snapid.val);
+      }
+      return false;
+    }
+  };
 
   bool check_mode(uid_t uid, gid_t gid, gid_t *sgids, int sgid_count, uint32_t flags);