#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include "scfs.h"
#include "scrw.h"

/* global variables */
struct scconfig_str scconfig;
struct file_ent *root_node;

unsigned char doti_name[2] = {0x2e, 0x69};

/* extenal variables */
extern int fd;
extern unsigned char cur_fid; /* in scfs.c */

/* usage : scdir [filename] */

/* str is yes if it is "yes" or "1" */
int isyes(char *str)
{
    if (strncasecmp (str, "yes", 3) == 0) return 1;
    if (strncasecmp (str, "1", 1) == 0) return 1;
    return 0;
}

/* set default to the scconfig structure */
void scconfig_setdefault(struct scconfig_str *scc)
{
    scc->cla_default = 0xc0;
    scc->cla_select = CLA_UNDEFINED;
    scc->cla_verifykey = CLA_UNDEFINED;
    scc->cla_create = CLA_UNDEFINED;
    scc->cla_deletefile = CLA_UNDEFINED;
    scc->cla_verifypin = CLA_UNDEFINED;
    scc->cla_readbinary = CLA_UNDEFINED;
    scc->cla_updatebinary = CLA_UNDEFINED;
    scc->cla_readrecord = CLA_UNDEFINED;
    scc->cla_updaterecord = CLA_UNDEFINED;
    scc->cla_inauth = CLA_UNDEFINED;
    scc->cla_exauth = CLA_UNDEFINED;
    scc->cla_getresponse = CLA_UNDEFINED;
    scc->cla_getchallenge = CLA_UNDEFINED;
    scc->multiflexpin = 0;
    scc->multiflexgetres = 0;
}

