Index: main/processarc.c
===================================================================
RCS file: /cvs/dpkg/dpkg/main/processarc.c,v
retrieving revision 1.37
diff -u -d -r1.37 processarc.c
--- main/processarc.c	2002/05/26 03:53:43	1.37
+++ main/processarc.c	2002/08/06 04:56:06
@@ -736,6 +736,8 @@
   }
   pop_cleanup(ehflag_normaltidy); /* closedir */
 
+  write_filelist_sha1sums(pkg, newfileslist);
+
   /* Update the status database.
    * This involves copying each field across from the `available'
    * to the `installed' half of the pkg structure.
Index: main/main.h
===================================================================
RCS file: /cvs/dpkg/dpkg/main/main.h,v
retrieving revision 1.20
diff -u -d -r1.20 main.h
--- main/main.h	2002/05/20 05:56:01	1.20
+++ main/main.h	2002/08/06 04:56:07
@@ -50,7 +50,7 @@
 
 enum action { act_unset, act_install, act_unpack, act_avail, act_configure,
               act_remove, act_purge, act_listpackages, act_avreplace, act_avmerge,
-              act_unpackchk, act_status, act_searchfiles, act_audit, act_listfiles,
+              act_unpackchk, act_status, act_searchfiles, act_audit, act_verify, act_listfiles,
               act_assertpredep, act_printarch, act_predeppackage, act_cmpversions,
               act_printinstarch, act_compareversions, act_printavail, act_avclear,
               act_forgetold, act_getselections, act_setselections, act_printgnuarch,
@@ -113,6 +113,7 @@
 
 void listpackages(const char *const *argv);
 void audit(const char *const *argv);
+void verify(const char *const *argv);
 void unpackchk(const char *const *argv);
 void showpackages(const char *const *argv);
 void searchfiles(const char *const *argv);
Index: main/main.c
===================================================================
RCS file: /cvs/dpkg/dpkg/main/main.c,v
retrieving revision 1.54
diff -u -d -r1.54 main.c
--- main/main.c	2002/06/02 04:26:46	1.54
+++ main/main.c	2002/08/06 04:56:07
@@ -75,6 +75,7 @@
   dpkg -l|--list [<pattern> ...]           list packages concisely\n\
   dpkg -S|--search <pattern> ...           find package(s) owning file(s)\n\
   dpkg -C|--audit                          check for broken package(s)\n\
+  dpkg --verify-sha1sums                   check for changed files in all packages\n\
   dpkg --print-architecture                print target architecture (uses GCC)\n\
   dpkg --print-gnu-build-architecture      print GNU version of target arch\n\
   dpkg --print-installation-architecture   print host architecture (for inst'n)\n\
@@ -374,6 +375,7 @@
   ACTION( "clear-avail",                     0,  act_avclear,              updateavailable ),
   ACTION( "forget-old-unavail",              0,  act_forgetold,            forgetold       ),
   ACTION( "audit",                          'C', act_audit,                audit           ),
+  ACTION( "verify-sha1sums",                 0,  act_verify,               verify          ),
   ACTION( "yet-to-unpack",                   0,  act_unpackchk,            unpackchk       ),
   ACTIONBACKEND( "list",                    'l', DPKGQUERY),
   ACTIONBACKEND( "search",                  'S', DPKGQUERY),
Index: main/filesdb.h
===================================================================
RCS file: /cvs/dpkg/dpkg/main/filesdb.h,v
retrieving revision 1.9
diff -u -d -r1.9 filesdb.h
--- main/filesdb.h	2002/05/06 16:18:15	1.9
+++ main/filesdb.h	2002/08/06 04:56:07
@@ -69,6 +69,7 @@
     fnnf_no_atomic_overwrite= 000020, /* >=1 instance is a dir, cannot rename over */
   } flags; /* Set to zero when a new node is created. */
   const char *oldhash; /* valid iff this namenode is in the newconffiles list */
+  char *sha1sum;
   struct stat *filestat;
 };
  
@@ -138,6 +139,7 @@
 void note_must_reread_files_inpackage(struct pkginfo *pkg);
 struct filenamenode *findnamenode(const char *filename, enum fnnflags flags);
 void write_filelist_except(struct pkginfo *pkg, struct fileinlist *list, int leaveout);
+void write_filelist_sha1sums(struct pkginfo *pkg, struct fileinlist *list);
 
 struct reversefilelistiter { struct fileinlist *todo; };
 
Index: main/filesdb.c
===================================================================
RCS file: /cvs/dpkg/dpkg/main/filesdb.c,v
retrieving revision 1.33
diff -u -d -r1.33 filesdb.c
--- main/filesdb.c	2002/05/06 16:18:15	1.33
+++ main/filesdb.c	2002/08/06 04:56:08
@@ -302,6 +302,51 @@
   while (reversefilelist_next(iterptr));
 }
 
