/*

    File: ewf.c

    Copyright (C) 2006-2007 Christophe GRENIER <grenier@cgsecurity.org>
  
    This software is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.
  
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
  
    You should have received a copy of the GNU General Public License along
    with this program; if not, write the Free Software Foundation, Inc., 51
    Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

 */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#if defined(HAVE_LIBEWF_H) && defined(HAVE_LIBEWF)
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>	/* lseek, read, write, close */
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h> 	/* open */
#endif
#include <stdio.h>
#include <errno.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>     /* free */
#endif
#ifdef HAVE_GLOB_H
#include <glob.h>
#endif
#include "types.h"
#include "common.h"
#include "ewf.h"
#include "fnctdsk.h"
#ifndef O_BINARY
#define O_BINARY 0
#endif

#include <libewf.h>
#include "log.h"

static const char *fewf_description(disk_t *disk_car);
static const char *fewf_description_short(disk_t *disk_car);
static int fewf_clean(disk_t *disk_car);
static int fewf_read(disk_t *disk_car, const unsigned int count, void *nom_buffer, const uint64_t offset);
static int fewf_write(disk_t *disk_car, const unsigned int count, const void *nom_buffer, const uint64_t offset);
static int fewf_nowrite(disk_t *disk_car, const unsigned int count, const void *nom_buffer, const uint64_t offset);


struct info_fewf_struct
{
  LIBEWF_HANDLE *handle;
  uint64_t offset;
  char file_name[DISKNAME_MAX];
  int mode;
  void *buffer;
  unsigned int buffer_size;
};

disk_t *fewf_init(const char *device, const int debug, const arch_fnct_t *arch, const int mode)
{
  unsigned int num_files=0;
  char **filenames= NULL;
  disk_t *disk_car=NULL;
  struct info_fewf_struct *data;
#ifdef HAVE_GLOB_H
  glob_t globbuf;
#endif
  data=MALLOC(sizeof(*data));
  data->offset=0;
  strncpy(data->file_name,device,sizeof(data->file_name));
  data->file_name[sizeof(data->file_name)-1]='\0';
  data->buffer=NULL;
  data->buffer_size=0;
  data->mode=mode;
  data->handle=NULL;
//  data->handle=libewf_open(filenames, 1, ((mode&O_RDWR)==O_RDWR?LIBEWF_OPEN_WRITE:LIBEWF_OPEN_READ));
#ifdef HAVE_GLOB_H
  {
    globbuf.gl_offs = 0;
    glob(data->file_name, GLOB_DOOFFS, NULL, &globbuf);
    if(globbuf.gl_pathc>0)
    {
      filenames=MALLOC(globbuf.gl_pathc * sizeof(*filenames));
      for (num_files=0; num_files<globbuf.gl_pathc; num_files++) {
	filenames[num_files]=globbuf.gl_pathv[num_files];
      }
    }
  }
#else
  filenames=MALLOC(1*sizeof(*filenames));
  filenames[num_files] = data->file_name;
  num_files++;
#endif /*HAVE_GLOB_H*/
  if(filenames!=NULL)
    data->handle=libewf_open(filenames, num_files, LIBEWF_OPEN_READ);
  if(data->handle==NULL)
  {
#ifdef HAVE_GLOB_H
    globfree(&globbuf);
#endif
    free(filenames);
    free(data);
    return NULL;
  }
  if( libewf_parse_header_values( data->handle, LIBEWF_DATE_FORMAT_DAYMONTH) != 1 )
  {
    fprintf( stderr, "Unable to parse header values.\n" );
  }
  disk_car=(disk_t *)MALLOC(sizeof(*disk_car));
  disk_car->arch=arch;
  disk_car->sector_size=libewf_get_bytes_per_sector(data->handle);
//  printf("libewf_get_bytes_per_sector %u\n",disk_car->sector_size);
  if(disk_car->sector_size==0)
    disk_car->sector_size=DEFAULT_SECTOR_SIZE;
  disk_car->disk_size=libewf_get_media_size(data->handle);
  disk_car->disk_real_size=disk_car->disk_size;
//  printf("libewf_get_media_size %llu\n",(long long unsigned) (disk_car->sector_size/disk_car->sector_size));
  disk_car->CHS.head=255-1;
  disk_car->CHS.sector=63;
  disk_car->CHS.cylinder=(disk_car->disk_size/(disk_car->CHS.head+1))/disk_car->CHS.sector/disk_car->sector_size-1;
  disk_car->device=strdup(device);
  disk_car->write_used=0;
  disk_car->description_txt[0]='\0';
  disk_car->description=fewf_description;
  disk_car->description_short=fewf_description_short;
  disk_car->read=fewf_read;
  disk_car->write=((mode&O_RDWR)==O_RDWR?fewf_write:fewf_nowrite);
  disk_car->clean=fewf_clean;
  disk_car->data=data;
#ifdef HAVE_GLOB_H
  globfree(&globbuf);
#endif
  free(filenames);
  return disk_car;
}