/* get scconfig information from /etc/scfs.scdb */
int config_smartcard (FILE *cnfg_fd, int *line)
{
    char buf[256], *tmp;
    int cla, flag;
    
    scconfig_setdefault(&scconfig);

    for (;;) {
	if (fgets(buf, 255, cnfg_fd) == NULL) {
	    /*printf("line %d : requires \"}\" here.\n", *line);*/
	    return 1;
	}
	(*line)++;
	/*printf("buf=%s", buf);*/
	tmp = strtok(buf, Separator) ; /* Get the first token */
	if (tmp[0] == '#') continue;
	
	if (strcasecmp (tmp, STR_CARDNAME) == 0) {
	    strncpy (scconfig.name, strtok(NULL, Separator), 255);
	}
	else if (strcasecmp (tmp, STR_MULTIFLEXPIN) == 0) {
	    scconfig.multiflexpin = isyes(strtok(NULL, Separator));
	}
	else if (strcasecmp (tmp, STR_MULTIFLEXGETRES) == 0) {
	    scconfig.multiflexgetres = isyes(strtok(NULL, Separator));
	}
	else if (strcasecmp (tmp, STR_DEFAULT) == 0) {
	    tmp = strtok(NULL, Separator);
	    sscanf (tmp, "%x", &cla);
	    scconfig.cla_default = cla;
	}
	else if (strcasecmp (tmp, STR_VERIFYKEY) == 0) {
	    tmp = strtok(NULL, Separator);
	    sscanf (tmp, "%x", &cla);
	    scconfig.cla_verifykey = cla;
	}
	else if (strcasecmp (tmp, STR_VERIFYPIN) == 0) {
	    tmp = strtok(NULL, Separator);
	    sscanf (tmp, "%x", &cla);
	    scconfig.cla_verifypin = cla;
	}
	else if (strcasecmp (tmp, STR_SELECT) == 0) {
	    tmp = strtok(NULL, Separator);
	    sscanf (tmp, "%x", &cla);
	    scconfig.cla_select = cla;
	}
	else if (strcasecmp (tmp, STR_READBINARY) == 0) {
	    tmp = strtok(NULL, Separator);
	    sscanf (tmp, "%x", &cla);
	    scconfig.cla_readbinary = cla;
	}
	else if (strcasecmp (tmp, STR_UPDATEBINARY) == 0) {
	    tmp = strtok(NULL, Separator);
	    sscanf (tmp, "%x", &cla);
	    scconfig.cla_updatebinary = cla;
	}
	else if (strcasecmp (tmp, STR_CREATE) == 0) {
	    tmp = strtok(NULL, Separator);
	    sscanf (tmp, "%x", &cla);
	    scconfig.cla_create = cla;
	}
	else if (strcasecmp (tmp, STR_DELETEFILE) == 0) {
	    tmp = strtok(NULL, Separator);
	    sscanf (tmp, "%x", &cla);
	    scconfig.cla_deletefile = cla;
	}
	else if (strcasecmp (tmp, STR_READRECORD) == 0) {
	    tmp = strtok(NULL, Separator);
	    sscanf (tmp, "%x", &cla);
	    scconfig.cla_readrecord = cla;
	}
	else if (strcasecmp (tmp, STR_UPDATERECORD) == 0) {
	    tmp = strtok(NULL, Separator);
	    sscanf (tmp, "%x", &cla);
	    scconfig.cla_updaterecord = cla;
	}
	else if (strcasecmp (tmp, STR_INAUTH) == 0) {
	    tmp = strtok(NULL, Separator);
	    sscanf (tmp, "%x", &cla);
	    scconfig.cla_inauth = cla;
	}
	else if (strcasecmp (tmp, STR_EXAUTH) == 0) {
	    tmp = strtok(NULL, Separator);
	    sscanf (tmp, "%x", &cla);
	    scconfig.cla_exauth = cla;
	}
	else if (strcasecmp (tmp, STR_GETRESPONSE) == 0) {
	    tmp = strtok(NULL, Separator);
	    sscanf (tmp, "%x", &cla);
	    scconfig.cla_getresponse = cla;
	}
	else if (strcasecmp (tmp, STR_GETCHALLENGE) == 0) {
	    tmp = strtok(NULL, Separator);
	    sscanf (tmp, "%x", &cla);
	    scconfig.cla_getchallenge = cla;
	}
	else if (strcasecmp (tmp, STR_CREATETYPE) == 0) {
	    tmp = strtok(NULL, Separator);
	    sscanf (tmp, "%x", &flag);
	    scconfig.create_type = flag;
	}
	else if (strcasecmp (tmp, "}") == 0) {
	    break;
	}
    }

    if (scconfig.cla_verifykey == CLA_UNDEFINED)
	scconfig.cla_verifykey = scconfig.cla_default;
    if (scconfig.cla_create == CLA_UNDEFINED)
	scconfig.cla_create = scconfig.cla_default;
    if (scconfig.cla_deletefile == CLA_UNDEFINED)
	scconfig.cla_deletefile = scconfig.cla_default;
    if (scconfig.cla_verifypin == CLA_UNDEFINED)
	scconfig.cla_verifypin = scconfig.cla_default;
    if (scconfig.cla_select == CLA_UNDEFINED)
	scconfig.cla_select = scconfig.cla_default;
    if (scconfig.cla_readbinary == CLA_UNDEFINED)
	scconfig.cla_readbinary = scconfig.cla_default;
    if (scconfig.cla_updatebinary == CLA_UNDEFINED)
	scconfig.cla_updatebinary = scconfig.cla_default;
    if (scconfig.cla_readrecord == CLA_UNDEFINED)
	scconfig.cla_readrecord = scconfig.cla_default;
    if (scconfig.cla_updaterecord == CLA_UNDEFINED)
	scconfig.cla_updaterecord = scconfig.cla_default;
    if (scconfig.cla_inauth == CLA_UNDEFINED)
	scconfig.cla_inauth = scconfig.cla_default;
    if (scconfig.cla_exauth == CLA_UNDEFINED)
	scconfig.cla_exauth = scconfig.cla_default;
    if (scconfig.cla_getresponse == CLA_UNDEFINED)
	scconfig.cla_getresponse = scconfig.cla_default;
    if (scconfig.cla_getchallenge == CLA_UNDEFINED)
	scconfig.cla_getchallenge = scconfig.cla_default;
    
    /*print_scconfig(&scconfig);*/
    return 0;
}


