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]

Reply via email to