#include "libclamav.h"


int detect_virus_files(char *file)
{
    int fd, ret;
    unsigned long int size = 0;
    unsigned int sigs = 0;
    long double mb;
    const char *virname;
    const char *filename;
    struct cl_engine *engine;
    struct cl_scan_options options;

    filename = (const char *)file;

    if ((fd = open(file, O_RDONLY)) == -1) {
        printf("Can't open file %s\n", file);
        return 2;
    }

    if ((ret = cl_init(CL_INIT_DEFAULT)) != CL_SUCCESS) {
        printf("Can't initialize libclamav: %s\n", cl_strerror(ret));
        return 2;
    }

    if (!(engine = cl_engine_new())) {
        printf("Can't create new engine\n");
        return 2;
    }

    /* Example version macro usage to determine if new feature is available */
#if defined(LIBCLAMAV_VERSION_NUM) && (LIBCLAMAV_VERSION_NUM >= 0x090400)
    /* Example feature usage lowering max scan time to 15 seconds. */
    cl_engine_set_num(engine, CL_ENGINE_MAX_SCANTIME, 15000);
#endif

    /* load all available databases from default directory */
    if ((ret = cl_load(cl_retdbdir(), engine, &sigs, CL_DB_STDOPT)) != CL_SUCCESS) {
        printf("cl_load: %s\n", cl_strerror(ret));
        close(fd);
        cl_engine_free(engine);
        return 2;
    }

    printf("Loaded %u signatures.\n", sigs);

    /* build engine */
    if ((ret = cl_engine_compile(engine)) != CL_SUCCESS) {
        printf("Database initialization error: %s\n", cl_strerror(ret));
        cl_engine_free(engine);
        close(fd);
        return 2;
    }

    /* scan file descriptor */
    memset(&options, 0, sizeof(struct cl_scan_options));
    options.parse |= ~0;        /* enable all parsers */
    options.general |= CL_SCAN_GENERAL_HEURISTICS; /* enable heuristic alert options */

    if ((ret = cl_scandesc(fd, filename, &virname, &size, engine, &options)) == CL_VIRUS) {
        printf("Virus detected: %s\n", virname);
        
        #if IS_MOVE
            char temp[sizeof(file) + 3];
            sprintf(temp, "rm_ %s", file);
            //system("rm filename");
            FILE *fp = popen(temp, "r");
            pclose(fp);
            fp = NULL;
        #endif
    } else {
        if (ret == CL_CLEAN) {
            printf("No virus detected.\n");
        } else {
            printf("Error: %s\n", cl_strerror(ret));
            cl_engine_free(engine);
            close(fd);
            return 2;
        }
    }
    close(fd);

    /* free memory */
    cl_engine_free(engine);

    /* calculate size of scanned data */
    mb = size * (CL_COUNT_PRECISION / 1024) / 1024.0;
    printf("Data scanned: %2.2Lf MB\n", mb);

    return ret == CL_VIRUS ? 1 : 0;
}

int recursive_dir(char *path)
{
    DIR *dp = NULL;
    struct dirent *st;
    struct stat sta;
    int ret = 0;
    char tmp_name[2048] = { 0 };

    st = NULL;
    memset(&sta, 0, sizeof(struct stat));
    memset(tmp_name, 0, 2048);
    
    dp = opendir(path);
    if (dp == NULL) {
        printf("open dir error!!\n");
        return -1;
    }

    while (1) {
        st = readdir(dp);
        if (NULL == st)                     //读取完毕
        {
            break;
        }
        strcpy(tmp_name, path);
        if (path[strlen(path) - 1] != '/')  //判断路径名是否带/
            strcat(tmp_name, "/");
        strcat(tmp_name, st->d_name);       //新文件路径名
        ret = stat(tmp_name, &sta);         //查看目录下文件属性
        if (ret < 0)
        {
            printf("read stat fail\n");
            return -1;
        }

        if (S_ISDIR(sta.st_mode))           //如果为目录文件
        {
            if (0 == strcmp("..", st->d_name) || 0 == strcmp(".", st->d_name)) //忽略当前目录和上一层目录
                continue;
            else
            {
                recursive_dir(tmp_name);       //递归读取
            }
        }
        else                                //不为目录则打印文件路径名
        {
            printf("%s\n", tmp_name);
            detect_virus_files(tmp_name);
        }
    }

    closedir(dp);
    
    return 0;
}

int is_file_dir(char *file)
{
    struct stat buf;
    int result = 0;
    
    
    result = stat(file, &buf);
    if(S_IFDIR & buf.st_mode)
    {
        return 2;
    }
    else if(S_IFREG & buf.st_mode)
    {
        return 1;
    }

    return result; 
}

int _clamav(int argc, char *argv[], char **env)
{
    int is_fd = is_file_dir(argv[argc-1]);
    if (1 == is_fd)
    {
        detect_virus_files(argv[argc-1]);
    }
    else if (2 == is_fd)
    {
        recursive_dir(argv[argc-1]);
    }
    
    return 0;
}
