/* * Show filelist from current area, called from the menu. */ void Copy_Home() { char *File, *temp1, *temp2; int err, Found = FALSE; struct _fdbarea *fdb_area = NULL; File = calloc(81, sizeof(char)); temp1 = calloc(PATH_MAX, sizeof(char)); temp2 = calloc(PATH_MAX, sizeof(char)); Enter(1); /* Please enter filename: */ pout(YELLOW, BLACK, (char *) Language(245)); colour(CFG.InputColourF, CFG.InputColourB); GetstrC(File, 80); Enter(2); if ((strcmp(File, "")) == 0) { /* No filename entered, Aborting. */ pout(CFG.HiliteF, CFG.HiliteB, (char *) Language(246)); Enter(2); Pause(); free(File); free(temp1); free(temp2); return; } if (*(File) == '/' || *(File) == ' ') { /* Illegal Filename! */ pout(CFG.HiliteF, CFG.HiliteB, (char *) Language(247)); Enter(2); Pause(); free(File); free(temp1); free(temp2); return; } if (Access(exitinfo.Security, area.DLSec) == FALSE) { pout(YELLOW, BLACK, (char *) Language(236)); Enter(2); Pause(); free(File); free(temp1); free(temp2); return; } if ((fdb_area = mbsedb_OpenFDB(iAreaNumber, 30)) == NULL) { free(File); free(temp1); free(temp2); return; } while (fread(&fdb, fdbhdr.recsize, 1, fdb_area->fp) == 1) { if ((strcasecmp(File, fdb.Name) == 0) || (strcasecmp(File, fdb.LName) == 0)) { Found = TRUE; if (((fdb.Size + Quota()) > (CFG.iQuota * 1048576))) { /* You have not enough diskspace free to copy this file */ pout(CFG.HiliteF, CFG.HiliteB, (char *) Language(279)); Enter(1); Syslog('+', "Copy homedir, not enough quota"); } else { snprintf(temp1, PATH_MAX, "%s/%s", area.Path, fdb.LName); /* Use real longname here */ snprintf(temp2, PATH_MAX, "%s/%s/wrk/%s", CFG.bbs_usersdir, exitinfo.Name, File); colour(CFG.TextColourF, CFG.TextColourB); /* Start copy: */ pout(CFG.HiliteF, CFG.HiliteB, (char *) Language(289)); PUTSTR(File); PUTCHAR(' '); Syslog('b', "Copy from : %s", temp1); Syslog('b', "Copy to : %s", temp2); if ((err = file_cp(temp1, temp2))) { /* Failed! */ pout(CFG.HiliteF, CFG.HiliteB, (char *) Language(353)); WriteError("Copy %s to homedir failed, code %d", File, err); } else { /* Ok */ PUTSTR((char *) Language(200)); Syslog('+', "Copied %s from area %d to homedir", File, iAreaNumber); } Enter(1); } } } mbsedb_CloseFDB(fdb_area); if (!Found) { /* File does not exist, please try again ... */ pout(CFG.HiliteF, CFG.HiliteB, (char *) Language(296)); Enter(1); } Pause(); free(File); free(temp1); free(temp2); }
void *thread_fun(void *arg) { struct sigaction act,oact;//设置信号 act.sa_handler = sig_alrm;// act.sa_flags = 0; sigemptyset(&act.sa_mask); // sigaction(SIGALRM, &act, &oact); while(1) { printf("pid=%lu tid=%lu\n", getpid(), pthread_self()); unsigned long ret; ret=get_file_size("2.cpp"); //sleep(3); struct itimerval itv; itv.it_interval.tv_sec = 5; itv.it_interval.tv_usec = 0; itv.it_value.tv_sec = 5; itv.it_value.tv_usec = 0; setitimer(ITIMER_REAL, &itv, &oldtv); if(ret>0) { printf("file is too big.....\n"); get_local_time(); file_cp("1","2"); // sleep(3); } // sleep(3); } }
/* * from_client_commit * Handle an incoming commit message from a client. * XXX: If commit succeeds and snapshot/startup fails, we have strange state: * the commit has succeeded but an error message is returned. */ int from_client_commit(clicon_handle h, int s, struct clicon_msg *msg, const char *label) { char *candidate, *running; uint32_t snapshot, startup; int retval = -1; char *snapshot_0; if (clicon_msg_commit_decode(msg, &candidate, &running, &snapshot, &startup, label) < 0) goto err; if (candidate_commit(h, candidate, running) < 0){ clicon_debug(1, "Commit %s failed", candidate); retval = 0; /* We ignore errors from commit, but maybe we should fail on fatal errors? */ goto err; } clicon_debug(1, "Commit %s", candidate); if (snapshot && config_snapshot(clicon_dbspec_key(h), running, clicon_archive_dir(h)) < 0) goto err; if (startup){ snapshot_0 = chunk_sprintf(__FUNCTION__, "%s/0", clicon_archive_dir(h)); if (file_cp(snapshot_0, clicon_startup_config(h)) < 0){ clicon_err(OE_PROTO, errno, "%s: Error when creating startup", __FUNCTION__); goto err; } } retval = 0; if (send_msg_ok(s) < 0) goto done; goto done; err: /* XXX: more elaborate errstring? */ if (send_msg_err(s, clicon_errno, clicon_suberrno, "%s", clicon_err_reason) < 0) retval = -1; done: unchunk_group(__FUNCTION__); return retval; /* may be zero if we ignoring errors from commit */ } /* from_client_commit */
/* * Move or rename a file. Not fullproof if using NFS, see * man 2 rename. If we are trying to move a file accross * filesystems, which is not allowed, we fall back to simple * copy the file and then delete the old file. */ int file_mv(char *oldpath, char *newpath) { static int error; if (rename(oldpath, newpath) != 0) { error = errno; if (error != EXDEV) return error; /* * We tried cross-device link, now the slow way :-) */ error = file_cp(oldpath, newpath); if (error != 0) return error; error = file_rm(oldpath); return 0; } return 0; }
static int copy_default_file (const char *srcfile, const char *dstfile) { char *local_path, *default_path, *target_dir; target_dir = stringf_dup ("%s/FastTrack", platform_local_dir()); local_path = stringf_dup ("%s/FastTrack/%s", platform_local_dir(), dstfile); default_path = stringf_dup ("%s/FastTrack/%s", platform_data_dir(), srcfile); if (!file_exists (local_path)) { FST_WARN_2 ("Local file \"%s\" does not exist, copying default from \"%s\"", local_path, default_path); /* make sure the target directory exists */ if (!file_mkdir (target_dir, 0777)) { FST_ERR_1 ("Unable to create directory \"%s\"", target_dir); free (target_dir); free (local_path); free (default_path); return FALSE; } if (!file_cp (default_path, local_path)) { FST_ERR_1 ("Unable to copy default file \"%s\"", default_path); free (target_dir); free (local_path); free (default_path); return FALSE; } } free (target_dir); free (local_path); free (default_path); return TRUE; }
void Magic_CopyFile(void) { int First = TRUE, rc; char *From, *To; From = calloc(PATH_MAX, sizeof(char)); To = calloc(PATH_MAX, sizeof(char)); while (GetMagicRec(MG_COPY, First)) { First = FALSE; snprintf(From, PATH_MAX, "%s/%s", TIC.BBSpath, TIC.NewFile); snprintf(To, PATH_MAX, "%s/%s", magic.Path, TIC.NewFile); if ((rc = file_cp(From, To) == 0)) { MagicResult((char *)"%s copied to %s", From, To); Magic_CheckCompile(); } else WriteError("Magic: copy: %s to %s failed, %s", strerror(rc)); } free(From); free(To); }
/* * 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; struct _fdbarea *fdb_area = NULL; char *temp, *dest, *lnk; Syslog('f', "AddFile Area : %d", Area); Syslog('f', "AddFile DestPath: %s", FTND_SS(DestPath)); Syslog('f', "AddFile FromPath: %s", FTND_SS(FromPath)); Syslog('f', "AddFile LinkPath: %s", FTND_SS(LinkPath)); /* * 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) || (file_exist(LinkPath, F_OK) == 0)) { if (do_force) { Syslog('+', "File %s (%s) already exists in area %d, forced overwrite", f_db.Name, f_db.LName, Area); } else { WriteError("File %s (%s) already exists in area %d", f_db.Name, f_db.LName, Area); if (!do_quiet) printf("\nFile %s (%s) already exists in area %d\n", f_db.Name, f_db.LName, Area); return FALSE; } } if ((rc = file_cp(FromPath, DestPath))) { WriteError("Can't copy file to %s, %s", DestPath, strerror(rc)); if (!do_quiet) printf("\nCan't copy file to %s, %s\n", DestPath, strerror(rc)); return FALSE; } chmod(DestPath, 0644); if (LinkPath) { temp = calloc(PATH_MAX, sizeof(char)); if (getcwd(temp, PATH_MAX-1)) { if (chdir(area.Path)) { WriteError("$Can't chdir to %s", area.Path); free(temp); return FALSE; } unlink(LinkPath); dest = xstrcpy(basename(DestPath)); lnk = xstrcpy(basename(LinkPath)); if ((rc = symlink(dest, lnk))) { WriteError("Can't create symbolic link %s", lnk); if (!do_quiet) printf("\nCan't create symbolic link %s, %s\n", lnk, strerror(rc)); unlink(DestPath); return FALSE; } free(dest); free(lnk); chdir(temp); } free(temp); } if ((fdb_area = ftnddb_OpenFDB(Area, 30))) { rc = ftnddb_InsertFDB(fdb_area, f_db, TRUE); ftnddb_CloseFDB(fdb_area); return rc; } else { return FALSE; } }
/* * Return values: * 0 - Success * 1 - Some error * 2 - Orphaned tic */ int ProcessTic(fa_list **sbl, orphans **opl) { int First, Listed = FALSE, DownLinks = 0, MustRearc = FALSE; int UnPacked = FALSE, IsArchive = FALSE, rc, i, j, k; char *Temp, *unarc = NULL, *cmd = NULL; char temp1[PATH_MAX], temp2[PATH_MAX], sbe[24], TDesc[1024]; unsigned int crc, crc2, Kb; sysconnect Link; FILE *fp; struct utimbuf ut; int BBS_Imp = FALSE, DidBanner = FALSE; faddr *p_from; qualify *qal = NULL, *tmpq; orphans *topl; if (TIC.TicIn.PathError) { WriteError("Our Aka is in the path"); tic_bad++; return 1; } Temp = calloc(PATH_MAX, sizeof(char)); if (!do_quiet) { mbse_colour(LIGHTGREEN, BLACK); printf("Checking \b\b\b\b\b\b\b\b\b\b"); fflush(stdout); } if (TIC.Orphaned) { fill_orphans(opl, TIC.TicName, TIC.TicIn.Area, TIC.TicIn.File, TRUE, FALSE); Syslog('+', "File not in inbound: %s", TIC.TicIn.File); free(Temp); return 2; } snprintf(Temp, PATH_MAX, "%s/%s", TIC.Inbound, TIC.TicIn.File); crc = file_crc(Temp, CFG.slow_util && do_quiet); TIC.FileSize = file_size(Temp); TIC.FileDate = file_time(Temp); if (TIC.TicIn.Size) { if (TIC.TicIn.Size != TIC.FileSize) WriteError("Size is %ld, expected %ld", TIC.FileSize, TIC.TicIn.Size); } else { /* * No filesize in TIC file, add filesize. */ TIC.TicIn.Size = TIC.FileSize; } if (TIC.Crc_Int) { if (crc != TIC.Crc_Int) { Syslog('!', "CRC: expected %08lX, the file is %08lX", TIC.Crc_Int, crc); fill_orphans(opl, TIC.TicName, TIC.TicIn.Area, TIC.TicIn.File, FALSE, TRUE); if (check_crc) { Syslog('+', "Bad CRC, will check this ticfile later"); free(Temp); return 1; } else { Syslog('!', "CRC: error, recalculating crc"); ReCalcCrc(Temp); } } } else { Syslog('+', "CRC: missing, calculating CRC"); ReCalcCrc(Temp); } /* * Load and check the .TIC area. */ if (!SearchTic(TIC.TicIn.Area)) { UpdateNode(); Syslog('f', "Unknown file area %s", TIC.TicIn.Area); p_from = fido2faddr(TIC.Aka); if (!create_ticarea(TIC.TicIn.Area, p_from)) { Bad((char *)"Unknown file area %s", TIC.TicIn.Area); free(Temp); tidy_faddr(p_from); return 1; } tidy_faddr(p_from); /* * Try to load the .TIC area again. */ if (!SearchTic(TIC.TicIn.Area)) { Bad((char *)"Reload of new created file area %s failed", TIC.TicIn.Area); free(Temp); return 1; } } if ((tic.Secure) && (!TIC.TicIn.Hatch)) { First = TRUE; while (GetTicSystem(&Link, First)) { First = FALSE; if (Link.aka.zone) { if ((Link.aka.zone == TIC.Aka.zone) && (Link.aka.net == TIC.Aka.net) && (Link.aka.node == TIC.Aka.node) && (Link.aka.point== TIC.Aka.point) && (Link.receivefrom)) Listed = TRUE; } } if (!Listed) { Bad((char *)"%s NOT connected to %s", aka2str(TIC.Aka), TIC.TicIn.Area); free(Temp); return 1; } } if ((!SearchNode(TIC.Aka)) && (!TIC.TicIn.Hatch)) { Bad((char *)"%s NOT known", aka2str(TIC.Aka)); free(Temp); return 1; } if (!TIC.TicIn.Hatch) { if (strcasecmp(TIC.TicIn.Pw, nodes.Fpasswd)) { Bad((char *)"Pwd error, got %s, expected %s", TIC.TicIn.Pw, nodes.Fpasswd); free(Temp); return 1; } } else { if (strcasecmp(TIC.TicIn.Pw, CFG.hatchpasswd)) { Bad((char *)"Password error in local Hatch"); WriteError("WARNING: it might be a Trojan in your inbound"); free(Temp); return 1; } } if (Magic_DeleteFile()) { snprintf(temp1, PATH_MAX, "%s/%s", TIC.Inbound, TIC.TicName); file_rm(temp1); Syslog('+', "Deleted file %s", temp1); file_rm(Temp); free(Temp); return 0; } if (Magic_MoveFile()) { if (!SearchTic(TIC.TicIn.Area)) { Bad((char *)"Unknown Area: %s", TIC.TicIn.Area); free(Temp); return 1; } } strncpy(T_File.Echo, tic.Name, 20); strncpy(T_File.Group, tic.Group, 12); TIC.KeepNum = tic.KeepLatest; Magic_Keepnum(); if (!tic.FileArea) { Syslog('+', "Passthru TIC area!"); strcpy(TIC.BBSpath, CFG.ticout); strcpy(TIC.BBSdesc, tic.Comment); } else { snprintf(Temp, PATH_MAX, "%s/etc/fareas.data", getenv("MBSE_ROOT")); if ((fp = fopen(Temp, "r")) == NULL) { WriteError("Can't access fareas.data area: %ld", tic.FileArea); free(Temp); return 1; } fread(&areahdr, sizeof(areahdr), 1, fp); if (fseek(fp, ((tic.FileArea -1) * areahdr.recsize) + areahdr.hdrsize, SEEK_SET)) { fclose(fp); WriteError("Can't seek area %ld in fareas.data", tic.FileArea); free(Temp); return 1; } if (fread(&area, areahdr.recsize, 1, fp) != 1) { fclose(fp); WriteError("Can't read area %ld in fareas.data", tic.FileArea); free(Temp); return 1; } fclose(fp); strcpy(TIC.BBSpath, area.Path); strcpy(TIC.BBSdesc, area.Name); /* * If the File area has a special announce group, change * the group to that name. */ if (strlen(area.NewGroup)) strncpy(T_File.Group, area.NewGroup, 12); } strncpy(T_File.Comment, tic.Comment, 55); /* * Check if the destination area really exists, it may be that * the area is not linked to an existing BBS area. */ if (tic.FileArea && access(TIC.BBSpath, W_OK)) { WriteError("No write access to \"%s\"", TIC.BBSpath); Bad((char *)"Dest directory not available"); free(Temp); return 1; } if ((tic.DupCheck) && (check_dupe)) { snprintf(Temp, PATH_MAX, "%s%s", TIC.TicIn.Area, TIC.TicIn.Crc); crc2 = 0xffffffff; crc2 = upd_crc32(Temp, crc2, strlen(Temp)); if (CheckDupe(crc2, D_FILEECHO, CFG.tic_dupes)) { Bad((char *)"Duplicate file"); tic_dup++; free(Temp); return 1; } } /* * Count the actual downlinks for this area and build the list of * systems qualified to receive this file. */ First = TRUE; while (GetTicSystem(&Link, First)) { First = FALSE; if ((Link.aka.zone) && (Link.sendto) && (!Link.pause)) { DownLinks++; p_from = fido2faddr(Link.aka); if (TIC.TicIn.Hatch) { fill_qualify(&qal, Link.aka, FALSE, in_list(p_from, sbl, TRUE)); } else { fill_qualify(&qal, Link.aka, ((TIC.Aka.zone == Link.aka.zone) && (TIC.Aka.net == Link.aka.net) && (TIC.Aka.node == Link.aka.node) && (TIC.Aka.point == Link.aka.point)), in_list(p_from, sbl, TRUE)); } tidy_faddr(p_from); } } T_File.Size = TIC.FileSize; T_File.SizeKb = TIC.FileSize / 1024; /* * Update the uplink's counters. */ Kb = TIC.FileSize / 1024; if (SearchNode(TIC.Aka)) { StatAdd(&nodes.FilesRcvd, 1L); StatAdd(&nodes.F_KbRcvd, Kb); UpdateNode(); SearchNode(TIC.Aka); } /* * Update the fileecho and group counters. */ StatAdd(&fgroup.Files, 1L); StatAdd(&fgroup.KBytes, Kb); fgroup.LastDate = time(NULL); StatAdd(&tic.Files, 1L); StatAdd(&tic.KBytes, Kb); tic.LastAction = time(NULL); UpdateTic(); if (!do_quiet) { printf("Unpacking \b\b\b\b\b\b\b\b\b\b"); fflush(stdout); } /* * Check if this is an archive, and if so, which compression method * is used for this file. */ if (strlen(tic.Convert) || tic.FileId || tic.ConvertAll || strlen(tic.Banner)) { /* * Create tmp workdir */ if (create_tmpwork()) { free(Temp); tidy_qualify(&qal); return 1; } if ((unarc = unpacker(TIC.TicIn.File)) == NULL) Syslog('+', "Unknown archive format %s", TIC.TicIn.File); else { IsArchive = TRUE; if ((strlen(tic.Convert) && (strcmp(unarc, tic.Convert) == 0)) || (tic.ConvertAll)) MustRearc = TRUE; } } /* * Copy the file if there are downlinks and we send the * original file, but want to rearc it for ourself, or if * it's a passthru area. */ if (((tic.SendOrg) && (MustRearc || strlen(tic.Banner))) || (!tic.FileArea)) { snprintf(temp1, PATH_MAX, "%s/%s", TIC.Inbound, TIC.TicIn.File); snprintf(temp2, PATH_MAX, "%s/%s", CFG.ticout, TIC.TicIn.File); if ((rc = file_cp(temp1, temp2) == 0)) { TIC.SendOrg = TRUE; } else { WriteError("Copy %s to %s failed: %s", temp1, temp2, strerror(rc)); } } if (MustRearc && IsArchive) { snprintf(temp2, PATH_MAX, "%s/tmp/arc%d", getenv("MBSE_ROOT"), (int)getpid()); if (!checkspace(temp2, TIC.TicIn.File, UNPACK_FACTOR)) { Bad((char *)"Not enough free diskspace left"); free(Temp); tidy_qualify(&qal); clean_tmpwork(); return 1; } if (chdir(temp2) != 0) { WriteError("$Can't change to %s", temp2); free(Temp); tidy_qualify(&qal); clean_tmpwork(); return 1; } if (!getarchiver(unarc)) { WriteError("Can't get archiver for %s", unarc); chdir(TIC.Inbound); free(Temp); tidy_qualify(&qal); clean_tmpwork(); return 1; } if (strlen(archiver.funarc) == 0) { Syslog('!', "No unarc command available"); } else { cmd = xstrcpy(archiver.funarc); snprintf(temp1, PATH_MAX, "%s/%s", TIC.Inbound, TIC.TicIn.File); if (execute_str(cmd, temp1, (char *)NULL, (char *)"/dev/null", (char *)"/dev/null", (char *)"/dev/null") == 0) { UnPacked = TRUE; } else { chdir(TIC.Inbound); Bad((char *)"Archive maybe corrupt"); free(Temp); clean_tmpwork(); return 1; } free(cmd); } } /* * Scan file for viri. */ if (tic.VirScan) { snprintf(temp1, PATH_MAX, "%s/%s", TIC.Inbound, TIC.TicIn.File); if (!do_quiet) { printf("Virscan \b\b\b\b\b\b\b\b\b\b"); fflush(stdout); } if (VirScanFile(temp1)) { chdir(TIC.Inbound); Bad((char *)"Possible virus found!"); free(Temp); tidy_qualify(&qal); clean_tmpwork(); return 1; } if (!do_quiet) { printf("Checking \b\b\b\b\b\b\b\b\b\b"); fflush(stdout); } } if (tic.FileId && tic.FileArea && IsArchive) { if (UnPacked) { snprintf(temp1, PATH_MAX, "%s/tmp/arc%d", getenv("MBSE_ROOT"), (int)getpid()); snprintf(Temp, PATH_MAX, "FILE_ID.DIZ"); if (getfilecase(temp1, Temp)) { Syslog('f', "Found %s", Temp); snprintf(temp1, PATH_MAX, "%s/tmp/arc%d/%s", getenv("MBSE_ROOT"), (int)getpid(), Temp); snprintf(temp2, PATH_MAX, "%s/tmp/FILE_ID.DIZ", getenv("MBSE_ROOT")); } else { Syslog('f', "Didn't find a FILE_ID.DIZ"); } } else { if (!getarchiver(unarc)) { chdir(TIC.Inbound); } else { cmd = xstrcpy(archiver.iunarc); if (cmd == NULL) { WriteError("No unarc command available"); } else { snprintf(temp1, PATH_MAX, "%s/tmp", getenv("MBSE_ROOT")); chdir(temp1); snprintf(temp1, PATH_MAX, "%s/%s FILE_ID.DIZ", TIC.Inbound, TIC.TicIn.File); if (execute_str(cmd, temp1, (char *)NULL, (char *)"/dev/null", (char *)"/dev/null", (char *)"/dev/null")) { snprintf(temp1, PATH_MAX, "%s/%s file_id.diz", TIC.Inbound, TIC.TicIn.File); execute_str(cmd, temp1, (char *)NULL, (char *)"/dev/null", (char *)"/dev/null", (char *)"/dev/null"); } free(cmd); } } /* if getarchiver */ } /* if not unpacked */ } /* if need FILE_ID.DIZ and not passthru */ /* * Create internal file description, priority is FILE_ID.DIZ, * 2nd LDesc, and finally the standard description. */ if (!Get_File_Id()) { if (TIC.TicIn.TotLDesc > 2) { for (i = 0; i < TIC.TicIn.TotLDesc; i++) { strncpy(TIC.File_Id[i], TIC.TicIn.LDesc[i], 48); } TIC.File_Id_Ct = TIC.TicIn.TotLDesc; } else { /* * Format the description line (max 255 chars) in parts of 48 characters. */ if (strlen(TIC.TicIn.Desc) <= 48) { strcpy(TIC.File_Id[0], TIC.TicIn.Desc); TIC.File_Id_Ct++; } else { memset(&TDesc, 0, sizeof(TDesc)); strcpy(TDesc, TIC.TicIn.Desc); while (strlen(TDesc) > 48) { j = 48; while ((TDesc[j] != ' ') && (j > 0)) j--; if (j == 0) { Syslog('f', "Panic, no spaces"); j = 47; } strncpy(TIC.File_Id[TIC.File_Id_Ct], TDesc, j); Syslog('f', "%2d/%2d: \"%s\"", TIC.File_Id_Ct, j, TIC.File_Id[TIC.File_Id_Ct]); TIC.File_Id_Ct++; k = strlen(TDesc); j++; /* Correct space */ for (i = 0; i <= k; i++, j++) TDesc[i] = TDesc[j]; if (TIC.File_Id_Ct == 23) break; } strncpy(TIC.File_Id[TIC.File_Id_Ct], TDesc, 48); Syslog('f', "%2d/%2d: \"%s\"", TIC.File_Id_Ct, strlen(TIC.File_Id[TIC.File_Id_Ct]), TIC.File_Id[TIC.File_Id_Ct]); TIC.File_Id_Ct++; } } } /* not get FILE_ID.DIZ */ /* * Now check if other (older) ticfiles point to this file, * if found mark it to purge later. */ for (topl = *opl; topl; topl = topl->next) { if ((strcmp(topl->Area, TIC.TicIn.Area) == 0) && (strcmp(topl->FileName, TIC.TicIn.File) == 0)) { topl->Purged = TRUE; } } /* * Rearc file if it is an unpacked archive. */ if ((MustRearc) && (UnPacked) && (tic.FileArea)) { if (Rearc(tic.Convert)) { /* * Get new filesize for import and announce */ snprintf(temp1, PATH_MAX, "%s/%s", TIC.Inbound, TIC.NewFile); TIC.FileSize = file_size(temp1); T_File.Size = TIC.FileSize; T_File.SizeKb = TIC.FileSize / 1024; /* * Calculate the CRC if we must send the new archived file. */ if (!TIC.SendOrg) { ReCalcCrc(temp1); } } else { WriteError("Rearc failed"); } /* if Rearc() */ } /* * Change banner if needed. */ if ((strlen(tic.Banner)) && IsArchive) { cmd = xstrcpy(archiver.barc); if ((cmd == NULL) || (!strlen(cmd))) { Syslog('+', "No banner command for %s", archiver.name); } else { snprintf(temp1, PATH_MAX, "%s/%s", TIC.Inbound, TIC.NewFile); snprintf(Temp, PATH_MAX, "%s/etc/%s", getenv("MBSE_ROOT"), tic.Banner); if (execute_str(cmd, temp1, (char *)NULL, Temp, (char *)"/dev/null", (char *)"/dev/null")) { WriteError("Changing the banner failed"); } else { Syslog('+', "New banner %s", tic.Banner); TIC.FileSize = file_size(temp1); T_File.Size = TIC.FileSize; T_File.SizeKb = TIC.FileSize / 1024; ReCalcCrc(temp1); DidBanner = TRUE; } } } clean_tmpwork(); chdir(TIC.Inbound); /* * If the file is converted, we set the date of the original * received file as the file creation date. */ snprintf(Temp, PATH_MAX, "%s/%s", TIC.Inbound, TIC.NewFile); if ((MustRearc || DidBanner) && CFG.ct_KeepDate) { if ((tic.Touch) && (tic.FileArea)) { ut.actime = mktime(localtime(&TIC.FileDate)); ut.modtime = mktime(localtime(&TIC.FileDate)); utime(Temp, &ut); Syslog('-', "Restamp filedate %s to %s", Temp, rfcdate(ut.modtime)); } } /* * Now make sure the file timestamp is updated. The file may be restamped, * altered by banners etc. */ TIC.FileDate = file_time(Temp); /* * If not passthru, import in the BBS. */ if (tic.FileArea) { Syslog('+', "Import: %s (%s) Area: %s", TIC.NewFile, TIC.NewFullName, TIC.TicIn.Area); BBS_Imp = Add_BBS(&qal); if (!BBS_Imp) { Bad((char *)"File Import Error"); free(Temp); tidy_qualify(&qal); clean_tmpwork(); return 1; } } chdir(TIC.Inbound); /* * Create file announce record */ if (tic.FileArea) { if (strlen(TIC.TicIn.Magic)) magic_update(TIC.TicIn.Magic, TIC.NewFile); else Magic_UpDateAlias(); for (i = 0; i < TIC.File_Id_Ct; i++) strncpy(T_File.LDesc[i], TIC.File_Id[i], 48); T_File.TotLdesc = TIC.File_Id_Ct; T_File.Announce = tic.Announce; strncpy(T_File.Name, TIC.NewFile, 12); strncpy(T_File.LName, TIC.NewFullName, 80); T_File.Fdate = TIC.FileDate; Add_ToBeRep(T_File); } if (TIC.SendOrg && !tic.FileArea) { /* * If it's a passthru area we don't need the * file in the inbound anymore so it can be * deleted. */ snprintf(temp1, PATH_MAX, "%s/%s", TIC.Inbound, TIC.TicIn.File); if (file_rm(temp1) == 0) Syslog('f', "Deleted %s", temp1); } if (DownLinks) { First = TRUE; /* * Add all our system aka's to the seenby lines in the same zone, * omit aka's already in the seenby list. */ for (i = 0; i < 39; i++) { if (CFG.akavalid[i] && (tic.Aka.zone == CFG.aka[i].zone)) { p_from = fido2faddr(CFG.aka[i]); if (! in_list(p_from, sbl, TRUE)) { if (CFG.aka[i].point) snprintf(sbe, 24, "%u:%u/%u.%u", CFG.aka[i].zone, CFG.aka[i].net, CFG.aka[i].node, CFG.aka[i].point); else snprintf(sbe, 24, "%u:%u/%u", CFG.aka[i].zone, CFG.aka[i].net, CFG.aka[i].node); fill_list(sbl, sbe, NULL); } tidy_faddr(p_from); } } /* * Add seen-by lines for all systems that will receive this file. */ for (tmpq = qal; tmpq; tmpq = tmpq->next) { if (tmpq->send) { if (CFG.aka[i].point) snprintf(sbe, 24, "%u:%u/%u.%u", tmpq->aka.zone, tmpq->aka.net, tmpq->aka.node, tmpq->aka.point); else snprintf(sbe, 24, "%u:%u/%u", tmpq->aka.zone, tmpq->aka.net, tmpq->aka.node); fill_list(sbl, sbe, NULL); } } uniq_list(sbl); sort_list(sbl); /* * Now forward this file to the qualified downlinks. */ for (tmpq = qal; tmpq; tmpq = tmpq->next) { if (tmpq->send) { ForwardFile(tmpq->aka, *sbl); tic_out++; } } } Magic_ExecCommand(); Magic_CopyFile(); Magic_UnpackFile(); Magic_AdoptFile(); snprintf(Temp, PATH_MAX, "%s/%s", TIC.Inbound, TIC.TicName); if (unlink(Temp)) { WriteError("$Can't delete %s", Temp); } free(Temp); tidy_qualify(&qal); return 0; }
void AdoptFile(int Area, char *File, char *Description) { FILE *fp; char *temp, *temp2, *tmpdir, *unarc, *pwd, *lname, *fileid; char Desc[256], TDesc[256]; int MustRearc = FALSE, UnPacked = FALSE; int IsVirus = FALSE, File_Id = FALSE; int i, j, k, lines = 0, File_id_cnt = 0; struct FILE_record f_db; Syslog('f', "Adopt(%d, %s, %s)", Area, FTND_SS(File), FTND_SS(Description)); if (!do_quiet) ftnd_colour(CYAN, BLACK); if (LoadAreaRec(Area) == FALSE) die(FTNERR_INIT_ERROR); if (area.Available) { temp = calloc(PATH_MAX, sizeof(char)); temp2 = calloc(PATH_MAX, sizeof(char)); pwd = calloc(PATH_MAX, sizeof(char)); tmpdir = calloc(PATH_MAX, sizeof(char)); if (CheckFDB(Area, area.Path)) die(FTNERR_INIT_ERROR); getcwd(pwd, PATH_MAX); if (!do_quiet) { printf("Adopt file: %s ", File); printf("Unpacking \b\b\b\b\b\b\b\b\b\b"); fflush(stdout); } snprintf(tmpdir, PATH_MAX, "%s/tmp/arc%d", getenv("FTND_ROOT"), (int)getpid()); if (create_tmpwork()) { WriteError("Can't create %s", tmpdir); if (!do_quiet) printf("\nCan't create dir %s\n", tmpdir); die(FTNERR_INIT_ERROR); } snprintf(temp, PATH_MAX, "%s/%s", pwd, File); if (do_novir == FALSE) { if (!do_quiet) { printf("Virscan \b\b\b\b\b\b\b\b\b\b"); fflush(stdout); } IsVirus = VirScanFile(temp); } if (IsVirus) { WriteError("Virus found"); if (!do_quiet) printf("\nVirus found\n"); die(FTNERR_VIRUS_FOUND); } if ((unarc = unpacker(File))) { if (strlen(area.Archiver) && (strcmp(unarc, area.Archiver) == 0)) MustRearc = TRUE; UnPacked = UnpackFile(temp); if (!UnPacked) die(FTNERR_INIT_ERROR); } if (!do_quiet) { printf("Checking \b\b\b\b\b\b\b\b\b\b"); fflush(stdout); } memset(&f_db, 0, sizeof(f_db)); strcpy(f_db.Uploader, CFG.sysop_name); f_db.UploadDate = time(NULL); if (do_annon) f_db.Announced = TRUE; if (UnPacked) { /* * Try to get a FILE_ID.DIZ */ fileid = calloc(PATH_MAX, sizeof(char)); snprintf(temp, PATH_MAX, "%s/tmp/arc%d", getenv("FTND_ROOT"), (int)getpid()); snprintf(fileid, PATH_MAX, "FILE_ID.DIZ"); if (getfilecase(temp, fileid)) { snprintf(temp, PATH_MAX, "%s/tmp/arc%d/%s", getenv("FTND_ROOT"), (int)getpid(), fileid); snprintf(temp2, PATH_MAX, "%s/tmp/FILE_ID.DIZ", getenv("FTND_ROOT")); if (file_cp(temp, temp2) == 0) { File_Id = TRUE; } } free(fileid); if (File_Id) { Syslog('f', "FILE_ID.DIZ found"); if ((fp = fopen(temp2, "r"))) { /* * Read no more then 25 lines */ while (((fgets(Desc, 255, fp)) != NULL) && (File_id_cnt < 25)) { lines++; /* * Check if the FILE_ID.DIZ is in a normal layout. * This should be max. 10 lines of max. 48 characters. * We check at 51 characters and if the lines are longer, * we discard the FILE_ID.DIZ file. */ if (strlen(Desc) > 51) { File_id_cnt = 0; File_Id = FALSE; Syslog('!', "Discarding illegal formated FILE_ID.DIZ"); break; } if (strlen(Desc)) { if (strlen(Desc) > 48) Desc[48] = '\0'; j = 0; for (i = 0; i < strlen(Desc); i++) { if ((Desc[i] >= ' ') || (Desc[i] < 0)) { f_db.Desc[File_id_cnt][j] = Desc[i]; j++; } } File_id_cnt++; } } fclose(fp); unlink(temp2); /* * Strip empty lines at end of FILE_ID.DIZ */ while ((strlen(f_db.Desc[File_id_cnt-1]) == 0) && (File_id_cnt)) File_id_cnt--; Syslog('f', "Got %d FILE_ID.DIZ lines", File_id_cnt); for (i = 0; i < File_id_cnt; i++) Syslog('f', "\"%s\"", f_db.Desc[i]); } } } if (!File_id_cnt) { if (Description == NULL) { WriteError("No FILE_ID.DIZ and no description on the commandline"); if (!do_quiet) printf("\nNo FILE_ID.DIZ and no description on the commandline\n"); clean_tmpwork(); die(FTNERR_COMMANDLINE); } else { /* * Create description from the commandline. */ if (strlen(Description) < 48) { /* * Less then 48 chars, copy and ready. */ strcpy(f_db.Desc[0], Description); File_id_cnt++; } else { /* * More then 48 characters, break into multiple * lines not longer then 48 characters. */ memset(&TDesc, 0, sizeof(TDesc)); strcpy(TDesc, Description); while (strlen(TDesc) > 48) { j = 48; while (TDesc[j] != ' ') j--; strncat(f_db.Desc[File_id_cnt], TDesc, j); File_id_cnt++; k = strlen(TDesc); j++; /* Correct space */ for (i = 0; i <= k; i++, j++) TDesc[i] = TDesc[j]; } strcpy(f_db.Desc[File_id_cnt], TDesc); File_id_cnt++; } } } /* * Import the file. */ chdir(pwd); clean_tmpwork(); /* * Work out the kind of filename, is it a long filename * or a 8.3 DOS filename. The file on disk must become * 8.3 for import. */ if (is_real_8_3(File)) { Syslog('f', "Adopt, file is 8.3"); strcpy(f_db.Name, File); strcpy(f_db.LName, File); for (i = 0; i < strlen(File); i++) if (isupper(f_db.LName[i])) f_db.LName[i] = tolower(f_db.LName[i]); } else { Syslog('f', "Adopt, file is LFN"); strcpy(temp2, File); name_mangle(temp2); if (rename(File, temp2)) { Syslog('+', "Can't rename %s to %s", File, temp2); if (!do_quiet) printf("\nCan't rename %s to %s\n", File, temp2); die(FTNERR_GENERAL); } strcpy(f_db.Name, temp2); strcpy(f_db.LName, File); } f_db.Size = file_size(f_db.Name); f_db.Crc32 = file_crc(f_db.Name, TRUE); f_db.FileDate = file_time(f_db.Name); snprintf(temp2, PATH_MAX, "%s/%s", area.Path, f_db.Name); if (!do_quiet) { printf("Adding \b\b\b\b\b\b\b\b\b\b"); fflush(stdout); } if (strcmp(f_db.Name, f_db.LName)) { lname = calloc(PATH_MAX, sizeof(char)); snprintf(lname, PATH_MAX, "%s/%s", area.Path, f_db.LName); if (AddFile(f_db, Area, temp2, f_db.Name, lname) == FALSE) { die(FTNERR_GENERAL); } free(lname); } else { if (AddFile(f_db, Area, temp2, File, NULL) == FALSE) { die(FTNERR_GENERAL); } } Syslog('+', "File %s added to area %d", File, Area); if (MustRearc) { /* Here we should call the rearc function */ } free(pwd); free(temp2); free(temp); free(tmpdir); } else { WriteError("Area %d is not available", Area); if (!do_quiet) printf("\nArea %d is not available\n", Area); } if (!do_quiet) { printf("\r \r"); fflush(stdout); } }
/* * Add file to the BBS file database and place it in the download * directory. If it is replacing a file, a file with a matching name * will be deleted. If there is a limit on the number of files with * the same name pattern, the oldest files will be deleted. The * files database will be packed if necessary. All modifications are * done on temp files first. */ int Add_BBS(qualify **qal) { struct FILE_record frec; int rc, i, Found = FALSE, Keep = 0, DidDelete = FALSE; char temp1[PATH_MAX], temp2[PATH_MAX], *fname, *lname, *p; fd_list *fdl = NULL; struct _fdbarea *fdb_area = NULL; qualify *tmpq; faddr *taka; /* * First check for an existing record with the same filename, * if it exists, update the record and we are ready. This will * prevent for example allfiles.zip to get a new record everytime * and thus the download counters will be reset after a new update. */ if ((fdb_area = mbsedb_OpenFDB(tic.FileArea, 30))) { while (fread(&frec, fdbhdr.recsize, 1, fdb_area->fp) == 1) { if (strcmp(frec.Name, TIC.NewFile) == 0) { snprintf(temp1, PATH_MAX, "%s/%s", TIC.Inbound, TIC.NewFile); snprintf(temp2, PATH_MAX, "%s/%s", TIC.BBSpath, TIC.NewFile); mkdirs(temp2, 0755); if ((rc = file_cp(temp1, temp2))) { WriteError("Copy to %s failed: %s", temp2, strerror(rc)); mbsedb_CloseFDB(fdb_area); return FALSE; } chmod(temp2, 0644); strncpy(frec.TicArea, TIC.TicIn.Area, sizeof(frec.TicArea) -1); frec.Size = TIC.FileSize; frec.Crc32 = TIC.Crc_Int; frec.Announced = TRUE; frec.FileDate = TIC.FileDate; frec.UploadDate = time(NULL); for (i = 0; i <= TIC.File_Id_Ct; i++) { strcpy(frec.Desc[i], TIC.File_Id[i]); if (i == 24) break; } if (mbsedb_LockFDB(fdb_area, 30)) { fseek(fdb_area->fp, 0 - fdbhdr.recsize, SEEK_CUR); fwrite(&frec, fdbhdr.recsize, 1, fdb_area->fp); mbsedb_UnlockFDB(fdb_area); } mbsedb_CloseFDB(fdb_area); tic_imp++; if ((i = file_rm(temp1))) WriteError("file_rm(%s): %s", temp1, strerror(i)); return TRUE; } } mbsedb_CloseFDB(fdb_area); } /* * Create filedatabase record. */ memset(&frec, 0, sizeof(frec)); strncpy(frec.Name, TIC.NewFile, sizeof(frec.Name) -1); if (strlen(TIC.NewFullName)) { strncpy(frec.LName, TIC.NewFullName, sizeof(frec.LName) -1); } else { /* * No LFN, fake it with a lowercase copy of the 8.3 filename. */ strncpy(frec.LName, TIC.NewFile, sizeof(frec.LName) -1); for (i = 0; i < strlen(frec.LName); i++) frec.LName[i] = tolower(frec.LName[i]); } strncpy(frec.TicArea, TIC.TicIn.Area, 20); frec.Size = TIC.FileSize; frec.Crc32 = TIC.Crc_Int; frec.Announced = TRUE; snprintf(frec.Uploader, 36, "Filemgr"); frec.UploadDate = time(NULL); frec.FileDate = TIC.FileDate; for (i = 0; i <= TIC.File_Id_Ct; i++) { strcpy(frec.Desc[i], TIC.File_Id[i]); if (i == 24) break; } if (strlen(TIC.TicIn.Magic)) { strncpy(frec.Magic, TIC.TicIn.Magic, sizeof(frec.Magic) -1); } snprintf(temp1, PATH_MAX, "%s/%s", TIC.Inbound, TIC.NewFile); snprintf(temp2, PATH_MAX, "%s/%s", TIC.BBSpath, frec.Name); mkdirs(temp2, 0755); if ((rc = file_cp(temp1, temp2))) { WriteError("Copy to %s failed: %s", temp2, strerror(rc)); return FALSE; } chmod(temp2, 0644); /* * If LFN = 8.3 name and is DOS 8.3 format, change the LFN to lowercase. */ if (strcmp(frec.Name, frec.LName) == 0) { p = frec.LName; while (*p) { if (islower(*p)) Found = TRUE; p++; } if (!Found) { /* * All uppercase, change to lowercase. */ tl(frec.LName); Syslog('f', "Converted LFN to lowercase: \"%s\"", frec.LName); } } Found = FALSE; lname = calloc(PATH_MAX, sizeof(char)); if (getcwd(lname, PATH_MAX -1)) { if (chdir(TIC.BBSpath)) { WriteError("$Can't chdir %s", TIC.BBSpath); } else { // snprintf(lname, PATH_MAX, "%s/%s", TIC.BBSpath, frec.LName); if (symlink(frec.Name, frec.LName)) { WriteError("$Create link %s to %s failed", frec.Name, frec.LName); } } } free(lname); if ((fdb_area = mbsedb_OpenFDB(tic.FileArea, 30)) == NULL) return FALSE; mbsedb_InsertFDB(fdb_area, frec, area.AddAlpha); mbsedb_CloseFDB(fdb_area); /* * Delete file from the inbound */ if ((i = file_rm(temp1))) WriteError("file_rm(%s): %s", temp1, strerror(i)); /* * Handle the replace option. */ if ((strlen(TIC.TicIn.Replace)) && (tic.Replace)) { Syslog('f', "Must Replace: %s", TIC.TicIn.Replace); if ((fdb_area = mbsedb_OpenFDB(tic.FileArea, 30))) { while (fread(&fdb, fdbhdr.recsize, 1, fdb_area->fp) == 1) { if (strlen(fdb.LName) == strlen(frec.LName)) { // FIXME: Search must be based on a reg_exp search if (strcasecmp(fdb.LName, frec.LName) != 0) { Found = TRUE; for (i = 0; i < strlen(frec.LName); i++) { if ((TIC.TicIn.Replace[i] != '?') && (toupper(TIC.TicIn.Replace[i]) != toupper(fdb.LName[i]))) Found = FALSE; } if (Found) { Syslog('+', "Replace: Deleting: %s", fdb.LName); fdb.Deleted = TRUE; if (mbsedb_LockFDB(fdb_area, 30)) { fseek(fdb_area->fp , - fdbhdr.recsize, SEEK_CUR); fwrite(&fdb, fdbhdr.recsize, 1, fdb_area->fp); mbsedb_UnlockFDB(fdb_area); } DidDelete = TRUE; } } } } mbsedb_CloseFDB(fdb_area); } } /* * Handle the Keep number of files option */ if (TIC.KeepNum) { if ((fdb_area = mbsedb_OpenFDB(tic.FileArea, 30))) { while (fread(&fdb, fdbhdr.recsize, 1, fdb_area->fp) == 1) { if ((strlen(fdb.LName) == strlen(frec.LName)) && (!fdb.Deleted)) { Found = TRUE; for (i = 0; i < strlen(fdb.LName); i++) { if ((frec.LName[i] < '0') || (frec.LName[i] > '9')) { if (frec.LName[i] != fdb.LName[i]) { Found = FALSE; } } } if (Found) { Keep++; fill_fdlist(&fdl, fdb.LName, fdb.UploadDate); } } } mbsedb_CloseFDB(fdb_area); } /* * If there are files to delete, mark them. */ if (Keep > TIC.KeepNum) { sort_fdlist(&fdl); if ((fdb_area = mbsedb_OpenFDB(tic.FileArea, 30))) { for (i = 0; i < (Keep - TIC.KeepNum); i++) { fname = pull_fdlist(&fdl); fseek(fdb_area->fp, fdbhdr.hdrsize, SEEK_SET); while (fread(&fdb, fdbhdr.recsize, 1, fdb_area->fp) == 1) { if (strcmp(fdb.LName, fname) == 0) { Syslog('+', "Keep %d files, deleting: %s", TIC.KeepNum, fdb.LName); fdb.Deleted = TRUE; if (mbsedb_LockFDB(fdb_area, 30)) { fseek(fdb_area->fp , - fdbhdr.recsize, SEEK_CUR); fwrite(&fdb, fdbhdr.recsize, 1, fdb_area->fp); mbsedb_UnlockFDB(fdb_area); } DidDelete = TRUE; } } } mbsedb_CloseFDB(fdb_area); } } tidy_fdlist(&fdl); } /* * Now realy delete the marked files and clean the file * database. */ if (DidDelete) { if ((fdb_area = mbsedb_OpenFDB(tic.FileArea, 30))) { while (fread(&fdb, fdbhdr.recsize, 1, fdb_area->fp) == 1) { if (fdb.Deleted) { snprintf(temp2, PATH_MAX, "%s/%s", area.Path, fdb.LName); if (unlink(temp2) != 0) WriteError("$Can't unlink file %s", temp2); snprintf(temp2, PATH_MAX, "%s/%s", area.Path, fdb.Name); /* * With the path to the 8.3 name, we can check if this file * is attached for any possible downlink. We use the qualify * list created by the ptic function to check connected nodes * only. */ for (tmpq = *qal; tmpq; tmpq = tmpq->next) { if (tmpq->send) { taka = fido2faddr(tmpq->aka); un_attach(taka, temp2); tidy_faddr(taka); } } if (unlink(temp2) != 0) WriteError("$Can't unlink file %s", temp2); snprintf(temp2, PATH_MAX, "%s/.%s", area.Path, fdb.Name); unlink(temp2); /* Thumbnail, no logging if there is an error */ } } mbsedb_PackFDB(fdb_area); mbsedb_CloseFDB(fdb_area); DidDelete = FALSE; } } tic_imp++; return TRUE; }
/* * candidate_commit * Do a diff between candidate and running, and then call plugins to * commit the changes. * The code reverts changes if the commit fails. But if the revert * fails, we just ignore the errors and proceed. Maybe we should * do something more drastic? * Arguments: * running: The current database. The state of the router corresponds * to these values. Also called db1. * candidate: The candidate database. We are aiming to put the router in this * state. Also called db2. (_dp) [op, callback] (dpe_) +---------------+ +---------------+ | dbdep_t |--> | dbdep_ent_t | [key, var] +---------------+ +---------------+ ^ Database dependency description from dbdep_commit() | +---------------+* |dd_dep | dbdep_dd_t |-----+ +---------------+ |dd_dbdiff (dd_) | v +---------------+ +---------------+ | dbdiff |---->| dbdiff_ent | [key1, key2, add/change/rm] (dfe_) +---------------+ +---------------+ (df_) from dbdiff(), (dfe_) */ int candidate_commit(clicon_handle h, char *candidate, char *running) { struct dbdiff df; dbdep_t *dp; struct dbdiff_ent *dfe; dbdep_dd_t *ddvec = NULL; dbdep_dd_t *dd; int nvec; int retval = -1; int i, j; int failed = 0; struct stat sb; void *firsterr = NULL; /* Sanity checks that databases exists. */ if (stat(running, &sb) < 0){ clicon_err(OE_DB, errno, "%s", running); goto done; } if (stat(candidate, &sb) < 0){ clicon_err(OE_DB, errno, "%s", candidate); goto done; } memset(&df, 0, sizeof(df)); /* Find the differences between the two databases and store it in dd vector. */ if (db_diff(running, candidate, __FUNCTION__, clicon_dbspec_key(h), &df ) < 0) goto done; /* 1. Get commit processing dbdiff vector: one entry per key that changed. changes are registered as if they exist in the 1st(candidate) or 2nd(running) dbs. */ if (dbdep_commitvec(h, &df, &nvec, &ddvec) < 0) goto done; /* 2. Call plugin pre-commit hooks */ if (plugin_begin_hooks(h, candidate) < 0) goto done; /* call generic cv_validate() on all new or changed keys. */ if (generic_validate(h, candidate, &df) < 0) goto done; /* user-defined callbacks */ if (validate_db(h, nvec, ddvec, candidate) < 0) goto done; /* Call plugin post-commit hooks */ if (plugin_complete_hooks(h, candidate) < 0) goto done; /* Now follows commit rules in order. * 4. For all keys that are in candidate, delete key (from running). */ for (i = nvec-1; i >= 0; i--){ dd = &ddvec[i]; dfe = dd->dd_dbdiff; /* key1/key2/op */ dp = dd->dd_dep; /* op, callback, arg */ if (dp->dp_type & TRANS_CB_COMMIT && dfe->dfe_op & DBDIFF_OP_FIRST && plugin_modify_key_value(h, running, /* db */ dfe->dfe_key1, /* key */ TRANS_CB_COMMIT, /* commit|validate */ LV_DELETE, /* operation */ dp /* callback(arg) */ ) < 0){ firsterr = clicon_err_save(); /* save this error */ break; } } /* 5. Failed deletion of running, add the key value back (from running) */ if (i >= 0){ /* failed */ for (j=i+1; j<nvec; j++){ /* revert in opposite order */ dd = &ddvec[j]; dfe = dd->dd_dbdiff; /* key1/key2/op */ dp = dd->dd_dep; /* op, callback, arg */ if (dp->dp_type & TRANS_CB_COMMIT && dfe->dfe_op & DBDIFF_OP_FIRST && plugin_modify_key_value(h, running, /* db */ dfe->dfe_key1, /* key */ TRANS_CB_COMMIT, /* commit|validate */ LV_SET, /* operation */ dp /* callback(arg) */ ) < 0) continue; /* ignore errors or signal major setback ? */ } goto done; } /* 6. Set keys (from candidate) */ for (i=0; i < nvec; i++){ dd = &ddvec[i]; dfe = dd->dd_dbdiff; /* key1/key2/op */ dp = dd->dd_dep; /* op, callback, arg */ if (dp->dp_type & TRANS_CB_COMMIT && dfe->dfe_op & DBDIFF_OP_SECOND && plugin_modify_key_value(h, candidate, /* db */ dfe->dfe_key2, /* key */ TRANS_CB_COMMIT, /* commit|validate */ LV_SET, /* operation */ dp /* callback(arg) */ ) < 0){ firsterr = clicon_err_save(); /* save this error */ failed++; break; } } if (!failed) if (file_cp(candidate, running) < 0){ clicon_err(OE_UNIX, errno, "file_cp"); failed++; } /* 7. Failed setting keys in running, first remove the keys set */ if (failed){ /* failed */ for (j=i-1; j>=0; j--){ /* revert in opposite order */ dd = &ddvec[j]; dfe = dd->dd_dbdiff; /* key1/key2/op */ dp = dd->dd_dep; /* op, callback, arg */ if (dp->dp_type & TRANS_CB_COMMIT && dfe->dfe_op & DBDIFF_OP_SECOND && plugin_modify_key_value(h, candidate, /* db */ dfe->dfe_key2, /* key */ TRANS_CB_COMMIT, /* commit|validate */ LV_DELETE, /* operation */ dp /* callback(arg) */ ) < 0) continue; /* ignore errors or signal major setback ? */ } /* 7. Set back original running values */ for (j=0; j < nvec; j++){ /* revert in opposite order */ dd = &ddvec[j]; dfe = dd->dd_dbdiff; /* key1/key2/op */ dp = dd->dd_dep; /* op, callback, arg */ if (dp->dp_type & TRANS_CB_COMMIT && dfe->dfe_op & DBDIFF_OP_FIRST && plugin_modify_key_value(h, running, /* db */ dfe->dfe_key1, /* key */ TRANS_CB_COMMIT, /* commit|validate */ LV_SET, /* operation */ dp /* callback(arg) */ ) < 0) continue; /* ignore errors or signal major setback ? */ } goto done; } /* Copy running back to candidate in case end functions triggered updates in running */ /* XXX: check for errors */ file_cp(running, candidate); /* Call plugin post-commit hooks */ plugin_end_hooks(h, candidate); retval = 0; done: if (retval < 0) /* Call plugin fail-commit hooks */ plugin_abort_hooks(h, candidate); if (ddvec) free(ddvec); unchunk_group(__FUNCTION__); if (firsterr) clicon_err_restore(firsterr); return retval; }
void flush_dir(char *ndir) { struct dirent *de; DIR *dp; FILE *fp, *inf, *ouf; faddr noden, *bestaka; fidoaddr nodenr; int flavor, mode, Attach, fage, first, bread, rc; int fsize; char *p, *temp, *fname, *arcfile, *pktfile, *ext, maxnr, nr, oldnr, *buf; time_t Now; struct tm *ptm; struct stat sbuf; fd_list *fdl = NULL; temp = calloc(PATH_MAX, sizeof(char)); snprintf(temp, PATH_MAX, "%s/%s", CFG.out_queue, ndir); if (chdir(temp) == -1) { WriteError("$Error chdir to %s", temp); free(temp); return; } /* * Get the nodenumber from the filename */ noden.domain = NULL; noden.name = NULL; noden.zone = atoi(strtok(ndir, ".")); noden.net = atoi(strtok(NULL, ".")); noden.node = atoi(strtok(NULL, ".")); noden.point = atoi(strtok(NULL, "\0")); if (SearchFidonet(noden.zone)) noden.domain = xstrcpy(fidonet.domain); memset(&nodenr, 0, sizeof(nodenr)); nodenr.zone = noden.zone; nodenr.net = noden.net; nodenr.node = noden.node; nodenr.point = noden.point; snprintf(nodenr.domain, 13, "%s", noden.domain); if (!SearchNode(nodenr)) { /* * Node not in setup, blank noderecord and fill in some details * so that we are able to send mail crash or immediate. */ Syslog('+', "Node %s not in setup, using default settings", aka2str(nodenr)); memset(&nodes, 0, sizeof(nodes)); nodes.Aka[0].zone = noden.zone; nodes.Aka[0].net = noden.net; nodes.Aka[0].node = noden.node; nodes.Aka[0].point = noden.point; snprintf(nodes.Archiver, 6, (char *)"ZIP"); } /* * If we route via another aka, change everything. */ if (nodes.RouteVia.zone) { p = xstrcpy(aka2str(nodenr)); Syslog('+', "Route to %s via %s", p, aka2str(nodes.RouteVia)); free(p); noden.zone = nodes.RouteVia.zone; noden.net = nodes.RouteVia.net; noden.node = nodes.RouteVia.node; noden.point = nodes.RouteVia.point; if (noden.domain) free(noden.domain); noden.domain = xstrcpy(nodes.RouteVia.domain); /* * Load routevia noderecord to get the correct flavor. * If there is no noderecord, reload the old one. */ if (!SearchNode(nodes.RouteVia)) SearchNode(nodenr); } /* * At this point we are ready to add everything to the real outbound. * Lock the node, if this fails because the node is busy we abort * and try to add at a later time. */ if (nodes.Session_out == S_DIR) { if (islocked(nodes.Dir_out_clock, nodes.Dir_out_chklck, nodes.Dir_out_waitclr, 'p')) { Syslog('+', "Mail and files stay in queue, will be added later"); if (noden.domain) free(noden.domain); free(temp); return; } else { if (! setlock(nodes.Dir_out_mlock, nodes.Dir_out_mklck, 'p')) { Syslog('+', "Mail and files stay in queue, will be added later"); if (noden.domain) free(noden.domain); free(temp); return; } } } else { if (nodelock(&noden, mypid)) { Syslog('+', "Mail and files stay in queue, will be added later"); if (noden.domain) free(noden.domain); free(temp); return; } } /* * Create arcmail filename for this node. */ Now = time(NULL); arcfile = calloc(PATH_MAX, sizeof(char)); if (nodes.Session_out == S_DIR) { ptm = localtime(&Now); ext = dow[ptm->tm_wday]; if (!nodes.ARCmailCompat && (nodes.Aka[0].zone != noden.zone)) { /* * Generate ARCfile name from the CRC of the ASCII string of the node address. */ snprintf(arcfile, PATH_MAX, "%s/%08x.%s0", nodes.Dir_out_path, StringCRC32(ascfnode(&noden, 0x1f)), ext); } else { bestaka = bestaka_s(&noden); if (noden.point) { snprintf(arcfile, PATH_MAX, "%s/%04x%04x.%s0", nodes.Dir_out_path, ((bestaka->net) - (noden.net)) & 0xffff, ((bestaka->node) - (noden.node) + (noden.point)) & 0xffff, ext); } else if (bestaka->point) { /* * Inserted the next code for if we are a point, * I hope this is ARCmail 0.60 compliant. 21-May-1999 */ snprintf(arcfile, PATH_MAX, "%s/%04x%04x.%s0", nodes.Dir_out_path, ((bestaka->net) - (noden.net)) & 0xffff, ((bestaka->node) - (noden.node) - (bestaka->point)) & 0xffff, ext); } else { snprintf(arcfile, PATH_MAX, "%s/%04x%04x.%s0", nodes.Dir_out_path, ((bestaka->net) - (noden.net)) & 0xffff, ((bestaka->node) - (noden.node)) &0xffff, ext); } } } else { snprintf(arcfile, PATH_MAX, "%s", arcname(&noden, nodes.Aka[0].zone, nodes.ARCmailCompat)); } /* * If there is a mailpkt.qqq file, close it and rename it. */ pktfile = calloc(PATH_MAX, sizeof(char)); fname = calloc(PATH_MAX, sizeof(char)); snprintf(fname, PATH_MAX, "%s/mailpkt.qqq", temp); if (access(fname, W_OK) == 0) { snprintf(pktfile, PATH_MAX, "%s/%08x.pkt", temp, sequencer()); if (rename(fname, pktfile)) { WriteError("$Can't rename %s to %s", fname, pktfile); } else { /* * Add zero word to end of .pkt file */ if ((fp = fopen(pktfile, "a+")) == NULL) { WriteError("$Can't open %s", pktfile); } putc('\0', fp); putc('\0', fp); fsync(fileno(fp)); fclose(fp); } } free(fname); /* * Now all mail pkts are ready to archive */ if ((dp = opendir(temp)) == NULL) { WriteError("$Can't open %s", temp); free(temp); free(arcfile); if (nodes.Session_out == S_DIR) remlock(nodes.Dir_out_mlock, nodes.Dir_out_mklck, 'p'); else nodeulock(&noden, mypid); if (noden.domain) free(noden.domain); return; } /* * Read all .pkt filenames, get the timestamp and add them * to the memory array for later sort on filedate. */ while ((de = readdir(dp))) if ((strlen(de->d_name) == 12) && (strncasecmp(de->d_name+8,".pkt",4) == 0)) { stat(de->d_name, &sbuf); Syslog('p', "Adding %s to filelist", de->d_name); fill_fdlist(&fdl, de->d_name, sbuf.st_mtime); } closedir(dp); sort_fdlist(&fdl); if (getarchiver(nodes.Archiver)) { flavor = 'f'; if (nodes.Crash) flavor = 'c'; if (nodes.Hold) flavor = 'h'; } else { WriteError("Archiver %s not found", nodes.Archiver); if (noden.domain) free(noden.domain); free(temp); free(arcfile); return; } first = TRUE; while ((fname = pull_fdlist(&fdl)) != NULL) { /* * Check the size of the existing archive if there is a size limit. * Change to new archive names if the existing is too large. * If the archive size is zero, it's an already sent archive, the * number will be bumped also. * If the archive is older then 6 days, the name is also bumped. * Do this until we find a new name or if the last digit is a '9' or 'z'. * Purge archives older then toss_days. */ nr = oldnr = '0'; if (nodes.ARCmailAlpha) maxnr = 'z'; else maxnr = '9'; Attach = FALSE; for (;;) { fsize = file_size(arcfile); fage = (int)((Now - file_time(arcfile)) / 86400); if (fsize == -1L) { Attach = TRUE; break; } if (fsize == 0L) { if ((fage > 6) && (nr < maxnr)) { /* * Remove truncated ARCmail files older then 6 days. */ unlink(arcfile); fsize = -1L; Attach = TRUE; break; } /* * Increase filename extension if there is a truncated file of today. */ if (nr < maxnr) { nr++; if (nr == ('9' +1)) nr = 'a'; arcfile[strlen(arcfile) -1] = nr; } else { Syslog('!', "Warning: archive filename extensions exhausted for today"); break; } } else if (CFG.maxarcsize && (fsize > (CFG.maxarcsize * 1024)) && (nr < maxnr)) { /* * Use a new ARCmail file if the last one is too big. */ nr++; if (nr == ('9' +1)) nr = 'a'; arcfile[strlen(arcfile) -1] = nr; } fsize = file_size(arcfile); fage = (int)((Now - file_time(arcfile)) / 86400); if ((fsize > 0L) && (fage > 6) && (nr < maxnr)) { /* * If there is ARCmail of a week old or older, add mail * to a new ARCmail bundle. */ nr++; if (nr == ('9' +1)) nr = 'a'; arcfile[strlen(arcfile) -1] = nr; } if (oldnr == nr) break; else oldnr = nr; } fsize = file_size(arcfile); /* * If arcfile names were exhausted then the file ending on a z could still * be in the outbound but truncated if it has been sent. Since we are * reusing that filename (not a good solution) we must erase it or the * archiver program will complain. */ if (fsize == 0L) { unlink(arcfile); Attach = TRUE; } if (first) { Syslog('+', "Pack ARCmail for %s via %s with %s", aka2str(nodenr), ascfnode(&noden, 0x1f), nodes.Archiver); if (!do_quiet) { printf("\rAdding ARCmail for %s ", ascfnode(&noden, 0x1f)); fflush(stdout); } first = FALSE; flushed = TRUE; } if (execute_str(archiver.marc, arcfile, fname, (char *)"/dev/null", (char *)"/dev/null", (char *)"/dev/null") == 0) { unlink(fname); } else { WriteError("Can't add %s to ARCmail archive", fname); Attach = FALSE; } /* * Change filemode so downlink has rights to the file. */ if (nodes.Session_out == S_DIR) chmod(arcfile, 0660); /* * Attach file to .flo, not for FTP or Directory sessions. */ if (Attach && nodes.Session_out == S_DIRECT) attach(noden, arcfile, TFS, flavor); } /* * Open directory again. */ if ((dp = opendir(temp)) == NULL) { WriteError("$Can't open %s", temp); free(temp); free(arcfile); if (nodes.Session_out == S_DIR) remlock(nodes.Dir_out_mlock, nodes.Dir_out_mklck, 'p'); else nodeulock(&noden, mypid); if (noden.domain) free(noden.domain); return; } /* * Read all other mail filenames, get the timestamp and add them * to the memory array for later sort on filedate. */ while ((de = readdir(dp))) if ((strlen(de->d_name) == 11) && (strncasecmp(de->d_name,"mailpkt.",8) == 0)) { stat(de->d_name, &sbuf); Syslog('p', "Adding %s to filelist", de->d_name); fill_fdlist(&fdl, de->d_name, sbuf.st_mtime); } closedir(dp); sort_fdlist(&fdl); first = TRUE; while ((fname = pull_fdlist(&fdl)) != NULL) { if (first) { Syslog('+', "Pack unpacked mail for %s via %s", aka2str(nodenr), ascfnode(&noden, 0x1f)); if (!do_quiet) { printf("\rAdding netmail for %s ", ascfnode(&noden, 0x1f)); fflush(stdout); } first = FALSE; flushed = TRUE; } snprintf(pktfile, PATH_MAX, "%s/%s", temp, fname); if (strstr(fname, ".ddd")) flavor = 'd'; else if (strstr(fname, ".ccc")) flavor = 'c'; else if (strstr(fname, ".hhh")) flavor = 'h'; else flavor = 'o'; if (nodes.Session_out == S_DIR) { snprintf(arcfile, PATH_MAX, "%s/%08x.pkt", nodes.Dir_out_path, sequencer()); } else { snprintf(arcfile, PATH_MAX, "%s", pktname(&noden, flavor)); } /* * Now we must see if there is already mail in the outbound. * If that's the case, we must skip the .pkt header from the queue * because there is already a .pkt header also, append to the * outbound 2 bytes before the end of file, this is the zero word. */ if ((inf = fopen(pktfile, "r")) != NULL) { if (access(arcfile, R_OK) == -1) { ouf = fopen(arcfile, "w"); /* create new */ Syslog('p', "Create new %s", arcfile); } else { ouf = fopen(arcfile, "r+"); /* open R/W */ fseek(ouf, -2, SEEK_END); /* b4 0 word */ fseek(inf, 58, SEEK_SET); /* skip header */ Syslog('p', "Append to %s", arcfile); } if (ouf != NULL) { buf = malloc(16384); do { bread = fread(buf, 1, 16384, inf); fwrite(buf, 1, bread, ouf); } while (bread); free(buf); putc('\0', ouf); putc('\0', ouf); fsync(fileno(ouf)); fclose(ouf); fclose(inf); unlink(pktfile); } else { WriteError("$Can't open %s", arcfile); fclose(inf); } } /* * Change filemode so downlink has rights to the file. */ if (nodes.Session_out == S_DIR) chmod(arcfile, 0660); } /* * Now add the files for the node, information is in the .filelist * file, this tells the location of the file and what to do with * it after it is sent. */ snprintf(pktfile, PATH_MAX, "%s/.filelist", temp); if ((fp = fopen(pktfile, "r")) != NULL) { Syslog('+', "Adding files for %s via %s", aka2str(nodenr), ascfnode(&noden, 0x1f)); if (!do_quiet) { printf("\rAdding files for %s ", ascfnode(&noden, 0x1f)); fflush(stdout); flushed = TRUE; } buf = calloc(PATH_MAX + 1, sizeof(char)); while (fgets(buf, PATH_MAX, fp)) { Striplf(buf); Syslog('p', ".filelist: %s", buf); flavor = buf[0]; p = strchr(buf, ' '); p++; if (strncmp(p, "LEAVE ", 6) == 0) mode = LEAVE; else if (strncmp(p, "KFS ", 4) == 0) mode = KFS; else if (strncmp(p, "TFS ", 4) == 0) mode = TFS; else { WriteError("Syntax error in filelist \"%s\"", buf); mode = LEAVE; } p = strchr(p, ' '); p++; // Here is a extra now unused keyword. p = strchr(p, ' '); p++; Syslog('p', "File attach %s to %s", p, ascfnode(&noden, 0x1f)); if (nodes.Session_out == S_DIRECT) { attach(noden, p, mode, flavor); } else if (nodes.Session_out == S_DIR) { snprintf(arcfile, PATH_MAX, "%s/%s", nodes.Dir_out_path, Basename(p)); if (mode == LEAVE) { /* * LEAVE file, so we copy this one. */ rc = file_cp(p, arcfile); Syslog('p', "file_cp(%s, %s) rc=%d", p, arcfile, rc); } else { /* * KFS or TFS, move file to node directory */ rc = file_mv(p, arcfile); Syslog('p', "file_mv(%s, %s) rc=%d", p, arcfile, rc); } chmod(arcfile, 0660); } } free(buf); fclose(fp); unlink(pktfile); } /* * We are done, the queue is flushed, unlock the node. */ if (nodes.Session_out == S_DIR) remlock(nodes.Dir_out_mlock, nodes.Dir_out_mklck, 'p'); else nodeulock(&noden, mypid); if (noden.domain) free(noden.domain); free(temp); free(arcfile); free(pktfile); return; }