#
# comphead patch is copyrighted by MATSUI Nag.
# 
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
# 
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
# 
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

diff -r b733b98fea86 -r ab008afb13f0 afio.1
--- a/afio.1	Mon Feb 06 10:51:10 2012 +0900
+++ b/afio.1	Mon Feb 06 11:03:25 2012 +0900
@@ -696,6 +696,34 @@
 is run twice of the file,
 the first time to determine the length of the result, the second time
 to get the compressed data itself.
+.\"
+.\"
+.TP
+.BI -N
+Using
+.B -N
+option compresses the header part of the archive.
+Same program and options are used for both header and file,
+so use
+.B -Z
+(and 
+.B -P
+,
+.B -Q
+) with 
+.B -N
+option.
+.RS
+.PP
+If the compression program, specified by 
+.B -P
+, is an encryption/decryption script, it may require passphrase file redirection. 
+.B -3
+option specifies filedescriptor number in this case,
+but both the number and number+1 are used internally
+to separate header compression process and file's.
+So you must add one more redirection, for example, -3 3 3< pass_file 4< passfile .
+.RE
 .TP
 .BI \-P "\ progname"
 Use the program 
@@ -1606,6 +1634,23 @@
 .I cat
 will read the parts in the right (alphabetic) order.
 .PP
+Create an archive with encrypted files and headers, and extract from the archive:
+.br
+.I "find .... | afio -ovzNUZ -1 C -3 3 -P egzip archive 3< passphrase-file 4< passphrase-file"
+.PP
+.I "afio -ivzZ -1 C -3 3 -P egunzip archive 3< passphrase-file 4< passphrase-file"
+.PP
+Examples of egzip and egunzip are
+.nf
+  #!/bin/sh
+  gzip -c | openssl enc -e -aes-256-cbc -salt -pass fd:3
+.fi
+.PP
+.nf
+  #!/bin/sh
+  openssl enc -d -aes-256-cbc -pass fd:3 | gzip -dc
+.fi
+.PP
 .SH "SEE ALSO"
 cpio(1), find(1), tar(1), compress(1), gzip(1).
 .SH WEB SITE AND INTERNET RESOURCES
diff -r b733b98fea86 -r ab008afb13f0 afio.c
--- a/afio.c	Mon Feb 06 10:51:10 2012 +0900
+++ b/afio.c	Mon Feb 06 11:03:25 2012 +0900
@@ -325,6 +325,8 @@
      STATIC int useoutmodetoc=0; /* used in tocentry() */
      STATIC short noglob=0; /* disable globbing */
 
+     STATIC ushort comphead = 0;  /* Compress header */
+
 int main (int ac, char **av)
 {
   reg int c;
@@ -358,7 +360,7 @@
    */
 
   while ((c = options (ac, av, 
-         "aioprtIOVCb:c:de:fghjklmns:uvxXy:Y:zFKZL:R:qAE:G:M:w:W:T:SBD:P:Q:U4JH:0@:N:3:1:92:56:7"))
+         "aioprtIOVCb:c:de:fghjklmns:uvxXy:Y:zFKZL:R:qAE:G:M:w:W:T:SBD:P:Q:U4JH:0@:N3:1:92:56:7"))
         )
     {
       switch (c)
@@ -400,8 +402,8 @@
 	  fn = copyout;
 	  break;
 	case 'V':
-	  VOID printf ("%s: Version %s dated %s\n",
-		       myname, VERSION, DATE);
+	  VOID printf ("%s: Version %s dated %s %s\n",
+                 myname, VERSION, DATE, PATCH);
 	  exit (0);
 #ifdef	CTC3B2
 	case 'C':
@@ -613,6 +615,9 @@
        case '7':
 	 noglob = 1-noglob;
 	 break;
+       case 'N':
+         comphead=1;
+         break;
 
 	default:
 	  usage ();
@@ -1443,6 +1448,97 @@
     return (warnarch ("Corrupt header", (off_t) 0));
   return (0);
 }
