Synchronet now requires the libarchive development package (e.g. libarchive-dev on Debian-based Linux distros, libarchive.org for more info) to build successfully.

delfiles.c 8.93 KB
Newer Older
1
/* delfiles.c */
deuce's avatar
deuce committed
2

3 4 5 6 7 8 9 10
/* Program to delete expired files from a Synchronet file database */

/* $Id$ */

/****************************************************************************
 * @format.tab-size 4		(Plain Text/Source Code File Header)			*
 * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
 *																			*
11
 * Copyright Rob Swindell - http://www.synchro.net/copyright.html			*
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
 *																			*
 * 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										*
 *																			*
 * Anonymous FTP access to the most recent released source is available at	*
 * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
 *																			*
 * Anonymous CVS access to the development source and modification history	*
 * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
 * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
 *     (just hit return, no password is necessary)							*
 * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
 *																			*
 * For Synchronet coding style and modification guidelines, see				*
 * http://www.synchro.net/source.html										*
 *																			*
 * You are encouraged to submit any modifications (preferably in Unix diff	*
 * format) via e-mail to mods@synchro.net									*
 *																			*
 * Note: If this box doesn't appear square, then you need to fix your tabs.	*
 ****************************************************************************/
deuce's avatar
deuce committed
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53

#include "sbbs.h"

#define DELFILES_VER "1.01"

char tmp[256];
char *crlf="\r\n";

#define MAX_NOTS	25

#define ALL 	(1L<<0)
#define OFFLINE (1L<<1)
#define NO_LINK (1L<<2)
#define REPORT	(1L<<3)

void bail(int code)
{
54
	exit(code);
deuce's avatar
deuce committed
55 56
}

deuce's avatar
deuce committed
57
long lputs(char *str)
deuce's avatar
deuce committed
58 59 60 61
{
    char tmp[256];
	int i,j,k;

62 63 64 65 66 67 68 69
	j=strlen(str);
	for(i=k=0;i<j;i++)      /* remove CRs */
		if(str[i]==CR && str[i+1]==LF)
			continue;
		else
			tmp[k++]=str[i];
	tmp[k]=0;
	return(fputs(tmp,stdout));
deuce's avatar
deuce committed
70 71 72 73 74 75
}

/****************************************************************************/
/* Performs printf() through local assembly routines                        */
/* Called from everywhere                                                   */
/****************************************************************************/
76
int lprintf(const char *fmat, ...)
deuce's avatar
deuce committed
77 78 79 80 81
{
	va_list argptr;
	char sbuf[256];
	int chcount;

82 83 84 85 86
	va_start(argptr,fmat);
	chcount=vsprintf(sbuf,fmat,argptr);
	va_end(argptr);
	lputs(sbuf);
	return(chcount);
deuce's avatar
deuce committed
87 88 89 90 91 92
}