+void write_filelist_sha1sums(struct pkginfo *pkg, struct fileinlist *list) {
+  /* If leaveout is nonzero, will not write any file whose filenamenode
+   * has the fnnf_elide_other_lists flag set.
+   */
+  static struct varbuf vb, newvb;
+  FILE *file;
+
+  varbufreset(&vb);
+  varbufaddstr(&vb,admindir);
+  varbufaddstr(&vb,"/" INFODIR);
+  varbufaddstr(&vb,pkg->name);
+  varbufaddstr(&vb,"." SHA1SUMFILE);
+  varbufaddc(&vb,0);
+
+  varbufreset(&newvb);
+  varbufaddstr(&newvb,vb.buf);
+  varbufaddstr(&newvb,NEWDBEXT);
+  varbufaddc(&newvb,0);
+  
+  file= fopen(newvb.buf,"w");
+  if (!file)
+    ohshite(_("unable to create SHA1 sum list file for package %s"),pkg->name);
+  push_cleanup(cu_closefile,ehflag_bombout, 0,0, 1,(void*)file);
+  while (list) {
+    if (list->namenode->sha1sum) {
+      fputs(list->namenode->sha1sum, file);
+      putc('\t', file);
+      fputs(list->namenode->name,file);
+      /* We null-terminate the filenames in order to allow newlines in
+	 the filename, and to be UTF-8 safe.  Of course, the rest of
+	 dpkg doesn't allow newlines yet, but it doesn't hurt to be
+	 prepared for the future.  */
+      putc('\0',file);
+    }
+    list= list->next;
+  }
+  if (ferror(file) || fflush(file) || fsync(fileno(file)))
+    ohshite(_("failed to write to updated SHA1 sum list file for package %s"),pkg->name);
+  pop_cleanup(ehflag_normaltidy);
+  if (fclose(file))
+    ohshite(_("failed to close updated SHA1 sum list file for package %s"),pkg->name);
+  if (rename(newvb.buf,vb.buf))
+    ohshite(_("failed to install updated SHA1 sum list file for package %s"),pkg->name);
+}
+
 void ensure_statoverrides(void) {
   static struct varbuf vb;
 
@@ -599,6 +644,7 @@
   newnode->next= 0;
   newnode->divert= 0;
   newnode->statoverride= 0;
+  newnode->sha1sum = NULL;
   newnode->filestat= 0;
   *pointerp= newnode;
   nfiles++;
Index: main/enquiry.c
===================================================================
RCS file: /cvs/dpkg/dpkg/main/enquiry.c,v
retrieving revision 1.47
diff -u -d -r1.47 enquiry.c
--- main/enquiry.c	2002/05/20 05:56:01	1.47
+++ main/enquiry.c	2002/08/06 04:56:08
@@ -39,6 +39,7 @@
 #include <myopt.h>
 
 #include "filesdb.h"
+#include "../lib/sha.h"
 #include "main.h"
 
 int pkglistqsortcmp(const void *a, const void *b) {
@@ -110,6 +111,76 @@
   if (l>20) maxl -= (l-20);
   limiteddescription(pkg,maxl,&pdesc,&l);
   printf(" %-20s %.*s\n",pkg->name,l,pdesc);
+}
+
+void verify(const char *const *argv) {
+  struct pkgiterator *it;
+  struct pkginfo *pkg;
+  ssize_t fnamebuf_size = 1024;
+  char *fnamebuf = m_malloc(fnamebuf_size);
+
+  if (*argv) badusage(_("--verify-sha1sums does not take any arguments"));
+
+  modstatdb_init(admindir,msdbrw_readonly);
+  ensure_allinstfiles_available();
+
+  it= iterpkgstart(); 
+  while ((pkg = iterpkgnext(it))) {
+    int shasums_line_count = 0;
+    struct fileinlist *files = pkg->clientdata->files;
+    const char *shasums_filename = m_strdup(pkgadminfile(pkg, SHA1SUMFILE));
+    FILE *shasums_file = fopen(shasums_filename, "r");
+    char db_shasum[41];
+
+    if (!shasums_file){
+      debug(dbg_general,"verify no SHA1 sums for %s", shasums_filename);
+      continue;
+    }
+
+    while (files != NULL) {
+      int i = 0;
+      int c = 0;
+      while ((c = fgetc(shasums_file)) != EOF && c != '\t' && i <= 40)
+	db_shasum[i++] = c;
+      if (c == EOF)
+	break;
+      db_shasum[i] = '\0';
+
+      i = 0;
+      while ((c = fgetc(shasums_file)) != EOF && c != '\0') {
+	if (i == fnamebuf_size)
+	  fnamebuf = m_realloc(fnamebuf, fnamebuf_size *= 2);
+	fnamebuf[i++] = c;
+      }
+      if (c == EOF)
+	ohshit(_("unexpected eof before end of line %d"), shasums_line_count);
+      fnamebuf[i] = '\0';
+
+      /* Find the entry in files for this SHA1 sum. */ 
+      while (files != NULL && strcmp(files->namenode->name, fnamebuf))
+	files = files->next;
+      if (files == NULL)
+	ohshit(_("couldn't find file %s in database"), fnamebuf);
+
+      {
+	FILE *target = fopen(fnamebuf, "r");
+	unsigned char digest[20], *p = digest;
+	char target_shasum[41], *shap = target_shasum;
+	if (sha_stream(target, digest))
+	  ohshit(_("unable to compute SHA1 sum of %s"), fnamebuf);
+	for (i = 0; i < (int) sizeof(digest); ++i) {
+	  sprintf(shap, "%02x", *p++);
+	  shap += 2;
+	}
+	*shap = 0;
+	if (strcmp(db_shasum, target_shasum))
+	  fprintf(stdout, "%s  %s  %s\n", fnamebuf, db_shasum, target_shasum);
+      }
+    }
+    free((void *) shasums_filename);
+    files = files->next;
+  }
+  iterpkgend(it);
 }
 
 void audit(const char *const *argv) {
Index: main/archives.c
===================================================================
RCS file: /cvs/dpkg/dpkg/main/archives.c,v
retrieving revision 1.35
diff -u -d -r1.35 archives.c
--- main/archives.c	2002/05/20 01:22:31	1.35
+++ main/archives.c	2002/08/06 04:56:09
@@ -497,8 +497,13 @@
     push_cleanup(cu_closefd,ehflag_bombout, 0,0, 1,&fd);
     debug(dbg_eachfiledetail,"tarobject NormalFile[01] open size=%lu",
           (unsigned long)ti->Size);
-    { char fnamebuf[256];
-    fd_fd_copy(tc->backendpipe, fd, ti->Size, _("backend dpkg-deb during `%.255s'"),quote_filename(fnamebuf,256,ti->Name));
+    {
+      char fnamebuf[256];
+      /* We don't take its SHA1 sum if it's a conffile. */
+      if (nifd->namenode->flags & fnnf_new_conff)
+	fd_fd_copy(tc->backendpipe, fd, ti->Size, _("backend dpkg-deb during `%.255s'"),quote_filename(fnamebuf,256,ti->Name));
+      else
+	fd_fd_copy_sha1(tc->backendpipe, fd, &nifd->namenode->sha1sum, ti->Size, _("backend dpkg-deb during `%.255s'"),quote_filename(fnamebuf,256,ti->Name));
     }
     r= ti->Size % TARBLKSZ;
     if (r > 0) r= safe_read(tc->backendpipe,databuf,TARBLKSZ - r);
Index: lib/mlib.c
===================================================================
RCS file: /cvs/dpkg/dpkg/lib/mlib.c,v
retrieving revision 1.30
diff -u -d -r1.30 mlib.c
--- lib/mlib.c	2002/05/26 03:53:43	1.30
+++ lib/mlib.c	2002/08/06 04:56:09
@@ -34,6 +34,7 @@
 #include <dpkg.h>
 #include <dpkg-db.h>
 #include <md5.h>
+#include <sha.h>
 
 /* Incremented when we do some kind of generally necessary operation, so that
  * loops &c know to quit if we take an error exit.  Decremented again afterwards.
@@ -67,6 +68,16 @@
   return r;
 }
 
+void *m_strdup(const char *str) {
+  onerr_abort++;
+  {
+    char *ret = strdup(str);
+    if (!ret) ohshite(_("strdup failed (%ld bytes)"),strlen(str));
+    onerr_abort--;
+    return ret;
+  }
+}
+
 static void print_error_forked(const char *emsg, const char *contextstring) {
   fprintf(stderr, _("%s (subprocess): %s\n"), thisname, emsg);
 }
@@ -148,83 +159,97 @@
 }
 
 struct buffer_write_md5ctx {
-  struct MD5Context ctx;
+  struct md5_ctx ctx;
+  unsigned char **hash;
+};
+struct buffer_write_sha1ctx {
+  struct sha_ctx ctx;
   unsigned char **hash;
 };
+
 ssize_t buffer_write(buffer_data_t data, void *buf, ssize_t length, const char *desc) {
   ssize_t ret= length;
-  if(data->type & BUFFER_WRITE_SETUP) {
-    switch(data->type ^ BUFFER_WRITE_SETUP) {
-      case BUFFER_WRITE_MD5:
-	{
-	  struct buffer_write_md5ctx *ctx = malloc(sizeof(struct buffer_write_md5ctx));
-	  ctx->hash = data->data.ptr;
-	  data->data.ptr = ctx;
-	  MD5Init(&ctx->ctx);
-	}
-	break;
+  int type = data->type & BUFFER_WRITE_TYPE_MASK;
+  int flags = data->type & BUFFER_WRITE_FLAG_MASK;
+  if (type == BUFFER_WRITE_SETUP) {
+    if (flags & BUFFER_WRITE_MD5) {
+      struct buffer_write_md5ctx *ctx = malloc(sizeof(struct buffer_write_md5ctx));
+      ctx->hash = data->data2.ptr;
+      data->data2.ptr = ctx;
+      md5_init_ctx(&ctx->ctx);
+    } else if (flags & BUFFER_WRITE_SHA1) {
+      struct buffer_write_sha1ctx *ctx = malloc(sizeof(struct buffer_write_sha1ctx));
+      ctx->hash = data->data2.ptr;
+      data->data2.ptr = ctx;
+      sha_init_ctx(&ctx->ctx);
     }
     return 0;
-  }
-  if(data->type & BUFFER_WRITE_SHUTDOWN) {
-    switch(data->type ^ BUFFER_WRITE_SHUTDOWN) {
-      case BUFFER_WRITE_MD5:
-	{
-	  int i;
-	  unsigned char digest[16], *p = digest;
-	  struct buffer_write_md5ctx *ctx = (struct buffer_write_md5ctx *)data->data.ptr;
-	  unsigned char *hash = *ctx->hash = malloc(33);
-	  MD5Final(digest, &ctx->ctx);
-	  for (i = 0; i < 16; ++i) {
-	    sprintf(hash, "%02x", *p++);
-	    hash += 2;
-	  }
-	  *hash = 0;
-	  free(ctx);
-	}
-	break;
+  } else if (type == BUFFER_WRITE_SHUTDOWN) {
+    if (flags & BUFFER_WRITE_MD5) {
+      int i;
+      unsigned char digest[16], *p = digest;
+      struct buffer_write_md5ctx *ctx = (struct buffer_write_md5ctx *)data->data2.ptr;
+      unsigned char *hash = *ctx->hash = malloc(33);
+      md5_finish_ctx(&ctx->ctx, digest);
+      for (i = 0; i < (int) sizeof(digest); ++i) {
+	sprintf(hash, "%02x", *p++);
+	hash += 2;
+      }
+      *hash = 0;
+      free(ctx);
+    } else if (flags & BUFFER_WRITE_SHA1) {
+      int i;
+      unsigned char digest[20], *p = digest;
+      struct buffer_write_sha1ctx *ctx = (struct buffer_write_sha1ctx *)data->data2.ptr;
+      unsigned char *hash = *ctx->hash = malloc(41);
+      sha_finish_ctx(&ctx->ctx, digest);
+      for (i = 0; i < (int) sizeof(digest); ++i) {
+	sprintf(hash, "%02x", *p++);
+	hash += 2;
+      }
+      *hash = 0;
+      free(ctx);
     }
     return 0;
   }
-  switch(data->type) {
-    case BUFFER_WRITE_BUF:
-      memcpy(data->data.ptr, buf, length);
-      (char*)data->data.ptr += length;
-      break;
-    case BUFFER_WRITE_VBUF:
-      varbufaddbuf((struct varbuf *)data->data.ptr, buf, length);
-      break;
-    case BUFFER_WRITE_FD:
-      if((ret= write(data->data.i, buf, length)) < 0 && errno != EINTR)
-	ohshite(_("failed in buffer_write(fd) (%i, ret=%zi %s): %s"), data->data.i, ret, desc);
-      break;
-    case BUFFER_WRITE_NULL:
-      break;
-    case BUFFER_WRITE_STREAM:
-      ret= fwrite(buf, 1, length, (FILE *)data->data.ptr);
-      if(feof((FILE *)data->data.ptr))
-	ohshite(_("eof in buffer_write(stream): %s"), desc);
-      if(ferror((FILE *)data->data.ptr))
-	ohshite(_("error in buffer_write(stream): %s"), desc);
-      break;
-    case BUFFER_WRITE_MD5:
-      MD5Update(&(((struct buffer_write_md5ctx *)data->data.ptr)->ctx), buf, length);
-      break;
-    default:
-      fprintf(stderr, _("unknown data type `%i' in buffer_write\n"), data->type);
-   }
-   return ret;
+
+  if (flags & BUFFER_WRITE_MD5) {
+    md5_process_bytes(buf, length, &(((struct buffer_write_md5ctx *)data->data2.ptr)->ctx));
+  } else if (flags & BUFFER_WRITE_SHA1) {
+    sha_process_bytes(buf, length, &(((struct buffer_write_sha1ctx *)data->data2.ptr)->ctx));
+  }
+
+  switch(type) {
+  case BUFFER_WRITE_BUF:
+    memcpy(data->data.ptr, buf, length);
+    (char*)data->data.ptr += length;
+    break;
+  case BUFFER_WRITE_VBUF:
+    varbufaddbuf((struct varbuf *)data->data.ptr, buf, length);
+    break;
+  case BUFFER_WRITE_FD:
+    if((ret= write(data->data.i, buf, length)) < 0 && errno != EINTR)
+      ohshite(_("failed in buffer_write(fd) (%i, ret=%zi %s): %s"), data->data.i, ret, desc);
+    break;
+  case BUFFER_WRITE_NULL:
+    break;
+  case BUFFER_WRITE_STREAM:
+    ret= fwrite(buf, 1, length, (FILE *)data->data.ptr);
+    if(feof((FILE *)data->data.ptr))
+      ohshite(_("eof in buffer_write(stream): %s"), desc);
+    if(ferror((FILE *)data->data.ptr))
+      ohshite(_("error in buffer_write(stream): %s"), desc);
+    break;
+  default:
+    fprintf(stderr, _("unknown data type `%i' in buffer_write\n"), data->type);
+  }
+  return ret;
 }
 
 ssize_t buffer_read(buffer_data_t data, void *buf, ssize_t length, const char *desc) {
   ssize_t ret= length;
-  if(data->type & BUFFER_READ_SETUP) {
-    return 0;
-  }
-  if(data->type & BUFFER_READ_SHUTDOWN) {
-    return 0;
-  }
-  switch(data->type) {
+  int type = data->type & BUFFER_WRITE_TYPE_MASK;
+  switch(type) {
     case BUFFER_READ_FD:
       if((ret= read(data->data.i, buf, length)) < 0 && errno != EINTR)
 	ohshite(_("failed in buffer_read(fd): %s"), desc);
@@ -236,6 +261,9 @@
       if(ferror((FILE *)data->data.ptr))
 	ohshite(_("error in buffer_read(stream): %s"), desc);
       break;
+  case BUFFER_READ_SETUP:
+  case BUFFER_READ_SHUTDOWN:
+    return 0;
     default:
       fprintf(stderr, _("unknown data type `%i' in buffer_read\n"), data->type);
    }
@@ -244,21 +272,42 @@
 
 #define buffer_copy_setup_dual(name, type1, name1, type2, name2) \
 ssize_t buffer_copy_setup_##name(type1 n1, int typeIn, void *procIn,\
-					type2 n2, int typeOut, void *procOut,\
-					ssize_t limit, const char *desc, ...)\
-{\
+				 type2 n2, int typeOut, void *procOut,	\
+				 ssize_t limit, const char *desc, ...)	\
+{									\
   va_list al;\
-  buffer_arg a1, a2;\
+  buffer_arg a1, a2;				\
   struct varbuf v;\
   ssize_t ret;\
-  a1.name1 = n1; a2.name2 = n2;\
+  a1.name1 = n1; a2.name2 = n2;	\
   varbufinit(&v);\
   va_start(al,desc);\
   varbufvprintf(&v, desc, al);\
   va_end(al);\
-  ret = buffer_copy_setup(a1, typeIn, procIn,\
-			   a2, typeOut, procOut,\
-			   limit, v.buf);\
+  ret = buffer_copy_setup(a1, typeIn, procIn,			\
+			  a2, typeOut, procOut,		\
+			  limit, v.buf);			\
+  varbuffree(&v);\
+  return ret;\
+}
+
+#define buffer_copy_setup_dual_extra(name, type1, name1, type2, name2, type3, name3) \
+ssize_t buffer_copy_setup_##name(type1 n1, int typeIn, void *procIn,\
+				 type2 n2, type3 n3, int typeOut, void *procOut, \
+				 ssize_t limit, const char *desc, ...)	\
+{									\
+  va_list al;\
+  buffer_arg a1, a2, a3;				\
+  struct varbuf v;\
+  ssize_t ret;\
+  a1.name1 = n1; a2.name2 = n2; a3.name3 = n3;	\
+  varbufinit(&v);\
+  va_start(al,desc);\
+  varbufvprintf(&v, desc, al);\
+  va_end(al);\
+  ret = buffer_copy_setup_full(a1, typeIn, procIn,\
+			       a2, a3, typeOut, procOut,	\
+			       limit, v.buf);			\
   varbuffree(&v);\
   return ret;\
 }
@@ -267,27 +316,42 @@
 buffer_copy_setup_dual(IntPtr, int, i, void *, ptr);
 buffer_copy_setup_dual(PtrInt, void *, ptr, int, i);
 buffer_copy_setup_dual(PtrPtr, void *, ptr, void *, ptr);
+buffer_copy_setup_dual_extra(IntIntPtr, int, i, int, i, void *, ptr);
+buffer_copy_setup_dual_extra(IntPtrPtr, int, i, void *, ptr, void *, ptr);
+buffer_copy_setup_dual_extra(PtrPtrPtr, void *, ptr, void *, ptr, void *, ptr);
 
 ssize_t buffer_copy_setup(buffer_arg argIn, int typeIn, void *procIn,
-		       buffer_arg argOut, int typeOut, void *procOut,
-		       ssize_t limit, const char *desc)
+			  buffer_arg argOut, int typeOut, void *procOut,
+			  ssize_t limit, const char *desc)
 {
-  struct buffer_data read_data = { procIn, argIn, typeIn },
-		     write_data = { procOut, argOut, typeOut };
+  buffer_arg empty;
+  return buffer_copy_setup_full(argIn, typeIn, procIn, argOut, empty, typeOut,
+				procOut, limit, desc);
+}
+
+ssize_t buffer_copy_setup_full(buffer_arg argIn, int typeIn, void *procIn,
+			       buffer_arg argOut, buffer_arg argOut2,
+			       int typeOut, void *procOut,
+			       ssize_t limit, const char *desc)
+{
+  struct buffer_data read_data = { procIn, argIn, {NULL}, typeIn },
+    write_data = { procOut, argOut, argOut2, typeOut };
   ssize_t ret;
+  int write_type = write_data.type & BUFFER_WRITE_TYPE_MASK;
+  int write_flags = write_data.type & BUFFER_WRITE_FLAG_MASK;
 
   if ( procIn == NULL )
     read_data.proc = buffer_read;
   if ( procOut == NULL )
     write_data.proc = buffer_write;
-  read_data.type |= BUFFER_READ_SETUP;
+  read_data.type = BUFFER_READ_SETUP;
   read_data.proc(&read_data, NULL, 0, desc);
   read_data.type = typeIn;
-  write_data.type |= BUFFER_WRITE_SETUP;
+  write_data.type = BUFFER_WRITE_SETUP | write_flags;
   write_data.proc(&write_data, NULL, 0, desc);
   write_data.type = typeOut;
   ret = buffer_copy(&read_data, &write_data, limit, desc);
-  write_data.type |= BUFFER_WRITE_SHUTDOWN;
+  write_data.type = BUFFER_WRITE_SHUTDOWN | write_flags;
   write_data.proc(&write_data, NULL, 0, desc);
   read_data.type |= BUFFER_READ_SHUTDOWN;
   read_data.proc(&read_data, NULL, 0, desc);
Index: lib/md5.h
===================================================================
RCS file: /cvs/dpkg/dpkg/lib/md5.h,v
retrieving revision 1.3
diff -u -d -r1.3 md5.h
--- lib/md5.h	2002/05/06 16:18:15	1.3
+++ lib/md5.h	2002/08/06 04:56:09
@@ -1,39 +1,161 @@
+/* md5.h - Declaration of functions and data types used for MD5 sum
+   computing library functions.
+   Copyright (C) 1995, 1996, 1999 Free Software Foundation, Inc.
+   NOTE: The canonical source of this file is maintained with the GNU C
+   Library.  Bugs can be reported to bug-glibc@prep.ai.mit.edu.
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 2, or (at your option) any
+   later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#ifndef _MD5_H
+#define _MD5_H 1
+
+#include <stdio.h>
+
+#if defined HAVE_LIMITS_H || _LIBC
+# include <limits.h>
+#endif
+
+/* The following contortions are an attempt to use the C preprocessor
+   to determine an unsigned integral type that is 32 bits wide.  An
+   alternative approach is to use autoconf's AC_CHECK_SIZEOF macro, but
+   doing that would require that the configure script compile and *run*
+   the resulting executable.  Locally running cross-compiled executables
+   is usually not possible.  */
+
+#ifdef _LIBC
+# include <sys/types.h>
+typedef u_int32_t md5_uint32;
+#else
+# if defined __STDC__ && __STDC__
+#  define UINT_MAX_32_BITS 4294967295U
+# else
+#  define UINT_MAX_32_BITS 0xFFFFFFFF
+# endif
+
+/* If UINT_MAX isn't defined, assume it's a 32-bit type.
+   This should be valid for all systems GNU cares about because
+   that doesn't include 16-bit systems, and only modern systems
+   (that certainly have <limits.h>) have 64+-bit integral types.  */
+
+# ifndef UINT_MAX
+#  define UINT_MAX UINT_MAX_32_BITS
+# endif
+
+# if UINT_MAX == UINT_MAX_32_BITS
+   typedef unsigned int md5_uint32;
+# else
+#  if USHRT_MAX == UINT_MAX_32_BITS
+    typedef unsigned short md5_uint32;
+#  else
+#   if ULONG_MAX == UINT_MAX_32_BITS
+     typedef unsigned long md5_uint32;
+#   else
+     /* The following line is intended to evoke an error.
+        Using #error is not portable enough.  */
+     "Cannot determine unsigned 32-bit data type."
+#   endif
+#  endif
+# endif
+#endif
+
+#undef __P
+#if defined (__STDC__) && __STDC__
+#define	__P(x) x
+#else
+#define	__P(x) ()
+#endif
+
+/* Structure to save state of computation between the single steps.  */
+struct md5_ctx
+{
+  md5_uint32 A;
+  md5_uint32 B;
+  md5_uint32 C;
+  md5_uint32 D;
+
+  md5_uint32 total[2];
+  md5_uint32 buflen;
+  char buffer[128];
+};
+
 /*
- * This is the header file for the MD5 message-digest algorithm.
- * The algorithm is due to Ron Rivest.  This code was
- * written by Colin Plumb in 1993, no copyright is claimed.
- * This code is in the public domain; do with it what you wish.
- *
- * Equivalent code is available from RSA Data Security, Inc.
- * This code has been tested against that, and is equivalent,
- * except that you don't need to include two pages of legalese
- * with every copy.
- *
- * To compute the message digest of a chunk of bytes, declare an
- * MD5Context structure, pass it to MD5Init, call MD5Update as
- * needed on buffers full of bytes, and then call MD5Final, which
- * will fill a supplied 16-byte array with the digest.
- *
- * Changed so as no longer to depend on Colin Plumb's `usual.h'
- * header definitions; now uses stuff from dpkg's config.h
- *  - Ian Jackson <ian@chiark.greenend.org.uk>.
- * Still in the public domain.
+ * The following three functions are build up the low level used in
+ * the functions `md5_stream' and `md5_buffer'.
  */
 
-#ifndef MD5_H
-#define MD5_H
+/* Initialize structure containing state of computation.
+   (RFC 1321, 3.3: Step 3)  */
+extern void md5_init_ctx __P ((struct md5_ctx *ctx));
 
-#define md5byte unsigned char
+/* Starting with the result of former calls of this function (or the
+   initialization function update the context for the next LEN bytes
+   starting at BUFFER.
+   It is necessary that LEN is a multiple of 64!!! */
+extern void md5_process_block __P ((const void *buffer, size_t len,
+				    struct md5_ctx *ctx));
 
-struct MD5Context {
-	UWORD32 buf[4];
-	UWORD32 bytes[2];
-	UWORD32 in[16];
-};
+/* Starting with the result of former calls of this function (or the
+   initialization function update the context for the next LEN bytes
+   starting at BUFFER.
+   It is NOT required that LEN is a multiple of 64.  */
+extern void md5_process_bytes __P ((const void *buffer, size_t len,
+				    struct md5_ctx *ctx));
 
-void MD5Init(struct MD5Context *context);
-void MD5Update(struct MD5Context *context, md5byte const *buf, unsigned len);
-void MD5Final(unsigned char digest[16], struct MD5Context *context);
-void MD5Transform(UWORD32 buf[4], UWORD32 const in[16]);
+/* Process the remaining bytes in the buffer and put result from CTX
+   in first 16 bytes following RESBUF.  The result is always in little
+   endian byte order, so that a byte-wise output yields to the wanted
+   ASCII representation of the message digest.
 
-#endif /* !MD5_H */
+   IMPORTANT: On some systems it is required that RESBUF be correctly
+   aligned for a 32 bits value.  */
+extern void *md5_finish_ctx __P ((struct md5_ctx *ctx, void *resbuf));
+
+
+/* Put result from CTX in first 16 bytes following RESBUF.  The result is
+   always in little endian byte order, so that a byte-wise output yields
+   to the wanted ASCII representation of the message digest.
+
+   IMPORTANT: On some systems it is required that RESBUF is correctly
+   aligned for a 32 bits value.  */
+extern void *md5_read_ctx __P ((const struct md5_ctx *ctx, void *resbuf));
+
+
+/* Compute MD5 message digest for bytes read from STREAM.  The
+   resulting message digest number will be written into the 16 bytes
+   beginning at RESBLOCK.  */
+extern int md5_stream __P ((FILE *stream, void *resblock));
+
+/* Compute MD5 message digest for LEN bytes beginning at BUFFER.  The
+   result is always in little endian byte order, so that a byte-wise
+   output yields to the wanted ASCII representation of the message
+   digest.  */
+extern void *md5_buffer __P ((const char *buffer, size_t len, void *resblock));
+
+/* The following is from gnupg-1.0.2's cipher/bithelp.h.  */
+/* Rotate a 32 bit integer by n bytes */
+#if defined __GNUC__ && defined __i386__
+static inline md5_uint32
+rol(md5_uint32 x, int n)
+{
+  __asm__("roll %%cl,%0"
+	  :"=r" (x)
+	  :"0" (x),"c" (n));
+  return x;
+}
+#else
+# define rol(x,n) ( ((x) << (n)) | ((x) >> (32-(n))) )
+#endif
+
+#endif
Index: lib/md5.c
===================================================================
RCS file: /cvs/dpkg/dpkg/lib/md5.c,v
retrieving revision 1.3
diff -u -d -r1.3 md5.c
--- lib/md5.c	2002/05/06 16:18:15	1.3
+++ lib/md5.c	2002/08/06 04:56:10
@@ -1,241 +1,416 @@
-/*
- * This code implements the MD5 message-digest algorithm.
- * The algorithm is due to Ron Rivest.  This code was
- * written by Colin Plumb in 1993, no copyright is claimed.
- * This code is in the public domain; do with it what you wish.
- *
- * Equivalent code is available from RSA Data Security, Inc.
- * This code has been tested against that, and is equivalent,
- * except that you don't need to include two pages of legalese
- * with every copy.
- *
- * To compute the message digest of a chunk of bytes, declare an
- * MD5Context structure, pass it to MD5Init, call MD5Update as
- * needed on buffers full of bytes, and then call MD5Final, which
- * will fill a supplied 16-byte array with the digest.
- *
- * Changed so as no longer to depend on Colin Plumb's `usual.h' header
- * definitions; now uses stuff from dpkg's config.h.
- *  - Ian Jackson <ian@chiark.greenend.org.uk>.
- * Still in the public domain.
- */
+/* md5.c - Functions to compute MD5 message digest of files or memory blocks
+   according to the definition of MD5 in RFC 1321 from April 1992.
+   Copyright (C) 1995, 1996, 2001 Free Software Foundation, Inc.
+   NOTE: The canonical source of this file is maintained with the GNU C
+   Library.  Bugs can be reported to bug-glibc@prep.ai.mit.edu.
 
-#include <string.h>		/* for memcpy() */
-#include <sys/types.h>		/* for stupid systems */
-#include <netinet/in.h>		/* for ntohl() */
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 2, or (at your option) any
+   later version.
 
-#include "config.h"
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+/* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+
+#if STDC_HEADERS || defined _LIBC
+# include <stdlib.h>
+# include <string.h>
+#else
+# ifndef HAVE_MEMCPY
+#  define memcpy(d, s, n) bcopy ((s), (d), (n))
+# endif
+#endif
+
 #include "md5.h"
 
+#ifdef _LIBC
+# include <endian.h>
+# if __BYTE_ORDER == __BIG_ENDIAN
+#  define WORDS_BIGENDIAN 1
+# endif
+#endif
+
 #ifdef WORDS_BIGENDIAN
+# define SWAP(n)							\
+    (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24))
+#else
+# define SWAP(n) (n)
+#endif
+
+
+/* This array contains the bytes used to pad the buffer to the next
+   64-byte boundary.  (RFC 1321, 3.1: Step 1)  */
+static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ...  */ };
+
+
+/* Initialize structure containing state of computation.
+   (RFC 1321, 3.3: Step 3)  */
 void
-byteSwap(UWORD32 *buf, unsigned words)
+md5_init_ctx (ctx)
+     struct md5_ctx *ctx;
 {
-	md5byte *p = (md5byte *)buf;
+  ctx->A = 0x67452301;
+  ctx->B = 0xefcdab89;
+  ctx->C = 0x98badcfe;
+  ctx->D = 0x10325476;
 
-	do {
-		*buf++ = (UWORD32)((unsigned)p[3] << 8 | p[2]) << 16 |
-			((unsigned)p[1] << 8 | p[0]);
-		p += 4;
-	} while (--words);
+  ctx->total[0] = ctx->total[1] = 0;
+  ctx->buflen = 0;
 }
-#else
-#define byteSwap(buf,words)
-#endif
 
-/*
- * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
- * initialization constants.
- */
-void
-MD5Init(struct MD5Context *ctx)
+/* Put result from CTX in first 16 bytes following RESBUF.  The result
+   must be in little endian byte order.
+
+   IMPORTANT: On some systems it is required that RESBUF is correctly
+   aligned for a 32 bits value.  */
+void *
+md5_read_ctx (ctx, resbuf)
+     const struct md5_ctx *ctx;
+     void *resbuf;
 {
-	ctx->buf[0] = 0x67452301;
-	ctx->buf[1] = 0xefcdab89;
-	ctx->buf[2] = 0x98badcfe;
-	ctx->buf[3] = 0x10325476;
+  ((md5_uint32 *) resbuf)[0] = SWAP (ctx->A);
+  ((md5_uint32 *) resbuf)[1] = SWAP (ctx->B);
+  ((md5_uint32 *) resbuf)[2] = SWAP (ctx->C);
+  ((md5_uint32 *) resbuf)[3] = SWAP (ctx->D);
 
-	ctx->bytes[0] = 0;
-	ctx->bytes[1] = 0;
+  return resbuf;
 }
 
-/*
- * Update context to reflect the concatenation of another buffer full
- * of bytes.
- */
-void
-MD5Update(struct MD5Context *ctx, md5byte const *buf, unsigned len)
+/* Process the remaining bytes in the internal buffer and the usual
+   prolog according to the standard and write the result to RESBUF.
+
+   IMPORTANT: On some systems it is required that RESBUF is correctly
+   aligned for a 32 bits value.  */
+void *
+md5_finish_ctx (ctx, resbuf)
+     struct md5_ctx *ctx;
+     void *resbuf;
 {
-	UWORD32 t;
+  /* Take yet unprocessed bytes into account.  */
+  md5_uint32 bytes = ctx->buflen;
+  size_t pad;
 
-	/* Update byte count */
+  /* Now count remaining bytes.  */
+  ctx->total[0] += bytes;
+  if (ctx->total[0] < bytes)
+    ++ctx->total[1];
 
-	t = ctx->bytes[0];
-	if ((ctx->bytes[0] = t + len) < t)
-		ctx->bytes[1]++;	/* Carry from low to high */
+  pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes;
+  memcpy (&ctx->buffer[bytes], fillbuf, pad);
 
-	t = 64 - (t & 0x3f);	/* Space available in ctx->in (at least 1) */
-	if (t > len) {
-		memcpy((md5byte *)ctx->in + 64 - t, buf, len);
-		return;
-	}
-	/* First chunk is an odd size */
-	memcpy((md5byte *)ctx->in + 64 - t, buf, t);
-	byteSwap(ctx->in, 16);
-	MD5Transform(ctx->buf, ctx->in);
-	buf += t;
-	len -= t;
+  /* Put the 64-bit file length in *bits* at the end of the buffer.  */
+  *(md5_uint32 *) &ctx->buffer[bytes + pad] = SWAP (ctx->total[0] << 3);
+  *(md5_uint32 *) &ctx->buffer[bytes + pad + 4] = SWAP ((ctx->total[1] << 3) |
+							(ctx->total[0] >> 29));
 
-	/* Process data in 64-byte chunks */
-	while (len >= 64) {
-		memcpy(ctx->in, buf, 64);
-		byteSwap(ctx->in, 16);
-		MD5Transform(ctx->buf, ctx->in);
-		buf += 64;
-		len -= 64;
-	}
+  /* Process last bytes.  */
+  md5_process_block (ctx->buffer, bytes + pad + 8, ctx);
 
-	/* Handle any remaining bytes of data. */
-	memcpy(ctx->in, buf, len);
+  return md5_read_ctx (ctx, resbuf);
 }
 
-/*
- * Final wrapup - pad to 64-byte boundary with the bit pattern 
- * 1 0* (64-bit count of bits processed, MSB-first)
- */
-void
-MD5Final(md5byte digest[16], struct MD5Context *ctx)
+/* Compute MD5 message digest for bytes read from STREAM.  The
+   resulting message digest number will be written into the 16 bytes
+   beginning at RESBLOCK.  */
+int
+md5_stream (stream, resblock)
+     FILE *stream;
+     void *resblock;
 {
-	int count = ctx->bytes[0] & 0x3f;	/* Number of bytes in ctx->in */
-	md5byte *p = (md5byte *)ctx->in + count;
+  /* Important: BLOCKSIZE must be a multiple of 64.  */
+#define BLOCKSIZE 4096
+  struct md5_ctx ctx;
+  char buffer[BLOCKSIZE + 72];
+  size_t sum;
 
-	/* Set the first char of padding to 0x80.  There is always room. */
-	*p++ = 0x80;
+  /* Initialize the computation context.  */
+  md5_init_ctx (&ctx);
 
-	/* Bytes of padding needed to make 56 bytes (-8..55) */
-	count = 56 - 1 - count;
+  /* Iterate over full file contents.  */
+  while (1)
+    {
+      /* We read the file in blocks of BLOCKSIZE bytes.  One call of the
+	 computation function processes the whole buffer so that with the
+	 next round of the loop another block can be read.  */
+      size_t n;
+      sum = 0;
 
-	if (count < 0) {	/* Padding forces an extra block */
-		memset(p, 0, count + 8);
-		byteSwap(ctx->in, 16);
-		MD5Transform(ctx->buf, ctx->in);
-		p = (md5byte *)ctx->in;
-		count = 56;
+      /* Read block.  Take care for partial reads.  */
+      do
+	{
+	  n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream);
+
+	  sum += n;
 	}
-	memset(p, 0, count);
-	byteSwap(ctx->in, 14);
+      while (sum < BLOCKSIZE && n != 0);
+      if (n == 0 && ferror (stream))
+        return 1;
 
-	/* Append length in bits and transform */
-	ctx->in[14] = ctx->bytes[0] << 3;
-	ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29;
-	MD5Transform(ctx->buf, ctx->in);
+      /* If end of file is reached, end the loop.  */
+      if (n == 0)
+	break;
 
-	byteSwap(ctx->buf, 4);
-	memcpy(digest, ctx->buf, 16);
-	memset(ctx, 0, sizeof(ctx));	/* In case it's sensitive */
+      /* Process buffer with BLOCKSIZE bytes.  Note that
+			BLOCKSIZE % 64 == 0
+       */
+      md5_process_block (buffer, BLOCKSIZE, &ctx);
+    }
+
+  /* Add the last bytes if necessary.  */
+  if (sum > 0)
+    md5_process_bytes (buffer, sum, &ctx);
+
+  /* Construct result in desired memory.  */
+  md5_finish_ctx (&ctx, resblock);
+  return 0;
 }
 
-#ifndef ASM_MD5
+/* Compute MD5 message digest for LEN bytes beginning at BUFFER.  The
+   result is always in little endian byte order, so that a byte-wise
+   output yields to the wanted ASCII representation of the message
+   digest.  */
+void *
+md5_buffer (buffer, len, resblock)
+     const char *buffer;
+     size_t len;
+     void *resblock;
+{
+  struct md5_ctx ctx;
 
-/* The four core functions - F1 is optimized somewhat */
+  /* Initialize the computation context.  */
+  md5_init_ctx (&ctx);
 
-/* #define F1(x, y, z) (x & y | ~x & z) */
-#define F1(x, y, z) (z ^ (x & (y ^ z)))
-#define F2(x, y, z) F1(z, x, y)
-#define F3(x, y, z) (x ^ y ^ z)
-#define F4(x, y, z) (y ^ (x | ~z))
+  /* Process whole buffer but last len % 64 bytes.  */
+  md5_process_bytes (buffer, len, &ctx);
 
-/* This is the central step in the MD5 algorithm. */
-#define MD5STEP(f,w,x,y,z,in,s) \
-	 (w += f(x,y,z) + in, w = (w<<s | w>>(32-s)) + x)
+  /* Put result in desired memory area.  */
+  return md5_finish_ctx (&ctx, resblock);
+}
 
-/*
- * The core of the MD5 algorithm, this alters an existing MD5 hash to
- * reflect the addition of 16 longwords of new data.  MD5Update blocks
- * the data and converts bytes into longwords for this routine.
- */
+
 void
-MD5Transform(UWORD32 buf[4], UWORD32 const in[16])
+md5_process_bytes (buffer, len, ctx)
+     const void *buffer;
+     size_t len;
+     struct md5_ctx *ctx;
 {
-	register UWORD32 a, b, c, d;
-
-	a = buf[0];
-	b = buf[1];
-	c = buf[2];
-	d = buf[3];
+  /* When we already have some bits in our internal buffer concatenate
+     both inputs first.  */
+  if (ctx->buflen != 0)
+    {
+      size_t left_over = ctx->buflen;
+      size_t add = 128 - left_over > len ? len : 128 - left_over;
 
-	MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
-	MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
-	MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
-	MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
-	MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
-	MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
-	MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
-	MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
-	MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
-	MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
-	MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
-	MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
-	MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
-	MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
-	MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
-	MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+      memcpy (&ctx->buffer[left_over], buffer, add);
+      ctx->buflen += add;
 
-	MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
-	MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
-	MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
-	MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
-	MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
-	MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
-	MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
-	MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
-	MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
-	MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
-	MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
-	MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
-	MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
-	MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
-	MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
-	MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+      if (left_over + add > 64)
+	{
+	  md5_process_block (ctx->buffer, (left_over + add) & ~63, ctx);
+	  /* The regions in the following copy operation cannot overlap.  */
+	  memcpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~63],
+		  (left_over + add) & 63);
+	  ctx->buflen = (left_over + add) & 63;
+	}
 
-	MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
-	MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
-	MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
-	MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
-	MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
-	MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
-	MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
-	MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
-	MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
-	MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
-	MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
-	MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
-	MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
-	MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
-	MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
-	MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+      buffer = (const char *) buffer + add;
+      len -= add;
+    }
 
-	MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
-	MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
-	MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
-	MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
-	MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
-	MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
-	MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
-	MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
-	MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
-	MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
-	MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
-	MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
-	MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
-	MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
-	MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
-	MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+  /* Process available complete blocks.  */
+  if (len > 64)
+    {
+      md5_process_block (buffer, len & ~63, ctx);
+      buffer = (const char *) buffer + (len & ~63);
+      len &= 63;
+    }
 
-	buf[0] += a;
-	buf[1] += b;
-	buf[2] += c;
-	buf[3] += d;
+  /* Move remaining bytes in internal buffer.  */
+  if (len > 0)
+    {
+      memcpy (ctx->buffer, buffer, len);
+      ctx->buflen = len;
+    }
 }
 
