Reverse engineered AmiBack (Amiga) extraction utility.

This is really a quick hack to read AmiBack backups - I don't know if it works with floppy based backups - but probably the source below is most useful for understanding the format.

I used it succesfully to restore all of my backups that were stored on QIC Tape (45/150mb).

/*---------------------------------------------------------------------------
 *
 *      Title:          AmiBack extraction utility
 *
 *      File:           amiread.cpp
 *
 *      Date:           May 2005
 *
 *      Description:
 *          Reads/extracts files from a dumped amibackup format archive.
 *
 *      Rev     By              Description                            Date
 *      1.0     R.J.Harrison    Implement                             05-05-2005
 *
 *      Copyright © 2005 R.J.Harrison
 *---------------------------------------------------------------------------*/

#pragma warning(disable : 4786)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <direct.h>
#include <io.h>

#include <fcntl.h>
#include <vector>
#include <string>

#pragma pack(1)
typedef struct {
	char header[4]; // FHDR
	char name[108];// fname
	long aa; //???
	long filesize;
	long ee;
	long ff;
	long gg;
	long hh;
	char depth;
	char type;
	// content follows. (unless filesize 0);
}AmiHeader;

void check_path(const char *path)
{
	FILE *q;
	static char *ptr,*name, *end, tmp [200];
	
	strcpy (tmp,path);
	end = ptr = tmp+strlen(tmp);
	while (*--ptr && *ptr != '/');
	if(*ptr)
	{
		*++ptr = 0; /* Remove file name */
		name = ptr = tmp;
		do
		{
			while (*ptr && *ptr != '/') ptr++;
			if(*ptr)
			{
				*ptr = 0;
				if(!(q=fopen(name,"r")))
				{
					mkdir (name);
				}
				else
				{
					fclose (q);
				}
				*ptr++ = '/';
			}
			
		}while (*ptr && ptr < end);
	}
}

main()
{
	FILE *f = fopen("N:/Users/Richard/tape/Tapes/amiga_wb_work.amiback","rb");
	std::vector<std::string> dirz(100);
	#define BUFFER_SIZE 1000 /* k */
	int buffer_size = BUFFER_SIZE;
    buffer_size *= 1024;
    void *file_buffer = malloc(buffer_size + 10);
	
	if (!f)
	{
		fprintf (stderr, "Not found\n");
		exit(-1);
	}
	char hdr[512];
#define SWAP_LONG(v) (((v & 0xff000000) >> 24) | ((v & 0xff0000) >> 8) | ((v &  0xff00) << 8) | ((v & 0xff) << 24))
	fread(hdr,1,sizeof(hdr),f);
	printf ("%d\n",sizeof(AmiHeader));
	int fc=0;
	std::string fname;
chdir("C:/temp/amiga/");
	while(!feof(f))
	{
		AmiHeader fhdr;
		fread (&fhdr, 1, sizeof(fhdr),f);
		fhdr.filesize = SWAP_LONG(fhdr.filesize);
		if (fc == 9175)
			printf("%x\n", ftell(f));
		//? Colon in name is new device...
		if (strncmp(fhdr.header, "FHDR", 4))
			printf ("???Header???");
		printf ("%5d: %10d - ",fc++,fhdr.filesize);
		fname = std::string();
		switch (fhdr.type)
		{
		case 0x2:
			{
				char *s = strchr(fhdr.name, ':');
				if (s)
					*s = 0; // zoink colon from devname
				dirz[0] = fhdr.name;
			}
			break;
		case 0x0:
			dirz[fhdr.depth] = fhdr.name;
			break;
		default:
			for (size_t i = 0; i < fhdr.depth; i++)
			{
//				printf ("%s/",dirz[i].c_str());
				fname = fname + dirz[i] + "/";
			}
			break;
		}
		fname = fname + fhdr.name;
		printf ("%s\n",fname.c_str());
		if (fhdr.filesize)
		{
			bool list = false;
			int size = fhdr.filesize;
			int of;
			if(!list)
			{
				check_path(fname.c_str());
				of = open(fname.c_str(), O_BINARY | O_CREAT | O_WRONLY | O_TRUNC, 0x666);// need mode..hdr.mode);
				if(!of) fprintf(stderr,"unable to open %s\n", fname.c_str());
			}
			
			while(size >= buffer_size)
			{
				fread(file_buffer, 1, buffer_size, f);
				if(!list)
					write(of, file_buffer, buffer_size);
				size -= buffer_size;
			}
			if(size > 0)
			{
				fread(file_buffer, 1, size, f);
				if(!list )
					write(of, file_buffer, size);
			}
			if (!list )
				close(of);
//			if (fseek(f, fhdr.filesize, SEEK_CUR))
//			{
//				fprintf (stderr,"Seek failed\n");
//				exit(-1);
//			}
		}
		else
		{
			printf ("Directory\n");
			if (fhdr.type)
				printf ("Type %d\n", fhdr.type);
		}
		//ii[0] - 0x2 = device;
		//ii[0] - 0x0 = dir;
		//ii[0] - 0x1 = file?
	}
}