#ifndef LINT /* @(#) zoodel.c 2.19 88/02/06 21:23:36 */ /*$Source: /usr/home/dhesi/zoo/RCS/zoodel.c,v $*/ /*$Id: zoodel.c,v 1.4 91/07/09 01:54:11 dhesi Exp $*/ static char sccsid[]="$Source: /usr/home/dhesi/zoo/RCS/zoodel.c,v $\n\ $Id: zoodel.c,v 1.4 91/07/09 01:54:11 dhesi Exp $"; #endif /* LINT */ /* Copyright (C) 1986, 1987 Rahul Dhesi -- All rights reserved (C) Copyright 1988 Rahul Dhesi -- All rights reserved */ #include "options.h" /* Deletes or undeletes entries from an archive. choice=1 requests deletion and choice=0 requests undeletion. */ #include "zoo.h" #include "portable.h" #ifndef OK_STDIO #include #define OK_STDIO #endif #include "various.h" /* may not be needed */ #include "zooio.h" #include "zoofns.h" #include "errors.i" #ifndef NOSIGNAL #include #endif int needed PARMS((char *, struct direntry *, struct zoo_header *)); int ver_too_high PARMS((struct zoo_header *)); extern int quiet; void zoodel (zoo_path, option, choice) char *zoo_path; char *option; int choice; { #ifndef NOSIGNAL T_SIGNAL (*oldsignal)(); /* to save previous SIGINT handler */ #endif int delcount = 0; /* how many entries we [un]deleted */ char matchname[PATHSIZE]; /* will hold full pathname */ register ZOOFILE zoo_file; struct zoo_header zoo_header; struct direntry direntry; unsigned int latest_date = 0; /* so we can set time of archive later */ unsigned int latest_time = 0; int pack = 0; /* pack after deletion? */ int file_deleted = 0; /* any files deleted? */ int one = 0; /* del/undel one file only */ int done; /* loop control */ int action; /* delete/undelete or adjust generation */ int subopt; /* sub option to action */ long gencount; /* generation count */ int doarchive = 0; /* whether to adjust archive gen count */ unsigned valtoshow; /* value to show in informative message */ int dodel = 0; /* selection of deleted files */ int selected; /* if current direntry selected */ /* values for action */ #define NO_ACTION 0 /* nothing */ #define DEL_UNDEL 1 /* delete or undelete file */ #define ADJ_LIM 2 /* adjust generation limit */ #define ADJ_GCNT 3 /* adjust generation count */ #define GEN_ON 4 /* turn on generations */ #define GEN_OFF 5 /* turn off generations */ /* values for subopt */ #define SET 0 #define INC 1 action = NO_ACTION; if (*option == 'g') { while (*(++option)) { switch (*option) { case 'A': doarchive = 1; break; case 'q': quiet++; break; case 'l': action = ADJ_LIM; break; case 'c': action = ADJ_GCNT; break; case '=': subopt = SET; gencount = calc_ofs (++option); if (action == ADJ_GCNT && gencount == 0) prterror ('f', "Generation count must be nonzero.\n"); goto opts_done; case '+': if (action == NO_ACTION) { if (option[1] =='\0') { action = GEN_ON; goto opts_done; } else prterror ('f', garbled); } else { subopt = INC; gencount = calc_ofs (++option); goto opts_done; } case '-': if (action == NO_ACTION) { if (option[1] =='\0') { action = GEN_OFF; goto opts_done; } else prterror ('f', garbled); } else { subopt = INC; gencount = - calc_ofs (++option); goto opts_done; } case 'd': dodel++; break; default: prterror ('f', garbled); } /* end switch */ } /* end while */ /* if normal exit from while loop, it means bad command string */ prterror ('f', garbled); opts_done: /* jump here from exit in while loop above */ if (action == NO_ACTION) prterror ('f', garbled); } else { action = DEL_UNDEL; while (*(++option)) { switch (*option) { case 'P': pack++; break; /* pack after adding */ case 'q': quiet++; break; /* be quiet */ case '1': one++; break; /* del or undel only one file */ default: prterror ('f', inv_option, *option); } } /* end while */ } /* Open archive for read/write/binary access. It must already exist */ if ((zoo_file = zooopen (zoo_path, Z_RDWR)) == NOFILE) { prterror ('f', could_not_open, zoo_path); } /* read archive header */ frd_zooh (&zoo_header, zoo_file); if ((zoo_header.zoo_start + zoo_header.zoo_minus) != 0L) prterror ('f', failed_consistency); if (ver_too_high (&zoo_header)) prterror ('f', wrong_version, zoo_header.major_ver, zoo_header.minor_ver); if (doarchive) { /* manipulate archive gen val */ unsigned zoo_date, zoo_time; #ifdef GETUTIME getutime (zoo_path, &zoo_date, &zoo_time); /* save archive timestamp */ #else gettime (zoo_file, &zoo_date, &zoo_time); #endif if (zoo_header.type == 0) prterror ('f', packfirst); if (action == ADJ_LIM) { unsigned newgencount; if (subopt == SET) newgencount = (unsigned) gencount; else /* INC */ newgencount = (zoo_header.vdata & VFL_GEN) + (unsigned) gencount; newgencount &= VFL_GEN; /* reduce to allowed bits */ zoo_header.vdata &= (~VFL_GEN); zoo_header.vdata |= newgencount; prterror ('M', "Archive generation limit is now %u\n", newgencount); } else if (action == GEN_ON) { zoo_header.vdata |= VFL_ON; prterror ('M', "Archive generations on\n"); } else if (action == GEN_OFF) { zoo_header.vdata &= (~VFL_ON); prterror ('M', "Archive generations off\n"); } else prterror ('f', garbled); zooseek (zoo_file, 0L, 0); /* back to begining of file */ fwr_zooh (&zoo_header, zoo_file); #ifdef NIXTIME zooclose (zoo_file); setutime (zoo_path, zoo_date, zoo_time); /* restore archive timestamp */ #else settime (zoo_file, zoo_date, zoo_time); zooclose (zoo_file); #endif return; } zooseek (zoo_file, zoo_header.zoo_start, 0); /* seek to where data begins */ done = 0; /* loop not done yet */ while (1) { long this_dir_offset; this_dir_offset = zootell (zoo_file); /* save pos'n of this dir entry */ frd_dir (&direntry, zoo_file); if (direntry.zoo_tag != ZOO_TAG) { prterror ('f', bad_directory); } if (direntry.next == 0L) { /* END OF CHAIN */ break; /* EXIT on end of chain */ } /* select directory entry if it matches criteria */ selected = ( (action == DEL_UNDEL && direntry.deleted != choice) || (action != DEL_UNDEL && (dodel && direntry.deleted || (dodel < 2 && !direntry.deleted)) ) ); /* WARNING: convention of choice=1 for deleted entry must be same as in direntry definition in zoo.h */ /* Test for "done" so if "one" option requested, [un]del only 1 file */ /* But we go through the whole archive to adjust archive time */ strcpy (matchname, fullpath (&direntry)); /* get full pathname */ if (zoo_header.vdata & VFL_ON) add_version (matchname, &direntry); /* add version suffix */ if (!done && selected && needed(matchname, &direntry, &zoo_header)) { prterror ('m', "%-14s -- ", matchname); delcount++; if (action == DEL_UNDEL) { direntry.deleted = choice; if (choice) file_deleted++; /* remember if any files actually deleted */ } else { /* ADJ_LIM or ADJ_GENCNT */ if (direntry.vflag & VFL_ON) { /* skip if no versions */ if (action == ADJ_LIM) { unsigned newgencount; if (subopt == SET) newgencount = (unsigned) gencount; else /* INC */ newgencount = (int) (direntry.vflag & VFL_GEN) + (int) gencount; newgencount &= VFL_GEN; direntry.vflag &= (~VFL_GEN); direntry.vflag |= newgencount; valtoshow = newgencount; } else { /* ADJ_GCNT */ if (subopt == SET) direntry.version_no = (unsigned) gencount; else /* INC */ direntry.version_no += (int) gencount; direntry.version_no &= VER_MASK; /* avoid extra bits */ valtoshow = direntry.version_no; } } } zooseek (zoo_file, this_dir_offset, 0); #ifndef NOSIGNAL oldsignal = signal (SIGINT, SIG_IGN); /* disable ^C for write */ #endif if (fwr_dir (&direntry, zoo_file) == -1) prterror ('f', "Could not write to archive\n"); #ifndef NOSIGNAL signal (SIGINT, oldsignal); #endif if (action == DEL_UNDEL) prterror ('M', choice ? "deleted\n" : "undeleted\n"); else { if (direntry.vflag & VFL_ON) prterror ('M', "adjusted to %u\n", valtoshow); else prterror ('M', "no generations\n"); } if (one) done = 1; /* if 1 option, done after 1 file */ } /* remember most recent date and time if entry is not deleted */ if (!direntry.deleted) if (direntry.date > latest_date || (direntry.date == latest_date && direntry.time > latest_time)) { latest_date = direntry.date; latest_time = direntry.time; } zooseek (zoo_file, direntry.next, 0); /* ..seek to next dir entry */ } /* endwhile */ if (!delcount) printf ("Zoo: No files matched.\n"); else { #ifdef NIXTIME zooclose (zoo_file); setutime (zoo_path, latest_date, latest_time); #else #if 0 fflush (zoo_file); /* superstition: might help time stamp */ #endif settime (zoo_file, latest_date, latest_time); #endif } #ifndef NIXTIME zooclose (zoo_file); #endif if (file_deleted && pack) { /* pack if files were deleted and user asked */ prterror ('M', "-----\nPacking..."); zoopack (zoo_path, "PP"); prterror ('M', "done\n"); } }