/*
 *  linux/drivers/bootldr/labcopy.c
 *
 *  Copyright (C) 2003 Joshua Wise
 *  Bootloader port to Linux Kernel, May 09, 2003
 *
 * "copy" command for LAB CLI.
 */

#include <linux/module.h>
#include <linux/init.h> 
#include <linux/kernel.h>
#include <asm/dma.h>
#include <asm/io.h>
#include <linux/config.h>
#include <linux/slab.h>
#include <linux/unistd.h>
#include <linux/ctype.h>
#include <linux/blk.h>
#include <linux/bootldr/commands.h>
#include <linux/bootldr/copy.h>
#include <linux/vmalloc.h>

struct lab_srclist* srclist;
struct lab_destlist* destlist;

void lab_cmd_copy(int argc,const char** argv);

int labcopy_init(void)
{
	/* We don't need to do much here. */
	lab_addcommand("copy", lab_cmd_copy, "Copies data from a source to a destination.");
	return 0;
};

void labcopy_cleanup(void)
{
};

void lab_copy_addsrc(char* name, int(*check)(char* fn), unsigned char*(*get)(int* count,char* fn))
{
	struct lab_srclist *mylist;
	
	mylist = srclist;
	if (!mylist)
	{
		srclist=mylist=kmalloc(sizeof(struct lab_srclist), GFP_KERNEL);
		goto buildentry;
	};
	
	while (mylist->next)
		mylist = mylist->next;
	
	mylist->next=kmalloc(sizeof(struct lab_srclist), GFP_KERNEL);
	mylist = mylist->next;
	
buildentry:
	mylist->next = NULL;
	mylist->src = kmalloc(sizeof(struct lab_src), GFP_KERNEL);
	mylist->src->name = name;
	mylist->src->check = check;
	mylist->src->get = get;
	
	printk(KERN_NOTICE "lab: loaded copy source [%s]\n", name);
};

void lab_copy_adddest(char* name, int(*check)(char* fn), int(*put)(int count,unsigned char* data,char* fn))
{
	struct lab_destlist *mylist;
	
	mylist = destlist;
	if (!mylist)
	{
		destlist=mylist=kmalloc(sizeof(struct lab_destlist), GFP_KERNEL);
		goto buildentry;
	};
	
	while (mylist->next)
		mylist = mylist->next;
	
	mylist->next=kmalloc(sizeof(struct lab_srclist), GFP_KERNEL);
	mylist = mylist->next;
	
buildentry:
	mylist->next = NULL;
	mylist->dest = kmalloc(sizeof(struct lab_dest), GFP_KERNEL);
	mylist->dest->name = name;
	mylist->dest->check = check;
	mylist->dest->put = put;
	
	printk(KERN_NOTICE "lab: loaded copy destination [%s]\n", name);
};

void lab_copy(char* source, char* sourcefile, char* dest, char* destfile)
{
	struct lab_srclist *mysrclist;
	struct lab_destlist *mydestlist;
	int srcsize;
	int destsize;
	int count;
	unsigned char* data;
	
	mysrclist = srclist;
	
	while(mysrclist)
	{
		if (!strcmp(source,mysrclist->src->name))
			break;
		mysrclist = mysrclist->next;
	};
	
	if (!mysrclist)
	{
		putstr("Source [");
		putstr(source);
		putstr("] does not exist.\r\n");
		return;
	};
	
	mydestlist = destlist;
	
	while(mydestlist)
	{
		if (!strcmp(dest,mydestlist->dest->name))
			break;
		mydestlist = mydestlist->next;
	};
	
	if (!mydestlist)
	{
		putstr("Destination [");
		putstr(dest);
		putstr("] does not exist.\r\n");
		return;
	};
	
	if (!mysrclist->src->check(sourcefile))
	{
		putstr("Source [");
		putstr(source);
		putstr("] rejected filename \"");
		putstr(sourcefile);
		putstr("\".\r\n");
		return;
	};
	
	if (!mydestlist->dest->check(destfile))
	{
		putstr("Destination [");
		putstr(dest);
		putstr("] rejected filename \"");
		putstr(destfile);
		putstr("\".\r\n");
		return;
	};
	
	data = mysrclist->src->get(&count,sourcefile);
	if (!data)
	{
		putstr("Error occured while getting file.\r\n");
		return;
	};
	
//	printk("lab: got file.....\n");
	
	if (mydestlist->dest->put(count,data,destfile) == 0)
	{
		putstr("Error occured while putting file.\r\n");
		vfree(data);
		return;
	};
//	printk("lab: put file....\n");
	
	vfree(data);
//	printk("lab: freed data....\n");
};

void lab_cmd_copy(int argc,const char** argv)
{
	char *temp;
	char *source;
	char *sourcefile;
	char *dest;
	char *destfile;

	if (argc != 3)
	{
		putstr("Usage: boot> copy filespec filespec\r\n");
		putstr("filespec is device:[file]\r\n");
		putstr("example: boot> copy ymodem: flash:bootldr\r\n");
		putstr("would receive data over ymodem, and flash it to the bootldr partition.\r\n");
		putstr("example 2: boot> copy fs:/flash/boot/params ymodem:\r\n");
		return;
	};
	
	temp = source = argv[1];
	while (*temp != ':' && *temp != '\0')
		temp++;
	if (*temp == '\0')
	{
		putstr("Illegal filespec\r\n");
		return;
	};
	*temp = '\0';
	temp++;
	sourcefile = temp;
	
	temp = dest = argv[2];
	while (*temp != ':' && *temp != '\0')
		temp++;
	if (*temp == '\0')
	{
		putstr("Illegal filespec\r\n");
		return;
	};
	*temp = '\0';
	temp++;
	destfile = temp;
	
	putstr("Copying [");
	putstr(source);
	putstr("]");
	putstr(sourcefile);
	putstr(" to [");
	putstr(dest);
	putstr("]");
	putstr(destfile);
	putstr("...\r\n");
	lab_copy(source, sourcefile, dest, destfile);
	
};

MODULE_AUTHOR("Joshua Wise");
MODULE_DESCRIPTION("LAB copy command module");
MODULE_LICENSE("GPL");
module_init(labcopy_init);
module_exit(labcopy_cleanup);