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<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; i0) 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