-#endif
+
+/* These are the four functions used in the four steps of the MD5 algorithm
+   and defined in the RFC 1321.  The first function is a little bit optimized
+   (as found in Colin Plumbs public domain implementation).  */
+/* #define FF(b, c, d) ((b & c) | (~b & d)) */
+#define FF(b, c, d) (d ^ (b & (c ^ d)))
+#define FG(b, c, d) FF (d, b, c)
+#define FH(b, c, d) (b ^ c ^ d)
+#define FI(b, c, d) (c ^ (b | ~d))
+
+/* Process LEN bytes of BUFFER, accumulating context into CTX.
+   It is assumed that LEN % 64 == 0.  */
+
+void
+md5_process_block (buffer, len, ctx)
+     const void *buffer;
+     size_t len;
+     struct md5_ctx *ctx;
+{
+  md5_uint32 correct_words[16];
+  const md5_uint32 *words = buffer;
+  size_t nwords = len / sizeof (md5_uint32);
+  const md5_uint32 *endp = words + nwords;
+  md5_uint32 A = ctx->A;
+  md5_uint32 B = ctx->B;
+  md5_uint32 C = ctx->C;
+  md5_uint32 D = ctx->D;
+
+  /* First increment the byte count.  RFC 1321 specifies the possible
+     length of the file up to 2^64 bits.  Here we only compute the
+     number of bytes.  Do a double word increment.  */
+  ctx->total[0] += len;
+  if (ctx->total[0] < len)
+    ++ctx->total[1];
+
+  /* Process all bytes in the buffer with 64 bytes in each round of
+     the loop.  */
+  while (words < endp)
+    {
+      md5_uint32 *cwp = correct_words;
+      md5_uint32 A_save = A;
+      md5_uint32 B_save = B;
+      md5_uint32 C_save = C;
+      md5_uint32 D_save = D;
+
+      /* First round: using the given function, the context and a constant
+	 the next context is computed.  Because the algorithms processing
+	 unit is a 32-bit word and it is determined to work on words in
+	 little endian byte order we perhaps have to change the byte order
+	 before the computation.  To reduce the work for the next steps
+	 we store the swapped words in the array CORRECT_WORDS.  */
+
+#define OP(a, b, c, d, s, T)						\
+      do								\
+        {								\
+	  a += FF (b, c, d) + (*cwp++ = SWAP (*words)) + T;		\
+	  ++words;							\
+	  a = rol (a, s);						\
+	  a += b;							\
+        }								\
+      while (0)
+
+      /* Before we start, one word to the strange constants.
+	 They are defined in RFC 1321 as
+
+	 T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64, or
+	 perl -e 'foreach(1..64){printf "0x%08x\n", int (4294967296 * abs (sin $_))}'
+       */
+
+      /* Round 1.  */
+      OP (A, B, C, D,  7, 0xd76aa478);
+      OP (D, A, B, C, 12, 0xe8c7b756);
+      OP (C, D, A, B, 17, 0x242070db);
+      OP (B, C, D, A, 22, 0xc1bdceee);
+      OP (A, B, C, D,  7, 0xf57c0faf);
+      OP (D, A, B, C, 12, 0x4787c62a);
+      OP (C, D, A, B, 17, 0xa8304613);
+      OP (B, C, D, A, 22, 0xfd469501);
+      OP (A, B, C, D,  7, 0x698098d8);
+      OP (D, A, B, C, 12, 0x8b44f7af);
+      OP (C, D, A, B, 17, 0xffff5bb1);
+      OP (B, C, D, A, 22, 0x895cd7be);
+      OP (A, B, C, D,  7, 0x6b901122);
+      OP (D, A, B, C, 12, 0xfd987193);
+      OP (C, D, A, B, 17, 0xa679438e);
+      OP (B, C, D, A, 22, 0x49b40821);
+
+      /* For the second to fourth round we have the possibly swapped words
+	 in CORRECT_WORDS.  Redefine the macro to take an additional first
+	 argument specifying the function to use.  */
+#undef OP
+#define OP(f, a, b, c, d, k, s, T)					\
+      do 								\
+	{								\
+	  a += f (b, c, d) + correct_words[k] + T;			\
+	  a = rol (a, s);						\
+	  a += b;							\
+	}								\
+      while (0)
+
+      /* Round 2.  */
+      OP (FG, A, B, C, D,  1,  5, 0xf61e2562);
+      OP (FG, D, A, B, C,  6,  9, 0xc040b340);
+      OP (FG, C, D, A, B, 11, 14, 0x265e5a51);
+      OP (FG, B, C, D, A,  0, 20, 0xe9b6c7aa);
+      OP (FG, A, B, C, D,  5,  5, 0xd62f105d);
+      OP (FG, D, A, B, C, 10,  9, 0x02441453);
+      OP (FG, C, D, A, B, 15, 14, 0xd8a1e681);
+      OP (FG, B, C, D, A,  4, 20, 0xe7d3fbc8);
+      OP (FG, A, B, C, D,  9,  5, 0x21e1cde6);
+      OP (FG, D, A, B, C, 14,  9, 0xc33707d6);
+      OP (FG, C, D, A, B,  3, 14, 0xf4d50d87);
+      OP (FG, B, C, D, A,  8, 20, 0x455a14ed);
+      OP (FG, A, B, C, D, 13,  5, 0xa9e3e905);
+      OP (FG, D, A, B, C,  2,  9, 0xfcefa3f8);
+      OP (FG, C, D, A, B,  7, 14, 0x676f02d9);
+      OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a);
+
+      /* Round 3.  */
+      OP (FH, A, B, C, D,  5,  4, 0xfffa3942);
+      OP (FH, D, A, B, C,  8, 11, 0x8771f681);
+      OP (FH, C, D, A, B, 11, 16, 0x6d9d6122);
+      OP (FH, B, C, D, A, 14, 23, 0xfde5380c);
+      OP (FH, A, B, C, D,  1,  4, 0xa4beea44);
+      OP (FH, D, A, B, C,  4, 11, 0x4bdecfa9);
+      OP (FH, C, D, A, B,  7, 16, 0xf6bb4b60);
+      OP (FH, B, C, D, A, 10, 23, 0xbebfbc70);
+      OP (FH, A, B, C, D, 13,  4, 0x289b7ec6);
+      OP (FH, D, A, B, C,  0, 11, 0xeaa127fa);
+      OP (FH, C, D, A, B,  3, 16, 0xd4ef3085);
+      OP (FH, B, C, D, A,  6, 23, 0x04881d05);
+      OP (FH, A, B, C, D,  9,  4, 0xd9d4d039);
+      OP (FH, D, A, B, C, 12, 11, 0xe6db99e5);
+      OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8);
+      OP (FH, B, C, D, A,  2, 23, 0xc4ac5665);
+
+      /* Round 4.  */
+      OP (FI, A, B, C, D,  0,  6, 0xf4292244);
+      OP (FI, D, A, B, C,  7, 10, 0x432aff97);
+      OP (FI, C, D, A, B, 14, 15, 0xab9423a7);
+      OP (FI, B, C, D, A,  5, 21, 0xfc93a039);
+      OP (FI, A, B, C, D, 12,  6, 0x655b59c3);
+      OP (FI, D, A, B, C,  3, 10, 0x8f0ccc92);
+      OP (FI, C, D, A, B, 10, 15, 0xffeff47d);
+      OP (FI, B, C, D, A,  1, 21, 0x85845dd1);
+      OP (FI, A, B, C, D,  8,  6, 0x6fa87e4f);
+      OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0);
+      OP (FI, C, D, A, B,  6, 15, 0xa3014314);
+      OP (FI, B, C, D, A, 13, 21, 0x4e0811a1);
+      OP (FI, A, B, C, D,  4,  6, 0xf7537e82);
+      OP (FI, D, A, B, C, 11, 10, 0xbd3af235);
+      OP (FI, C, D, A, B,  2, 15, 0x2ad7d2bb);
+      OP (FI, B, C, D, A,  9, 21, 0xeb86d391);
+
+      /* Add the starting values of the context.  */
+      A += A_save;
+      B += B_save;
+      C += C_save;
+      D += D_save;
+    }
+
+  /* Put checksum in context given as argument.  */
+  ctx->A = A;
+  ctx->B = B;
+  ctx->C = C;
+  ctx->D = D;
+}
Index: lib/Makefile.in
===================================================================
RCS file: /cvs/dpkg/dpkg/lib/Makefile.in,v
retrieving revision 1.15
diff -u -d -r1.15 Makefile.in
--- lib/Makefile.in	2002/05/24 05:16:43	1.15
+++ lib/Makefile.in	2002/08/06 04:56:10
@@ -8,7 +8,7 @@
 
 SOURCES		= compat.c database.c dbmodify.c dump.c ehandle.c fields.c \
 		    lock.c mlib.c myopt.c nfmalloc.c parse.c parsehelp.c \
