123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475 |
- /*
- * CDE - Common Desktop Environment
- *
- * Copyright (c) 1993-2012, The Open Group. All rights reserved.
- *
- * These libraries and programs are free software; you can
- * redistribute them and/or modify them under the terms of the GNU
- * Lesser General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * These libraries and programs are distributed in the hope that
- * they will be useful, but WITHOUT ANY WARRANTY; without even the
- * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU Lesser General Public License for more
- * details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with these libraries and programs; if not, write
- * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
- * Floor, Boston, MA 02110-1301 USA
- */
- /*%% (c) Copyright 1993, 1994 Hewlett-Packard Company */
- /*%% (c) Copyright 1993, 1994 International Business Machines Corp. */
- /*%% (c) Copyright 1993, 1994 Sun Microsystems, Inc. */
- /*%% (c) Copyright 1993, 1994 Novell, Inc. */
- /*%% $TOG: isrepair.c /main/5 1998/04/10 08:04:42 mgreess $ */
- /* @(#)isrepair.c 1.7 93/07/30
- * Copyright (c) 1988, 1993 by Sun Microsystems, Inc.
- */
- /*
- * isrepair.c
- *
- * Description:
- * Repair an ISAM file.
- */
- #include "isam_impl.h"
- #include <unistd.h>
- #include <stdlib.h>
- #include <signal.h>
- #include <stdio.h>
- /*
- * err = isrepair(isfname, verbose)
- *
- * isrepair repairs an ISAM file.
- *
- * The algorithm used is as the following:
- * 1. Read the control page of the possibly damaged file. We assume
- * that the control page is not damaged.
- * 2. Open a new ISAM file with ~ suffix.
- * 3. Scan .rec file (and .var file if variable length records file)
- * retrieve all records not marked as deleted, and write them
- * to the ~ ISAM file.
- * 4. Delete the old ISAM file.
- * 5. Rename ~ file to the original file name.
- * 6. Build all indexes.
- *
- * verbose option (if set to nonzero) will print messages to stdout.
- */
- Static char *rp_readrecord_v(), *rp_readrecord_f();
- Static int printkey(int, struct keydesc *, int (*)(const char *, ...));
- Static void cmd_error(const char *, int (*)(const char *, ...));
- Static int typeletter();
- Static int rp_readcntlpg();
- static int isnoprintf(const char *, ...);
- int isrepair(char *isfname, int verbose)
- {
- extern char *rp_readrecord_v(), *rp_readrecord_f();
- char cntlpg[ISCNTLSIZE];
- int datfd = -1, indfd = -1, varfd = -1;
- int minreclen, maxreclen;
- int nrecords_fromcntl;
- int varflag;
- char nameBuf [MAXPATHLEN];
- char *namebuf;
- int isfd = -1;
- struct keydesc2 keydesc2;
- int i;
- long offset, recfile_end;
- char *prec;
- long recnum;
- int nrecords_found, diff;
- long lastrecno;
- struct keydesc keydesc;
- int (*print)(const char *, ...);
- sigset_t oldmask;
- sigset_t allsignals;
- char Buffer[BUFSIZ];
- char *buffer = NULL;
- print = verbose ? printf : isnoprintf;
- datfd = indfd = varfd = -1;
- /*
- * Open UNIX files.
- */
- if (strlen(isfname) + 10 >= MAXPATHLEN)
- namebuf = (char*) malloc(strlen(isfname) + 10);
- else
- namebuf = nameBuf;
- (void)strcpy(namebuf, isfname);
- _makedat_isfname(namebuf);
- datfd = open(namebuf, O_RDONLY);
- if (datfd > -1) {
- if(fcntl(datfd, F_SETFD, 1) == -1) {
- close(datfd);
- datfd = -1;
- }
- }
- (void)strcpy(namebuf, isfname);
- _makeind_isfname(namebuf);
- indfd = open(namebuf, O_RDONLY);
- if (indfd > -1) {
- if(fcntl(indfd, F_SETFD, 1) == -1) {
- close(indfd);
- indfd = -1;
- }
- }
- (void)strcpy(namebuf, isfname);
- _makevar_isfname(namebuf);
- varfd = open(namebuf, O_RDONLY);
- if (varfd > -1) {
- if(fcntl(varfd, F_SETFD, 1) == -1) {
- close(varfd);
- varfd = -1;
- }
- }
- (void)print("Reading control page from %s.rec file...\n",
- isfname);
- if (rp_readcntlpg(datfd, cntlpg) == ISERROR) {
- (void)print("Cannot read the control page\n");
- goto ERROR;
- }
- /*
- * Check magic. Repair only ISAM files!!!
- */
- if (strncmp(cntlpg + CP_MAGIC_OFF, ISMAGIC, strlen(ISMAGIC)) != 0) {
- (void)print("Bad magic in %s.rec\n", isfname);
- goto ERROR;
- }
- varflag = ldint(cntlpg + CP_VARFLAG_OFF);
- minreclen = ldint(cntlpg + CP_MINRECLEN_OFF);
- maxreclen = ldint(cntlpg + CP_MAXRECLEN_OFF);
- /*
- * Check for maxreclen field value of -1. This could have occurred due to
- * ISMAXRECLEN being incorrectly set to 65535 in an earlier version. If
- * this field is -1 and it's a variable length record, reset to the new
- * value of MAXRECLEN. This means that this field will be repaired when
- * the control block is written back to disk.
- */
- if (maxreclen == -1 && varflag) {
- maxreclen = ISMAXRECLEN;
- }
- lastrecno = ldlong(cntlpg + CP_LASTRECNO_OFF);
- nrecords_fromcntl = ldlong(cntlpg + CP_NRECORDS_OFF);
- /*
- * Open output file. Use ~ as suffix.
- */
- (void)sprintf(namebuf, "%s~", isfname);
- (void)print("Opening temporary ISAM file '%s'...\n",
- namebuf);
- isreclen = minreclen;
- if ((isfd = isbuild(namebuf, maxreclen, nokey, ISINOUT + ISEXCLLOCK +
- (varflag?ISVARLEN:0))) == ISERROR) {
- (void)print("Cannot open temporary ISAM file %s\n",
- namebuf);
- if (iserrno == EEXIST)
- (void)print("File %s already exists\n", namebuf);
- goto ERROR;
- }
- /*
- * Scan .rec file and read all undeleted records.
- */
- (void)print("Salvaging records from %s.rec%s file...\n",
- isfname, varflag?" (and .var file)" : "");
- offset = ISCNTLSIZE;
- recfile_end = lseek(datfd, 0L, 2);
- recnum = 1;
- nrecords_found = 0;
-
- while (recnum <= lastrecno && offset < recfile_end - minreclen) {
- if (varflag) {
- prec = rp_readrecord_v(datfd, varfd, offset, minreclen, maxreclen);
- offset += minreclen + LONGSIZE;
- }
- else {
- prec = rp_readrecord_f(datfd, offset, minreclen);
- offset += minreclen + 1;
- }
-
- if (prec != NULL) {
- if (iswrrec(isfd, recnum, prec) == ISERROR) {
- cmd_error("iswrrec", print);
- goto ERROR;
- }
- nrecords_found++;
- }
- recnum++;
- }
- diff = nrecords_found - nrecords_fromcntl;
- if (diff == 0)
- (void)print("All records found - total %d records\n",
- nrecords_found);
- else
- (void)print("%d records found - %d records %s than in header\n",
- nrecords_found, diff, diff > 0 ?
- "more" : "less");
- /*
- * Close all file descriptors.
- */
- if(datfd != -1) {
- close(datfd);
- datfd = -1;
- }
- if(indfd != -1) {
- close(indfd);
- indfd = -1;
- }
- if(varfd != -1) {
- close(varfd);
- varfd = -1;
- }
- (void)isclose(isfd);
- (void) sigfillset(&allsignals);
- (void) sigprocmask(SIG_SETMASK, &allsignals, &oldmask);
- (void)print("Erasing ISAM file '%s'...\n", isfname);
- /* if (iserase(isfname) != ISOK) {
- cmd_error("iserase", print);
- goto ERROR;
- }
- */
- if (strlen(isfname) + 5 >= MAXPATHLEN)
- buffer = (char*) malloc(strlen(isfname) + 5);
- else
- buffer = Buffer;
- (void)sprintf(buffer,"%s.rec", isfname);
- (void)unlink(buffer);
- (void)sprintf(buffer,"%s.ind", isfname);
- (void)unlink(buffer);
- (void)sprintf(buffer,"%s.var", isfname);
- (void)unlink(buffer);
- (void)sprintf(namebuf, "%s~", isfname);
- (void)print("Renaming ISAM file '%s' to '%s'...\n",
- namebuf, isfname);
- if (isrename(namebuf, isfname) != ISOK) {
- cmd_error("isrename", print);
- goto ERROR;
- }
- /*
- * Re-open the file and add keys.
- */
- if (ldshort(cntlpg + CP_NKEYS_OFF) > 0) {
- (void)print("Adding keys...\n");
- if ((isfd = isopen(isfname, ISEXCLLOCK + ISINOUT +
- (varflag?ISVARLEN:0))) == ISERROR) {
- cmd_error("isopen", print);
- goto ERROR;
- }
-
- for (i = 0; i < ldshort(cntlpg + CP_NKEYS_OFF); i++) {
- ldkey(&keydesc2, cntlpg + CP_KEYS_OFF + i * K2_LEN);
- _iskey_itox(&keydesc2, &keydesc);
- if (keydesc.k_nparts == 0) /* special case for no primary */
- continue;
- printkey (i+1, &keydesc, print);
- if (i == 0) {
- if (isaddprimary(isfd, &keydesc) == ISERROR) {
- cmd_error("isaddprimary", print);
- (void)isclose(isfd);
- goto ERROR;
- }
- }
- else {
- if (isaddindex(isfd, &keydesc) == ISERROR) {
- cmd_error("isaddindex", print);
- (void)isclose(isfd);
- goto ERROR;
- }
- }
- }
- }
- (void)isclose(isfd);
- (void)sigprocmask(SIG_SETMASK, &oldmask, NULL);
- print("...File repaired\n");
- if (buffer != Buffer) free(buffer);
- return (ISOK);
- ERROR:
- (void)print("\007Didn't repair ISAM file '%s'\n", isfname);
- if(datfd != -1) {
- close(datfd);
- }
- if(indfd != -1) {
- close(indfd);
- }
- if(varfd != -1) {
- close(varfd);
- }
- (void)isclose(isfd);
- if (namebuf != nameBuf) free(namebuf);
- if (buffer != Buffer) free(buffer);
- return (ISERROR);
- }
- /******* low level data access used by the 'repair' utility ******************/
- static char recordbuffer[ISMAXRECLEN + LONGSIZE];
- /* rp_readcntlpg() - Read the control page */
- Static int
- rp_readcntlpg(int datfd, char *cntlpg)
- {
- if (read (datfd, cntlpg, ISCNTLSIZE) != ISCNTLSIZE)
- return (ISERROR);
- return (ISOK);
- }
- /* rp_readrecord_f() - Read a record from .rec file */
- Static char *
- rp_readrecord_f(int datfd, long offset, int reclen)
- {
- if (lseek(datfd, offset, 0) != offset)
- return ((char *) NULL);
- if (read(datfd, recordbuffer, reclen + 1) != (reclen + 1))
- return ((char *) NULL);
- if (recordbuffer[0] == FL_RECDELETED)
- return ((char *) NULL);
- return (recordbuffer + 1);
- }
- /* rp_readrecord_v() - Read a record from .rec file */
- Static char *
- rp_readrecord_v(int datfd, int varfd, long offset, int minreclen, int maxreclen)
- {
- long tailoff;
- char frameheadbuf [2 * SHORTSIZE];
- int taillen;
-
- if (lseek(datfd, offset, 0) != offset)
- return ((char *) NULL);
- if (read(datfd, recordbuffer, minreclen + LONGSIZE) != (minreclen + LONGSIZE))
- return ((char *) NULL);
- if ((tailoff = ldlong(recordbuffer)) == VL_RECDELETED)
- return ((char *) NULL);
- isreclen = minreclen;
- /* Recover tail of the record */
- if (tailoff != VL_RECNOTAIL) {
- if (lseek(varfd, tailoff, 0) != tailoff)
- goto OKEXIT;
- if (read(varfd, frameheadbuf, 2 * SHORTSIZE) != 2 * SHORTSIZE)
- goto OKEXIT;
- taillen = (int) ldshort(frameheadbuf + VR_TAILLEN_OFF);
- if (taillen <= 0 || taillen + minreclen > maxreclen)
- goto OKEXIT;
- if (read(varfd, recordbuffer + LONGSIZE + isreclen, taillen) != taillen)
- goto OKEXIT;
- isreclen += taillen;
- }
- OKEXIT:
- return (recordbuffer + LONGSIZE);
- }
- static int
- isnoprintf(const char *s, ...)
- {
- return(0);
- }
- static int
- printkey(int n, struct keydesc *pkdesc, int (*print)(const char *, ...))
- {
- int i;
- struct keypart *pk;
- if (pkdesc->k_nparts == 0) {
- print("%3d: --- NO PRIMARY KEY ---\n", n);
- return 0;
- }
- if (n == 1)
- print("P%3d: %s ", n, (pkdesc->k_flags&ISDUPS) ?
- "DUPS " : "NODUPS");
- else
- print(" %3d: %s ", n, (pkdesc->k_flags&ISDUPS) ?
- "DUPS " : "NODUPS");
- for (i = 0; i < pkdesc->k_nparts; i++) {
- pk = pkdesc->k_part + i;
- print(" %d%c%d%s", pk->kp_start,
- typeletter(pk->kp_type & ~ISDESC), pk->kp_leng,
- (pk->kp_type & ISDESC)?"D":" ");
- }
- print("\n");
- return 1;
- }
- static void
- cmd_error(const char *str, int (*print)(const char *, ...))
- {
- (void)print("%s: ISAM error %d\n", str, iserrno);
- }
- static int
- typeletter(int type)
- {
- switch (type) {
- case INTTYPE:
- return 'I';
- case LONGTYPE:
- return 'L';
- case FLOATTYPE:
- return 'F';
- case DOUBLETYPE:
- return 'D';
- case CHARTYPE:
- return 'C';
- case BINTYPE:
- return 'B';
- default:
- assert(0);
- }
- /* NOTREACHED */
- }
|