static const char *fewf_description(disk_t *disk_car)
{
  const struct info_fewf_struct *data=(const struct info_fewf_struct *)disk_car->data;
  char buffer_disk_size[100];
  snprintf(disk_car->description_txt, sizeof(disk_car->description_txt),"Image %s - %s - CHS %u %u %u%s",
      data->file_name, size_to_unit(disk_car->disk_size,buffer_disk_size),
      disk_car->CHS.cylinder+1, disk_car->CHS.head+1, disk_car->CHS.sector,((data->mode&O_RDWR)==O_RDWR?"":" (RO)"));
  return disk_car->description_txt;
}

static const char *fewf_description_short(disk_t *disk_car)
{
  const struct info_fewf_struct *data=(const struct info_fewf_struct *)disk_car->data;
  char buffer_disk_size[100];
  snprintf(disk_car->description_short_txt, sizeof(disk_car->description_txt),"Image %s - %s%s",
      data->file_name, size_to_unit(disk_car->disk_size,buffer_disk_size),
      ((data->mode&O_RDWR)==O_RDWR?"":" (RO)"));
  return disk_car->description_short_txt;
}

static int fewf_clean(disk_t *disk_car)
{
  if(disk_car->data!=NULL)
  {
    struct info_fewf_struct *data=(struct info_fewf_struct *)disk_car->data;
    libewf_close(data->handle);
    if(data->buffer!=NULL)
    {
      free(data->buffer);
      data->buffer=NULL;
    }
    free(disk_car->data);
    disk_car->data=NULL;
  }
  return 0;
}

static int fewf_read(disk_t *disk_car,const unsigned int count, void *nom_buffer, const uint64_t offset)
{
  struct info_fewf_struct *data=(struct info_fewf_struct *)disk_car->data;
  int64_t taille;
  taille=libewf_read_random(data->handle, nom_buffer, count, offset);
  if(taille!=count)
  {
    log_error("fewf_read(xxx,%u,buffer,%lu(%u/%u/%u)) read err: ",
	(unsigned)(count/disk_car->sector_size), (long unsigned)(offset/disk_car->sector_size),
	offset2cylinder(disk_car,offset), offset2head(disk_car,offset), offset2sector(disk_car,offset));
    if(taille<0)
      log_error("%s\n", strerror(errno));
    else if(taille==0)
      log_error("read after end of file\n");
    else
      log_error("Partial read\n");
    if(taille<=0)
      return -1;
  }
  return 0;
}

static int fewf_write(disk_t *disk_car,const unsigned int count, const void *nom_buffer, const uint64_t offset)
{
  struct info_fewf_struct *data=(struct info_fewf_struct *)disk_car->data;
  return -1;
}

static int fewf_nowrite(disk_t *disk_car,const unsigned int count, const void *nom_buffer, const uint64_t offset)
{
  struct info_fewf_struct *data=(struct info_fewf_struct *)disk_car->data;
  log_error("fewf_nowrite(xx,%u,buffer,%lu(%u/%u/%u)) write refused\n",
      (unsigned)(count/disk_car->sector_size), (long unsigned)(offset/disk_car->sector_size),
      offset2cylinder(disk_car,offset), offset2head(disk_car,offset), offset2sector(disk_car,offset));
  return -1;
}

const char*td_ewf_version(void)
{
#ifdef LIBEWF_VERSION
  return LIBEWF_VERSION;
#else
  return "available";
#endif
}
#else
#include "ewf.h"
const char*td_ewf_version(void)
{
  return "none";
}
#endif


syntax highlighted by Code2HTML, v. 0.9.1