Bug#691099: iceweasel: resolves symlinks for local files and breaks relative links
Michael Gold
michael at bitplane.org
Sun Mar 9 00:37:50 UTC 2014
On Sun, Oct 21, 2012 at 16:01:23 +0200, Dominik George wrote:
> When opening local URLs and the file is a symbolic link, iceweasel resolves
> them to their target before opening. This breaks relative links in the document
> and also deviates from the behaviour when using symbolic links on a webserver
This bug makes it effectively impossible to browse any documentation in
a git-annex repository. I'm using an LD_PRELOAD hack (attached) to work
around it:
./gen-with-links-as-files \
| gcc -shared -fPIC -x c -pipe -ldl -o with-links-as-files.so -
LD_PRELOAD=`pwd`/with-links-as-files.so /usr/bin/iceweasel
(Only the __lxstat* parts are really needed in this case.)
-- Michael
-------------- next part --------------
#!/bin/sh
cat_lxstat () {
cat <<__EOF__
int
__lxstat$1(int ver, const char *path, struct stat$1 *buf)
{
static int (*real_lxstat$1)(int, const char*, struct stat$1*);
static int (*real_xstat$1)(int, const char*, struct stat$1*);
int ret = -1;
if (!real_lxstat$1) {
real_lxstat$1 = dlsym(RTLD_NEXT, "__lxstat$1");
real_xstat$1 = dlsym(RTLD_NEXT, "__xstat$1");
if (!real_xstat$1 || !real_lxstat$1) {
errno = ELIBACC;
goto out;
}
}
ret = real_lxstat$1(ver, path, buf);
if (ret != 0) goto out;
if (S_ISLNK(buf->st_mode)) {
struct stat$1 tmp;
ret = real_xstat$1(ver, path, &tmp);
if (ret != 0) {
// We can still use the lstat$1 result.
ret = 0;
goto out;
}
if (S_ISDIR(tmp.st_mode)) {
*buf = tmp;
} else if (S_ISREG(tmp.st_mode)
&& ((tmp.st_mode & 0111) == 0)) {
*buf = tmp;
}
}
out:
return ret;
}
__EOF__
}
cat_readdir () {
cat <<__EOF__
static void
fix_dirent$1(DIR *dir, struct dirent$1 *ent)
{
if (ent->d_type == DT_LNK || ent->d_type == DT_UNKNOWN) {
int fd = openat(dirfd(dir), &ent->d_name[0], O_RDONLY);
if (fd >= 0) {
struct stat64 stbuf;
if (fstat64(fd, &stbuf) == 0) {
if (S_ISREG(stbuf.st_mode)) {
ent->d_type = DT_REG;
} else if (S_ISDIR(stbuf.st_mode)) {
ent->d_type = DT_DIR;
} else if (S_ISFIFO(stbuf.st_mode)) {
ent->d_type = DT_FIFO;
} else if (S_ISCHR(stbuf.st_mode)) {
ent->d_type = DT_CHR;
} else if (S_ISBLK(stbuf.st_mode)) {
ent->d_type = DT_BLK;
} else if (S_ISSOCK(stbuf.st_mode)) {
ent->d_type = DT_SOCK;
}
}
do {} while (close(fd) != 0 && errno == EINTR);
}
}
}
struct dirent$1*
readdir$1(DIR *dir)
{
static struct dirent$1* (*real_readdir$1)(DIR*);
struct dirent$1 *ret = NULL;
if (!real_readdir$1) {
real_readdir$1 = dlsym(RTLD_NEXT, "readdir$1");
if (!real_readdir$1) {
errno = ELIBACC;
goto out;
}
}
ret = real_readdir$1(dir);
if (ret) {
fix_dirent$1(dir, ret);
}
out:
return ret;
}
int
readdir$1_r(DIR *dir, struct dirent$1 *entry, struct dirent$1 **result)
{
static int (*real_readdir${1}_r)(DIR*,
struct dirent$1*, struct dirent$1*);
int ret = -1;
if (!real_readdir${1}_r) {
real_readdir${1}_r = dlsym(RTLD_NEXT, "readdir${1}_r");
if (!real_readdir${1}_r) {
errno = ELIBACC;
goto out;
}
}
ret = real_readdir${1}_r(dir, entry, *result);
if (ret == 0 && *result) {
fix_dirent$1(dir, *result);
}
out:
return ret;
}
__EOF__
}
cat_preload () {
cat <<__EOF__
#define _GNU_SOURCE
#include <dlfcn.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
$(cat_lxstat '')
$(cat_lxstat '64')
$(cat_readdir '')
$(cat_readdir '64')
__EOF__
}
cat_preload
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.alioth.debian.org/pipermail/pkg-mozilla-maintainers/attachments/20140308/c50ade30/attachment.sig>
More information about the pkg-mozilla-maintainers
mailing list