int init_virusdb() { int ret; unsigned int no = 0; virusdb = malloc(sizeof(struct virus_db)); memset(virusdb, 0, sizeof(struct virus_db)); if (!virusdb) return 0; #ifdef HAVE_LIBCLAMAV_095 if((ret = cl_init(CL_INIT_DEFAULT))) { ci_debug_printf(1, "!Can't initialize libclamav: %s\n", cl_strerror(ret)); return 0; } if(!(virusdb->db = cl_engine_new())) { ci_debug_printf(1, "Clamav DB load: Cannot create new clamav engine\n"); return 0; } if ((ret = cl_load(cl_retdbdir(), virusdb->db, &no, CL_DB_STDOPT))) { ci_debug_printf(1, "Clamav DB load: cl_load failed: %s\n", cl_strerror(ret)); #elif defined(HAVE_LIBCLAMAV_09X) if ((ret = cl_load(cl_retdbdir(), &(virusdb->db), &no, CL_DB_STDOPT))) { ci_debug_printf(1, "Clamav DB load: cl_load failed: %s\n", cl_strerror(ret)); #else if ((ret = cl_loaddbdir(cl_retdbdir(), &(virusdb->db), &no))) { ci_debug_printf(1, "cl_loaddbdir: %s\n", cl_perror(ret)); #endif return 0; } #ifdef HAVE_LIBCLAMAV_095 if ((ret = cl_engine_compile(virusdb->db))) { #else if ((ret = cl_build(virusdb->db))) { #endif ci_debug_printf(1, "Database initialization error: %s\n", cl_strerror(ret)); #ifdef HAVE_LIBCLAMAV_095 cl_engine_free(virusdb->db); #else cl_free(virusdb->db); #endif free(virusdb); virusdb = NULL; return 0; } ci_thread_mutex_init(&db_mutex); virusdb->refcount = 1; old_virusdb = NULL; return 1; } /* Instead of using struct virus_db and refcount's someone can use the cl_dup function of clamav library, but it is undocumented so I did not use it. The following implementation we are starting to reload clamav db while threads are scanning for virus but we are not allow any child to start a new scan until we are loading DB. */ /*#define DB_NO_FULL_LOCK 1*/ #undef DB_NO_FULL_LOCK int reload_virusdb() { struct virus_db *vdb = NULL; int ret; unsigned int no = 0; ci_thread_mutex_lock(&db_mutex); if (old_virusdb) { ci_debug_printf(1, "Clamav DB reload pending, cancelling.\n"); ci_thread_mutex_unlock(&db_mutex); return 0; } #ifdef DB_NO_FULL_LOCK ci_thread_mutex_unlock(&db_mutex); #endif vdb = malloc(sizeof(struct virus_db)); if (!vdb) return 0; memset(vdb, 0, sizeof(struct virus_db)); ci_debug_printf(9, "db_reload going to load db\n"); #ifdef HAVE_LIBCLAMAV_095 if(!(vdb->db = cl_engine_new())) { ci_debug_printf(1, "Clamav DB load: Cannot create new clamav engine\n"); return 0; } if ((ret = cl_load(cl_retdbdir(), vdb->db, &no, CL_DB_STDOPT))) { ci_debug_printf(1, "Clamav DB reload: cl_load failed: %s\n", cl_strerror(ret)); #elif defined(HAVE_LIBCLAMAV_09X) if ((ret = cl_load(cl_retdbdir(), &(vdb->db), &no, CL_DB_STDOPT))) { ci_debug_printf(1, "Clamav DB reload: cl_load failed: %s\n", cl_strerror(ret)); #else if ((ret = cl_loaddbdir(cl_retdbdir(), &(vdb->db), &no))) { ci_debug_printf(1, "Clamav DB reload: cl_loaddbdir failed: %s\n", cl_perror(ret)); #endif return 0; } ci_debug_printf(9, "loaded. Going to build\n"); #ifdef HAVE_LIBCLAMAV_095 if ((ret = cl_engine_compile(vdb->db))) { #else if ((ret = cl_build(vdb->db))) { #endif ci_debug_printf(1, "Clamav DB reload: Database initialization error: %s\n", cl_strerror(ret)); #ifdef HAVE_LIBCLAMAV_095 cl_engine_free(vdb->db); #else cl_free(vdb->db); #endif free(vdb); vdb = NULL; #ifdef DB_NO_FULL_LOCK /*no lock needed */ #else ci_thread_mutex_unlock(&db_mutex); #endif return 0; } ci_debug_printf(9, "Done releasing.....\n"); #ifdef DB_NO_FULL_LOCK ci_thread_mutex_lock(&db_mutex); #endif old_virusdb = virusdb; old_virusdb->refcount--; ci_debug_printf(9, "Old VirusDB refcount:%d\n", old_virusdb->refcount); if (old_virusdb->refcount <= 0) { #ifdef HAVE_LIBCLAMAV_095 cl_engine_free(old_virusdb->db); #else cl_free(old_virusdb->db); #endif free(old_virusdb); old_virusdb = NULL; } virusdb = vdb; virusdb->refcount = 1; ci_thread_mutex_unlock(&db_mutex); return 1; } CL_ENGINE *get_virusdb() { struct virus_db *vdb; ci_thread_mutex_lock(&db_mutex); vdb = virusdb; vdb->refcount++; ci_thread_mutex_unlock(&db_mutex); return vdb->db; } void release_virusdb(CL_ENGINE * db) { ci_thread_mutex_lock(&db_mutex); if (virusdb && db == virusdb->db) virusdb->refcount--; else if (old_virusdb && (db == old_virusdb->db)) { old_virusdb->refcount--; ci_debug_printf(9, "Old VirusDB refcount: %d\n", old_virusdb->refcount); if (old_virusdb->refcount <= 0) { #ifdef HAVE_LIBCLAMAV_095 cl_engine_free(old_virusdb->db); #else cl_free(old_virusdb->db); #endif free(old_virusdb); old_virusdb = NULL; } } else { ci_debug_printf(1, "BUG in srv_clamav service! please contact the author\n"); } ci_thread_mutex_unlock(&db_mutex); } void destroy_virusdb() { if (virusdb) { #ifdef HAVE_LIBCLAMAV_095 cl_engine_free(virusdb->db); #else cl_free(virusdb->db); #endif free(virusdb); virusdb = NULL; } if (old_virusdb) { #ifdef HAVE_LIBCLAMAV_095 cl_engine_free(old_virusdb->db); #else cl_free(old_virusdb->db); #endif free(old_virusdb); old_virusdb = NULL; } } void set_istag(ci_service_xdata_t * srv_xdata) { char istag[SERVICE_ISTAG_SIZE + 1]; char str_version[64]; char *daily_path; char *s1, *s2; struct cl_cvd *d1; int version = 0, cfg_version = 0; struct stat daily_stat; /*instead of 128 should be strlen("/daily.inc/daily.info")+1*/ daily_path = malloc(strlen(cl_retdbdir()) + 128); if (!daily_path) /*???????? */ return; sprintf(daily_path, "%s/daily.cvd", cl_retdbdir()); if(stat(daily_path,&daily_stat) != 0){ /* if the clamav_lib_path/daily.cvd does not exists */ sprintf(daily_path, "%s/daily.cld", cl_retdbdir()); if(stat(daily_path,&daily_stat) != 0){ /* else try to use the clamav_lib_path/daily.inc/daly.info file instead" */ sprintf(daily_path, "%s/daily.inc/daily.info", cl_retdbdir()); } } if ((d1 = cl_cvdhead(daily_path))) { version = d1->version; free(d1); } free(daily_path); s1 = (char *) cl_retver(); s2 = str_version; while (*s1 != '\0' && s2 - str_version < 64) { if (*s1 != '.') { *s2 = *s1; s2++; } s1++; } *s2 = '\0'; /*cfg_version maybe must set by user when he is changing the srv_clamav configuration.... */ snprintf(istag, SERVICE_ISTAG_SIZE, "-%.3d-%s-%d%d", cfg_version, str_version, cl_retflevel(), version); istag[SERVICE_ISTAG_SIZE] = '\0'; ci_service_set_istag(srv_xdata, istag); }
static int updatedb(const char *dbname, const char *hostname, char *ip, int *signo, const struct optstruct *opts, const char *dnsreply, char *localip, int outdated, struct mirdat *mdat, int logerr) { struct cl_cvd *current, *remote; const struct optstruct *opt; unsigned int nodb = 0, currver = 0, newver = 0, port = 0, i, j; int ret, ims = -1; char *pt, cvdfile[32], localname[32], *tmpdir = NULL, *newfile, newdb[32], cwd[512]; const char *proxy = NULL, *user = NULL, *pass = NULL, *uas = NULL; unsigned int flevel = cl_retflevel(), remote_flevel = 0, maxattempts; unsigned int can_whitelist = 0; int ctimeout, rtimeout; snprintf(cvdfile, sizeof(cvdfile), "%s.cvd", dbname); if(!(current = currentdb(dbname, localname))) { nodb = 1; } else { mdat->dbflevel = current->fl; } if(!nodb && dnsreply) { int field = 0; if(!strcmp(dbname, "main")) { field = 1; } else if(!strcmp(dbname, "daily")) { field = 2; } else if(!strcmp(dbname, "safebrowsing")) { field = 6; } else { logg("!updatedb: Unknown database name (%s) passed.\n", dbname); cl_cvdfree(current); return 70; } if(field && (pt = cli_strtok(dnsreply, field, ":"))) { if(!cli_isnumber(pt)) { logg("^Broken database version in TXT record.\n"); } else { newver = atoi(pt); logg("*%s version from DNS: %d\n", cvdfile, newver); } free(pt); } else { logg("^Invalid DNS reply. Falling back to HTTP mode.\n"); } } if(dnsreply) { if((pt = cli_strtok(dnsreply, 5, ":"))) { remote_flevel = atoi(pt); free(pt); if(remote_flevel && (remote_flevel - flevel < 4)) can_whitelist = 1; } } /* Initialize proxy settings */ if((opt = optget(opts, "HTTPProxyServer"))->enabled) { proxy = opt->strarg; if(strncasecmp(proxy, "http://", 7) == 0) proxy += 7; if((opt = optget(opts, "HTTPProxyUsername"))->enabled) { user = opt->strarg; if((opt = optget(opts, "HTTPProxyPassword"))->enabled) { pass = opt->strarg; } else { logg("HTTPProxyUsername requires HTTPProxyPassword\n"); if(current) cl_cvdfree(current); return 56; } } if((opt = optget(opts, "HTTPProxyPort"))->enabled) port = opt->numarg; logg("Connecting via %s\n", proxy); } if((opt = optget(opts, "HTTPUserAgent"))->enabled) uas = opt->strarg; ctimeout = optget(opts, "ConnectTimeout")->numarg; rtimeout = optget(opts, "ReceiveTimeout")->numarg; if(!nodb && !newver) { remote = remote_cvdhead(cvdfile, localname, hostname, ip, localip, proxy, port, user, pass, uas, &ims, ctimeout, rtimeout, mdat, logerr, can_whitelist); if(!nodb && !ims) { logg("%s is up to date (version: %d, sigs: %d, f-level: %d, builder: %s)\n", localname, current->version, current->sigs, current->fl, current->builder); *signo += current->sigs; cl_cvdfree(current); return 1; } if(!remote) { logg("^Can't read %s header from %s (IP: %s)\n", cvdfile, hostname, ip); cl_cvdfree(current); return 58; } newver = remote->version; cl_cvdfree(remote); } if(!nodb && (current->version >= newver)) { logg("%s is up to date (version: %d, sigs: %d, f-level: %d, builder: %s)\n", localname, current->version, current->sigs, current->fl, current->builder); if(!outdated && flevel < current->fl) { /* display warning even for already installed database */ logg("^Current functionality level = %d, recommended = %d\n", flevel, current->fl); logg("Please check if ClamAV tools are linked against the proper version of libclamav\n"); logg("DON'T PANIC! Read http://www.clamav.net/support/faq\n"); } *signo += current->sigs; cl_cvdfree(current); return 1; } if(current) { currver = current->version; cl_cvdfree(current); } /* if(ipaddr[0]) { hostfd = wwwconnect(ipaddr, proxy, port, NULL, localip); } else { hostfd = wwwconnect(hostname, proxy, port, ipaddr, localip); if(!ip[0]) strcpy(ip, ipaddr); } if(hostfd < 0) { if(ipaddr[0]) logg("Connection with %s (IP: %s) failed.\n", hostname, ipaddr); else logg("Connection with %s failed.\n", hostname); return 52; }; */ if(!optget(opts, "ScriptedUpdates")->enabled) nodb = 1; if(!getcwd(cwd, sizeof(cwd))) { logg("!updatedb: Can't get path of current working directory\n"); return 50; /* FIXME */ } newfile = cli_gentemp(cwd); if(nodb) { ret = getcvd(cvdfile, newfile, hostname, ip, localip, proxy, port, user, pass, uas, newver, ctimeout, rtimeout, mdat, logerr, can_whitelist); if(ret) { memset(ip, 0, 16); free(newfile); return ret; } snprintf(newdb, sizeof(newdb), "%s.cvd", dbname); } else { ret = 0; tmpdir = cli_gentemp("."); maxattempts = optget(opts, "MaxAttempts")->numarg; for(i = currver + 1; i <= newver; i++) { for(j = 0; j < maxattempts; j++) { int llogerr = logerr; if(logerr) llogerr = (j == maxattempts - 1); ret = getpatch(dbname, tmpdir, i, hostname, ip, localip, proxy, port, user, pass, uas, ctimeout, rtimeout, mdat, llogerr, can_whitelist); if(ret == 52 || ret == 58) { memset(ip, 0, 16); continue; } else { break; } } if(ret) break; } if(ret) { cli_rmdirs(tmpdir); free(tmpdir); logg("^Incremental update failed, trying to download %s\n", cvdfile); mirman_whitelist(mdat, 2); ret = getcvd(cvdfile, newfile, hostname, ip, localip, proxy, port, user, pass, uas, newver, ctimeout, rtimeout, mdat, logerr, can_whitelist); if(ret) { free(newfile); return ret; } snprintf(newdb, sizeof(newdb), "%s.cvd", dbname); } else { if(buildcld(tmpdir, dbname, newfile, optget(opts, "CompressLocalDatabase")->enabled) == -1) { logg("!Can't create local database\n"); cli_rmdirs(tmpdir); free(tmpdir); free(newfile); return 70; /* FIXME */ } snprintf(newdb, sizeof(newdb), "%s.cld", dbname); cli_rmdirs(tmpdir); free(tmpdir); } } if(!(current = cl_cvdhead(newfile))) { logg("!Can't parse new database %s\n", newfile); unlink(newfile); free(newfile); return 55; /* FIXME */ } if(!nodb && !access(localname, R_OK) && unlink(localname)) { logg("!Can't unlink %s. Please fix it and try again.\n", localname); unlink(newfile); free(newfile); return 53; } #ifdef C_WINDOWS if(!access(newdb, R_OK) && unlink(newdb)) { logg("!Can't unlink %s. Please fix the problem manually and try again.\n", newdb); unlink(newfile); free(newfile); return 53; } #endif if(rename(newfile, newdb) == -1) { logg("!Can't rename %s to %s: %s\n", newfile, newdb, strerror(errno)); unlink(newfile); free(newfile); return 57; } free(newfile); logg("%s updated (version: %d, sigs: %d, f-level: %d, builder: %s)\n", newdb, current->version, current->sigs, current->fl, current->builder); if(flevel < current->fl) { logg("Your ClamAV installation is out of date.\n"); logg("Current functionality level = %d, recommended = %d\n", flevel, current->fl); logg("A firmware upgrade might resolve this issue.\n"); logg("Also read http://sgkb.securecomputing.com/article.asp?article=11282&p=2\n"); } *signo += current->sigs; cl_cvdfree(current); return 0; }
int cli_cvdload(FILE *fs, struct cl_engine *engine, unsigned int *signo, unsigned int options, unsigned int dbtype, const char *filename, unsigned int chkonly) { struct cl_cvd cvd, dupcvd; FILE *dupfs; int ret; time_t s_time; int cfd; struct cli_dbio dbio; struct cli_dbinfo *dbinfo = NULL; char *dupname; dbio.hashctx = NULL; cli_dbgmsg("in cli_cvdload()\n"); /* verify */ if((ret = cli_cvdverify(fs, &cvd, dbtype))) return ret; if(dbtype <= 1) { /* check for duplicate db */ dupname = cli_strdup(filename); if(!dupname) return CL_EMEM; dupname[strlen(dupname) - 2] = (dbtype == 1 ? 'v' : 'l'); if(!access(dupname, R_OK) && (dupfs = fopen(dupname, "rb"))) { if((ret = cli_cvdverify(dupfs, &dupcvd, !dbtype))) { fclose(dupfs); free(dupname); return ret; } fclose(dupfs); if(dupcvd.version > cvd.version) { cli_warnmsg("Detected duplicate databases %s and %s. The %s database is older and will not be loaded, you should manually remove it from the database directory.\n", filename, dupname, filename); free(dupname); return CL_SUCCESS; } else if(dupcvd.version == cvd.version && !dbtype) { cli_warnmsg("Detected duplicate databases %s and %s, please manually remove one of them\n", filename, dupname); free(dupname); return CL_SUCCESS; } } free(dupname); } if(strstr(filename, "daily.")) { time(&s_time); if(cvd.stime > s_time) { if(cvd.stime - (unsigned int ) s_time > 3600) { cli_warnmsg("******************************************************\n"); cli_warnmsg("*** Virus database timestamp in the future! ***\n"); cli_warnmsg("*** Please check the timezone and clock settings ***\n"); cli_warnmsg("******************************************************\n"); } } else if((unsigned int) s_time - cvd.stime > 604800) { cli_warnmsg("**************************************************\n"); cli_warnmsg("*** The virus database is older than 7 days! ***\n"); cli_warnmsg("*** Please update it as soon as possible. ***\n"); cli_warnmsg("**************************************************\n"); } engine->dbversion[0] = cvd.version; engine->dbversion[1] = cvd.stime; } if(cvd.fl > cl_retflevel()) { cli_warnmsg("***********************************************************\n"); cli_warnmsg("*** This version of the ClamAV engine is outdated. ***\n"); cli_warnmsg("*** DON'T PANIC! Read http://www.clamav.net/support/faq ***\n"); cli_warnmsg("***********************************************************\n"); } cfd = fileno(fs); dbio.chkonly = 0; if(dbtype == 2) ret = cli_tgzload(cfd, engine, signo, options | CL_DB_UNSIGNED, &dbio, NULL); else ret = cli_tgzload(cfd, engine, signo, options | CL_DB_OFFICIAL, &dbio, NULL); if(ret != CL_SUCCESS) return ret; dbinfo = engine->dbinfo; if(!dbinfo || !dbinfo->cvd || (dbinfo->cvd->version != cvd.version) || (dbinfo->cvd->sigs != cvd.sigs) || (dbinfo->cvd->fl != cvd.fl) || (dbinfo->cvd->stime != cvd.stime)) { cli_errmsg("cli_cvdload: Corrupted CVD header\n"); return CL_EMALFDB; } dbinfo = engine->dbinfo ? engine->dbinfo->next : NULL; if(!dbinfo) { cli_errmsg("cli_cvdload: dbinfo error\n"); return CL_EMALFDB; } dbio.chkonly = chkonly; if(dbtype == 2) options |= CL_DB_UNSIGNED; else options |= CL_DB_SIGNED | CL_DB_OFFICIAL; ret = cli_tgzload(cfd, engine, signo, options, &dbio, dbinfo); while(engine->dbinfo) { dbinfo = engine->dbinfo; engine->dbinfo = dbinfo->next; mpool_free(engine->mempool, dbinfo->name); mpool_free(engine->mempool, dbinfo->hash); if(dbinfo->cvd) cl_cvdfree(dbinfo->cvd); mpool_free(engine->mempool, dbinfo); } return ret; }
BOOL init() { char whereami[PATH_MAX], *slash; int ret; ret = GetModuleFileName((HINSTANCE)&__ImageBase, whereami, sizeof(whereami) -1); if(!ret || ret == sizeof(whereami) -1) { printf("ERROR: GetModuleFileName failed\n"); return FALSE; } whereami[sizeof(whereami)-1] = '\0'; slash = strrchr(whereami, '\\'); if(!slash) { printf("ERROR: No slash found in path %s\n", whereami); return FALSE; } slash++; *slash='\0'; SetDllDirectory(whereami); __try { cl_set_clcb_msg(msg_callback); ret = cl_init(CL_INIT_DEFAULT); } __except(EXCEPTION_EXECUTE_HANDLER) { ret = -1; } SetDllDirectory(NULL); if(ret) { printf("ERROR: Failed cl_init() returned %d\n", ret); return FALSE; } strncpy(slash, "clamav_log_verbose", sizeof(whereami) - (slash - whereami)); whereami[sizeof(whereami)-1] = '\0'; logg_verbose = access(whereami, 0) == -1 ? 0 : 1; strncpy(slash, "clamav.log", sizeof(whereami) - (slash - whereami)); whereami[sizeof(whereami)-1] = '\0'; logg_nowarn = 0; logg_lock = 0; logg_time = 1; // bb #5659: force log rotation at 100 MB logg_size = 104857600; logg_rotate = 1; logg_file = strdup(whereami); if(!logg_file) { printf("ERROR: failed to duplicate log filename\n"); return FALSE; } strncpy(slash, "clamav.old.log", sizeof(whereami) - (slash - whereami)); whereami[sizeof(whereami)-1] = '\0'; if(!MoveFileEx(logg_file, whereami, MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH)) DeleteFile(logg_file); logg_noflush = 1;/* only flush on errors and warnings */ if(logg("ClamAV core initialized (version %s, flevel %d)\n", cl_retver(), cl_retflevel())<0) { printf("ERROR: logg failed\n"); return FALSE; } if(init_errors()) { logg("!Failed to initialize errors\n"); return FALSE; } ret = interface_setup(); logg("ClamAV module initialization %s\n", ret == TRUE ? "succeeded" : "failed! Aborting..."); return ret; }
int cli_cvdload(FILE *fs, struct cl_engine **engine, unsigned int *signo, short warn, unsigned int options) { char *dir; struct cl_cvd cvd; int ret; time_t s_time; int cfd; cli_dbgmsg("in cli_cvdload()\n"); /* verify */ if((ret = cli_cvdverify(fs, &cvd))) return ret; if(cvd.stime && warn) { time(&s_time); if((int) s_time - cvd.stime > 604800) { cli_warnmsg("**************************************************\n"); cli_warnmsg("*** The virus database is older than 7 days! ***\n"); cli_warnmsg("*** Please update it as soon as possible. ***\n"); cli_warnmsg("**************************************************\n"); } } if(cvd.fl > cl_retflevel()) { cli_warnmsg("***********************************************************\n"); cli_warnmsg("*** This version of the ClamAV engine is outdated. ***\n"); cli_warnmsg("*** DON'T PANIC! Read http://www.clamav.net/support/faq ***\n"); cli_warnmsg("***********************************************************\n"); } dir = cli_gentemp(NULL); if(mkdir(dir, 0700)) { cli_errmsg("cli_cvdload(): Can't create temporary directory %s\n", dir); free(dir); return CL_ETMPDIR; } cfd = fileno(fs); /* use only operations on file descriptors, and not on the FILE* from here on * if we seek the FILE*, the underlying descriptor may not seek as expected * (for example on OpenBSD, cygwin, etc.). * So seek the descriptor directly. */ if(lseek(cfd, 512, SEEK_SET) == -1) { cli_errmsg("cli_cvdload(): lseek(fs, 512, SEEK_SET) failed\n"); return CL_EIO; } if(cli_untgz(cfd, dir)) { cli_errmsg("cli_cvdload(): Can't unpack CVD file.\n"); free(dir); return CL_ECVDEXTR; } /* load extracted directory */ ret = cl_load(dir, engine, signo, options); cli_rmdirs(dir); free(dir); return ret; }
int mirman_check (uint32_t * ip, int af, struct mirdat *mdat, struct mirdat_ip **md) { unsigned int i, flevel = cl_retflevel (); if (md) *md = NULL; if (!mdat->active) return 0; for (i = 0; i < mdat->num; i++) { if ((af == AF_INET && mdat->mirtab[i].ip4 == *ip) || (af == AF_INET6 && !memcmp (mdat->mirtab[i].ip6, ip, 4 * sizeof (uint32_t)))) { if (!mdat->mirtab[i].atime && !mdat->mirtab[i].ignore) { if (md) *md = &mdat->mirtab[i]; return 0; } if (mdat->dbflevel && (mdat->dbflevel > flevel) && (mdat->dbflevel - flevel > 3)) if (time (NULL) - mdat->mirtab[i].atime < (mdat->dbflevel - flevel) * 3600) return 2; if (mdat->mirtab[i].ignore) { if (!mdat->mirtab[i].atime) return 1; if (time (NULL) - mdat->mirtab[i].atime > IGNORE_LONG) { mdat->mirtab[i].ignore = 0; if (md) *md = &mdat->mirtab[i]; return 0; } else { if (mdat->mirtab[i].ignore == 2 && (time (NULL) - mdat->mirtab[i].atime > IGNORE_SHORT)) { if (md) *md = &mdat->mirtab[i]; return 0; } return 1; } } if (md) *md = &mdat->mirtab[i]; return 0; } } return 0; }