Просмотр исходного кода

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.
Guillem Jover лет назад: 17
Родитель
Сommit
353b02acb3
3 измененных файлов с 30 добавлено и 34 удалено
  1. 3 0
      debian/changelog
  2. 5 5
      src/archives.c
  3. 22 29
      src/configure.c

+ 3 - 0
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

+ 5 - 5
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);

+ 22 - 29
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')"),