-		    showcright.c showpkg.c tarfn.c varbuf.c vercmp.c md5.c \
+		    showcright.c showpkg.c tarfn.c varbuf.c vercmp.c md5.c sha.c \
 		    utils.c startup.c
 
 OBJECTS		= $(patsubst %.c, %.o, $(SOURCES))
Index: include/dpkg.h.in
===================================================================
RCS file: /cvs/dpkg/dpkg/include/dpkg.h.in,v
retrieving revision 1.34
diff -u -d -r1.34 dpkg.h.in
--- include/dpkg.h.in	2002/05/24 05:16:43	1.34
+++ include/dpkg.h.in	2002/08/06 04:56:10
@@ -68,6 +68,7 @@
 #define PRERMFILE          "prerm"
 #define POSTRMFILE         "postrm"
 #define LISTFILE           "list"
+#define SHA1SUMFILE        "sha1sums"
 
 #define ADMINDIR          "#ADMINDIR#"
 #define CONFIGDIR         "#CONFIGDIR#"
@@ -122,6 +123,7 @@
 #define DPKGQUERY	"dpkg-query"
 #define SPLITTER	"dpkg-split"
 #define MD5SUM		"md5sum"
+#define SHA1SUM		"sha1sum"
 #define DSELECT		"dselect"
 #define DPKG		"dpkg"
 #define DEBSIGVERIFY	"/usr/bin/debsig-verify"
