/* iffar - IFF CAT archiver replace functions By Karl Lehenbauer, version 1.2, release date 5/9/88. This code is released to the public domain. See the README file for more information. */ #include #include #include #include #include "assert.h" #include "iff.h" /* if a "insert before" or "insert after" position modifier is * not specified, the program attepts to replace entries at the * same place as where they occurred in the original archive. * if the entry could not be found, the file is appended to the * end of the archive. hence, when a position modifier is not * specified and a file being replaced did not exist in the archive, * the file needs to be appended onto the * end - we do this by nulling out the argument if and only if * neiter insert_before or insert_after is set, else a bug would * be introduced as when they are selected the delete and insert * portions are asynchronous and either could occur before the * other, hence one guy nulling it makes the other guy not see * it. it's not a problem for the specified case, though, 'cuz * it's only looked at in this one place and at the end, * where, again only when neither insert_before and insert_after * are checked, we run through the arguments and if the first byte * of any entry is not null, this implies that entry was not in * the original archive, hence not replaced in-place, so we tack * it on to the end. * if insert_before or insert_after is selected, archive entries * are deleted on the fly as they are read from the original * archive by being skipped and, when the insert conditions are * met, all of the names in the list of names are appended, thus, * we don't have to worry about it * * note that it's kind of broken for insert_after and insert_before * when the after or before name isn't found the old entries will * be deleted but the new ones won't be inserted, heck, the program * may even blow up */ extern ULONG nextchunk(); extern int insert_before; extern int insert_after; extern char *location_modifier_name; int replace_entries(archive_name,fnames,nfiles) char *archive_name; char *fnames[]; int nfiles; { int old_archive_fd, new_archive_fd; ULONG cat_type, chunkid, innerchunkid, subtype; long chunksize, innerchunksize, filesize; char textbuf[128], old_archive_name[128]; int i, replace_file, file_bytes; int entryindex, insert_next_time = 0; int modifier_matches, did_insert = 0; extern int verbose; /* rename the archive to its old name concatenated with ".old" */ sprintf(old_archive_name,"%s.old",archive_name); unlink(old_archive_name); rename(archive_name,old_archive_name); if ((old_archive_fd = OpenCAT(old_archive_name,&cat_type,&filesize)) == -1) { fprintf(stderr,"Can't open archive '%s'\n",old_archive_name); return(0); } if ((new_archive_fd = create_archive(archive_name,ID_MISC)) < 0) return(0); while ((chunkid = nextCATchunk(old_archive_fd,&subtype,&textbuf[0],&chunksize,&filesize)) != 0L) { /* if the chunk type isn't FORM, CAT or LIST, copy it across * without looking at it */ if (chunkid != ID_FORM && chunkid != ID_CAT && chunkid != ID_LIST) { if (!WriteChunkHeader(new_archive_fd,chunkid,chunksize)) return(0); copychunkbytes(old_archive_fd,new_archive_fd,chunksize,&filesize); break; } /* we shouldn't ever not get a filename back here at the top level * that is, we saw a CAT, LIST or FORM, we expect a FNAM chunk*/ if (textbuf[0] == '\0') { fprintf(stderr,"FORM, CAT or LIST in archive doesn't have an FNAM chunk, abandoning\n"); return(0); } if (insert_before || insert_after) modifier_matches = !strnicmp(location_modifier_name,textbuf,128); /* if insert_before option has been selected and the chunk ID * we just read from the old archive matches global * location_modifier_name, append all the named files to the * new archive. also do this if it's insert_after and * we matched the name last time */ if ((modifier_matches && insert_before) || insert_next_time) { insert_next_time = 0; for (entryindex = 0; entryindex < nfiles; entryindex++) { if (verbose) { if (insert_before) fprintf(stderr,"inserting "); else fprintf(stderr,"appending "); fprintf(stderr,"%s\n",fnames[entryindex]); } append_file_to_archive(fnames[entryindex],new_archive_fd); } did_insert = 1; } /* if this is a match and insert_after is selected, set * insert_next_time so we'll know to do the appends after the * next entry */ if (modifier_matches && insert_after) insert_next_time = 1; /* search to see if this chunk's name is one specified in fnames, * an array of pointer to char strings */ replace_file = 0; for (i = 0; i < nfiles; i++) { if (!strnicmp(basename(fnames[i]),textbuf,128)) { /* it is */ replace_file = 1; break; } } /* if we want to replace it, */ if (replace_file) { /* copy the file being replaced into the archive if * neither insert_before or insert_after are set. * if they are set, this will be done elsewhere */ if (!insert_before && !insert_after) { if (verbose) fprintf(stderr,"replacing %s\n",textbuf); append_file_to_archive(fnames[i],new_archive_fd); /* null out the first byte of the name so we won't * append it again at the end */ *fnames[i] = '\0'; } else if (verbose) fprintf(stderr,"removing old %s\n",textbuf); /* in either case (replace selected, we don't care if * before or after are chosen), skip the chunk in the * old archive */ if (!skipchunk(old_archive_fd,chunksize,&filesize)) { fprintf(stderr,"replace: skipchunk failed\n"); return(0); } } else /* not on the replacement list, we copy it */ { if (!WriteCATentry(new_archive_fd,textbuf,chunkid,subtype,chunksize)) return(0); copychunkbytes(old_archive_fd,new_archive_fd,chunksize,&filesize); } } /* now if insert_before or insert_after were not set, for all entries * in the list that don't have a null byte for their first byte, * append them to the archive */ if ((!insert_before && !insert_after) || !did_insert) { /* if we didn't do the insert, report that we're planning * to append. note that if insert_after and !insert_next_time * it means that they said append after the last one, so * don't mention it */ if (insert_before || (insert_after && !insert_next_time)) fprintf(stderr,"couldn't find entry %s that was specified as a position modifier\n, appending your entries\n",textbuf); for (i = 0; i < nfiles; i++) { if (*fnames[i] != '\0') { if (verbose) fprintf(stderr,"appending %s\n",fnames[i]); append_file_to_archive(fnames[i],new_archive_fd); } } } /* write the right length in for the header */ rewrite_archive_header(new_archive_fd); /* close the old and new archive files and return success */ close(old_archive_fd); close(new_archive_fd); return(1); } /* end of extract.c */