/* @(#)arcv.c 2.1 */ #include <stdio.h> #include <signal.h> abort(); /* interrupt handler, defined below */ char *tempnam();/* C library routine for creating temp file name */ long time(); /* C library routine which gives you the time of day */ long genarc(); /* routine for converting archives and their member files. the routine returns the number of bytes in the converted file. the converted file is assumed to be in tmpfil. a returned value of 0 implies that something has gotten screwed up */ long gencpy(); /* routine for copying a file which does not (or can not) need to be converted. the tmpfil file is made a copy of the infil input file. */ /* input/output/temporary files */ char *infilname, *outfilname, *tmpfilname, *nm_newarc, *nm_member; FILE *infil, *outfil, *tmpfil, *newarc, *member; char buffer[BUFSIZ]; /* file copy buffer */ /* archive file header format */ /* COMMON ARCHIVE FORMAT ARCHIVE File Organization: _______________________________________________ |__________ARCHIVE_HEADER_DATA________________| | | | Archive Header "ar_hdr" | |.............................................| | | | Symbol Directory "ar_sym" | | | |_____________________________________________| |________ARCHIVE_FILE_MEMBER_1________________| | | | Archive File Header "arf_hdr" | |.............................................| | | | Member Contents (either a.out.h | | format or text file) | |_____________________________________________| | | | . . . | | . . . | | . . . | |_____________________________________________| |________ARCHIVE_FILE_MEMBER_n________________| | | | Archive File Header "arf_hdr" | |.............................................| | | | Member Contents (either a.out.h | | format or text file) | |_____________________________________________| */ #define ARMAG "<ar>" #define SARMAG 4 struct ar_hdr { /* archive header */ char ar_magic[SARMAG]; /* magic number */ char ar_name[16]; /* archive name */ char ar_date[4]; /* date of last archive modification */ char ar_syms[4]; /* number of ar_sym entries */ }; struct ar_sym { /* archive symbol table entry */ char sym_name[8]; /* symbol name, recognized by ld */ char sym_ptr[4]; /* archive position of symbol */ }; struct arf_hdr { /* archive file member header */ char arf_name[16]; /* file member name */ char arf_date[4]; /* file member date */ char arf_uid[4]; /* file member user identification */ char arf_gid[4]; /* file member group identification */ char arf_mode[4]; /* file member mode */ char arf_size[4]; /* file member size */ }; /* old pdp11 format */ #define OARMAG 0177545 struct oar_hdr { char ar_name[14]; long ar_date; char ar_uid; char ar_gid; int ar_mode; long ar_size; }; /* main program for arcv usage is 'arcv infile outfile' Reference: "UNIX 5.0 Machine Language Processors: VAX and 3B Processor Requirements Specification", R.M. Klein, Memorandum for File Case 12143-116, October 7, 1981. */ main ( argc, argv ) int argc; char * argv[]; { unsigned int in_magic; /* magic number of input file */ long bytes_out; int bytes_in; /* trap for interrupts */ if ((signal(SIGINT, SIG_IGN)) == SIG_DFL) signal(SIGINT, abort); if ((signal(SIGHUP, SIG_IGN)) == SIG_DFL) signal(SIGHUP, abort); if ((signal(SIGQUIT, SIG_IGN)) == SIG_DFL) signal(SIGQUIT, abort); if ((signal(SIGTERM, SIG_IGN)) == SIG_DFL) signal(SIGTERM, abort); if (argc != 3) { /* usage is 'arcv inargument outargument' */ fprintf(stderr,"usage: arcv infile outfile\n"); exit(1); } infilname = argv[1]; /* get input file name from command line */ outfilname = argv[2];/* get output file name from command line*/ if ((infil = fopen(infilname,"r")) == NULL) /* can't get the input file */ readerr(infilname); tmpfilname = tempnam("","arcv"); if ((tmpfil = fopen(tmpfilname,"w")) == NULL) /* can't write onto the temporary file */ writerr(tmpfilname); /* let's get down to business: are we dealing with an archive or some other kind of file? answer: look at the 'magic number' */ if (fread(&in_magic,1,sizeof(in_magic),infil) != sizeof(in_magic)) readerr(infilname); in_magic &= 0177777; fseek(infil,0L,0); switch (in_magic) { case OARMAG: /* archive input */ bytes_out = genarc(infil); break; default: /* questionable input */ bytes_out = gencpy(infil, infilname); fprintf(stderr,"arcv: warning, contents of file %s not modified\n", infilname); break; }; /* copy converted output, which resides in the tmpfil file to the outfil file */ fclose(infil); if ((outfil = fopen(outfilname,"w")) == NULL) /* can't write onto the output file */ writerr(outfilname); /* always begin at the beginning */ fclose(tmpfil); if ((tmpfil = fopen(tmpfilname,"r")) == NULL) /* can't read the temporary file */ readerr(tmpfilname); while (bytes_out) { bytes_in = fread(buffer,1,BUFSIZ,tmpfil); bytes_out -= (long)fwrite(buffer,1,bytes_in,outfil); }; /* we are all done, so clean up! */ fclose(outfil); fclose(tmpfil); unlink(tmpfilname); exit(0); } /* interrupt handler: delete all the temp files, unlink the output and then bug out with an error code of 1 */ abort () { fclose(infil); /* close all files */ fclose(outfil); fclose(tmpfil); fclose(newarc); fclose(member); unlink(tmpfilname); /* delete temp file and output */ if (strcmp(infilname,outfilname)) unlink(outfilname); unlink(nm_newarc); unlink(nm_member); exit(1); /* bug out! */ } readerr(filname) /* input read error, give the user a reason and bug out */ char *filname; { fprintf(stderr,"arcv: input error on file %s ",filname); perror(" "); abort(); } writerr(filname) /* output write error, give the user a reason and bug out */ char *filname; { fprintf(stderr,"arcv: output error on file %s ",filname); perror(" "); abort(); } long genarc (arcfile) /* procedure to convert a pdp11 archive into a 5.0+ archive format. the converted file is written onto the temp file tmpfil. the genarc function returns the number of bytes in the arcved file tmpfil. */ FILE *arcfile; { long arc_size; /* size of arcved archive file on output */ int mem_size; /* size of an archive member file */ short incr; struct ar_hdr new_header; struct oar_hdr oldf_header; struct arf_hdr newf_header; /* set up temporary files */ nm_newarc = tempnam("","arcv"); nm_member = tempnam("","arcv"); if ((newarc = fopen(nm_newarc,"w")) == NULL) writerr(nm_newarc); /* skip past the magic number in the input file: arcfile */ fseek(arcfile,(long)sizeof(int),0); /* set up the new archive header */ strncpy(new_header.ar_magic,ARMAG,SARMAG); strncpy(new_header.ar_name,infilname,sizeof(new_header.ar_name)); sputl(time(NULL),new_header.ar_date); sputl(0L,new_header.ar_syms); /* recreate archive without symbols */ if ((arc_size = (long)fwrite(&new_header,1,sizeof(new_header),newarc)) != sizeof(new_header)) writerr(nm_newarc); /* now process each archive member in turn */ while (fread(&oldf_header,1,sizeof(oldf_header),arcfile) == sizeof(oldf_header)) { /* if the member has a name of "__.SYMDEF" then we can delete it from the new archive. this special member was used with earlier versions of random access libraries. it has no application or use in the new archive format. */ if (strcmp(oldf_header.ar_name,"__.SYMDEF") == 0) { fseek(arcfile,oldf_header.ar_size,1); /* skip */ continue; /* and go on to the next archive member */ }; /* translate header data for each member */ strncpy(newf_header.arf_name,oldf_header.ar_name, sizeof(oldf_header.ar_name)); sputl(oldf_header.ar_date,newf_header.arf_date); sputl((long)oldf_header.ar_uid,newf_header.arf_uid); sputl((long)oldf_header.ar_gid,newf_header.arf_gid); sputl((long)oldf_header.ar_mode,newf_header.arf_mode); /* prepare the member for conversion */ if ((member = fopen(nm_member,"w")) == NULL) writerr(nm_member); mem_size = oldf_header.ar_size; if (mem_size & 1) { /* ar expects members to be evenly sized */ mem_size++; incr = 1; } else incr = 0; while (mem_size >= BUFSIZ) { if (fread(buffer,1,BUFSIZ,arcfile) != BUFSIZ) readerr(infilname); if (fwrite(buffer,1,BUFSIZ,member) != BUFSIZ) writerr(nm_member); mem_size -= BUFSIZ; }; if (mem_size) { if ((long)fread(buffer,1,(int)mem_size,arcfile) != mem_size) readerr(infilname); if ((long)fwrite(buffer,1,(int)mem_size,member) != mem_size) writerr(nm_member); }; /* now perform the actual conversion */ fclose(member); if ((member = fopen(nm_member,"r")) == NULL) readerr(nm_member); mem_size = gencpy(member,newf_header.arf_name); fclose(member); /* now let's put the sucker back into the new archive */ sputl((long)(mem_size-(long)incr),newf_header.arf_size); /* finish up */ if (fwrite(&newf_header,1,sizeof(newf_header),newarc) != sizeof(newf_header)) writerr(nm_newarc); arc_size += mem_size + sizeof(newf_header); /* put the new member into the new archive */ fclose(tmpfil); if ((tmpfil = fopen(tmpfilname,"r")) == NULL) readerr(tmpfilname); while (mem_size = (long)fread(buffer,1,BUFSIZ,tmpfil)) fwrite(buffer,1,(int)mem_size,newarc); }; /* copy new archive file to tmpfil */ fclose(newarc); fclose(tmpfil); if ((newarc = fopen(nm_newarc,"r")) == NULL) readerr(nm_newarc); if ((tmpfil = fopen(tmpfilname,"w")) == NULL) writerr(tmpfilname); while (mem_size = (long)fread(buffer,1,BUFSIZ,newarc)) fwrite(buffer,1,(int)mem_size,tmpfil); /* time to clean up */ fclose(newarc); unlink(nm_newarc); fclose(member); unlink(nm_member); return(arc_size); } long gencpy(cpyfile, cpyname) /* routine for copying a file which does not need to be converted. the tmpfil file is made a copy of the infil input file. */ FILE *cpyfile; char *cpyname; { long cpy_size; int bytes_in; cpy_size = 0; fclose(tmpfil); /* start with a clean file */ if ((tmpfil = fopen(tmpfilname,"w")) == NULL) writerr(tmpfilname); while (bytes_in = fread(buffer,1,BUFSIZ,cpyfile)) { fwrite(buffer,1,bytes_in,tmpfil); cpy_size = cpy_size + bytes_in; } return(cpy_size); } /* * The intent here is to provide a means to make the value of * bytes in an io-stream correspond to the value of the long * in the memory while doing the io a `long' at a time. * Files written and read in this way are machine-independent. * */ #include <values.h> sputl(w, buffer) long w; register char *buffer; { register int i = BITSPERBYTE * sizeof(long); while ((i -= BITSPERBYTE) >= 0) *buffer++ = (char) (w >> i); }