The following commit has been merged in the master branch:
commit 353b02acb33224bc2d7e3b0295538d592b9c8bad
Author: Guillem Jover <[email protected]>
Date: Wed Sep 30 03:10:27 2009 +0200
dpkg: Use stat size to varbuf_grow the buffer for readlink
Do not expand the buffer indefinitely by trying several times until
the buffer is big enough. Pre-allocate just once using varbuf_grow
with the known size from stat.
diff --git a/debian/changelog b/debian/changelog
index 870cc0b..0e6ab3a 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -23,6 +23,9 @@ dpkg (1.15.5) UNRELEASED; urgency=low
* Use C99 snprintf function family semantics to avoid having to call them
in a loop to grow the varbuf buffer. This should reduce memory usage and
be slightly faster on varbufprintf calls.
+ * Use the size from stat to allocate the buffers for readlink, instead of
+ indefinitely calling readlink and growing the buffer. This should reduce
+ memory usage when handling lots of symlinks, and be slightly faster.
[ Raphaƫl Hertzog ]
* Add versioned dependency on base-files (>= 5.0.0) to dpkg-dev to ensure
diff --git a/src/archives.c b/src/archives.c
index fbe334a..17ae9a2 100644
--- a/src/archives.c
+++ b/src/archives.c
@@ -803,11 +803,11 @@ int tarobject(struct TarInfo *ti) {
* (Pretend that making a copy of a symlink is the same as linking to
it.)
*/
varbufreset(&symlinkfn);
- do {
- varbufextend(&symlinkfn);
- r= readlink(fnamevb.buf,symlinkfn.buf,symlinkfn.size);
- if (r<0) ohshite(_("unable to read link `%.255s'"),ti->Name);
- } while ((size_t)r == symlinkfn.size);
+ varbuf_grow(&symlinkfn, stab.st_size + 1);
+ r = readlink(fnamevb.buf, symlinkfn.buf, symlinkfn.size);
+ if (r < 0)
+ ohshite(_("unable to read link `%.255s'"), ti->Name);
+ assert(r == stab.st_size);
symlinkfn.used= r; varbufaddc(&symlinkfn,0);
if (symlink(symlinkfn.buf,fnametmpvb.buf))
ohshite(_("unable to make backup symlink for `%.255s'"),ti->Name);
diff --git a/src/configure.c b/src/configure.c
index 200d8ae..5971dca 100644
--- a/src/configure.c
+++ b/src/configure.c
@@ -354,10 +354,9 @@ deferred_configure(struct pkginfo *pkg)
int
conffderef(struct pkginfo *pkg, struct varbuf *result, const char *in)
{
- static char *linkreadbuf = NULL;
- static int linkreadbufsize = 0;
+ static struct varbuf symlink = VARBUF_INIT;
struct stat stab;
- int r, need;
+ int r;
int loopprotect;
varbufreset(result);
@@ -391,31 +390,25 @@ conffderef(struct pkginfo *pkg, struct varbuf *result,
const char *in)
" (= '%s')"), pkg->name, in,
result->buf);
return -1;
}
- need = 255;
- for (;;) {
- if (need > linkreadbufsize) {
- linkreadbuf = m_realloc(linkreadbuf,
need);
- linkreadbufsize = need;
- debug(dbg_conffdetail,
- "conffderef readlink
realloc(%d)=%p",
- need, linkreadbuf);
- }
- r = readlink(result->buf, linkreadbuf,
linkreadbufsize - 1);
- if (r < 0) {
- warning(_("%s: unable to readlink
conffile '%s'\n"
- " (= '%s'): %s"),
- pkg->name, in, result->buf,
strerror(errno));
- return -1;
- }
- debug(dbg_conffdetail,
- "conffderef readlink gave %d, '%.*s'",
- r, max(r, 0), linkreadbuf);
- if (r < linkreadbufsize - 1)
- break;
- need = r << 2;
+
+ varbufreset(&symlink);
+ varbuf_grow(&symlink, stab.st_size + 1);
+ r = readlink(result->buf, symlink.buf, symlink.size);
+ if (r < 0) {
+ warning(_("%s: unable to readlink conffile
'%s'\n"
+ " (= '%s'): %s"),
+ pkg->name, in, result->buf,
strerror(errno));
+ return -1;
}
- linkreadbuf[r] = '\0';
- if (linkreadbuf[0] == '/') {
+ assert(r == stab.st_size); // XXX: debug
+ symlink.used = r;
+ varbufaddc(&symlink, '\0');
+
+ debug(dbg_conffdetail,
+ "conffderef readlink gave %d, '%s'",
+ r, symlink.buf);
+
+ if (symlink.buf[0] == '/') {
varbufreset(result);
varbufaddstr(result, instdir);
debug(dbg_conffdetail,
@@ -426,7 +419,7 @@ conffderef(struct pkginfo *pkg, struct varbuf *result,
const char *in)
if (r < 0) {
warning(_("%s: conffile '%.250s'
resolves to degenerate filename\n"
" ('%s' is a symlink to
'%s')"),
- pkg->name, in, result->buf,
linkreadbuf);
+ pkg->name, in, result->buf,
symlink.buf);
return -1;
}
if (result->buf[r] == '/')
@@ -436,7 +429,7 @@ conffderef(struct pkginfo *pkg, struct varbuf *result,
const char *in)
"conffderef readlink relative to '%.*s'",
(int)result->used, result->buf);
}
- varbufaddstr(result, linkreadbuf);
+ varbufaddbuf(result, symlink.buf, symlink.used);
varbufaddc(result, 0);
} else {
warning(_("%s: conffile '%.250s' is not a plain file or
symlink (= '%s')"),
--
dpkg's main repository
--
To UNSUBSCRIBE, email to [email protected]
with a subject of "unsubscribe". Trouble? Contact [email protected]