int scdir_init(unsigned char *atr, char *filename)
{
    FILE *cnfg_fd;
#define BUFLEN 1024
    char buf[BUFLEN], *tmp=NULL;
    int found_field = 0, found = 0, line = 0, i, same=1, x1, rv;

    scconfig.num_entries = 0;
    scconfig.create_type = 0;
    
    if (filename) {
	strcpy (buf, filename);
    } else {
	strcpy (buf, SCDFILE);
    }
  
    if ((cnfg_fd = fopen (buf, "r")) == NULL) {
	fprintf (stderr, "cannot open %s\n", buf);
	exit (-1);
    }
    
    /* find correct smartcard type */
    /* find "ATR" field */
    found_field = 0; found = 0;
    while (1) {
	found_field = 0;
    
	if (fgets(buf, BUFSIZ-1, cnfg_fd) == NULL) {
	    break;
	}
	line++;
	
	tmp = strtok(buf, Separator);
	/* Look for "ATR" field */
	while (tmp) {
	    if (strcasecmp (tmp, STR_ATR) == 0) {
		found_field = 1;
		break;
	    }
	    tmp = strtok(NULL, Separator);
	}
	if (found_field == 1) {
	    /* Check ATR */
	    same = 1;
	    
	    for (i=0; i<4; i++) {
		tmp=strtok(NULL, Separator);
		/*printf("%s\n", tmp);*/
		sscanf (tmp, "%x", &x1);
		if (atr[i] != x1) {
		    same = 0;
		}
	    }
	    
	    if (same == 1) {
		/*printf("set found=1\n");*/
		found = 1;
		break;
	    }
	}
    }
    
    if (found == 1) {
	rv = config_smartcard (cnfg_fd, &line);
	fclose(cnfg_fd);
	return rv;
    } 
    
    if (found == 0) {
	fprintf (stderr, "scdir_init() : Cannot find correct ATR\n");
	return 1;
    }
    
    fprintf (stderr, "scdir_init() : Should not be here ...\n");
    return 1;  
}

/* Create a new file entry, and returns it.  */
file_ent *new_file_ent (unsigned char *name, enum file_type type,
			file_ent *parent)
{
    file_ent *new_fe;

    new_fe = (file_ent *)malloc(sizeof(struct file_ent_str));
    memcpy (new_fe->name, name, 2);
    new_fe->fid = scconfig.num_entries + 1;
    new_fe->type = type; 
    new_fe->parent = parent;
    new_fe->num_children = 0;
    scconfig.file_entries[scconfig.num_entries] = new_fe;
    scconfig.num_entries++;

    return new_fe;
}

/* create the file entry for the root (3f.00) */
int scdir_newroot()
{
    u_char root_name[] = {(u_char)0x3f, (u_char)0x00}; 
    file_ent *root_fe = NULL;

    root_fe = new_file_ent (root_name, SCFS_TYPE_DIR, NULL);
    assert (root_fe); 
    root_fe->p_size = 10;
    root_fe->l_size = 10;
    cur_fid = root_fe->fid;
    
    return 0;
}

void file_ent_dump(file_ent *fe, int depth)
{
    int i;

    for (i = 0 ; i <= depth ; i++)
	printf ("  ");
    
    printf ("file_ent: name %02x.%02x, fid %d, type %d, p_size %d, l_size %d, num_children %d\n",
	    fe->name[0], fe->name[1],
	    fe->fid, fe->type, fe->p_size, fe->l_size, fe->num_children);

    for (i = 0 ; i < fe->num_children ; i ++) {
	file_ent_dump (fe->child[i], depth+1);
    }
    return; 
}

void scdir_dump()
{
    file_ent_dump(scconfig.file_entries[0], 0);
    
    return; 
}