int main(int argc, char **argv)
{
	char str[256],fname[MAX_PATH+1],not[MAX_NOTS][9],nots=0,*p;
	int i,j,dirnum,libnum,file;
93
	ulong l,m;
deuce's avatar
deuce committed
94 95 96 97 98
	long misc=0;
	time_t now;
	file_t workfile;
	scfg_t cfg;
	glob_t gl;
deuce's avatar
deuce committed
99
	uchar *ixbbuf;
deuce's avatar
deuce committed
100

101
	setvbuf(stdout,NULL,_IONBF,0);
deuce's avatar
deuce committed
102

103 104
	fprintf(stderr,"\nDELFILES Version %s (%s) - Removes files from Synchronet "
		"Filebase\n" ,DELFILES_VER, PLATFORM_DESC );
deuce's avatar
deuce committed
105

106 107 108 109 110 111 112 113 114 115
	if(argc<2) {
		printf("\n   usage: DELFILES <dir_code or * for ALL> [switches]\n");
		printf("\nswitches: -LIB name All directories of specified library\n");
		printf("          -NOT code Exclude specific directory\n");
		printf("          -OFF      Remove files that are offline "
			"(don't exist on disk)\n");
		printf("          -NOL      Remove files with no link "
			"(don't exist in database)\n");
		printf("          -RPT      Report findings only "
			"(don't delete any files)\n");
116 117
		return(0); 
	}
deuce's avatar
deuce committed
118

119 120 121 122 123 124 125 126
	p=getenv("SBBSCTRL");
	if(p==NULL) {
		printf("\nSBBSCTRL environment variable not set.\n");
	#ifdef __unix__
		printf("\nExample: export SBBSCTRL=/sbbs/ctrl\n");
	#else
		printf("\nExample: SET SBBSCTRL=C:\\SBBS\\CTRL\n");
	#endif
127 128
		return(1); 
	}
deuce's avatar
deuce committed
129

130 131 132 133
	memset(&cfg, 0, sizeof(cfg));
	cfg.size=sizeof(cfg);
	SAFECOPY(cfg.ctrl_dir, p);
	backslash(cfg.ctrl_dir);
deuce's avatar
deuce committed
134

135 136
	load_cfg(&cfg, NULL, TRUE, str);
	chdir(cfg.ctrl_dir);
deuce's avatar
deuce committed
137

138 139 140 141 142 143 144
	dirnum=libnum=-1;
	if(argv[1][0]=='*')
		misc|=ALL;
	else if(argv[1][0]!='/' && argv[1][0]!='-') {
		strupr(argv[1]);
		for(i=0;i<cfg.total_dirs;i++)
			if(!stricmp(argv[1],cfg.dir[i]->code))
deuce's avatar
deuce committed
145
				break;
146 147
		if(i>=cfg.total_dirs) {
			printf("\nDirectory code '%s' not found.\n",argv[1]);
148 149 150 151
			return(1); 
		}
		dirnum=i; 
	}
152 153 154 155
	for(i=1;i<argc;i++) {
		if(!stricmp(argv[i]+1,"LIB")) {
			if(dirnum!=-1) {
				printf("\nBoth directory code and /LIB parameters were used.\n");
156 157
				return(1); 
			}
158 159 160
			i++;
			if(i>=argc) {
				printf("\nLibrary short name must follow /LIB parameter.\n");
161 162
				return(1); 
			}
163 164 165 166 167 168
			strupr(argv[i]);
			for(j=0;j<cfg.total_libs;j++)
				if(!stricmp(cfg.lib[j]->sname,argv[i]))
					break;
			if(j>=cfg.total_libs) {
				printf("\nLibrary short name '%s' not found.\n",argv[i]);
169 170 171 172
				return(1); 
			}
			libnum=j; 
		}
173 174 175 176
		else if(!stricmp(argv[i]+1,"NOT")) {
			if(nots>=MAX_NOTS) {
				printf("\nMaximum number of /NOT options (%u) exceeded.\n"
					,MAX_NOTS);
177 178
				return(1); 
			}
179 180 181
			i++;
			if(i>=argc) {
				printf("\nDirectory internal code must follow /NOT parameter.\n");
182 183 184 185
				return(1); 
			}
			sprintf(not[nots++],"%.8s",argv[i]); 
		}
186 187 188 189 190 191 192 193 194
		else if(!stricmp(argv[i]+1,"OFF"))
			misc|=OFFLINE;
		else if(!stricmp(argv[i]+1,"NOL"))
			misc|=NO_LINK;
		else if(!stricmp(argv[i]+1,"RPT"))
			misc|=REPORT;
		else if(!stricmp(argv[i]+1,"ALL")) {
			if(dirnum!=-1) {
				printf("\nBoth directory code and /ALL parameters were used.\n");
195 196
				return(1); 
			}
197 198
			if(libnum!=-1) {
				printf("\nBoth library name and /ALL parameters were used.\n");
199 200 201 202 203
				return(1); 
			}
			misc|=ALL; 
		} 
	}
deuce's avatar
deuce committed
204

205 206 207 208 209 210 211 212
	for(i=0;i<cfg.total_dirs;i++) {
		if(!(misc&ALL) && i!=dirnum && cfg.dir[i]->lib!=libnum)
			continue;
		for(j=0;j<nots;j++)
			if(!stricmp(not[j],cfg.dir[i]->code))
				break;
		if(j<nots)
			continue;
deuce's avatar
deuce committed
213

214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
		if(misc&NO_LINK && cfg.dir[i]->misc&DIR_FCHK) {
			strcpy(tmp,cfg.dir[i]->path);
			sprintf(str,"%s*.*",tmp);
			printf("\nSearching %s for unlinked files\n",str);
			if(!glob(str, GLOB_MARK, NULL, &gl)) {
				for(j=0; j<(int)gl.gl_pathc; j++) {
					/* emulate _A_NORMAL */
					if(isdir(gl.gl_pathv[j]))
						continue;
					if(access(gl.gl_pathv[j], R_OK|W_OK))
						continue;
					padfname(gl.gl_pathv[j],str);
					/* strupr(str); */
					if(!findfile(&cfg, i,str)) {
						sprintf(str,"%s%s",tmp,gl.gl_pathv[j]);
229
						printf("Removing %s (not in database)\n",gl.gl_pathv[j]);
230
						if(!(misc&REPORT) && remove(str))
231 232 233 234
							printf("Error removing %s\n",str); 
					} 
				} 
			}
235 236
			globfree(&gl);
		}
deuce's avatar
deuce committed
237

238 239
		if(!cfg.dir[i]->maxage && !(misc&OFFLINE))
			continue;
deuce's avatar
deuce committed
240

241
		printf("\nScanning %s %s\n",cfg.lib[cfg.dir[i]->lib]->sname,cfg.dir[i]->lname);
deuce's avatar
deuce committed
242

243 244 245 246 247 248
		sprintf(str,"%s%s.ixb",cfg.dir[i]->data_dir,cfg.dir[i]->code);
		if((file=nopen(str,O_RDONLY|O_BINARY))==-1)
			continue;
		l=filelength(file);
		if(!l) {
			close(file);
249 250
			continue; 
		}
251
		if((ixbbuf=malloc(l))==NULL) {
252 253
			close(file);
			printf("\7ERR_ALLOC %s %lu\n",str,l);
254 255
			continue; 
		}
256 257 258 259
		if(read(file,ixbbuf,l)!=(int)l) {
			close(file);
			printf("\7ERR_READ %s %lu\n",str,l);
			free((char *)ixbbuf);
260 261
			continue; 
		}
deuce's avatar
deuce committed
262 263
		close(file);

264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290
		m=0L;
		now=time(NULL);
		while(m<l) {
			memset(&workfile,0,sizeof(file_t));
			for(j=0;j<12 && m<l;j++)
				if(j==8)
					fname[j]='.';
				else
					fname[j]=ixbbuf[m++];
			fname[j]=0;
			strcpy(workfile.name,fname);
			unpadfname(workfile.name,fname);
			workfile.dir=i;
			sprintf(str,"%s%s"
				,workfile.altpath>0 && workfile.altpath<=cfg.altpaths
					? cfg.altpath[workfile.altpath-1]
				: cfg.dir[workfile.dir]->path,fname);
			workfile.datoffset=ixbbuf[m]|((long)ixbbuf[m+1]<<8)
				|((long)ixbbuf[m+2]<<16);
			workfile.dateuled=(ixbbuf[m+3]|((long)ixbbuf[m+4]<<8)
				|((long)ixbbuf[m+5]<<16)|((long)ixbbuf[m+6]<<24));
			workfile.datedled=(ixbbuf[m+7]|((long)ixbbuf[m+8]<<8)
				|((long)ixbbuf[m+9]<<16)|((long)ixbbuf[m+10]<<24));
			m+=11;
			if(cfg.dir[i]->maxage && cfg.dir[i]->misc&DIR_SINCEDL && workfile.datedled
				&& (now-workfile.datedled)/86400L>cfg.dir[i]->maxage) {
					printf("Deleting %s (%ld days since last download)\n",fname
291
						,(long)(now-workfile.datedled)/86400L);
292 293 294 295
					getfiledat(&cfg, &workfile);
					if(!(misc&REPORT)) {
						removefiledat(&cfg, &workfile);
						if(remove(str))
296 297 298
							printf("Error removing %s\n",str); 
					} 
			}
299 300 301 302
			else if(cfg.dir[i]->maxage
				&& !(workfile.datedled && cfg.dir[i]->misc&DIR_SINCEDL)
				&& (now-workfile.dateuled)/86400L>cfg.dir[i]->maxage) {
					printf("Deleting %s (uploaded %ld days ago)\n",fname
303
						,(long)(now-workfile.dateuled)/86400L);
304 305 306 307
					getfiledat(&cfg, &workfile);
					if(!(misc&REPORT)) {
						removefiledat(&cfg, &workfile);
						if(remove(str))
308 309 310
							printf("Error removing %s\n",str); 
					} 
			}
311 312 313 314
			else if(misc&OFFLINE && cfg.dir[i]->misc&DIR_FCHK && !fexist(str)) {
					printf("Removing %s (doesn't exist)\n",fname);
					getfiledat(&cfg, &workfile);
					if(!(misc&REPORT))
315 316 317
						removefiledat(&cfg, &workfile); 
			} 
		}
318

319 320
		free((char *)ixbbuf); 
	}
deuce's avatar
deuce committed
321

322
	return(0);
deuce's avatar
deuce committed
323
}