Index: base.c
===================================================================
RCS file: /cvsroot/translucency/translucency/base.c,v
retrieving revision 1.28
diff -u -r1.28 base.c
--- base.c	20 Oct 2003 13:17:38 -0000	1.28
+++ base.c	6 Nov 2003 08:45:13 -0000
@@ -12,7 +12,6 @@
 #include "base.h"
 #include "linked_list.h"
 
-#define LAYERS 8
 #define HASH_BITS 8
 #define HASH_TABLE_SIZE (1<<HASH_BITS)
 
@@ -337,6 +336,52 @@
         return outfd;
 }
 
+int redirect_path2(char *fname, struct translucent **t, int rflags, struct nameidata *n);
+int loopcount=0;
+int translucent_handle_symlink(char *path, struct nameidata *nds, int layer, int rflags, struct translucent *t)
+{
+        int result;
+        struct nameidata n=nds[layer];
+        if(loopcount>9) return -1;
+        { // brace only for limiting scope of variables
+          char *buf=malloc(2*REDIR_BUFSIZE), *buf2=buf+REDIR_BUFSIZE, *p=namei_to_path(&n,buf);
+          BEGIN_KMEM
+                  result=orig_sys_readlink(p, buf2, REDIR_BUFSIZE);
+          END_KMEM
+          if(result>=REDIR_BUFSIZE) result=REDIR_BUFSIZE-1;
+          buf2[result]=0;
+  //        printk("symlink %.8o %s -> %s\n", n.dentry->d_inode->i_mode, p, buf2);
+          if(buf2[0]=='/') memcpy(path, buf2, REDIR_BUFSIZE);
+          else {
+                  char *p2=strrchr(path, '/');
+                  int i_Len;
+                  if(p2==NULL) {
+                          printk(SYSLOGID ": should not get here id=1\n");
+			  free(buf);
+                          return -1;
+                  }
+                  *(++p2)=0;
+                  i_Len=p2-path;
+                  strncat(path, buf2, REDIR_BUFSIZE-i_Len);
+          }
+          //printk(SYSLOGID ": from %s ",p);
+          free(buf);
+        }
+        //printk("symlink %s ", path);
+        loopcount++;
+        result=redirect_path2(path, &t, rflags, nds);
+        loopcount--;
+        //printk("to %s %i %.8X %.8X\n", path, result, rflags, n->flags);
+        if(result>=0) {
+                if(result==MAX_LAYERS) {
+                        printk(SYSLOGID ": TODO handle open dir here\n");
+                        return -1;
+                }
+                path_release(&n);
+	} else result=-1;
+        return result;
+}
+
 void absolutize(char *name, struct dentry *d, struct vfsmount *m) {
 	char *p, *buf;
 	int l,l2 = strlen(name);
@@ -350,7 +395,7 @@
 	        name[l] = '/';
         } else {
                 printk(SYSLOGID ": buffer too small\n");
-	}
+        }
         free(buf);
 }
 
@@ -527,36 +572,58 @@
 	// return index of uppermost layer with valid entry
 	for(j=i-1; j>=0; --j) if(valid[j]) { path_release(&n[j]); valid[j]=0; }
 	if (endp) *endp=(slash?lastnp:NULL);
+        if((!(lflags&LOOKUP_NOFOLLOW)) && i>=0 && valid[i] && have_inode(&n[i]) && S_ISLNK(n[i].dentry->d_inode->i_mode)) {
+                j=translucent_handle_symlink(name, n, i, lflags, t);
+                if(j>=0) {
+                        something_redirected=1;
+                        i=j;
+                }
+                if(!n[i].dentry) i=-1;
+        }
 	if(!something_redirected && i>=0) {path_release(&n[i]); return (-1);}
 	return (i);
 }
 
-/* if 0 is returned no redirection could be done... 
-   either there was nothing to redirect or other errors occurred (maybe reflect this in return status later)
-   if 1 is returned fname will be some pathname
-   if 2 is returned fname has been redirected (from n1 to n2)
-*/
-int redirect_path(char *fname, struct translucent *t, int rflags) 
+int redirect_path2(char *fname, struct translucent **t, int rflags, struct nameidata *n)
 {
-	char *p,*p2;
-	int i,error=1,result=0,top=-1;
-	struct nameidata n[MAX_LAYERS];
-	if ((translucent_flags & no_translucency) || !match_uids()) return 0;
-	if ((translucent_flags & do_downcase)) for (i=strlen(fname)-1; i>=0; --i) 
-		if (fname[i]>='A' && fname[i]<='Z') fname[i]|=32;
-	if (t == NULL) {
+        char *p2;
+        int i, top=-1;
+        if ((translucent_flags & do_downcase)) for (i=strlen(fname)-1; i>=0; --i) 
+                if (fname[i]>='A' && fname[i]<='Z') fname[i]|=32;
+	if (*t == NULL) {
 		for (i=0; i<REDIRS; ++i) {
 			if (is_valid(&redirs[i])) {
-				t = &redirs[i];
-				redirect_path_init(fname,rflags,n,t);
-				top = redirect_path_walk(fname,&p2,n,t);
+				*t = &redirs[i];
+				redirect_path_init(fname, rflags, n, *t);
+				top = redirect_path_walk(fname, &p2, n, *t);
 				if (top>0) break;
 			}
 		}
 	} else {
-		redirect_path_init(fname,rflags,n,t);
-		top = redirect_path_walk(fname,&p2,n,t);
+		redirect_path_init(fname, rflags, n, *t);
+		top = redirect_path_walk(fname, &p2, n, *t);
 	}
+        return top;
+}
+
+/** redirect a pathname
+   @param char *fname pointer to the pathname to redirect - may get modified 
+   @param struct translucent *t
+   @param int rflags modify operation
+   @return int redirection status code
+   @retval 0 no redirection could be done - either there was nothing to redirect or other errors occurred (maybe later reflect this in return status)
+   @retval 1 fname will be some pathname
+   @retval 2 fname has been redirected
+   @retval 4 fname was resolved to a whiteout entry
+   @retval <0 indicates an error code to be returned by the syscall
+*/
+int redirect_path(char *fname, struct translucent *t, int rflags) 
+{
+	char *p;
+	int i,error=1,result=0,top;
+	struct nameidata n[MAX_LAYERS];
+        if ((translucent_flags & no_translucency) || !match_uids()) return 0;
+        top=redirect_path2(fname, &t, rflags, n);
 	error=top<0;
 	if (error) goto out_release;
         if(top==MAX_LAYERS) { // special merge-dir handling