+
+/*
+ * inascii3c()
+ *
+ * Read compressed ASCII header (large format). Returns zero if successful;
+ * -1 otherwise. Assumes that the entire magic number
+ * has been read.
+ */
+ 
+STATIC int
+inascii3c(char *magic, char *name, Stat *asb)
+{
+  uint namelen;
+  char header3c[H_STRLEN3C + 1];
+  char header[M_STRLEN + H_STRLEN3 + PATHSIZE + 1 + PATHSIZE + 1];
+  char buff[sizeof(header) * 2];
+
+  PHStat pasb;
+  uint specialflags;
+  uint extraheaderlen;
+
+  ulong size;
+
+  if (strncmp(magic, M_ASCII3C, M_STRLEN) != 0) {
+    return (-1);
+  }
+  if (inread(header3c, H_STRLEN3C) < 0) {
+    return (warnarch("Corrupt extended ASCII3C header",
+                     (off_t)H_STRLEN3C));
+  }
+  header[H_STRLEN3C] = '\0';
+
+  if (sscanf(header3c, PH_SCAN3C, &size) != H_COUNT3C) {
+    return (warnarch ("Bad extended ASCII3C header",
+                      (off_t)H_STRLEN));
+  }
+
+  if (inread(buff, size) < 0) {
+    return (warnarch("Corrupt extended ASCII3C header",
+                     (off_t)H_STRLEN3C));
+  }
+
+  compressheader(buff, size, header, sizeof(header) - 1, 0);
+
+  if (sscanf(header + M_STRLEN, PH_SCAN3, &pasb.PSt_dev,
+             &pasb.PSt_ino, &pasb.PSt_mode, &pasb.PSt_uid,
+             &pasb.PSt_gid, &pasb.PSt_nlink, &pasb.PSt_rdev,
+             &pasb.PSt_mtime, &namelen, &specialflags, &extraheaderlen,
+             &pasb.PSt_size) != H_COUNT3) {
+    return (warnarch("Bad compressed extended ASCII3 header",
+                     (off_t)H_STRLEN));
+  }
+
+  asb->sb_dev = pasb.PSt_dev;
+  asb->sb_ino = pasb.PSt_ino;
+  asb->sb_mode = pasb.PSt_mode;
+  asb->sb_uid = pasb.PSt_uid;
+  asb->sb_gid = pasb.PSt_gid;
+  asb->sb_nlink = pasb.PSt_nlink;
+  asb->sb_rdev = pasb.PSt_rdev;
+  asb->sb_mtime = pasb.PSt_mtime;
+  asb->sb_size = pasb.PSt_size;
+
+  if (namelen == 0 || namelen >= PATHSIZE)
+    return (warnarch ("Bad ASCII pathname length", (off_t) H_STRLEN));
+
+  strncpy(name, header + M_STRLEN + H_STRLEN3, namelen);
+  if (strlen(name) != namelen - 1)
+    return (warnarch ("Corrupt ASCII pathname", (off_t)namelen));
+  if (name[namelen - 1] != '\0')
+    return (warnarch ("Bad ASCII pathname", (off_t)namelen));
+
+  if (inskip ((off_t)extraheaderlen) < 0)
+    return (warnarch ("Corrupt header", (off_t)0));
+
+#ifdef S_IFLNK
+  if ((asb->sb_mode & S_IFMT) == S_IFLNK) {
+    asb->sb_link[asb->sb_size] = '\0';
+    strncpy(asb->sb_link, header + M_STRLEN + H_STRLEN3 + namelen,
+            (uint)asb->sb_size);
+    if (strlen(asb->sb_link) != (uint)asb->sb_size) {
+      warn(name, "Corrupt symbolic link");
+    }
+    asb->sb_link[asb->sb_size] = '\0';
+    asb->sb_size = 0;
+  }
+#endif /* S_IFLNK */
+
+  comphead = 1;
+  return (0);
+}
  
 
 /*
@@ -1960,10 +2056,12 @@
     {
       VOID inread (magic, M_STRLEN);
       skipped = 0;
+      comphead = 0;
 
       while (   ((align = inascii (magic, name, asb)) < 0)
  	     && ((align = inascii2 (magic, name, asb)) < 0)
 	     && ((align = inascii3 (magic, name, asb)) < 0)
+	     && ((align = inascii3c (magic, name, asb)) < 0)
 	     && ((align = inbinary (magic, name, asb)) < 0)
 	     && ((align = inswab (magic, name, asb)) < 0))
 	{
@@ -1997,7 +2095,7 @@
       VOID inskip (asb->sb_size + align);
     }
 #ifdef	S_IFLNK
-  if ((asb->sb_mode & S_IFMT) == S_IFLNK)
+  if (((asb->sb_mode & S_IFMT) == S_IFLNK) && !comphead)
     {
       if (inread (asb->sb_link, (uint) asb->sb_size) < 0)
 	{
@@ -3652,6 +3750,8 @@
 	*/
 	wantlarge=wantlarge || ((sb.sb_mtime&0x7fffffff)!=sb.sb_mtime);
 
