-
Rob Swindell authored
This won't impact Synchronet as it has a separate signal handling thread, but we still need to behave properly for processes that don't. I'm also saying that ENOMEM does not indicate a disconnection, though it may be better to pretend it was disconnected...
Rob Swindell authoredThis won't impact Synchronet as it has a separate signal handling thread, but we still need to behave properly for processes that don't. I'm also saying that ENOMEM does not indicate a disconnection, though it may be better to pretend it was disconnected...
fixsmb.c 9.21 KiB
/* Synchronet message base (SMB) index re-generator */
/****************************************************************************
* @format.tab-size 4 (Plain Text/Source Code File Header) *
* @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
* *
* Copyright Rob Swindell - http://www.synchro.net/copyright.html *
* *
* This program 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 *
* of the License, or (at your option) any later version. *
* See the GNU General Public License for more details: gpl.txt or *
* http://www.fsf.org/copyleft/gpl.html *
* *
* For Synchronet coding style and modification guidelines, see *
* http://www.synchro.net/source.html *
* *
* Note: If this box doesn't appear square, then you need to fix your tabs. *
****************************************************************************/
#include <stdio.h>
#include <stdlib.h> /* atoi, qsort */
#include <stdbool.h>
#include <string.h> /* strnicmp */
#include <ctype.h> /* toupper */
#include "smblib.h"
#include "genwrap.h" /* PLATFORM_DESC */
#include "str_list.h" /* strList API */
#include "crc16.h"
#include "git_branch.h"
#include "git_hash.h"
smb_t smb;
BOOL renumber=FALSE;
BOOL rehash=FALSE;
BOOL fixnums=FALSE;
BOOL smb_undelete=FALSE;
char* usage="usage: fixsmb [-renumber] [-undelete] [-fixnums] [-rehash] <smb_file> [[smb_file] [...]]";
int compare_index(const idxrec_t* idx1, const idxrec_t* idx2)
{
return(idx1->number - idx2->number);
}
void sort_index(smb_t* smb)
{
ulong l;
uint8_t* idxbuf;
size_t idxreclen = smb_idxreclen(smb);
printf("Sorting index... ");
if((idxbuf = malloc(idxreclen * smb->status.total_msgs))==NULL) {
perror("malloc");
return;
}
rewind(smb->sid_fp);
for(l=0;l<smb->status.total_msgs;l++)
if(smb_fread(smb, idxbuf + (l * idxreclen), idxreclen, smb->sid_fp) != idxreclen) {
perror("reading index");
break;
}
qsort(idxbuf, l, idxreclen
,(int(*)(const void*, const void*))compare_index);
rewind(smb->sid_fp);
chsize(fileno(smb->sid_fp),0L); /* Truncate the index */
printf("\nRe-writing index... \n");
smb->status.total_msgs=l;
for(l=0;l<smb->status.total_msgs;l++) {
if(smb_fwrite(smb, idxbuf + (l * idxreclen), idxreclen, smb->sid_fp) != idxreclen) {
perror("writing index");
break;
}
}
free(idxbuf);
printf("\n");
}
bool we_locked_the_base = false;
void unlock_msgbase(void)
{
int i;
if(we_locked_the_base && smb_islocked(&smb) && (i=smb_unlock(&smb))!=0)
printf("smb_unlock returned %d: %s\n",i,smb.last_error);
else
we_locked_the_base = false;
}
int fixsmb(char* sub)
{
char* p;
char* text;
char c;
int i,w;
ulong l,size,n;
off_t length;
smbmsg_t msg;
uint32_t* numbers = NULL;
long total = 0;
BOOL dupe_msgnum;
uint32_t highest = 0;
memset(&smb,0,sizeof(smb));
SAFECOPY(smb.file,sub);
if((p=getfext(smb.file))!=NULL && stricmp(p,".shd")==0)
*p=0; /* Chop off .shd extension, if supplied on command-line */
char path[MAX_PATH+1];
SAFEPRINTF(path, "%s.shd", smb.file);
if(!fexistcase(path)) {
printf("%s does not exist\n", path);
exit(1);
}
printf("Opening %s\n",smb.file);
if((i=smb_open(&smb))!=0) {
printf("smb_open returned %d: %s\n",i,smb.last_error);
exit(1);
}
if((i=smb_lock(&smb))!=0) {
printf("smb_lock returned %d: %s\n",i,smb.last_error);
exit(1);
}
we_locked_the_base = true;
if((i=smb_locksmbhdr(&smb))!=0) {
smb_close(&smb);
printf("smb_locksmbhdr returned %d: %s\n",i,smb.last_error);
exit(1);
}
if((i=smb_getstatus(&smb))!=0) {
smb_unlocksmbhdr(&smb);
smb_close(&smb);
printf("smb_getstatus returned %d: %s\n",i,smb.last_error);
exit(1);
}
uint32_t last_msg = smb.status.last_msg;
if(!(smb.status.attr&SMB_HYPERALLOC)) {
if((i=smb_open_ha(&smb))!=0) {
smb_close(&smb);
printf("smb_open_ha returned %d: %s\n",i,smb.last_error);
exit(1);
}
if((i=smb_open_da(&smb))!=0) {
smb_close(&smb);
printf("smb_open_da returned %d: %s\n",i,smb.last_error);
exit(1);
}
rewind(smb.sha_fp);
chsize(fileno(smb.sha_fp),0L); /* Truncate the header allocation file */
rewind(smb.sda_fp);
chsize(fileno(smb.sda_fp),0L); /* Truncate the data allocation file */
}
rewind(smb.sid_fp);
chsize(fileno(smb.sid_fp),0L); /* Truncate the index */
if(renumber || rehash) {
printf("Truncating hash file (due to renumbering/rehashing)\n");
if((i=smb_open_hash(&smb))!=SMB_SUCCESS) {
printf("smb_open_hash returned %d: %s\n", i, smb.last_error);
exit(1);
}
chsize(fileno(smb.hash_fp),0L);
}
if(!(smb.status.attr&SMB_HYPERALLOC)) {
length=filelength(fileno(smb.sdt_fp));
/* TODO: LE Only */
w=0;
for(l=0;l<length;l+=SDT_BLOCK_LEN) /* Init .SDA file to NULL */
fwrite(&w,2,1,smb.sda_fp);
length=filelength(fileno(smb.shd_fp));
c=0;
for(l=smb.status.header_offset;l<length;l+=SHD_BLOCK_LEN) /* Init .SHD file to NULL */
fwrite(&c,1,1,smb.sha_fp);
} else
length=filelength(fileno(smb.shd_fp));
n=0; /* message offset */
for(l=smb.status.header_offset;l<length;l+=size) {
size=SHD_BLOCK_LEN;
printf("\r%2lu%% ",(long)(100.0/((float)length/l)));
fflush(stdout);
ZERO_VAR(msg);
msg.idx.offset=l;
if((i=smb_lockmsghdr(&smb,&msg))!=0) {
printf("\n(%06lX) smb_lockmsghdr returned %d:\n%s\n",l,i,smb.last_error);
continue;
}
i=smb_getmsghdr(&smb,&msg);
smb_unlockmsghdr(&smb,&msg);
if(i!=0) {
printf("\n(%06lX) smb_getmsghdr returned %d:\n%s\n",l,i,smb.last_error);
continue;
}
size=smb_hdrblocks(smb_getmsghdrlen(&msg))*SHD_BLOCK_LEN;
printf("#%-5"PRIu32" (%06lX) %-25.25s ",msg.hdr.number,l
,msg.hdr.type == SMB_MSG_TYPE_FILE ? msg.subj : msg.from);
dupe_msgnum = FALSE;
for(i=0; i<total && !dupe_msgnum; i++)
if(msg.hdr.number == numbers[i])
dupe_msgnum = TRUE;
if(dupe_msgnum && fixnums && msg.hdr.number >= last_msg) {
printf("Fixed message number (%lu -> %lu)\n", (ulong)msg.hdr.number, (ulong)highest + 1);
msg.hdr.number = highest + 1;
dupe_msgnum = FALSE;
}
if(!dupe_msgnum) {
total++;
if((numbers = realloc(numbers, total * sizeof(*numbers))) == NULL) {
fprintf(stderr, "realloc failure: %lu\n", total * sizeof(*numbers));
return EXIT_FAILURE;
}
numbers[total-1] = msg.hdr.number;
}
if(dupe_msgnum)
msg.hdr.attr|=MSG_DELETE;
else if(smb_undelete)
msg.hdr.attr&=~MSG_DELETE;
/* Create hash record */
if(msg.hdr.attr&MSG_DELETE)
text=NULL;
else
text=smb_getmsgtxt(&smb,&msg,GETMSGTXT_BODY_ONLY);
i=smb_hashmsg(&smb,&msg,(uchar*)text,TRUE /* update */);
if(i!=SMB_SUCCESS)
printf("!ERROR %d hashing message\n", i);
if(text!=NULL)
free(text);
/* Index the header */
if(dupe_msgnum)
printf("Not indexing duplicate message number (%u)\n", msg.hdr.number);
else if(msg.hdr.attr&MSG_DELETE)
printf("Not indexing deleted message\n");
else if(msg.hdr.number==0)
printf("Not indexing invalid message number (0)!\n");
else {
msg.idx_offset=n;
if(renumber)
msg.hdr.number=n+1;
if(msg.hdr.number > highest)
highest = msg.hdr.number;
if(msg.hdr.netattr&MSG_INTRANSIT) {
printf("Removing 'in transit' attribute\n");
msg.hdr.netattr&=~MSG_INTRANSIT;
}
if((i=smb_putmsg(&smb,&msg))!=0) {
printf("\nsmb_putmsg returned %d: %s\n",i,smb.last_error);
continue;
}
n++;
}
if(!(smb.status.attr&SMB_HYPERALLOC)) {
/**************************/
/* Allocate header blocks */
/**************************/
fseek(smb.sha_fp,(l-smb.status.header_offset)/SHD_BLOCK_LEN,SEEK_SET);
if(msg.hdr.attr&MSG_DELETE) c=0; /* mark as free */
else c=1; /* or allocated */
for(i=0;i<(int)(size/SHD_BLOCK_LEN);i++)
fputc(c,smb.sha_fp);
/************************/
/* Allocate data blocks */
/************************/
if(!(msg.hdr.attr&MSG_DELETE))
smb_incmsg_dfields(&smb,&msg,1);
}
smb_freemsgmem(&msg);
}
printf("\r%79s\r100%%\n","");
smb.status.total_msgs=n;
if(renumber)
smb.status.last_msg = highest;
else {
if(highest > smb.status.last_msg)
smb.status.last_msg = highest;
sort_index(&smb);
}
printf("Saving message base status (%lu total messages).\n",n);
if((i=smb_putstatus(&smb))!=0)
printf("\nsmb_putstatus returned %d: %s\n",i,smb.last_error);
smb_unlocksmbhdr(&smb);
printf("Closing message base.\n");
smb_close(&smb);
unlock_msgbase();
printf("Done.\n");
FREE_AND_NULL(numbers);
return(0);
}
int main(int argc, char **argv)
{
int i;
str_list_t list;
int retval = EXIT_SUCCESS;
printf("\nFIXSMB v3.19-%s %s/%s SMBLIB %s - Rebuild Synchronet Message Base\n\n"
,PLATFORM_DESC, GIT_BRANCH, GIT_HASH, smb_lib_ver());
list=strListInit();
for(i=1;i<argc;i++) {
if(argv[i][0]=='-') {
if(!stricmp(argv[i],"-renumber"))
renumber=TRUE;
else if(!stricmp(argv[i],"-rehash"))
rehash=TRUE;
else if(!stricmp(argv[i],"-undelete"))
smb_undelete=TRUE;
else if(!stricmp(argv[i],"-fixnums"))
fixnums=TRUE;
} else
strListPush(&list,argv[i]);
}
if(!strListCount(list)) {
puts(usage);
exit(1);
}
atexit(unlock_msgbase);
for(i=0;list[i]!=NULL && retval == EXIT_SUCCESS;i++)
retval = fixsmb(list[i]);
return retval;
}