@@ -202,6 +204,7 @@
 void setcloexec(int fd, const char* fn);
 void *m_malloc(size_t);
 void *m_realloc(void*, size_t);
+char *m_strdup(const char *str);
 int m_fork(void);
 void m_dup2(int oldfd, int newfd);
 void m_pipe(int fds[2]);
@@ -212,19 +215,27 @@
 int checksubprocerr(int status, const char *description, int flags);
 int waitsubproc(pid_t pid, const char *description, int flags);
 
+
+#define BUFFER_WRITE_TYPE_MASK ((BUFFER_WRITE_SHUTDOWN << 1) - 1)
+#define BUFFER_WRITE_FLAG_MASK ~BUFFER_WRITE_TYPE_MASK
+  /* Types; mutually exclusive. */
 #define BUFFER_WRITE_BUF 0
 #define BUFFER_WRITE_VBUF 1
 #define BUFFER_WRITE_FD 2
-#define BUFFER_WRITE_NULL 3
-#define BUFFER_WRITE_STREAM 4
-#define BUFFER_WRITE_MD5 5
+#define BUFFER_WRITE_NULL 4
+#define BUFFER_WRITE_STREAM 8
+#define BUFFER_WRITE_SETUP 16
+#define BUFFER_WRITE_SHUTDOWN 32
+/* Flags. */
+#define BUFFER_WRITE_MD5 64
+#define BUFFER_WRITE_SHA1 128
+
+#define BUFFER_READ_TYPE_MASK ((BUFFER_READ_SHUTDOWN << 1) - 1)
+  /* Types; mutually exclusive. */
 #define BUFFER_READ_FD 0
 #define BUFFER_READ_STREAM 1
