/***************************************************************************** * * $Id$ * Purpose: File Database Maintenance - utilities * ***************************************************************************** * Copyright (C) 1997-2004 * * Michiel Broek FIDO: 2:280/2802 * Beekmansbos 10 * 1971 BV IJmuiden * the Netherlands * * This file is part of MBSE BBS. * * This BBS 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. * * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *****************************************************************************/ #include "../config.h" #include "../lib/mbselib.h" #include "../lib/users.h" #include "../lib/mbsedb.h" #include "mbfutil.h" #include "mbfile.h" extern int do_quiet; /* Suppress screen output */ extern int e_pid; /* Pid of external process */ extern time_t t_start; /* Start time */ extern time_t t_end; /* End time */ int marker = 0; /* Marker counter */ void ProgName(void) { if (do_quiet) return; colour(WHITE, BLACK); printf("\nMBFILE: MBSE BBS %s File maintenance utility\n", VERSION); colour(YELLOW, BLACK); printf(" %s\n", COPYRIGHT); } void die(int onsig) { /* * First check if a child is running, if so, kill it. */ if (e_pid) { if ((kill(e_pid, SIGTERM)) == 0) Syslog('+', "SIGTERM to pid %d succeeded", e_pid); else { if ((kill(e_pid, SIGKILL)) == 0) Syslog('+', "SIGKILL to pid %d succeded", e_pid); else WriteError("$Failed to kill pid %d", e_pid); } /* * In case the child had the tty in raw mode... */ if (!do_quiet) execute_pth((char *)"stty", (char *)"sane", (char *)"/dev/null", (char *)"/dev/null", (char *)"/dev/null"); } signal(onsig, SIG_IGN); if (onsig) { if (onsig <= NSIG) WriteError("Terminated on signal %d (%s)", onsig, SigName[onsig]); else WriteError("Terminated with error %d", onsig); } ulockprogram((char *)"mbfile"); t_end = time(NULL); Syslog(' ', "MBFILE finished in %s", t_elapsed(t_start, t_end)); if (!do_quiet) { colour(LIGHTGRAY, BLACK); fflush(stdout); } ExitClient(onsig); } void Help(void) { do_quiet = FALSE; ProgName(); colour(LIGHTCYAN, BLACK); printf("Usage: mbfile [command] \n\n"); colour(LIGHTBLUE, BLACK); printf(" Commands are:\n\n"); colour(CYAN, BLACK); printf(" a adopt [desc] Adopt file to area\n"); printf(" c check [area] Check filebase\n"); printf(" d delete \"\" Mark file(s) in area for deletion\n"); printf(" im import Import files in current dir to area\n"); printf(" in index Create filerequest index\n"); printf(" k kill Kill/move old files\n"); printf(" l list [area] List file areas or one area\n"); printf(" m move Move file from to area\n"); printf(" p pack Pack filebase\n"); printf(" r rearc \"\" Rearc file(s) in area to area archive type\n"); printf(" s sort Sort files in a file area\n"); printf(" t toberep Show toberep database\n"); printf(" u undelete \"\" Mark file(s) in area for undeletion\n"); colour(LIGHTBLUE, BLACK); printf("\n Options are:\n\n"); colour(CYAN, BLACK); printf(" -a -announce Suppress announce added files\n"); printf(" -q -quiet Quiet mode\n"); printf(" -v -virus Suppress virus scanning, use with care\n"); die(MBERR_COMMANDLINE); } void Marker(void) { /* * Keep the connection with the server alive */ Nopper(); /* * Release system resources when running in the background */ if (CFG.slow_util && do_quiet) msleep(1); if (do_quiet) return; switch (marker) { case 0: printf(">---"); break; case 1: printf(">>--"); break; case 2: printf(">>>-"); break; case 3: printf(">>>>"); break; case 4: printf("<>>>"); break; case 5: printf("<<>>"); break; case 6: printf("<<<>"); break; case 7: printf("<<<<"); break; case 8: printf("-<<<"); break; case 9: printf("--<<"); break; case 10:printf("---<"); break; case 11:printf("----"); break; } printf("\b\b\b\b"); fflush(stdout); if (marker < 11) marker++; else marker = 0; } void DeleteVirusWork() { char *buf, *temp; buf = calloc(PATH_MAX, sizeof(char)); temp = calloc(PATH_MAX, sizeof(char)); getcwd(buf, PATH_MAX); sprintf(temp, "%s/tmp", getenv("MBSE_ROOT")); if (chdir(temp) == 0) { Syslog('f', "DeleteVirusWork %s/arc", temp); execute_pth((char *)"rm", (char *)"-r -f arc", (char *)"/dev/null", (char *)"/dev/null", (char *)"/dev/null"); execute_pth((char *)"mkdir", (char *)"arc", (char *)"/dev/null", (char *)"/dev/null", (char *)"/dev/null"); } else WriteError("$Can't chdir to %s", temp); chdir(buf); free(temp); free(buf); } int UnpackFile(char *File) { char *temp, *pwd, *unarc, *cmd; Syslog('f', "UnpackFile(%s)", File); if ((unarc = unpacker(File)) == NULL) { Syslog('f', "Unknown archive format %s", File); return FALSE; } temp = calloc(PATH_MAX, sizeof(char)); pwd = calloc(PATH_MAX, sizeof(char)); getcwd(pwd, PATH_MAX); /* * Check if there is a temp directory to unpack the archive. */ sprintf(temp, "%s/tmp/arc", getenv("MBSE_ROOT")); if ((access(temp, R_OK)) != 0) { if (mkdir(temp, 0777)) { WriteError("$Can't create %s", temp); if (!do_quiet) printf("\nCan't create %s\n", temp); die(MBERR_GENERAL); } } /* * Check for stale FILE_ID.DIZ files */ sprintf(temp, "%s/tmp/arc/FILE_ID.DIZ", getenv("MBSE_ROOT")); if (!unlink(temp)) Syslog('+', "Removed stale %s", temp); sprintf(temp, "%s/tmp/arc/file_id.diz", getenv("MBSE_ROOT")); if (!unlink(temp)) Syslog('+', "Removed stale %s", temp); if (!getarchiver(unarc)) { WriteError("No archiver available for %s", File); if (!do_quiet) printf("\nNo archiver available for %s\n", File); return FALSE; } cmd = xstrcpy(archiver.funarc); if ((cmd == NULL) || (cmd == "")) { WriteError("No unarc command available"); if (!do_quiet) printf("\nNo unarc command available\n"); return FALSE; } sprintf(temp, "%s/tmp/arc", getenv("MBSE_ROOT")); if (chdir(temp) != 0) { WriteError("$Can't change to %s", temp); die(MBERR_GENERAL); } if (execute_str(cmd, File, (char *)NULL, (char *)"/dev/null", (char *)"/dev/null", (char *)"/dev/null") == 0) { chdir(pwd); free(temp); free(pwd); free(cmd); return TRUE; } else { chdir(pwd); WriteError("Unpack error, file may be corrupt"); DeleteVirusWork(); } return FALSE; } /* * Add file to the BBS. The file is in the current directory. * The f_db record already has all needed information. */ int AddFile(struct FILE_record f_db, int Area, char *DestPath, char *FromPath, char *LinkPath) { int rc; #ifdef USE_EXPERIMENT struct _fdbarea *fdb_area = NULL; #else int i, Insert, Done = FALSE, Found = FALSE; FILE *fp1, *fp2; char *temp1, *temp2; #endif /* * Copy file to the final destination and make a hard link with the * 8.3 filename to the long filename. */ mkdirs(DestPath, 0775); if (file_exist(DestPath, F_OK) == 0) { WriteError("File %s already exists in area %d", f_db.Name, Area); if (!do_quiet) printf("\nFile %s already exists in area %d\n", f_db.Name, Area); return FALSE; } if ((rc = file_cp(FromPath, DestPath))) { WriteError("Can't copy file in place"); if (!do_quiet) printf("\nCan't copy file to %s, %s\n", DestPath, strerror(rc)); return FALSE; } chmod(DestPath, 0644); if (LinkPath) { if ((rc = symlink(DestPath, LinkPath))) { WriteError("Can't create symbolic link %s", LinkPath); if (!do_quiet) printf("\nCan't create symbolic link %s, %s\n", LinkPath, strerror(rc)); unlink(DestPath); return FALSE; } } #ifdef USE_EXPERIMENT if ((fdb_area = mbsedb_OpenFDB(Area, 30))) { Syslog('f', "opened"); rc = mbsedb_InsertFDB(fdb_area, f_db, TRUE); mbsedb_CloseFDB(fdb_area); return rc; } else { Syslog('f', "not opened"); return FALSE; } #else temp1 = calloc(PATH_MAX, sizeof(char)); temp2 = calloc(PATH_MAX, sizeof(char)); sprintf(temp1, "%s/fdb/file%d.data", getenv("MBSE_ROOT"), Area); sprintf(temp2, "%s/fdb/file%d.temp", getenv("MBSE_ROOT"), Area); fp1 = fopen(temp1, "r+"); fread(&fdbhdr, sizeof(fdbhdr.hdrsize), 1, fp1); fseek(fp1, 0, SEEK_END); if (ftell(fp1) == fdbhdr.hdrsize) { /* * No records yet */ fwrite(&f_db, fdbhdr.recsize, 1, fp1); fclose(fp1); } else { /* * Files are already there. Find the right spot. */ fseek(fp1, fdbhdr.hdrsize, SEEK_SET); Insert = 0; do { if (fread(&fdb, fdbhdr.recsize, 1, fp1) != 1) Done = TRUE; if (!Done) { if (strcmp(f_db.LName, fdb.LName) == 0) { Found = TRUE; Insert++; } else { if (strcmp(f_db.LName, fdb.LName) < 0) Found = TRUE; else Insert++; } } } while ((!Found) && (!Done)); if (Found) { if ((fp2 = fopen(temp2, "a+")) == NULL) { WriteError("Can't create %s", temp2); return FALSE; } fwrite(&fdbhdr, fdbhdr.hdrsize, 1, fp2); fseek(fp1, fdbhdr.hdrsize, SEEK_SET); /* * Copy until the insert point */ for (i = 0; i < Insert; i++) { fread(&fdb, fdbhdr.recsize, 1, fp1); /* * If we are importing a file with the same name, * skip the original record and put the new one in place. */ if (strcmp(fdb.LName, f_db.LName) != 0) fwrite(&fdb, fdbhdr.recsize, 1, fp2); } if (area.AddAlpha) fwrite(&f_db, fdbhdr.recsize, 1, fp2); /* * Append the rest of the records */ while (fread(&fdb, fdbhdr.recsize, 1, fp1) == 1) { if (strcmp(fdb.LName, f_db.LName) != 0) fwrite(&fdb, fdbhdr.recsize, 1, fp2); } if (!area.AddAlpha) fwrite(&f_db, fdbhdr.recsize, 1, fp2); fclose(fp1); fclose(fp2); if (unlink(temp1) == 0) { rename(temp2, temp1); chmod(temp1, 0660); } else { WriteError("$Can't unlink %s", temp1); unlink(temp2); return FALSE; } } else { /* if (Found) */ /* * Append file record */ fseek(fp1, 0, SEEK_END); fwrite(&f_db, fdbhdr.recsize, 1, fp1); fclose(fp1); } } free(temp1); free(temp2); return TRUE; #endif } int CheckFDB(int Area, char *Path) { char *temp; FILE *fp; int rc = FALSE; temp = calloc(PATH_MAX, sizeof(char)); sprintf(temp, "%s/fdb/file%d.data", getenv("MBSE_ROOT"), Area); /* * Open the file database, create new one if it doesn't excist. */ if ((fp = fopen(temp, "r+")) == NULL) { Syslog('!', "Creating new %s", temp); if ((fp = fopen(temp, "a+")) == NULL) { WriteError("$Can't create %s", temp); rc = TRUE; } else { fdbhdr.hdrsize = sizeof(fdbhdr); fdbhdr.recsize = sizeof(fdb); fwrite(&fdbhdr, sizeof(fdbhdr), 1, fp); fclose(fp); } } else { fread(&fdbhdr, sizeof(fdbhdr), 1, fp); fclose(fp); } /* * Set the right attributes */ chmod(temp, 0660); /* * Now check the download directory */ if (access(Path, W_OK) == -1) { sprintf(temp, "%s/foobar", Path); if (mkdirs(temp, 0755)) Syslog('+', "Created directory %s", Path); } free(temp); return rc; } /* * Load Area Record */ int LoadAreaRec(int Area) { FILE *pAreas; char *sAreas; sAreas = calloc(PATH_MAX, sizeof(char)); sprintf(sAreas, "%s/etc/fareas.data", getenv("MBSE_ROOT")); if ((pAreas = fopen (sAreas, "r")) == NULL) { WriteError("$Can't open %s", sAreas); if (!do_quiet) printf("\nCan't open %s\n", sAreas); return FALSE; } fread(&areahdr, sizeof(areahdr), 1, pAreas); if (fseek(pAreas, ((Area - 1) * areahdr.recsize) + areahdr.hdrsize, SEEK_SET)) { WriteError("$Can't seek record %d in %s", Area, sAreas); if (!do_quiet) printf("\nCan't seek record %d in %s\n", Area, sAreas); fclose(pAreas); free(sAreas); return FALSE; } if (fread(&area, areahdr.recsize, 1, pAreas) != 1) { WriteError("$Can't read record %d in %s", Area, sAreas); if (!do_quiet) printf("\nCan't read record %d in %s\n", Area, sAreas); fclose(pAreas); free(sAreas); return FALSE; } fclose(pAreas); free(sAreas); return TRUE; }