/**************************************************************************************
$Id: format.c,v 1.6 2002/04/24 07:54:53 clive Exp $


**************************************************************************************/

#include <string.h>
#include <stdio.h>

unsigned long getfilesize(char *filename);
unsigned long ceil(double __x);

typedef struct {
  unsigned char jmp[4];	/* jump to code (4bytes) */
  unsigned char id[6];	/* Should be 'UbixFS' */
  unsigned long version;	/* Should be 1 */
  unsigned long fs_start;	/* LBA pointer to the start of the FS */
  unsigned long krnl_size; /* LBA pointer to Kernel file entry */
  unsigned int BytesPerSector;
  unsigned int SectorsPerTrack;
  unsigned int TotalHeads;
  unsigned long TotalSectors;
  unsigned char code[479];
  } __attribute__ ((packed)) t_bootsect;

typedef struct {
  unsigned char type;	/* 0 = unused. 1 = file entry. 2 = data_entry */
  unsigned long prev_entry;	/* LBA pointer to previous file entry */
  unsigned long next_entry;	/* LBA pointer to next file entry */
  unsigned char filename[255];	/* File name, padded with NULLs */
  /* Attributes
  * Bit 0: Read
  * Bit 1: Write
  * Bit 2: Execute
  * Bit 3: Hidden
  * Bit 4: Directory
  * Rest are unused, and available for future expansion
  */
  unsigned char attributes;
  unsigned long size;		/* size in bytes */
  unsigned long parent_dir;	/* LBA pointer to parent dir entry */
  unsigned long first_dataentry;	/* LBA pointer to next data struct */
  unsigned char padding[3819];
  } __attribute__ ((packed)) t_file_entry;

typedef struct {
  unsigned char type;	/* 0 = unused. 1 = file entry. 2 = data_entry */
  unsigned long prev_entry;	/* LBA pointer to previous data/file entry */
  unsigned long next_entry;	/* LBA pointer to next data/file entry */
  unsigned char data[4087];
  } __attribute__ ((packed)) t_data_entry;

// argv[1] = start of FS
// argv[2] = file to put onto FS
	
int main(int argc, char **argv) {
  t_bootsect bootsect;
  t_file_entry file_entry;
  t_data_entry data_entry;
  unsigned char *data;
  unsigned long _fs_start;
  unsigned long filesize=0;
  unsigned long cur_lbasector = 0;
  char filename[255];
  unsigned long no_of_files, file_loop=0;
  unsigned int loop=0;
  FILE *dev, *file;
  if (argc < 4) {
    printf("Usage: format <imagename> <fs_start> <no. of files> <filename> <filename>\n");
    exit(1);
    }
  sscanf(argv[2], "%d", &_fs_start);	
  sscanf(argv[3], "%d", &no_of_files);

  printf("Size of t_bootsect = %d\n", sizeof(bootsect));
  printf("Size of t_file_entry = %d\n", sizeof(t_file_entry));
  printf("Size of t_data_entry = %d\n", sizeof(t_data_entry));
  printf("Size of data_entry.data = %d\n", sizeof(data_entry.data));

  for (loop=0; loop<4; loop++) {
    bootsect.jmp[loop] = 0;
    }
	
  bootsect.id[0] = 'U';
  bootsect.id[1] = 'b';
  bootsect.id[2] = 'i';
  bootsect.id[3] = 'x';
  bootsect.id[4] = 'F';
  bootsect.id[5] = 'S';
  bootsect.version = 1;
  bootsect.fs_start = _fs_start;
  bootsect.BytesPerSector = 512;
  bootsect.SectorsPerTrack = 18;
  bootsect.TotalHeads = 2;
  bootsect.TotalSectors = 2880*512;
  bootsect.krnl_size = _fs_start;
	
  for (loop=0; loop<sizeof(bootsect.code); loop++) {
    bootsect.code[loop] = 0;
    }

  dev = fopen(argv[1], "wb");
  if (dev == NULL) {
    perror("open");
    exit(1);
    }

  fwrite(&bootsect, 512, 1, dev);
  cur_lbasector++;
  if (_fs_start!=1) {
    for (loop=0; loop<_fs_start-1; loop++) {	
      fwrite(&bootsect, 512, 1, dev);	
      cur_lbasector++;
      }
    }
	
  for (file_loop=4; file_loop<(4+no_of_files); file_loop++) {	
    printf("in loop, current file = \"%s\"\n", argv[file_loop]);
    strcpy(filename, argv[file_loop]);
    filesize = getfilesize(filename);
    file = fopen(filename, "rb");
    if (file == NULL) {
      perror(filename);
      exit(1);
      }
    data = (unsigned char *) malloc(filesize+sizeof(data_entry.data));
    if (!data) {
      printf("Insufficient memory\n");
      exit(1);
      }
	
    for (loop=0; loop<filesize; loop++) {
      data[loop] = fgetc(file);
      }

    file_entry.type = 1; /* Used - File entry */
    file_entry.prev_entry = 0;
    if ((file_loop+1)<(3+no_of_files)) {
      file_entry.next_entry = cur_lbasector + 8 + (ceil((double) filesize/ (double)4096)*8);
      }
    else {
      file_entry.next_entry = 0;
      }
    strcpy(file_entry.filename, filename);
    file_entry.attributes = (0xFF & (1 + 2));
    file_entry.size = ftell(file);
    file_entry.parent_dir = 0;
    file_entry.first_dataentry = cur_lbasector+8;
    fwrite(&file_entry, 4096, 1, dev);
    cur_lbasector += 8;
    for (loop=0; loop<ceil((double) filesize/ (double)sizeof(data_entry.data)); loop++) {
      data_entry.type = 2;
      data_entry.prev_entry = cur_lbasector-8; // _fs_start+(loop*8);
      if (loop+1 == ceil((double) filesize/ (double)sizeof(data_entry.data))) {
        data_entry.next_entry = 0;
        }
      else {
        data_entry.next_entry = cur_lbasector+8;// _fs_start+((loop+2)*8);
        }
      memcpy(data_entry.data, data+(loop*sizeof(data_entry.data)), sizeof(data_entry.data));	
      fwrite(&data_entry, 4096, 1, dev);
      cur_lbasector+=8;
      }
    fclose(file);
    free(data);
    }
  if ((2880 - cur_lbasector) != 0) {
    data = (unsigned char *)malloc(512);
    if (!data) {
      return;
      }
    memset(data, 0, 512);
    for (loop=0; loop<(2880-cur_lbasector); loop++) {
      fwrite(data, 512, 1, dev);
      }
    free(data);
    }
  fclose(dev);
  }

unsigned long getfilesize(char *filename) {
  FILE *in;
  unsigned long size=0;
  if ((in = fopen(filename, "rb"))==NULL) {
    return 0;
    }
  fseek(in, 0, SEEK_END);
  size = ftell(in);
  fclose(in);
  return size;
  }	

unsigned long ceil (double __x) {
  register double __value;
  __volatile unsigned short int __cw, __cwtmp;

  __asm __volatile ("fnstcw %0" : "=m" (__cw));
  __cwtmp = (__cw & 0xf3ff) | 0x0800; /* rounding up */
  __asm __volatile ("fldcw %0" : : "m" (__cwtmp));
  __asm __volatile ("frndint" : "=t" (__value) : "0" (__x));
  __asm __volatile ("fldcw %0" : : "m" (__cw));

  return __value;
  }
