/*
 * filesystem.c:
 *
 * Copyright (c) 2000 James McKenzie <james@fishsoup.dhs.org>,
 * All rights reserved.
 *
 */

static char rcsid[] =
    "$Id: filesystem.c,v 1.9 2001/10/04 18:00:36 root Exp $";

/*
 * $Log: filesystem.c,v $
 * Revision 1.9  2001/10/04 18:00:36  root
 * #
 *
 * Revision 1.8  2001/01/30 06:16:18  root
 * #
 *
 * Revision 1.7  2000/12/01 04:42:10  root
 * #
 *
 * Revision 1.6  2000/12/01 04:13:42  root
 * #
 *
 * Revision 1.5  2000/11/23 23:45:19  root
 * #
 *
 * Revision 1.4  2000/09/24 01:44:47  root
 * #
 *
 * Revision 1.3  2000/09/24 01:12:43  root
 * #
 *
 * Revision 1.2  2000/09/19 05:06:22  root
 * #
 *
 * Revision 1.1  2000/09/19 03:53:27  root
 * #
 *
 */

#include "project.h"


BEGIN_OBJECT(Collection_fs)
    COLLECTION_FILLER;
char *base;                     //Path to base;
END_OBJECT(Collection_fs)

static void fs_destructor(Collection_fs);

CREATOR(Collection_fs) = (Creator(Collection_fs)) Obj_DefaultCreator;
DESTRUCTOR(Collection_fs) = fs_destructor;

BEGIN_OBJECT(CFH_fs)
    CFH_FILLER;
FILE *f;
Eweid e;
char *path;                     //Absolute path to filename
char *rel;                      //Relative path to filename
Collection_fs c;                //My mummy
END_OBJECT(CFH_fs)

static void fh_destructor(CFH_fs);

CREATOR(CFH_fs) = (Creator(CFH_fs)) Obj_DefaultCreator;
DESTRUCTOR(CFH_fs) = fh_destructor;

static char collection_id[] = "collection.id";
static char collection_mtd[] = "collection.mtd";


static void fh_destructor(CFH_fs c)
{
#ifdef DEBUG
  if (c->path) {
    fprintf(stderr, "fs_close(%s)\n", c->path);
  }
#endif
  if (c->f)
    fclose(c->f);
  if (c->path)
    free(c->path);
  if (c->rel)
    free(c->rel);
  if (c->e)
    Obj_Delete(c->e);


  free(c);
}
static off_t fs_tell(CFH cfh)
{
  CFH_fs fh = (CFH_fs) cfh;
  off_t i = ftell(fh->f);
#ifdef DEBUG
  fprintf(stderr, "ftell()=%ld\n", i);
#endif
  return i;
}

#ifdef DEBUG
static int coredump = 0;
#endif


static off_t fs_seek(CFH cfh, off_t off, int whence)
{
  CFH_fs fh = (CFH_fs) cfh;
  off_t i = fseek(fh->f, off, whence);
#ifdef DEBUG
  fprintf(stderr, "fseek(,%ld,%d)=%ld\n", off, whence, i);
  if (coredump)
    abort();
#endif


  return i;
}

static int fs_read(CFH cfh, void *d, int s)
{
  CFH_fs fh = (CFH_fs) cfh;
  int i;
  i = fread(d, 1, s, fh->f);
#ifdef DEBUG
  fprintf(stderr, "fs_read(,,%d)=%d\n", s, i);
#endif
  return i;
}


static int fs_write(CFH cfh, void *d, int s)
{
  CFH_fs fh = (CFH_fs) cfh;
  return fwrite(d, 1, s, fh->f);
}

static int fs_get(CFH cfh)
{
  CFH_fs fh = (CFH_fs) cfh;
  return fgetc(fh->f);
}

static int fs_put(int c, CFH cfh)
{
  CFH_fs fh = (CFH_fs) cfh;
  return fputc(c, fh->f);
}


static int fs_eof(CFH cfh)
{
  CFH_fs fh = (CFH_fs) cfh;
  int i = feof(fh->f);
#ifdef DEBUG
  fprintf(stderr, "fs_eof()=%d\n", i);
#endif

  return feof(fh->f);
}

static off_t fs_size(CFH cfh)
{
  CFH_fs fh = (CFH_fs) cfh;
  struct stat s;

  if (stat(fh->path, &s))
    return (off_t) - 1;

#ifdef DEBUG
  fprintf(stderr, "fs_size()=%ld\n", s.st_size);
#endif


  return s.st_size;

}

static int fs_canread(CFH cfh)
{
  return 1;
}

static void fs_dispatch(CFH cfh)
{
}

static int fs_status(CFH cfh)
{
  return 100;
}

static void fs_close(CFH cfh)
{
  Obj_Delete(cfh);
}

static CFH fs_open(Collection rc, Eweid e, int mode)
{
  Collection_fs c = (Collection_fs) rc;
  CFH_fs fh;
  char *path;
  char *buf;
  FILE *f;

  path = eweid_to_filename(e);

  if (!path)
    return NULL;

  buf = malloc(strlen(path) + strlen(c->base) + 1);
  strcpy(buf, c->base);
  strcat(buf, path);

  switch (mode) {
  case O_RDONLY:
    f = fopen(buf, "r");
    break;
  case O_WRONLY:
    f = fopen(buf, "w");
    break;
  case O_RDWR:
    f = fopen(buf, "rw");
    break;
  default:
    f = NULL;
  }

#ifdef DEBUG
  fprintf(stderr, "fs_open(%s,%d)=%p\n", buf, mode, f);
#endif

  if (!f) {
    free(buf);
    return NULL;
  }

  fh = CREATE_OBJ(CFH_fs);
  fh->f = f;
  fh->e = eweid_dup(e);
  fh->path = buf;
  fh->rel = path;
  fh->c = c;

  fh->tell = fs_tell;
  fh->seek = fs_seek;
  fh->read = fs_read;
  fh->tread = fs_read;
  fh->write = fs_write;
  fh->get = fs_get;
  fh->put = fs_put;
  fh->eof = fs_eof;
  fh->size = fs_size;
  fh->close = fs_close;
  fh->canread = fs_canread;
  fh->dispatch = fs_dispatch;
  fh->status = fs_status;


  return (CFH) fh;
}


EXTERNAL Collection files_filesystem_collection(char *base)
{
  char *buf, *ptr;
  Eweid e;
  FILE *f;
  int i;

  Collection_fs c;

  base = directory_of(base);

  buf = malloc(strlen(base) + sizeof(collection_id));
  strcpy(buf, base);
  strcat(buf, collection_id);

  f = fopen(buf, "r");
  free(buf);

  if (!f) {
    free(base);
    return NULL;
  }

  e = CREATE_OBJ(Eweid);
  fread(e->e, 1, 4, f);
  fclose(f);

  buf = malloc(strlen(base) + strlen(collection_mtd) + 1);
  strcpy(buf, base);
  strcat(buf, collection_mtd);

  i = parse_mtd(buf);
  free(buf);

  if (i) {
    free(base);
    Obj_Delete(e);
    return NULL;
  }

  c = CREATE_OBJ(Collection_fs);

  c->name = "filesystem";
  c->e = e;
  c->open = fs_open;
  c->base = base;

  return (Collection) c;

}


static void fs_destructor(Collection_fs c)
{
  if (!c)
    return;
  if (c->base)
    free(c->base);
  free(c);
}
