/* * hptsqfix - rebuilding squish index and some info in sqd * made by Serguei Revtov 2:5021/19.1 * from hptUtil by Fedor Lizunkov 2:5020/960@Fidonet * * This file is part of HPT. * * HPT is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * HPT is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with HPT; see the file COPYING. If not, write to the Free * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. ***************************************************************************** */ #include #include #include #include #if !defined(UNIX) && !defined(SASC) #include #endif #include #include #include #if !defined(UNIX) && !defined(SASC) #include #endif #if !(defined(_MSC_VER) && (_MSC_VER >= 1200)) #include #endif #include #include #include #define fop_wpb (O_CREAT | O_TRUNC | O_RDWR | O_BINARY) #define fop_rpb (O_RDWR | O_BINARY) #define VERSION "v.1.2.4-release" int Open_File(char *name, word mode) { int handle; #ifdef UNIX handle = sopen(name, mode, SH_DENYNONE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); #else handle = sopen(name, mode, SH_DENYNONE, S_IREAD | S_IWRITE); #endif if (handle<0) fprintf(stderr, "Can't open file '%s'\n", name); return handle; } void usage() { fprintf(stderr, "hptsqfix - squish base repairing utility, %s\n", VERSION); fprintf(stderr, "Usage: hptsqfix [-f] [-e] [-u] [-s] areafilename ...\n"); fprintf(stderr, " -f - try to find next header after broken msg\n"); fprintf(stderr, " -e - 'areafilename' has extension, strip it\n"); fprintf(stderr, " -u - undelete (restore deleted messages)\n"); fprintf(stderr, " -s - sort messages by date written\n"); exit(-1); } int findhdr(int SqdHandle) { off_t pos; dword i=0, rc=1, stop=0; unsigned char chr; unsigned char sqhdrid[]={0x53, 0x44, 0xae, 0xaf}; fprintf(stderr, "Searching valid header ID... "); pos = tell(SqdHandle); do { if (read (SqdHandle, &chr, 1) == 1) { pos++; if (chr == sqhdrid[i]) { i++; if (i==4) { fprintf(stderr, " Wow! Found at pos %lu\n", (unsigned long) pos-4); lseek(SqdHandle, pos-4, SEEK_SET); rc = 0; stop = 1; } } else { if (chr == sqhdrid[0]) i = 1; else i = 0; } } else { fprintf(stderr, " not found\n"); stop = 1; rc = 1; } } while (!stop); return rc; } int tryfind=0; int unDelete=0; int mSort=0; typedef struct { time_t msgTime; dword frame_pos; } sortedbase; sortedbase *SortedBase = NULL; static int cmp_msgEntry(const void *a, const void *b) { const sortedbase* r1 = (sortedbase*)a; const sortedbase* r2 = (sortedbase*)b; if( r1->msgTime > r2->msgTime) return 1; else if( r1->msgTime < r2->msgTime) return -1; return 0; } int repair(char *areaName) { int SqdHandle; int NewSqdHandle, NewSqiHandle; dword i; long saved=0; int stop; int firstmsg=1; int sayFree=0; dword frame_length = 0; dword num_msg = 0; char *sqd, *newsqd, *newsqi, *text; SQBASE sqbase; SQHDR sqhdr; XMSG xmsg; SQIDX sqidx; size_t maxMsgLen; struct tm tmdate; sqd = (char*)malloc(strlen(areaName)+5); newsqd = (char*)malloc(strlen(areaName)+5); newsqi = (char*)malloc(strlen(areaName)+5); sprintf(sqd, "%s%s", areaName, EXT_SQDFILE); SqdHandle = Open_File(sqd, fop_rpb); if (SqdHandle == -1) { free(sqd); free(newsqd); free(newsqi); return 0; } /* endif */ sprintf(newsqd, "%s.tmd", areaName); sprintf(newsqi, "%s.tmi", areaName); NewSqdHandle = Open_File(newsqd, fop_wpb); if (NewSqdHandle == -1) { free(sqd); free(newsqd); free(newsqi); close(SqdHandle); return 0; } /* endif */ NewSqiHandle = Open_File(newsqi, fop_wpb); if (NewSqiHandle == -1) { free(sqd); free(newsqd); free(newsqi); close(NewSqdHandle); close(SqdHandle); return 0; } /* endif */ lseek(SqdHandle, 0L, SEEK_END); maxMsgLen = tell(SqdHandle) - SQBASE_SIZE - SQHDR_SIZE; lseek(SqdHandle, 0L, SEEK_SET); if (lock(SqdHandle, 0, 1) == 0) { read_sqbase(SqdHandle, &sqbase); if(mSort) { num_msg = sqbase.num_msg; SortedBase = calloc(sizeof(sortedbase),num_msg); if(!SortedBase) { fprintf(stderr, "\nNot enough memory to sort base\n"); mSort = 0; } } sqbase.num_msg = 0; sqbase.high_msg = 0; sqbase.skip_msg = 0; sqbase.begin_frame = SQBASE_SIZE; sqbase.last_frame = sqbase.begin_frame; sqbase.free_frame = sqbase.last_free_frame = 0; sqbase.end_frame = sqbase.begin_frame; write_sqbase(NewSqdHandle, &sqbase); for (stop = 0, i = 1; !stop; i++) { fprintf(stderr, "Msg %ld", i); if (read_sqhdr(SqdHandle, &sqhdr) == 0) { fprintf(stderr, "... end"); stop++; } if(sqhdr.frame_length != sqhdr.msg_length) fprintf(stderr, "\nFrame Length != Msg Length %ld:%ld\n",sqhdr.frame_length ,sqhdr.msg_length); if (stop==0 && sqhdr.id != SQHDRID) { fprintf(stderr, "\nLooks like Message header is damaged\n"); if ( tryfind ) { stop = findhdr(SqdHandle); continue; }else{ fprintf(stderr, "\nYou may want to use -f parameter\n"); stop++; } } if (stop==0 && sqhdr.msg_length <= XMSG_SIZE) { fprintf(stderr, "\nMessage body is too short: %ld\n",sqhdr.msg_length); if ( tryfind ) { stop = findhdr(SqdHandle); continue; }else{ fprintf(stderr, "\nYou may want to use -f parameter\n"); stop++; } } if (stop==0 && sqhdr.frame_length > maxMsgLen) { fprintf(stderr, "\nFrame is larger than rest of file\nLooks like Message header is damaged\n"); if ( tryfind ) { stop = findhdr(SqdHandle); continue; }else{ fprintf(stderr, "\nYou may want to use -f parameter\n"); stop++; } } if (!stop) { if (sqhdr.frame_type != FRAME_normal) { if (unDelete != 0 && sqhdr.frame_type == FRAME_free) { sqhdr.frame_type = FRAME_normal; fprintf(stderr, "... free, restoring\n"); } else { sayFree = 1; fprintf(stderr, "... free\r"); lseek(SqdHandle, sqhdr.frame_length, SEEK_CUR); continue; } } read_xmsg(SqdHandle, &xmsg); text = (char*)calloc(sqhdr.frame_length, sizeof(char*)); farread(SqdHandle, text, (sqhdr.frame_length - XMSG_SIZE)); memcpy(text,text,sqhdr.msg_length); frame_length = sqhdr.frame_length; sqhdr.frame_length = sqhdr.msg_length; if (firstmsg) { sqhdr.prev_frame = 0; firstmsg=0; } else { sqhdr.prev_frame = sqbase.last_frame; } /* endif */ sqhdr.next_frame = tell(NewSqdHandle) + SQHDR_SIZE + sqhdr.msg_length; sqbase.last_frame = tell(NewSqdHandle); sqidx.ofs = sqbase.last_frame; if(mSort) { if(num_msg == sqbase.num_msg) { num_msg = sqbase.num_msg+1; SortedBase = realloc(SortedBase,num_msg*sizeof(sortedbase)); if(!SortedBase) { fprintf(stderr, "\nNot enough memory to sort base\n"); mSort = 0; } } DosDate_to_TmDate((union stamp_combo *)&xmsg.date_written, &tmdate); SortedBase[sqbase.num_msg].frame_pos = sqbase.last_frame; SortedBase[sqbase.num_msg].msgTime = mktime(&tmdate); } write_sqhdr(NewSqdHandle, &sqhdr); write_xmsg(NewSqdHandle, &xmsg); farwrite(NewSqdHandle, text, (sqhdr.msg_length - XMSG_SIZE)); sqbase.end_frame = tell(NewSqdHandle); sqidx.hash = SquishHash(xmsg.to); if (xmsg.attr & MSGREAD) { sqidx.hash |= (dword) 0x80000000L; } sqidx.umsgid = sqbase.num_msg+1; write_sqidx(NewSqiHandle, &sqidx, 1); free(text); sqbase.num_msg++; sqbase.high_msg = sqbase.num_msg; saved++; if (sayFree) { fprintf(stderr, " "); sayFree=0; } fprintf(stderr, "\r"); maxMsgLen -= frame_length; } } /* endfor */ fprintf(stderr, "\n%ld messages read\n", i-2); lseek(NewSqiHandle, SQIDX_SIZE, SEEK_END); read_sqidx(NewSqiHandle, &sqidx, 1); lseek(NewSqdHandle, sqidx.ofs, SEEK_SET); read_sqhdr(NewSqdHandle, &sqhdr); sqhdr.next_frame = 0; lseek(NewSqdHandle, sqidx.ofs, SEEK_SET); write_sqhdr(NewSqdHandle, &sqhdr); lseek(NewSqdHandle, 0L, SEEK_SET); write_sqbase(NewSqdHandle, &sqbase); unlock(SqdHandle, 0, 1); close(NewSqdHandle); close(NewSqiHandle); close(SqdHandle); if(mSort) { num_msg = sqbase.num_msg; fprintf(stderr, "\nSorting msgbase...\n"); qsort( (void*)SortedBase, num_msg, sizeof(sortedbase), cmp_msgEntry ); sprintf(sqd, "%s.tmd", areaName ); SqdHandle = Open_File(sqd, fop_rpb); if (SqdHandle == -1) { free(sqd); free(newsqd); free(newsqi); return 0; } /* endif */ sprintf(newsqd, "%s.tsd", areaName); sprintf(newsqi, "%s.tsi", areaName); NewSqdHandle = Open_File(newsqd, fop_wpb); if (NewSqdHandle == -1) { free(sqd); free(newsqd); free(newsqi); close(SqdHandle); return 0; } /* endif */ NewSqiHandle = Open_File(newsqi, fop_wpb); if (NewSqiHandle == -1) { free(sqd); free(newsqd); free(newsqi); close(NewSqdHandle); close(SqdHandle); return 0; } /* endif */ lseek(SqdHandle, 0L, SEEK_END); maxMsgLen = tell(SqdHandle) - SQBASE_SIZE - SQHDR_SIZE; lseek(SqdHandle, 0L, SEEK_SET); if (lock(SqdHandle, 0, 1) == 0) { firstmsg=0; read_sqbase(SqdHandle, &sqbase); sqbase.num_msg = 0; sqbase.high_msg = 0; sqbase.skip_msg = 0; sqbase.begin_frame = SQBASE_SIZE; sqbase.last_frame = sqbase.begin_frame; sqbase.free_frame = sqbase.last_free_frame = 0; sqbase.end_frame = sqbase.begin_frame; write_sqbase(NewSqdHandle, &sqbase); for (i = 0; i < num_msg; i++) { lseek(SqdHandle, SortedBase[i].frame_pos , SEEK_SET); if (read_sqhdr(SqdHandle, &sqhdr) == 0) { fprintf(stderr, "... end"); break; } read_xmsg(SqdHandle, &xmsg); text = (char*)calloc(sqhdr.frame_length, sizeof(char*)); farread(SqdHandle, text, (sqhdr.frame_length - XMSG_SIZE)); memcpy(text,text,sqhdr.msg_length); if (firstmsg) { sqhdr.prev_frame = 0; firstmsg=0; } else { sqhdr.prev_frame = sqbase.last_frame; } /* endif */ sqhdr.next_frame = tell(NewSqdHandle) + SQHDR_SIZE + sqhdr.msg_length; sqbase.last_frame = tell(NewSqdHandle); sqidx.ofs = sqbase.last_frame; write_sqhdr(NewSqdHandle, &sqhdr); write_xmsg(NewSqdHandle, &xmsg); farwrite(NewSqdHandle, text, (sqhdr.msg_length - XMSG_SIZE)); sqbase.end_frame = tell(NewSqdHandle); sqidx.hash = SquishHash(xmsg.to); if (xmsg.attr & MSGREAD) { sqidx.hash |= (dword) 0x80000000L; } sqidx.umsgid = sqbase.num_msg+1; write_sqidx(NewSqiHandle, &sqidx, 1); free(text); sqbase.num_msg++; sqbase.high_msg = sqbase.num_msg; maxMsgLen -= sqhdr.frame_length; } lseek(NewSqiHandle, SQIDX_SIZE, SEEK_END); read_sqidx(NewSqiHandle, &sqidx, 1); lseek(NewSqdHandle, sqidx.ofs, SEEK_SET); read_sqhdr(NewSqdHandle, &sqhdr); sqhdr.next_frame = 0; lseek(NewSqdHandle, sqidx.ofs, SEEK_SET); write_sqhdr(NewSqdHandle, &sqhdr); lseek(NewSqdHandle, 0L, SEEK_SET); write_sqbase(NewSqdHandle, &sqbase); unlock(SqdHandle, 0, 1); close(NewSqdHandle); close(NewSqiHandle); close(SqdHandle); } } } else { close(NewSqdHandle); close(NewSqiHandle); close(SqdHandle); } /* endif */ free(sqd); free(newsqd); free(newsqi); fprintf(stderr, "%ld messages saved\n", saved); return 0; } int main(int argc, char *argv[]) { int i, j, extIndx; int stripExt=0; if (argc < 2) usage(); for (i=1; i 0) { argv[i][extIndx] = '\0'; } else { fprintf(stderr, "Warning: loose extension in '%s'\n", argv[i]); } } fprintf(stderr, "Repairing area '%s'\n", argv[i]); repair(argv[i]); fprintf(stderr, "Done\n\n"); } } return 0; }