#include <stdlib.h>
#include <string.h>

#include <sys/types.h>

# define vmalloc malloc
# define printk  printf
# define kdev_t  int

typedef unsigned int kernel_cap_t;
struct inode {
    unsigned long i_ino;
    kdev_t i_dev;

    /* clues to verify that inode has not changed */

    umode_t i_mode;
    uid_t i_uid;
    gid_t i_gid;
    time_t i_mtime;
    __u32 i_generation;
};
struct dentry {
    struct inode *d_inode;
};

int fs_capability_fn_register(void *blob)
{
    return 1;
}

#define IS_ERR(x) (x ? 0:1)

#define _CAP_FS_SET 1
#define _CAP_FS_GET 2

#define TEST_FCAP_C

#include "fcaps.c"

struct inode test_inode = {
    0,         /* ino */
    0,         /* dev */
    0522,      /* mode */
    12,        /* uid */
    23,        /* gid */
    924757731, /* mtime */
    33         /* generation */
};

struct dentry test_dentry = {
    &test_inode
};

void list_fis ()
{
    int i;
    for (i=0; i<FI_BINS; ++i) {
	struct file_index *col;

	printf("%3d>", i);
	for (col=fi_tab[i]; col; col=col->next) {
	    printf("[%d/%d]", col->fi_ino, col->fi_dev);
	}
	printf("\n");
    }
}

main()
{
    int i,x,y;

    if (init_module()) {
	printf("failed to init\n");
	exit(1);
    }

    for (i=1; i<12345; i+=91) {
	kernel_cap_t ef,in,pe;

	test_inode.i_ino = i;
	test_inode.i_dev = i % 3;

	ef = i*23;
	in = i*7;
	pe = i*13;

	if (cap_select_by_dentry(&test_dentry, _CAP_FS_SET, &ef, &in, &pe)) {
	    printf("failed to add: [%d/%d] %d,%d,%d\n", i, i%3, ef, in, pe);
	    exit(1);
	}
    }
    list_fis();

    for (x=y=0, i=1; i<12345; i+=91) {
	kernel_cap_t ef,in,pe;

	test_inode.i_ino = i;
	test_inode.i_dev = i % 3;

	ef = 0;
	in = 0;
	pe = 0;

	test_inode.i_uid = 12 + (i%2);

	x++;
	printf("looking up [%d/%d]%s ", i, i%3, (i%2)?"*":"");
	if (!cap_select_by_dentry(&test_dentry, _CAP_FS_GET, &ef, &in, &pe)) {
	    if (ef && in && pe) {
		printf("got: %d,%d,%d", ef, in, pe);
		y++;
	    }
	}
	printf("\n");
    }
    printf("looking up half broken entries: %d hits of %d total\n", y,x);
    list_fis();

    printf("\n");
    for (i=1; i<12345; i+=91) {
	kernel_cap_t ef,in,pe;

	test_inode.i_ino = i;
	test_inode.i_dev = i % 3;

	ef = i*29;
	in = i*17;
	pe = i*9;

	if (cap_select_by_dentry(&test_dentry, _CAP_FS_SET, &ef, &in, &pe)) {
	    printf("failed to add: [%d/%d] %d,%d,%d\n", i, i%3, ef, in, pe);
	    exit(1);
	}
    }
    list_fis();

    cleanup_module();
    exit(0);
}