/* scan a directory */
int scdir_newdir(file_ent *fe)
{
    int offset, rv, sw1, sw2, i, j;
    u_char buf[DOTI_LEN + 2];
    enum file_type type; 
    
    assert(fe);
    
    if (godown(fe)){
	fprintf (stderr, "Cannot go down to %02x.%02x",
		 fe->name[0], fe->name[1]);
	return -1;
    }
    
    /* create an entry for .i */
    fe->num_children = 1;
    fe->child[0] = new_file_ent(doti_name, SCFS_TYPE_ELFILE, fe);
    fe->child[0]->p_size = MAX_CHILDREN * DOTI_LEN;
    fe->child[0]->l_size = MAX_CHILDREN * DOTI_LEN;

    /* select the .i */
    if (scfs_open_file(doti_name)) {
	fprintf (stderr, "Cannot open file %02x.%02x\n",
		 doti_name[0], doti_name[1]);
	return -1;
    }
    /* now that I have opened .i, I have to set cur_fid. */
    cur_fid = fe->child[0]->fid; 

    /* scan the .i */
    offset = 0; 
    for (i = 1 ; ; i++) {/* start from i=1 because of .i */
	printf ("i = %d, offset = %d\n", i, offset);
	bzero (buf, DOTI_LEN+2);
	rv = sw1 = sw2 = 0;
	rv = scread (fd, scconfig.cla_readbinary, 0xb0, (offset >> 8) & 0xff,
		     offset & 0xff, DOTI_LEN, buf, &sw1, &sw2);
	printf ("rv = %d, sw1 = %d, sw2 = %d\n", rv, sw1, sw2);
	if (rv <= 0) {
	    goto endloop;
	}

	printf ("buf: ");
	for (j = 0 ; j < DOTI_LEN ; j ++)
	    printf ("%02x ", buf[j]);
	printf ("\n");
	
	/* have to unmarshal .i

	   scfs info is in .i (2e.69)
	   
	   0-1 file name
	   2-3 parent dir name
	   4-5 parent's parent
	   6-7 parent's parent
	   8 type: 0->null, 1->bin, 2->rec, 3->ddir
	   9 0
	   10-11 max size (LSB first)
	   12-13 actual size
	   14-15 rfu */

	type = buf[8];
	if (type <= SCFS_TYPE_NULL || type > SCFS_TYPE_DIR ||
	    buf[9] != 0) goto endloop;

	fe->child[i] = new_file_ent (buf, type, fe);
	fe->num_children++;
	fe->child[i]->name[0] = buf[0];
	fe->child[i]->name[1] = buf[1];
	fe->child[i]->type = buf[8];
	fe->child[i]->p_size = buf[10] + buf[11]*0x100;
	fe->child[i]->l_size = buf[12] + buf[13]*0x100; 
	
	if (fe->child[i]->type == SCFS_TYPE_DIR){
	    if (scdir_newdir(fe->child[i])) {
		fprintf (stderr, "new_dir for %02x.%02x failed.",
			 fe->child[i]->name[0], fe->child[i]->name[1]);
		return -1;
	    }
	}

	if (godown(fe)){
	    fprintf (stderr, "Cannot go down to %02x.%02x\n",
		    fe->name);
	    return -1;
	}

	/* select the .i */
	if (scfs_open_file(doti_name)) {
	    fprintf (stderr, "Cannot open file %02x.%02x\n",
		     doti_name[0], doti_name[1]);
	    return -1;
	}
	/* now that I have opened .i, I have to set cur_fid. */
	cur_fid = fe->child[0]->fid; 

	offset += DOTI_LEN;
    }
 endloop:

    return 0;
}

file_ent *fid_to_fe(u_long fid)
{
    printf ("fid %d, ne %d\n",
	    fid, scconfig.num_entries);
    assert (fid > 0 && fid <= scconfig.num_entries);

    assert (scconfig.file_entries[fid - 1]);
    
    return scconfig.file_entries[fid - 1];
}


/* create .i entry from file_ent

   return 0 on success.
   return -1 on failure. 
 */
int marshal_doti (unsigned char *buf, file_ent *fe)
{
    /*
      scfs info is in .i (2e.69)
	   
      0-1: file name
      2-7: unused
      8 type: 0->null, 1->bin, 2->rec, 3->ddir
      9 0
      10-11 max size (LSB first)
      12-13 actual size
      14-15 unused */

    assert (fe);
    assert (buf);

    if (fe->type <= SCFS_TYPE_NULL || fe->type > SCFS_TYPE_DIR)
	return -1;

    bzero (buf, DOTI_LEN);
    buf[0] = fe->name[0];
    buf[1] = fe->name[1];
    buf[8] = fe->type; 
    buf[10] = fe->p_size & 0xff;
    buf[11] = (fe->p_size * 0x100) & 0xff;
    buf[12] = fe->l_size & 0xff;
    buf[13] = (fe->l_size * 0x100) & 0xff;
    
    return 0;
}

/* update .i file

   return 0 on success.
   return -1 on failure. 
 */