-
-#define BUFFER_WRITE_SETUP 1 << 16
-#define BUFFER_READ_SETUP 1 << 17
-#define BUFFER_WRITE_SHUTDOWN 1 << 18
-#define BUFFER_READ_SHUTDOWN 1 << 19
+#define BUFFER_READ_SETUP 2
+#define BUFFER_READ_SHUTDOWN 4
 
 typedef struct buffer_data *buffer_data_t;
 typedef ssize_t (*buffer_proc_t)(buffer_data_t data, void *buf, ssize_t size, const char *desc);
@@ -236,21 +247,27 @@
 struct buffer_data {
   buffer_proc_t proc;
   buffer_arg data;
+  buffer_arg data2;
   int type;
 };
 
 #define fd_md5(fd, hash, limit, desc...)\
-	buffer_copy_setup_IntPtr(fd, BUFFER_READ_FD, NULL, \
-			 	 hash, BUFFER_WRITE_MD5, NULL, \
-				 limit, desc)
+	buffer_copy_setup_IntPtrPtr(fd, BUFFER_READ_FD, NULL, \
+				    NULL, hash, BUFFER_WRITE_NULL | BUFFER_WRITE_MD5, NULL, \
+				    limit, desc)
 #define stream_md5(file, hash, limit, desc...)\
