2008-08-07 10:24:11 +00:00
|
|
|
/***************************************************************************
|
|
|
|
* __________ __ ___.
|
|
|
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
|
|
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
|
|
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
|
|
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
|
|
|
* \/ \/ \/ \/ \/
|
|
|
|
* $Id$
|
|
|
|
*
|
|
|
|
* Copyright (C) 2008 by William Poetra Yoga Hadisoeseno
|
|
|
|
*
|
|
|
|
* This program 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
|
|
|
* KIND, either express or implied.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <libgen.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
|
|
|
void usage()
|
|
|
|
{
|
|
|
|
fprintf(stderr, "usage: IHFSsplit <ihfs_img> <output_dir>\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
uint32_t signature;
|
|
|
|
uint32_t fslen;
|
|
|
|
uint32_t unknown1;
|
|
|
|
uint32_t unknown2;
|
|
|
|
char timestamp[12];
|
|
|
|
uint32_t numfiles;
|
|
|
|
char zeros[476];
|
|
|
|
uint32_t marker;
|
|
|
|
} ihfs_header_t;
|
|
|
|
|
|
|
|
#define MAX_FILES 2048
|
|
|
|
#define MAX_IHFS_PATH 56
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
struct {
|
|
|
|
char fullpath[MAX_IHFS_PATH];
|
|
|
|
uint32_t sector;
|
|
|
|
uint32_t length;
|
|
|
|
} files[MAX_FILES];
|
|
|
|
} ihfs_file_table_t;
|
|
|
|
|
|
|
|
#define SECTOR_SIZE 512
|
|
|
|
|
|
|
|
int ihfs_sanity(const int ihfs_img)
|
|
|
|
{
|
|
|
|
struct stat statbuf;
|
|
|
|
ihfs_header_t ihfs_hdr;
|
|
|
|
|
|
|
|
printf("starting sanity check for IHFS image...\n");
|
|
|
|
|
|
|
|
lseek(ihfs_img, 0, SEEK_SET);
|
|
|
|
read(ihfs_img, &ihfs_hdr, sizeof (ihfs_hdr));
|
|
|
|
|
|
|
|
printf(" checking for IHFS signature...\n");
|
|
|
|
if (ihfs_hdr.signature != 0x49484653)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
printf(" checking for FS length...\n");
|
|
|
|
fstat(ihfs_img, &statbuf);
|
|
|
|
if (ihfs_hdr.fslen * SECTOR_SIZE != statbuf.st_size)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
printf(" checking for unknown value 1...\n");
|
|
|
|
if (ihfs_hdr.unknown1 != 0x00000004)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
printf(" checking for unknown value 2...\n");
|
|
|
|
if (ihfs_hdr.unknown2 != 0xfffff000)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
printf(" checking for number of files...\n");
|
|
|
|
if (ihfs_hdr.numfiles > MAX_FILES)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
printf(" checking for marker...\n");
|
|
|
|
if (ihfs_hdr.marker != 0x55aa55aa)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void mkdir_p(const char *path)
|
|
|
|
{
|
|
|
|
char *dir;
|
|
|
|
|
|
|
|
dir = dirname(strdup(path));
|
|
|
|
if (strchr(dir, '/'))
|
|
|
|
mkdir_p(dir);
|
|
|
|
|
2008-09-03 12:42:14 +00:00
|
|
|
#ifdef _WIN32
|
|
|
|
mkdir(dir);
|
|
|
|
#else
|
2008-08-07 10:24:11 +00:00
|
|
|
mkdir(dir, 0755);
|
2008-09-03 12:42:14 +00:00
|
|
|
#endif
|
2008-08-07 10:24:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#define BUF_SIZE 4096
|
|
|
|
|
|
|
|
void outputfile(const char *outpath, const int ihfs_img, const int offset, const int length)
|
|
|
|
{
|
|
|
|
int outfd;
|
|
|
|
int i, rem;
|
|
|
|
char buf[BUF_SIZE];
|
|
|
|
|
|
|
|
lseek(ihfs_img, offset, SEEK_SET);
|
|
|
|
|
|
|
|
outfd = creat(outpath, 0644);
|
|
|
|
|
|
|
|
for (i = 0; i < length / BUF_SIZE; ++i) {
|
|
|
|
read(ihfs_img, buf, BUF_SIZE);
|
|
|
|
write(outfd, buf, BUF_SIZE);
|
|
|
|
}
|
|
|
|
rem = length - i * BUF_SIZE;
|
|
|
|
if (rem > 0) {
|
|
|
|
read(ihfs_img, buf, rem);
|
|
|
|
write(outfd, buf, rem);
|
|
|
|
}
|
|
|
|
|
|
|
|
close(outfd);
|
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char **argv)
|
|
|
|
{
|
|
|
|
struct stat statbuf;
|
|
|
|
int ihfs_img;
|
|
|
|
ihfs_header_t ihfs_hdr;
|
|
|
|
ihfs_file_table_t ihfs_ftbl;
|
|
|
|
int i, j;
|
|
|
|
char *outpath, *base_path, ihfs_path[MAX_IHFS_PATH+1];
|
|
|
|
|
|
|
|
/* check the arguments */
|
|
|
|
|
|
|
|
if (argc != 3)
|
|
|
|
usage();
|
|
|
|
|
|
|
|
stat(argv[1], &statbuf);
|
|
|
|
if (!S_ISREG(statbuf.st_mode))
|
|
|
|
usage();
|
|
|
|
|
|
|
|
stat(argv[2], &statbuf);
|
|
|
|
if (!S_ISDIR(statbuf.st_mode))
|
|
|
|
usage();
|
|
|
|
|
|
|
|
/* check the file, then split */
|
|
|
|
|
|
|
|
ihfs_img = open(argv[1], O_RDONLY);
|
|
|
|
|
|
|
|
if (ihfs_sanity(ihfs_img)) {
|
|
|
|
printf("Non-IHFS format!\n");
|
|
|
|
return 1;
|
|
|
|
} else
|
|
|
|
printf("sanity check OK\n");
|
|
|
|
|
|
|
|
lseek(ihfs_img, 0, SEEK_SET);
|
|
|
|
read(ihfs_img, &ihfs_hdr, sizeof (ihfs_hdr));
|
|
|
|
lseek(ihfs_img, 4 * SECTOR_SIZE, SEEK_SET);
|
|
|
|
read(ihfs_img, &ihfs_ftbl, sizeof (ihfs_ftbl));
|
|
|
|
|
|
|
|
base_path = strdup(argv[2]);
|
|
|
|
outpath = malloc(strlen(base_path) + 1 + MAX_IHFS_PATH + 1);
|
|
|
|
for (i = 0; i < ihfs_hdr.numfiles; ++i) {
|
|
|
|
printf("\n");
|
|
|
|
printf("pathname: %s\n", ihfs_ftbl.files[i].fullpath);
|
|
|
|
printf("starts at sector %d, length is %d bytes\n", ihfs_ftbl.files[i].sector, ihfs_ftbl.files[i].length);
|
|
|
|
|
|
|
|
strncpy(ihfs_path, ihfs_ftbl.files[i].fullpath, MAX_IHFS_PATH);
|
|
|
|
ihfs_path[MAX_IHFS_PATH] = '\0';
|
|
|
|
for (j = 0; j < strlen(ihfs_path); ++j)
|
|
|
|
if (ihfs_path[j] == '\\')
|
|
|
|
ihfs_path[j] = '/';
|
|
|
|
|
|
|
|
sprintf(outpath, "%s/%s", base_path, ihfs_path);
|
|
|
|
mkdir_p(outpath);
|
|
|
|
outputfile(outpath, ihfs_img, ihfs_ftbl.files[i].sector * SECTOR_SIZE, ihfs_ftbl.files[i].length);
|
|
|
|
}
|
|
|
|
free(outpath);
|
|
|
|
|
|
|
|
close(ihfs_img);
|
|
|
|
|
|
|
|
return 0;
|
2008-08-12 16:55:59 +00:00
|
|
|
}
|