From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1HqNXq-0003PI-6v for qemu-devel@nongnu.org; Tue, 22 May 2007 02:08:30 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1HqNXp-0003P5-6C for qemu-devel@nongnu.org; Tue, 22 May 2007 02:08:29 -0400 Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1HqNXo-0003Ov-Qz for qemu-devel@nongnu.org; Tue, 22 May 2007 02:08:28 -0400 Received: from partizan.velesys.com ([213.184.230.195]) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1HqNXn-0004Od-DE for qemu-devel@nongnu.org; Tue, 22 May 2007 02:08:28 -0400 Received: from localhost (partizan [10.0.5.24]) by partizan.velesys.com (paritzan.velesys.com) with ESMTP id 5BBB9D68EAE for ; Tue, 22 May 2007 09:09:32 +0300 (EEST) Received: from partizan.velesys.com ([10.0.5.24]) by localhost (partizan.velesys.com [10.0.5.24]) (amavisd-new, port 10024) with ESMTP id N+Bmw87wfB9h for ; Tue, 22 May 2007 09:09:28 +0300 (EEST) Received: from localhost.localdomain (mm-185-159-57-86.adsl.mgts.by [86.57.159.185]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by partizan.velesys.com (paritzan.velesys.com) with ESMTP id 4340AD68D81 for ; Tue, 22 May 2007 09:09:27 +0300 (EEST) Date: Tue, 22 May 2007 09:08:24 +0300 From: "Kirill A. Shutemov" Subject: Re: [Qemu-devel] [PATCH][UPDATED] Fix path mangling in linux-user/path.c Message-ID: <20070522060824.GA5584@localhost.localdomain> References: <53fbb7580705211623n3c0c3bf2x9e68842fc25a43be@mail.gmail.com> MIME-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha1; protocol="application/pgp-signature"; boundary="cvVnyQ+4j833TQvp" Content-Disposition: inline In-Reply-To: <53fbb7580705211623n3c0c3bf2x9e68842fc25a43be@mail.gmail.com> Reply-To: qemu-devel@nongnu.org List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org --cvVnyQ+4j833TQvp Content-Type: multipart/mixed; boundary="mP3DRpeJDSE+ciuQ" Content-Disposition: inline --mP3DRpeJDSE+ciuQ Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-Transfer-Encoding: quoted-printable On [Tue, 22.05.2007 02:22], Lauri Leukkunen wrote: > Attached patch fixes the linux-user path mangling code for use with > real target root filesystems that have nasty symlinks and lots of > files. The old code is terribly slow and can easily end up going > through the entire host system /usr hierarchy in a recursive loop. >=20 > Compared to the previous version of this patch, fixes an issue with > attempting to free() a pointer returned by GNU basename(). My patch to solve same problems attached --=20 Regards, Kirill A. Shutemov + Belarus, Minsk + Velesys LLC, http://www.velesys.com/ + ALT Linux Team, http://www.altlinux.com/ --mP3DRpeJDSE+ciuQ Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="qemu-0.9.0-alt-path.patch" Content-Transfer-Encoding: quoted-printable --- qemu/linux-user/path.c +++ qemu/linux-user/path.c @@ -1,147 +1,81 @@ /* Code to mangle pathnames into those matching a given prefix. eg. open("/lib/foo.so") =3D> open("/usr/gnemul/i386-linux/lib/foo.so"); - - The assumption is that this area does not change. */ #include -#include +#include #include -#include #include -#include #include #include "qemu.h" =20 -struct pathelem -{ - /* Name of this, eg. lib */ - char *name; - /* Full path name, eg. /usr/gnemul/x86-linux/lib. */ - char *pathname; - struct pathelem *parent; - /* Children */ - unsigned int num_entries; - struct pathelem *entries[0]; +struct path_list_head { + struct path_list_head *next; + char* path; }; =20 -static struct pathelem *base; - -/* First N chars of S1 match S2, and S2 is N chars long. */ -static int strneq(const char *s1, unsigned int n, const char *s2) -{ - unsigned int i; - - for (i =3D 0; i < n; i++) - if (s1[i] !=3D s2[i]) - return 0; - return s2[i] =3D=3D 0; -} - -static struct pathelem *add_entry(struct pathelem *root, const char *name); - -static struct pathelem *new_entry(const char *root, - struct pathelem *parent, - const char *name) -{ - struct pathelem *new =3D malloc(sizeof(*new)); - new->name =3D strdup(name); - asprintf(&new->pathname, "%s/%s", root, name); - new->num_entries =3D 0; - return new; -} - -#define streq(a,b) (strcmp((a), (b)) =3D=3D 0) - -static struct pathelem *add_dir_maybe(struct pathelem *path) -{ - DIR *dir; - - if ((dir =3D opendir(path->pathname)) !=3D NULL) { - struct dirent *dirent; - - while ((dirent =3D readdir(dir)) !=3D NULL) { - if (!streq(dirent->d_name,".") && !streq(dirent->d_name,"..")){ - path =3D add_entry(path, dirent->d_name); - } - } - closedir(dir); - } - return path; -} - -static struct pathelem *add_entry(struct pathelem *root, const char *name) -{ - root->num_entries++; - - root =3D realloc(root, sizeof(*root) - + sizeof(root->entries[0])*root->num_entries); - - root->entries[root->num_entries-1] =3D new_entry(root->pathname, root,= name); - root->entries[root->num_entries-1] - =3D add_dir_maybe(root->entries[root->num_entries-1]); - return root; -} - -/* This needs to be done after tree is stabalized (ie. no more reallocs!).= */ -static void set_parents(struct pathelem *child, struct pathelem *parent) -{ - unsigned int i; - - child->parent =3D parent; - for (i =3D 0; i < child->num_entries; i++) - set_parents(child->entries[i], child); -} +static struct path_list_head* list_head; =20 void init_paths(const char *prefix) { if (prefix[0] !=3D '/' || - prefix[0] =3D=3D '\0' || - !strcmp(prefix, "/")) + prefix[0] =3D=3D '\0' || + !strcmp(prefix, "/")) return; =20 - base =3D new_entry("", NULL, prefix+1); - base =3D add_dir_maybe(base); - if (base->num_entries =3D=3D 0) { - free (base); - base =3D NULL; - } else { - set_parents(base, base); - } -} + list_head =3D malloc(sizeof(struct path_list_head)); =20 -/* FIXME: Doesn't handle DIR/.. where DIR is not in emulated dir. */ -static const char * -follow_path(const struct pathelem *cursor, const char *name) -{ - unsigned int i, namelen; - - name +=3D strspn(name, "/"); - namelen =3D strcspn(name, "/"); - - if (namelen =3D=3D 0) - return cursor->pathname; - - if (strneq(name, namelen, "..")) - return follow_path(cursor->parent, name + namelen); - - if (strneq(name, namelen, ".")) - return follow_path(cursor, name + namelen); - - for (i =3D 0; i < cursor->num_entries; i++) - if (strneq(name, namelen, cursor->entries[i]->name)) - return follow_path(cursor->entries[i], name + namelen); - - /* Not found */ - return NULL; + /* first element of list is prefix */ + list_head->path =3D strdup(prefix); + list_head->next =3D NULL; } =20 /* Look for path in emulation dir, otherwise return name. */ const char *path(const char *name) { + struct path_list_head *list =3D list_head; + int path_length =3D strlen(list_head->path) + strlen(name) + 1; + char *newname =3D malloc(path_length); + struct stat buf; + const char * result =3D name; + /* Only do absolute paths: quick and dirty, but should mostly be OK. Could do relative by tracking cwd. */ - if (!base || name[0] !=3D '/') - return name; - - return follow_path(base, name) ?: name; + if (!list_head || result[0] !=3D '/') + goto exit; + + strncpy(newname, list_head->path, path_length); + strncat(newname, name, path_length); + + /* look for place where path should be present */ + while ( list->next && (strcmp(list->next->path, newname) < 0) ) + list =3D list->next; + + /* if there is no path in list */ + if ( !list->next || strcmp(list->next->path, newname) ) { + /* add element to list if path exist in emulation dir */ + if ( !stat(newname, &buf) ) + { + struct path_list_head *new; + + new =3D malloc(sizeof(struct path_list_head)); + new->path =3D strdup(newname); + new->next =3D list->next; + list->next =3D new; + result =3D new->path; + } + + } else if ( stat(list->next->path, &buf) ) { + /* remove element from list if path doesn't exist in emulation dir */ + struct path_list_head* tmp; + + tmp =3D list->next; + list->next =3D tmp->next; + free(tmp->path); + free(tmp); + } else + result =3D list->next->path; + +exit: + free(newname); + return result; } --mP3DRpeJDSE+ciuQ-- --cvVnyQ+4j833TQvp Content-Type: application/pgp-signature; name="signature.asc" Content-Description: Digital signature Content-Disposition: inline -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.7 (GNU/Linux) iD8DBQFGUojvbWYnhzC5v6oRAnAAAJ0QHWNXOPF84rJO3+xntex1g5Kl8QCfVef9 BspYNs0S7wGNsTc/A5GibNg= =3kcz -----END PGP SIGNATURE----- --cvVnyQ+4j833TQvp--