-	buffer_copy_setup_PtrPtr(file, BUFFER_READ_STREAM, NULL, \
-				 hash, BUFFER_WRITE_MD5, NULL, \
-				 limit, desc)
+	buffer_copy_setup_PtrPtrPtr(file, BUFFER_READ_STREAM, NULL, \
+				    NULL, hash, BUFFER_WRITE_NULL | BUFFER_WRITE_MD5, NULL, \
+				    limit, desc)
 #define fd_fd_copy(fd1, fd2, limit, desc...)\
 	buffer_copy_setup_IntInt(fd1, BUFFER_READ_FD, NULL, \
 				 fd2, BUFFER_WRITE_FD, NULL, \
 				 limit, desc)
+#define fd_fd_copy_sha1(fd1, fd2, hash, limit, desc...)			\
+	buffer_copy_setup_IntIntPtr(fd1, BUFFER_READ_FD, NULL,		\
+				    fd2, hash, BUFFER_WRITE_FD | BUFFER_WRITE_SHA1, NULL, \
+				    limit, desc)
+
 #define fd_buf_copy(fd, buf, limit, desc...)\
 	buffer_copy_setup_IntPtr(fd, BUFFER_READ_FD, NULL, \
 				 buf, BUFFER_WRITE_BUF, NULL, \
@@ -289,9 +306,21 @@
 ssize_t buffer_copy_setup_IntInt(int i1, int typeIn, void *procIn,
 					int i2, int typeOut, void *procOut,
 					ssize_t limit, const char *desc, ...);
+ssize_t buffer_copy_setup_IntIntPtr(int i1, int typeIn, void *procIn,
+				    int i2, void *ptr, int typeOut, void *procOut,
+				    ssize_t limit, const char *desc, ...);
+ssize_t buffer_copy_setup_IntPtrPtr(int i1, int typeIn, void *procIn,
+				    void *p1, void *p2, int typeOut, void *procOut,
+				    ssize_t limit, const char *desc, ...);
+ssize_t buffer_copy_setup_PtrPtrPtr(void *p1, int typeIn, void *procIn,
+				    void *p2, void *p3, int typeOut, void *procOut,
+				    ssize_t limit, const char *desc, ...);
 ssize_t buffer_copy_setup(buffer_arg argIn, int typeIn, void *procIn,
-		       buffer_arg argOut, int typeOut, void *procOut,
-		       ssize_t limit, const char *desc);
+			  buffer_arg argOut, int typeOut, void *procOut,
+			  ssize_t limit, const char *desc);
+ssize_t buffer_copy_setup_full(buffer_arg argIn, int typeIn, void *procIn,
+			       buffer_arg argOut, buffer_arg argOut2, int typeOut,
+			       void *procOut, ssize_t limit, const char *desc);
 ssize_t buffer_write(buffer_data_t data, void *buf, ssize_t length, const char *desc);
 ssize_t buffer_read(buffer_data_t data, void *buf, ssize_t length, const char *desc);
 ssize_t buffer_copy(buffer_data_t read_data, buffer_data_t write_data, ssize_t limit, const char *desc);