int update_doti (file_ent *fe)
{
    int idx, rv, r1, r2;
    file_ent *par_fe, *doti_fe;
    u_long offset;
    unsigned char buf[DOTI_LEN];

    assert (fe);
    assert (fe->parent);
    assert (fe->parent->child[0]);

    par_fe = fe->parent;
    doti_fe = fe->parent->child[0];

    assert (strncmp (doti_fe->name, doti_name, 2) == 0); 

    /* marshal fe to buf */
    rv = marshal_doti (buf, fe);
    if (rv != 0) {
	printf ("could not marshal %02x.%02x\n",
		fe->name[0], fe->name[1]);
	return rv; 
    }
    
    /* fe is the idx'th child of the parent. */
    idx = find_child_in_parent (par_fe, fe);
    if (idx < 0) return -1; 
    
    /* select the .i of the parent */
    rv = godown (doti_fe);
    if (rv != 0) {
	printf ("could not go down to %02x.%02x\n",
		doti_fe->name[0], doti_fe->name[1]);
	return rv; 
    }

    /* update the idx'th entry of the parent's .i */
    offset = (idx - 1) * DOTI_LEN; /* idx - 1 because of .i */

    /* now write buf to the .i file */
    rv = scwrite (fd, scconfig.cla_updatebinary, 0xd6,
		  (offset >> 8) & 0xff, offset & 0xff,
		  DOTI_LEN, buf, &r1, &r2);
    if (rv < 0 || r1 != 0x90 || r2 != 0x00) {/* read failed */
	printf ("scwrite failed.  rv %d, r1 %02x, r2 %02x\n",
		rv, r1, r2);
	return -1; 
    }

    return 0; 
}

#ifdef NIXX
void print_scconfig(struct scconfig_str *scc)
{
  printf("Print out scconfig structure:\n");
  printf("\tname=%s\n", scc->name);
  printf("\tmultiflexpin=%d\n", scc->multiflexpin);
  printf("\tmultiflexgetres=%d\n", scc->multiflexgetres);
  printf("\tcla_default=%x\n", scc->cla_default);
  printf("\tcla_verifykey=%x\n", scc->cla_verifykey);
  printf("\tcla_create=%x\n", scc->cla_create);
  printf("\tcla_deletefile=%x\n", scc->cla_deletefile);
  printf("\tcla_verifypin=%x\n", scc->cla_verifypin);
  printf("\tcla_select=%x\n", scc->cla_select);
  printf("\tcla_readbinary=%x\n", scc->cla_readbinary);
  printf("\tcla_updatebinary=%x\n", scc->cla_updatebinary);
  printf("\tcla_readrecord=%x\n", scc->cla_readrecord);
  printf("\tcla_updaterecord=%x\n", scc->cla_updaterecord);
  printf("\tcla_inauth=%x\n", scc->cla_inauth);
  printf("\tcla_exauth=%x\n", scc->cla_exauth);
  printf("\tcla_getresponse=%x\n", scc->cla_getresponse);
  printf("\tcla_getchallenge=%x\n", scc->cla_getchallenge);
}  

struct scdnode *get_scdnode(unsigned char *fid)
{
  int i;

  /*arla_warnx (ADEBMSG, "get_scdnode called for %02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x, num_nodes = %d",
	      fid[0], fid[1], fid[2], fid[3],
	      fid[4], fid[5], fid[6], fid[7], scconfig.num_nodes);*/
  
  for (i=0; i<scconfig.num_nodes; i++) {
    if (fidcmp (fid, scconfig.scdnodes[i]->fileent.fid)) {
      return scconfig.scdnodes[i];
    }
  }
  return NULL;
}


int name2fid (char *name, unsigned char *fid, int *recnum)
{
  unsigned int tmp[FID_LEN], tmp2;
  /*if (strlen(name) != 2*FID_LEN) goto bad;*/

  if (sscanf(name, "%02x%02x%02x%02x%02x%02x%02x%02xr%02x",
	     &(tmp[0]), &(tmp[1]), &(tmp[2]), &(tmp[3]),
	     &(tmp[4]), &(tmp[5]), &(tmp[6]), &(tmp[7]), &tmp2)
      == FID_LEN+1) {
    /*fprintf(stderr, "name2fid : record file %02x.%02x\n", tmp[0], tmp[1]);*/
    *recnum = tmp2;
    goto success;
  }
  else if (sscanf(name, "%02x%02x%02x%02x%02x%02x%02x%02x",
	     &(tmp[0]), &(tmp[1]), &(tmp[2]), &(tmp[3]),
	     &(tmp[4]), &(tmp[5]), &(tmp[6]), &(tmp[7]))
      == FID_LEN) {
    /*fprintf(stderr, "name2fid : non-record file %02x.%02x\n", tmp[0], tmp[1]);*/
    *recnum = 0;
    goto success;
  } else {
    goto bad;
  }

 success:
  fid[0] = (unsigned char)(tmp[0] & 0xff);
  fid[1] = (unsigned char)(tmp[1] & 0xff);
  fid[2] = (unsigned char)(tmp[2] & 0xff);
  fid[3] = (unsigned char)(tmp[3] & 0xff);
  fid[4] = (unsigned char)(tmp[4] & 0xff);
  fid[5] = (unsigned char)(tmp[5] & 0xff);
  fid[6] = (unsigned char)(tmp[6] & 0xff);
  fid[7] = (unsigned char)(tmp[7] & 0xff);
  return 0;

 bad:
  arla_warnx (ADEBERROR, "name2fid failed.");
  return -1;
}