+	wantlarge=wantlarge || comphead;
+
 	if(cpiocompat && wantlarge)
 	  {
 	    /* if this was the >2GB case we already had a fatal elsewhere.. */
@@ -3668,7 +3768,10 @@
        
  	if(wantlarge) 
 	  {	   
-	    outhead3 (name, &sb); 
+	    if(comphead) 
+	      outhead3c (name, &sb); 
+	    else
+	      outhead3 (name, &sb); 
 	  } 
 	else
 	  {
@@ -4093,6 +4196,55 @@
 #endif /* S_IFLNK */
 }
 
+/*
+ * outhead3c()
+ *
+ * Write compressed large ASCII archive header.
+ */
+STATIC void
+outhead3c(char *name, Stat *asb)
+{
+  uint namelen;
+  char header3c[M_STRLEN + H_STRLEN3C + 1];
+  char header[M_STRLEN + H_STRLEN3 + PATHSIZE + 1];
+  char buff[(M_STRLEN + H_STRLEN3 + PATHSIZE * 2) * 2];
+  int total;
+  int size;
+
+  if ((name[0] == '/') && !abspaths) {
+    if (name[1])
+      ++name;
+    else
+      name = ".";
+  }
+  namelen = (uint)strlen(name) + 1;
+
+  strcpy(header, M_ASCII3);
+  sprintf(header + M_STRLEN, H_PRINT3, ulo (asb->sb_dev),
+          ull(asb->sb_ino), ulo (asb->sb_mode), ulo (asb->sb_uid),
+          ulo (asb->sb_gid), ulo (asb->sb_nlink), ulo (asb->sb_rdev),
+          mflag ? ull(timenow) : ull(asb->sb_mtime), namelen, 0, 0,
+          ull(asb->sb_size));
+  strcpy(header + M_STRLEN + H_STRLEN3, name);
+
+  total = M_STRLEN + H_STRLEN3 + namelen;
+
+#ifdef	S_IFLNK
+  if ((asb->sb_mode & S_IFMT) == S_IFLNK) {
+    strncpy(header + total, asb->sb_link, (uint) asb->sb_size);
+    total = total + (uint)asb->sb_size;
+  }
+#endif /* S_IFLNK */
+
+  size = compressheader(header, total, buff, sizeof(buff), 1);
+
+  strcpy(header3c, M_ASCII3C);
+  sprintf(header3c + M_STRLEN, H_PRINT3C, ulo(size));
+
+  outwrite(header3c, M_STRLEN + H_STRLEN3C);
+  outwrite(buff, size);
+}
+
 
 /*
  * outpad()
@@ -4758,7 +4910,7 @@
  Select:  -y [pattern] : only process files matching pattern\n\
           -Y [pattern] : do not process files matching pattern\n",
 		myname, myname, myname, myname);
-  VOID fprintf (stderr,"Version %s dated %s\n", VERSION, DATE);
+  VOID fprintf (stderr,"Version %s dated %s %s\n", VERSION, DATE, PATCH);
   exit (1);
 }
 
diff -r b733b98fea86 -r ab008afb13f0 afio.h
--- a/afio.h	Mon Feb 06 10:51:10 2012 +0900
+++ b/afio.h	Mon Feb 06 11:03:25 2012 +0900
@@ -156,6 +156,13 @@
 #define	PH_SCAN3  "%8lX%16llXm%6lo%8lX%8lX%8lX%8llX%16llXn%4X%4X%4Xs%16llX:"
 
 
+/* compressed large ASCII format */
+#define	H_STRLEN3C 9
+#define	M_ASCII3C "070728"
+#define H_COUNT3C 1
+#define	H_PRINT3C  "%08lX;"
+#define	PH_SCAN3C  "%8lX;"
+
 
 typedef struct {
 long unsigned int PSt_dev;
@@ -463,6 +470,7 @@
 void outhead (char *, Stat *);
 void outhead2 (char *, Stat *);
 void outhead3 (char *, Stat *);
+void outhead3c (char *, Stat *);
 void outpad (off_t);
 void outwait (void);
 void outwrite (char *,uint);
@@ -532,3 +540,6 @@
 extern ulonglong maxsizetocompress;
 extern short noglob;
 extern short flag0;
+
+int compressheader(const char *ibuff, const int isize,
+                   char *obuff, const int osize, const int comp);
diff -r b733b98fea86 -r ab008afb13f0 compfile.c
--- a/compfile.c	Mon Feb 06 10:51:10 2012 +0900
+++ b/compfile.c	Mon Feb 06 11:03:25 2012 +0900
@@ -382,3 +382,91 @@
 }
 
 
+int
+compressheader (const char *ibuff, const int isize,
+                char *obuff, const int osize, const int comp)
+{
+  int pid;
+  int pfd[2];
+  int pfdc[2];
+  int csize;
+
+  char farg[3];
+
+  farg[0]='-';
+  farg[1]=gzipfactor+'0';
+  farg[2]='\0';
+
+  if ((pipe(pfd) == -1) || (pipe(pfdc) == -1)) {
+    perror("pipe");
+    return -1;
+  }
+
+  if (rewindfd >= 1) {
+    if (lseek(rewindfd+1, (off_t)0, SEEK_SET) < 0) {
+      fatal("-3 option", syserr());
+    }
+  }
+
+  pid = xfork("out(), encrypting", NODIE);
+  if (pid < 0)  {
+    perror("folk");
+    return -1;
+  }
+  if (pid == 0)  {
+    if (arfd != STDIN && arfd != STDOUT) VOID close (arfd);
+
+    close(pfd[1]);
+    close(fileno(stdin));
+    dup(pfd[0]);
+    close(pfd[0]);
+
+    close(pfdc[0]);
+    close(fileno(stdout));
+    dup(pfdc[1]);
+    close(pfdc[1]);
+
+    close(rewindfd);
+    dup2(rewindfd+1, rewindfd);
+    close(rewindfd+1);
+
+    if (!compressargs) {
+      if (comp) {
+        execlp(compressprog, compressprog, "-c", farg, NULL);
+      } else {
+        execlp(compressprog, compressprog, "-d", "-c", farg, NULL);
+      }
+    } else {
+      execvp(compressprog, compress_arg_list);
+    }
+
+    exit (1);
+  } else {
+    int s;
+
+    close(pfd[0]);
+    close(pfdc[1]);
+
+    write(pfd[1], ibuff, (size_t)isize);
+    close(pfd[1]);
+
+    csize = 0;
+    while (s = read(pfdc[0], obuff + csize, osize - csize)) {
+      csize = csize + s;
+    }
+
+    if (csize < 0) {
+      perror("read");
+      return -1;
+    }
+
+    close(pfdc[0]);
+
+    if (xwait(pid, "out(), wait for crypt child", FALSE)!= 0) {
+      fprintf(stderr,
+              "Trouble (un)compressing header\n");
+    }
+
+    return csize;
+  }
+}
diff -r b733b98fea86 -r ab008afb13f0 patchlevel.h
--- a/patchlevel.h	Mon Feb 06 10:51:10 2012 +0900
+++ b/patchlevel.h	Mon Feb 06 11:03:25 2012 +0900
@@ -1,5 +1,6 @@
 #define VERSION	"2.5.1"
 #define DATE	"05 Feb 2012"
+#define PATCH	"+comphead-20120206"
 
 /*
  * Version 1.68		               1985	Mark Brukhartz
