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