void print_path (struct scdnode *node)
{
  struct scdnode *tmp;
  int path[MaxDepth][2], i;

  for (tmp = node, i=0; tmp != NULL; tmp = tmp->parent, i++) {
    path[i][0] = tmp->fileent.fid[0];
    path[i][1] = tmp->fileent.fid[1];
  }
  /*printf("path to %02x.%02x\n", node->fid[0], node->fid[1]);
    for (j=i-1; j>=0; j--) printf("%02x.%02x ", path[j][0], path[j][1]);
    printf("\n\n");*/
}

int scfs_getdirent(unsigned char *fid, unsigned char *parent_fid, char *dirent)
{
  struct scdnode *node, *child;
  struct dirent dire[MaxNumChildren + 2 + 1]; /* #children + . + .. + .i */
  int i, j;

  if ((node = get_scdnode (fid)) == NULL) {
    return -1;
  }

  if (node->fileent.d_type == SCFS_TYPE_ELFILE) {
    return -1;
  }

  dire[0].d_fileno = fid2inode(fid);
  dire[0].d_reclen = 12;
  dire[0].d_type = DT_DIR;
  dire[0].d_namlen = 1;
  strncpy(dire[0].d_name, ".\0\0\0", 4);
  
  dire[1].d_fileno = fid2inode(parent_fid);
  dire[1].d_reclen = 12;
  dire[1].d_type = DT_DIR;
  dire[1].d_namlen = 2;
  strncpy(dire[1].d_name, "..\0\0", 4);
  
  if (node->fileent.d_type == SCFS_TYPE_DIR) {
    for (i=0; i<node->num_children; i++) {
      child = node->child[i];
      dire[i+2].d_fileno = fid2inode(child->fileent.fid);
      dire[i+2].d_reclen = 12;
      /* type ? */
      if (child->fileent.d_type == SCFS_TYPE_ELFILE) 
	dire[i+2].d_type = DT_REG;
      else
	dire[i+2].d_type = DT_DIR;
      dire[i+2].d_namlen = 2;
      /* name ? */
      dire[i+2].d_name[0] = (unsigned char)child->fileent.fid[0];
      dire[i+2].d_name[1] = (unsigned char)child->fileent.fid[1];
      /*fprintf(stderr, "name=%c%c\n",
	dire[i+2].d_name[0], dire[i+2].d_name[1]);*/
    }
  }
  else if (node->fileent.d_type == SCFS_TYPE_RECFILE) {
    for (i=0; i<node->num_children; i++) {
      dire[i+2].d_fileno = 1;
      dire[i+2].d_reclen = 12;
      /* type ? */
      dire[i+2].d_type = DT_REG;
      dire[i+2].d_namlen = 4;
      /* name ? */
      dire[i+2].d_name[0] = (unsigned char)'0';
      dire[i+2].d_name[1] = (unsigned char)'0';
      dire[i+2].d_name[2] = (unsigned char)'0';
      dire[i+2].d_name[3] = (unsigned char)(i+1+'0');
    }
  }
  /* i = numchildren */
  dire[i-1+2].d_reclen = 1012 - 12*i;

  for (j=0; j<i+2; j++) {
    bcopy (&(dire[j]), dirent+12*j, 12);
  }
  
  return 0;
}

int scdir_free()
{
  return free_dir(root_node);
}

int free_dir(struct scdnode *node)
{
  int i;
  struct fileent *fe;

  if (node == NULL) return 0; 
  
  fe = &node->fileent;

  /*arla_warnx (ADEBERROR, "free_dir(%02x.%02x)",
    fe->fid[0], fe->fid[1]);*/
    
  if (fe->d_type == SCFS_TYPE_DIR){
    for (i=0; i<node->num_children; i++){
      free_dir(node->child[i]);
    }
  }
  /*if (node->parent) free(node->parent);*/
  if (node) free(node);

  return 0;
}
#endif NIXX
