Re: [AVFS] ~/.avfs and symlinks
Miklos Szeredi <[email protected]> Mon, 06 Mar 2006 12:08:11 +0100
| Newsgroups | gmane.comp.file-systems.avfs.user |
|---|---|
| Message-ID | <[email protected]> |
> On 2006-01-31 16:41, Peter wrote:
> > Don't know if this is even a bug, but avfs has problems when a symlinked
> > directory is used. For example,
>
> I have looked into this problem and I think it's not a bug in avfs. The
> kernel asks the avfsd for the attributes for each part of the path. In
> case of a symlink the kernel asks avfsd to "readlink" and avfs returns
> the destination of the symlinks. If this is an absolute link, the
> destination is outside the avfs mount point and the kernel don't ask
> avfsd again.
>
> The only solution I can think of is to concatenate the avfs mountpoint
> and the actual link destination for absolute links. On the one hand I
> don't like the idea of returning modified data but on the other hand the
> "file system in user space" can return whatever it want so it can also
> return a modified symlink destination.
>
> Miklos, what do think about this. And is there an easy way to get the
> mount point (except parsing /proc/mounts)?
There are problems with that. For example a filesystem may be mounted
in multiple places (mount --bind) or moved (mount --move). A better
solution is to turn absolute symlinks into relative ones.
For example: the link '/foo/link' pointing to '/bar/baz' could be
turned into a link pointing to '../bar/baz' etc.
> I'm not sure what will happen if someone does a chroot to the avfs
> mountpoint. In this case the symlink rewriting could be wrong again.
Yes, that is also a problematic case.
Attached the symlink transformation in sshfs. sshfs.base_path is the
path within the remote filesystem which is mounted. For example if
you mount 'user@host:/', then base path is '/', if you mount
'user@host:/foo' then the base path is '/foo'. If you mount
'user@host:', then the base path is '.' (which means the home
directory), in this case the transformation doesn't work.
Miklos
static int count_components(const char *p)
{
int ctr;
for (; *p == '/'; p++);
for (ctr = 0; *p; ctr++) {
for (; *p && *p != '/'; p++);
for (; *p == '/'; p++);
}
return ctr;
}
static void strip_common(const char **sp, const char **tp)
{
const char *s = *sp;
const char *t = *tp;
do {
for (; *s == '/'; s++);
for (; *t == '/'; t++);
*tp = t;
*sp = s;
for (; *s == *t && *s && *s != '/'; s++, t++);
} while ((*s == *t && *s) || (!*s && *t == '/') || (*s == '/' && !*t));
}
static void transform_symlink(const char *path, char **linkp)
{
const char *l = *linkp;
const char *b = sshfs.base_path;
char *newlink;
char *s;
int dotdots;
int i;
if (l[0] != '/' || b[0] != '/')
return;
strip_common(&l, &b);
if (*b)
return;
strip_common(&l, &path);
dotdots = count_components(path);
if (!dotdots)
return;
dotdots--;
newlink = malloc(dotdots * 3 + l ? strlen(l) : 1 + 10);
if (!newlink) {
fprintf(stderr, "sshfs: memory allocation failed\n");
exit(1);
}
for (s = newlink, i = 0; i < dotdots; i++, s += 3)
strcpy(s, "../");
if (l[0])
strcpy(s, l);
else if (!dotdots)
strcpy(s, ".");
else
s[0] = '\0';
free(*linkp);
*linkp = newlink;
}
-------------------------------------------------------
This SF.Net email is sponsored by xPML, a groundbreaking scripting language
that extends applications into web and mobile media. Attend the live webcast
and join the prime developer group breaking into this new coding territory!
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=110944&bid=241720&dat=121642