/* tfs2dir.c. Lists contents of Salora HDD-2510 harddisk */
/* Copyright (C) 2008 by jeroent.com */

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>

#define FIRST_DIR_ENTRY_ALIGNED  0x10005600    // we must read 512 aligned
#define FIRST_DIR_ENTRY_OFFSET   0x00
#define NUMBER_DIR_ENTRIES 2048
#define MAX_NAME_LENGTH 120

typedef unsigned int uint32;
typedef unsigned short uint16;

typedef struct _tfs2_dir_entry 
{
    uint16 utf16_name[MAX_NAME_LENGTH];  
    uint32 unknown1[3];
    uint32 address;
    uint32 unknown2[64];
} TFS2_DIR_ENTRY;

// apparently, we should read 512 multiples from a 512 aligned position, so we first read aligned into buffer
TFS2_DIR_ENTRY dir_entries_buffer[NUMBER_DIR_ENTRIES+1];
TFS2_DIR_ENTRY *dir_entries;

void dump_entries()
{
    int i;
    int entry;
    char name[MAX_NAME_LENGTH+1];
    for (entry=0; entry<NUMBER_DIR_ENTRIES;entry++) {
        i=0;
        while (i<MAX_NAME_LENGTH) 
        {
            if (dir_entries[entry].utf16_name[i]==0) 
            {
                break;
            }
            name[i]=dir_entries[entry].utf16_name[i]>>8; /*assuming ascii range*/
            i++;
        }
        name[i]='\0';
        printf ("entry: %4d  address: 0x%08x name: %s\n",entry,dir_entries[entry].address,name);
    }
}


main(int argc, char *argv[])
{
    int fd;
    int entry;
    if (argc!=2) {
       printf("Usage: tfs2dir [hdd device]\nexample:\n\n  tfs2dir /dev/hdd (linux)\n  tfs2dir /dev/ad3 (FreeBSD)\n\nMust be run as root\n");
       exit(-1);
    }
    printf ("Disk %s\n",argv[1]);
    fd=open(argv[1],O_RDONLY);
    if (-1==lseek(fd,FIRST_DIR_ENTRY_ALIGNED,SEEK_SET)) {
        printf ("SEEK ERROR\n");
        exit(-1);
    }
    int cnt;
    cnt = read(fd,dir_entries_buffer,(NUMBER_DIR_ENTRIES+1)*sizeof(TFS2_DIR_ENTRY)); 
    if (cnt!=(NUMBER_DIR_ENTRIES+1)*sizeof(TFS2_DIR_ENTRY)) {
      printf ("READ ERROR cnt=%d\n",cnt);
      exit(-1);
    }
    dir_entries = (TFS2_DIR_ENTRY *)(FIRST_DIR_ENTRY_OFFSET+(char *)dir_entries_buffer);
    close(fd);
    dump_entries();
}

