Unix version fopen(fname,"w+") bugs?

Nick Sayer mrapple at quack.UUCP
Mon Oct 9 16:25:28 AEST 1989


Source follows:

/* atob: version 4.0
 * stream filter to change printable ascii from "btoa" back into 8 bit bytes
 * if bad chars, or Csums do not match: exit(1) [and NO output]
 *
 *  Paul Rutter		Joe Orost
 *  philabs!per		petsd!joe
 */

#include <stdio.h>

#define reg register

#define streq(s0, s1)  strcmp(s0, s1) == 0

#define times85(x)	((((((x<<2)+x)<<2)+x)<<2)+x)

long int Ceor = 0;
long int Csum = 0;
long int Crot = 0;
long int word = 0;
long int bcount = 0;

fatal() {
  fprintf(stderr, "bad format or Csum to atob\n");
  exit(1);
}

#define DE(c) ((c) - '!')

decode(c) 
  reg c;
{
  if (c == 'z') {
    if (bcount != 0) {
      fatal();
    } else {
      byteout(0);
      byteout(0);
      byteout(0);
      byteout(0);
    }
  } else if ((c >= '!') && (c < ('!' + 85))) {
    if (bcount == 0) {
      word = DE(c);
      ++bcount;
    } else if (bcount < 4) {
      word = times85(word);
      word += DE(c);
      ++bcount;
    } else {
      word = times85(word) + DE(c);
      byteout((int)((word >> 24) & 255));
      byteout((int)((word >> 16) & 255));
      byteout((int)((word >> 8) & 255));
      byteout((int)(word & 255));
      word = 0;
      bcount = 0;
    }
  } else {
    fatal();
  }
}

FILE *tmp_file;

byteout(c) 
  reg c;
{
  Ceor ^= c;
  Csum += c;
  Csum += 1;
  if ((Crot & 0x80000000)) {
    Crot <<= 1;
    Crot += 1;
  } else {
    Crot <<= 1;
  }
  Crot += c;
  putc(c, tmp_file);
}

main(argc, argv) 
  char **argv;
  int argc;
{
  reg c;
  reg long int i;
  char tmp_name[100];
  char buf[100];
  long int n1, n2, oeor, osum, orot;

  if (argc != 1) {
    fprintf(stderr,"bad args to %s\n", argv[0]);
    exit(2);
  }
  sprintf(tmp_name, "/tmp/atob.%x", getpid());
  tmp_file = fopen(tmp_name, "w+");
  if (tmp_file == NULL) {
    fatal();
  }
  setbuf(tmp_file,NULL); /* hack to prevent w+ bugs */
  unlink(tmp_name);	/* Make file disappear */
  /*search for header line*/
  for (;;) {
    if (fgets(buf, sizeof buf, stdin) == NULL) {
      fatal();
    }
    if (streq(buf, "xbtoa Begin\n")) {
      break;
    }
  }

  while ((c = getchar()) != EOF) {
    if (c == '\n') {
      continue;
    } else if (c == 'x') {
      break;
    } else {
      decode(c);
    }
  }
  if(scanf("btoa End N %ld %lx E %lx S %lx R %lx\n",
         &n1, &n2, &oeor, &osum, &orot) != 5) {
    fatal();
  }
  if ((n1 != n2) || (oeor != Ceor) || (osum != Csum) || (orot != Crot)) {
    fatal();
  } else {
    /*copy OK tmp file to stdout*/;
    fseek(tmp_file, 0L, 0);
    for (i = n1; --i >= 0;) {
      putchar(getc(tmp_file));
    }
  }
  exit(0);
}

This is the standard atob.c file, except that the line
"setbuf(tmp_file,NULL);" has been added right after checking
to make sure tmp_file!=NULL (i.e. after making sure the
file really was opened). I've been told this fixes a bug
having to do with the way v7 munges buffering when opening
a file "w+." This seems to MODIFY the behaivor, but not fix
it, as the result of running this program on a known-good
btoa file is that you get exactly the correct number of
^? (EOF) characters. This is consistent. The same bug fix
applied to vnews (actually visual.c in news B) results in
the same behavior. Adding an ftell after the fseek near the
end of the file results, of course, in 0 being returned.
Anyone have any opinions?

---------------------------------------------------------------------
Nick Sayer | ...{ lll-winken!cheers ucdavis!uop } !quack!mrapple
.... or.... cheers!quack!mrapple at apple.com or quack!mrapple at uop.edu
Packet radio: N6QQQ @ WB6V | FredMail: NSAYER at MADERA%NORCAL
Disclaimer: The BBC would like to appologise for that announcement



More information about the Comp.unix.wizards mailing list