#include <stdio.h>
#include <stdlib.h>
#include <time.h>
/*
* Made by Maurus Cuelenaere
*
* Based on http://minnie.tuhs.org/VSTa/srctree/newsrc/srv/bfs/bfs.h.html
* and http://www.gruppo4.com/~tobia/zenrecover.shtml
*
*/
struct partition_header
{
unsigned char end[4];
unsigned char start[4];
char name[8];
};
struct main_header
{
char mblk[4];
unsigned char sector_size[4];
unsigned char disk_size[8];
struct partition_header partitions[31];
};
struct cfs_header
{
unsigned char unk[8];
unsigned char unk2[4];
unsigned char unk3[4];
unsigned char unk4[4];
unsigned char unk5[4];
char identifier[4];
unsigned char unk7[4];
unsigned char unk8[4];
unsigned char unk9[4];
unsigned char unk10[4];
unsigned char unk11[4];
};
#define CLUSTER_TO_OFFSET(n) ((n+1)*0x2000)
struct cfs_inode
{
unsigned char magic[4]; /* BE 3B D9 0A */
unsigned char number[4]; /* Inode number */
unsigned char parent[4];
unsigned char unk[4]; /* Always 0xFFFF */
unsigned char type[4];
unsigned char created_time[4];
unsigned char lastmodified_time[4];
unsigned char unk2[4];
unsigned char first_class_chain[12][4];
unsigned char unk3[4];
unsigned char unk4[4];
unsigned char second_class_chain_first_cluster[4];
unsigned char unk9[4];
unsigned char unk10[4];
unsigned char second_class_chain_second_cluster[4];
unsigned char unk11[4];
unsigned char unk12[4];
unsigned char unk13[4];
unsigned char filesize[4];
unsigned char serial_number[4];
unsigned char number_of_metadata_records[4];
};
struct cfs_inode_metadata
{
unsigned char identifier[2];
unsigned char length[2];
//type value
//"06" - uint16, eq 0x0100
//"07" - wchar_t[], original filename
//"0=" - wchar_t[], original path
//"0;" - uint16, eq 0x0002
//"0>" - uint32, filesize |
//"11" - wchar_t[], album |
//"12" - wchar_t[], artist | in general its copy of the
//"13" - wchar_t[], genre | metadata stored in the ID3 tag
//"14" - wchar_t[], title | of the file
//"15" - uint16, length in seconds |
//"16" - uint16, track number |
//"17" - uint16, year |
//not all of them must be used in the inode's metadata
unsigned char tag[6];
/* unsigned char data[le2int16(length)]; */
};
struct cfs_second_class_chain_cluster
{
/* sequence of cluster numbers that together form the part of the file's contents */
unsigned char cluster_numbers[2048][4];
};
static unsigned short le2int16(unsigned char* buf)
{
return (buf[1] << 8) | buf[0];
}
static unsigned int le2int32(unsigned char* buf)
{
return (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
}
static char* strrev(char *s)
{
int i;
static char ret[4];
for(i=0; i<4; i++)
ret[3-i] = s[i];
return ret;
}
static char* ucs2letochar(unsigned char* s)
{
static char res[3];
res[0] = s[2];
res[1] = s[0];
res[2] = 0;
return res;
}
static char* ucs2letostring(unsigned char* s)
{
static char res[256];
int i, end;
for(i=0; i < 255; i += 2)
{
if(s[i] == 0 && s[i+1] == 0)
end = i;
}
for(i=0; i<end; i++)
res[i] = s[i*2];
return (char*)&res;
}
int main(int argc, char *argv[])
{
FILE *image;
struct main_header hdr;
struct cfs_header *cfs_hdr;
struct cfs_inode *inode;
unsigned int i, j, k;
struct cfs_inode_metadata *metadata;
unsigned char* buffer;
image = fopen(argv[1], "rb");
fread(&hdr, sizeof(struct main_header), 1, image);
printf("[%s]: %d * 0x%x\n", strrev
(hdr.
mblk), le2int32
(hdr.
sector_size), le2int32
(hdr.
disk_size));
for(i=0; i<31; i++)
{
if(hdr.partitions[i].name[0] != 0)
printf(" * [%s]: 0x%x -> 0x%x\n", hdr.
partitions[i
].
name, le2int32
(hdr.
partitions[i
].
start), le2int32
(hdr.
partitions[i
].
end));
}
#define START (((le2int32(hdr.partitions[1].start)*le2int32(hdr.sector_size)) & ~0xFFFF) + 0x10000)
#define REL_START ( START - (le2int32(hdr.partitions[1].start)*le2int32(hdr.sector_size)) )
buffer = malloc((le2int32(hdr.partitions[1].end)-le2int32(hdr.partitions[1].start))*le2int32(hdr.sector_size));
fseek(image, le2int32(hdr.partitions[1].start)*le2int32(hdr.sector_size), SEEK_SET);
fread(buffer, (le2int32(hdr.partitions[1].end)-le2int32(hdr.partitions[1].start))*le2int32(hdr.sector_size), 1, image);
fclose(image);
printf("Start of CFS is at 0x%x...\n\n", START
);
cfs_hdr = (struct cfs_header*)&buffer[REL_START];
printf("[%s]\n", strrev
(cfs_hdr
->identifier
));
printf(" * [%s]: 0x%x\n", "unk2" , le2int32
(cfs_hdr
->unk2
));
printf(" * [%s]: 0x%x\n", "unk3" , le2int32
(cfs_hdr
->unk3
));
printf(" * [%s]: 0x%x\n", "unk4" , le2int32
(cfs_hdr
->unk4
));
printf(" * [%s]: 0x%x\n", "unk5" , le2int32
(cfs_hdr
->unk5
));
printf(" * [%s]: %d\n", "unk7" , le2int32
(cfs_hdr
->unk7
));
printf(" * [%s]: %d\n", "unk8" , le2int32
(cfs_hdr
->unk8
));
printf(" * [%s]: 0x%x\n", "unk9" , le2int32
(cfs_hdr
->unk9
));
printf(" * [%s]: 0x%x\n", "unk10" , le2int32
(cfs_hdr
->unk10
));
printf(" * [%s]: 0x%x\n", "unk11" , le2int32
(cfs_hdr
->unk11
));
for(i=0; i < (le2int32(hdr.partitions[1].end)-le2int32(hdr.partitions[1].start))*le2int32(hdr.sector_size); i += 4)
{
if(le2int32(&buffer[i]) == 0x3bbe0ad9)
{
inode = (struct cfs_inode*)&buffer[i];
printf("[0x%04x] at 0x%08x\n", le2int32
(inode
->magic
), i
);
printf(" * [current]: 0x%04x\n", le2int32
(inode
->number
));
printf(" * [parent]: 0x%04x\n", le2int32
(inode
->parent
));
printf(" * [type]: 0x%04x\n", le2int32
(inode
->type
));
printf(" * [created_time]: %s", ctime
((time_t
*)inode
->created_time
));
printf(" * [lastmodified_time]: %s", ctime
((time_t
*)inode
->lastmodified_time
));
printf(" * [first_class_chain]:\n");
for(j=0; j<12; j++)
{
if(le2int32(inode->first_class_chain[j]) != 0xFFFFFFFF)
printf(" * [%d]: 0x%x\n", j
+1
, le2int32
(inode
->first_class_chain
[j
]));
}
printf(" * [second_class_chain]:\n");
printf(" * [1] 0x%x\n", le2int32
(inode
->second_class_chain_first_cluster
));
printf(" * [2] 0x%x\n", le2int32
(inode
->second_class_chain_second_cluster
));
printf(" * [serial_number]: 0x%x\n", le2int32
(inode
->serial_number
));
printf(" * [metadata_records]: 0x%04x\n", le2int32
(inode
->number_of_metadata_records
));
k = 0;
for(j=0; j < le2int32(inode->number_of_metadata_records); j++)
{
metadata = (struct cfs_inode_metadata*)&buffer[i+sizeof(struct cfs_inode)+k];
if(le2int16(metadata->length) == 4)
printf(" * [%s]: 0x%x\n", ucs2letochar
(metadata
->tag
), le2int32
(&buffer
[i
+sizeof(struct cfs_inode
)+k
+sizeof(struct cfs_inode_metadata
)]));
else if(le2int16(metadata->length) == 2)
printf(" * [%s]: 0x%x\n", ucs2letochar
(metadata
->tag
), le2int16
(&buffer
[i
+sizeof(struct cfs_inode
)+k
+sizeof(struct cfs_inode_metadata
)]));
else
printf(" * [%s]: %s\n", ucs2letochar
(metadata
->tag
), ucs2letostring
(&buffer
[i
+sizeof(struct cfs_inode
)+k
+sizeof(struct cfs_inode_metadata
)]));
k += sizeof(struct cfs_inode_metadata)+le2int16(metadata->length);
}
}
}
free(buffer);
return 0;
}