Added support for building targetutils.

This commit is contained in:
Oliver Schmidt
2013-05-09 01:12:26 +02:00
parent bf59515a9e
commit 092653cb5b
11 changed files with 74 additions and 165 deletions

View File

@@ -74,6 +74,9 @@ MKINC = $(GEOS) \
atari \
nes
TARGETUTIL = apple2 \
geos-apple
GEOSDIRS = common \
conio \
disk \
@@ -90,59 +93,65 @@ GEOSDIRS = common \
ifeq ($(TARGET),apple2enh)
OBJPFX = a2
DRVPFX = a2e
DIRS = apple2
SRCDIR = apple2
else
DIRS = $(TARGET)
SRCDIR = $(TARGET)
endif
SRCDIRS = $(SRCDIR)
ifeq ($(TARGET),$(filter $(TARGET),$(CBMS)))
DIRS += cbm
SRCDIRS += cbm
endif
ifeq ($(TARGET),$(filter $(TARGET),$(GEOS)))
DIRS += $(addprefix $(TARGET)/, $(GEOSDIRS))
DIRS += $(addprefix geos-common/,$(GEOSDIRS))
SRCDIRS += $(addprefix $(TARGET)/, $(GEOSDIRS))
SRCDIRS += $(addprefix geos-common/,$(GEOSDIRS))
endif
DIRS += common \
conio \
dbg \
em \
joystick \
mouse \
runtime \
serial \
tgi \
zlib
SRCDIRS += common \
conio \
dbg \
em \
joystick \
mouse \
runtime \
serial \
tgi \
zlib
vpath %.s $(DIRS)
vpath %.c $(DIRS)
vpath %.s $(SRCDIRS)
vpath %.c $(SRCDIRS)
OBJS := $(patsubst %.s,%.o,$(foreach dir,$(DIRS),$(wildcard $(dir)/*.s)))
OBJS += $(patsubst %.c,%.o,$(foreach dir,$(DIRS),$(wildcard $(dir)/*.c)))
OBJS := $(patsubst %.s,%.o,$(foreach dir,$(SRCDIRS),$(wildcard $(dir)/*.s)))
OBJS += $(patsubst %.c,%.o,$(foreach dir,$(SRCDIRS),$(wildcard $(dir)/*.c)))
OBJS := $(addprefix ../wrk/$(TARGET)/,$(sort $(notdir $(OBJS))))
DEPS = $(OBJS:.o=.d)
EXTRA_SRCPAT = $(firstword $(DIRS))/extra/%.s
EXTRA_SRCPAT = $(SRCDIR)/extra/%.s
EXTRA_OBJPAT = ../lib/$(TARGET)-%.o
EXTRA_OBJS := $(patsubst $(EXTRA_SRCPAT),$(EXTRA_OBJPAT),$(wildcard $(firstword $(DIRS))/extra/*.s))
EXTRA_OBJS := $(patsubst $(EXTRA_SRCPAT),$(EXTRA_OBJPAT),$(wildcard $(SRCDIR)/extra/*.s))
ZPOBJ = ../wrk/$(TARGET)/zeropage.o
ifeq ($(TARGET),$(filter $(TARGET),$(EXTZP)))
ZPOBJ += ../wrk/$(TARGET)/extzp.o
endif
ifeq ($(TARGET),$(filter $(TARGET),$(MKINC)))
include $(TARGET)/Makefile.inc
ifeq ($(SRCDIR),$(filter $(SRCDIR),$(MKINC)))
include $(SRCDIR)/Makefile.inc
endif
ifeq ($(SRCDIR),$(filter $(SRCDIR),$(TARGETUTIL)))
include $(SRCDIR)/targetutil/Makefile.inc
endif
##########
define DRVTYPE_template
$1_SRCDIR = $$(firstword $$(DIRS))/$1
$1_SRCDIR = $$(SRCDIR)/$1
$1_OBJDIR = ../wrk/$$(TARGET)/$1
$1_DRVDIR = ../$1
@@ -158,14 +167,11 @@ $1_STCS = $$(patsubst $$($1_DRVPAT),$$($1_STCPAT),$$($1_DRVS))
$$($1_OBJS): | $$($1_OBJDIR)
$$($1_OBJDIR):
@$$(call MKDIR,$$@)
$$($1_DRVPAT): $$($1_OBJPAT) $$(ZPOBJ) | $$($1_DRVDIR)
@echo $$(TARGET) - $$(@F)
@$$(LD) -o $$@ -t module $$^
$$($1_DRVDIR):
$$($1_OBJDIR) $$($1_DRVDIR):
@$$(call MKDIR,$$@)
$(TARGET): $$($1_DRVS)
@@ -191,17 +197,32 @@ CC = $(if $(wildcard ../bin/cc65*),../bin/cc65,cc65)
CO = $(if $(wildcard ../bin/co65*),../bin/co65,co65)
LD = $(if $(wildcard ../bin/ld65*),../bin/ld65,ld65)
##########
define ASSEMBLE_recipe
@echo $(TARGET) - $<
@$(CA) -t $(TARGET) $(AFLAGS) --create-dep $(@:.o=.d) -o $@ $<
endef
##########
define COMPILE_recipe
@echo $(TARGET) - $<
@$(CC) -t $(TARGET) $(CFLAGS) --create-dep $(@:.o=.d) -o $(@:.o=.s) $<
@$(CA) -t $(TARGET) -o $@ $(@:.o=.s)
endef
##########
../wrk/$(TARGET)/%.o: %.s | ../wrk/$(TARGET)
@echo $(TARGET) - $<
@$(CA) -t $(TARGET) $(AFLAGS) --create-dep $(@:.o=.d) -o $@ $<
$(ASSEMBLE_recipe)
../wrk/$(TARGET)/%.o: %.c | ../wrk/$(TARGET)
@echo $(TARGET) - $<
@$(CC) -t $(TARGET) $(CFLAGS) --create-dep $(@:.o=.d) -o $(@:.o=.s) $<
@$(CA) -t $(TARGET) -o $@ $(@:.o=.s)
../wrk/$(TARGET):
@$(call MKDIR,$@)
$(COMPILE_recipe)
$(EXTRA_OBJPAT): $(EXTRA_SRCPAT) | ../lib
@echo $(TARGET) - $<
@@ -210,7 +231,7 @@ $(EXTRA_OBJPAT): $(EXTRA_SRCPAT) | ../lib
../lib/$(TARGET).lib: $(OBJS) | ../lib
$(AR) a $@ $?
../lib:
../wrk/$(TARGET) ../lib ../targetutil:
@$(call MKDIR,$@)
$(TARGET): $(EXTRA_OBJS) ../lib/$(TARGET).lib

View File

@@ -0,0 +1,7 @@
../wrk/$(TARGET)/loader.o: $(SRCDIR)/targetutil/loader.s | ../wrk/$(TARGET)
$(ASSEMBLE_recipe)
../targetutil/loader.system: ../wrk/$(TARGET)/loader.o $(SRCDIR)/targetutil/loader.cfg | ../targetutil
$(LD) -o $@ -C $(filter %.cfg,$^) $(filter-out %.cfg,$^)
$(TARGET): ../targetutil/loader.system

View File

@@ -0,0 +1,17 @@
#################################################################################
# #
# LOADER.SYSTEM - an Apple][ ProDOS 8 loader for cc65 programs (Oliver Schmidt) #
# #
#################################################################################
MEMORY {
MEMORY_2000: start = $2000, size = $0200, file = %O;
MEMORY_0300: start = $0300, size = $0100;
}
SEGMENTS {
CODE_2000: load = MEMORY_2000, type = ro;
DATA_2000: load = MEMORY_2000, type = rw;
CODE_0300: load = MEMORY_2000, run = MEMORY_0300, type = ro, define = yes;
DATA_0300: load = MEMORY_2000, run = MEMORY_0300, type = rw, define = yes;
}

Binary file not shown.

View File

@@ -0,0 +1,234 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ;
; LOADER.SYSTEM - an Apple][ ProDOS 8 loader for cc65 programs (Oliver Schmidt) ;
; ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
A1L := $3C
A1H := $3D
STACK := $0100
BUF := $0200
PATHNAME := $0280
MLI := $BF00
VERSION := $FBB3
RDKEY := $FD0C
PRBYTE := $FDDA
COUT := $FDED
QUIT_CALL = $65
GET_FILE_INFO_CALL = $C4
OPEN_CALL = $C8
READ_CALL = $CA
CLOSE_CALL = $CC
FILE_NOT_FOUND_ERR = $46
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.import __CODE_0300_SIZE__, __DATA_0300_SIZE__
.import __CODE_0300_LOAD__, __CODE_0300_RUN__
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.segment "DATA_2000"
GET_FILE_INFO_PARAM:
.byte $0A ;PARAM_COUNT
.addr PATHNAME ;PATHNAME
.byte $00 ;ACCESS
.byte $00 ;FILE_TYPE
FILE_INFO_ADDR: .word $0000 ;AUX_TYPE
.byte $00 ;STORAGE_TYPE
.word $0000 ;BLOCKS_USED
.word $0000 ;MOD_DATE
.word $0000 ;MOD_TIME
.word $0000 ;CREATE_DATE
.word $0000 ;CREATE_TIME
OPEN_PARAM:
.byte $03 ;PARAM_COUNT
.addr PATHNAME ;PATHNAME
.addr MLI - 1024 ;IO_BUFFER
OPEN_REF: .byte $00 ;REF_NUM
LOADING:
.byte $0D
.asciiz "Loading "
ELLIPSES:
.byte " ...", $0D, $0D, $00
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.segment "DATA_0300"
READ_PARAM:
.byte $04 ;PARAM_COUNT
READ_REF: .byte $00 ;REF_NUM
READ_ADDR: .addr $0000 ;DATA_BUFFER
.word $FFFF ;REQUEST_COUNT
.word $0000 ;TRANS_COUNT
CLOSE_PARAM:
.byte $01 ;PARAM_COUNT
CLOSE_REF: .byte $00 ;REF_NUM
QUIT_PARAM:
.byte $04 ;PARAM_COUNT
.byte $00 ;QUIT_TYPE
.word $0000 ;RESERVED
.byte $00 ;RESERVED
.word $0000 ;RESERVED
FILE_NOT_FOUND:
.asciiz "... File Not Found"
ERROR_NUMBER:
.asciiz "... Error $"
PRESS_ANY_KEY:
.asciiz " - Press Any Key "
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.segment "CODE_2000"
jmp :+
.byte $EE
.byte $EE
.byte 65
STARTUP:.res 65
; Reset stack
: ldx #$FF
txs
; Relocate CODE_0300 and DATA_0300
ldx #<(__CODE_0300_SIZE__ + __DATA_0300_SIZE__)
: lda __CODE_0300_LOAD__ - 1,x
sta __CODE_0300_RUN__ - 1,x
dex
bne :-
; Remove ".SYSTEM" from pathname
lda PATHNAME
sec
sbc #.strlen(".SYSTEM")
sta PATHNAME
; Add trailing '\0' to pathname
tax
lda #$00
sta PATHNAME + 1,x
; Copy ProDOS startup filename and trailing '\0' to stack
ldx STARTUP
lda #$00
beq :++ ; bra
: lda STARTUP + 1,x
: sta STACK,x
dex
bpl :--
; Provide some user feedback
lda #<LOADING
ldx #>LOADING
jsr PRINT
lda #<(PATHNAME + 1)
ldx #>(PATHNAME + 1)
jsr PRINT
lda #<ELLIPSES
ldx #>ELLIPSES
jsr PRINT
jsr MLI
.byte GET_FILE_INFO_CALL
.word GET_FILE_INFO_PARAM
bcc :+
jmp ERROR
: jsr MLI
.byte OPEN_CALL
.word OPEN_PARAM
bcc :+
jmp ERROR
; Copy file reference number
: lda OPEN_REF
sta READ_REF
sta CLOSE_REF
; Get load address from aux-type
lda FILE_INFO_ADDR
ldx FILE_INFO_ADDR + 1
sta READ_ADDR
stx READ_ADDR + 1
; It's high time to leave this place
jmp __CODE_0300_RUN__
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.segment "CODE_0300"
jsr MLI
.byte READ_CALL
.word READ_PARAM
bcs ERROR
jsr MLI
.byte CLOSE_CALL
.word CLOSE_PARAM
bcs ERROR
; Copy REM token and startup filename to BASIC input buffer
ldx #$00
lda #$B2
bne :++ ; bra
: inx
lda a:STACK - 1,x
: sta BUF,x
bne :--
; Go for it ...
jmp (READ_ADDR)
PRINT:
sta A1L
stx A1H
ldx VERSION
ldy #$00
: lda (A1L),y
beq :++
cpx #$06 ; //e ?
beq :+
cmp #$60 ; lowercase ?
bcc :+
and #$5F ; -> uppercase
: ora #$80
jsr COUT
iny
bne :-- ; bra
: rts
ERROR:
cmp #FILE_NOT_FOUND_ERR
bne :+
lda #<FILE_NOT_FOUND
ldx #>FILE_NOT_FOUND
jsr PRINT
beq :++ ; bra
: pha
lda #<ERROR_NUMBER
ldx #>ERROR_NUMBER
jsr PRINT
pla
jsr PRBYTE
: lda #<PRESS_ANY_KEY
ldx #>PRESS_ANY_KEY
jsr PRINT
jsr RDKEY
jsr MLI
.byte QUIT_CALL
.word QUIT_PARAM
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

View File

@@ -0,0 +1,80 @@
LOADER.SYSTEM - an Apple][ ProDOS 8 loader for cc65 programs (Oliver Schmidt)
=============================================================================
Background
----------
Apple][ ProDOS 8 system programs (filetype SYS) are always loaded into memory
starting at location $2000. This poses the problem of how to make efficient
use of the memory in the range $0800-$2000. The usual approach of relocation
has two downsides:
- Relocating e.g. 30 kB from $2000-$9800 to $0800-$8000 takes a considerable
amount of time.
- Really large programs just don't fit into memory when loaded starting at
location $2000.
The relocation can be eliminated by loading the major part(s) of the program
from disk right to the final location by a rather small system program.
LOADER.SYSTEM is such a small program. In fact it's so small that it fits into
a single block in the ProDOS 8 file system making it a so-called seedling file,
which are loaded really fast. LOADER.SYSTEM can load cc65 programs into memory
anywhere in the range $0800-$BB00 (44,75 kB).
Usage
-----
Link the cc65 program to the start address $0803 (or any other address) and
store it as binary program (filetype BIN). This is in fact no different from
a binary program to be run by BASIC.SYSTEM's BRUN command in the usual way.
If however the cc65 program isn't run by BASIC.SYSTEM but is rather run by
LOADER.SYSTEM then it behaves like a system program which means:
- It uses memory up to the ProDOS 8 system global page located at $BF00.
- It supports the ProDOS 8 startup file mechanism (mapped to argv[1]).
- It quits to the ProDOS 8 dispatcher.
Obviously LOADER.SYSTEM has to be told which cc65 program to run. Unfortunately
the ProDOS 8 dispatcher has no notion of system program parameters so the usual
approach would have been to make LOADER.SYSTEM bring up yet another menu to
select the cc65 program to run.
But to allow to select the cc65 program directly from the ProDOS 8 dispatcher
anyway LOADER.SYSTEM detects the path to the cc65 program from its own path by
just removing the '.SYSTEM' from its name. So if you want to run the cc65
program MYPROGRAM you'll need a copy of LOADER.SYSTEM in the same directory
being renamed to MYPROGRAM.SYSTEM.
This means you will end up with a copy of LOADER.SYSTEM for every cc65 program
to be run by it. But as LOADER.SYSTEM is a ProDOS 8 seedling file using up only
a single block in the ProDOS 8 file system this should be no issue.
Build
-----
In case you want to build 'loader.system' from the source code yourself you can
do so using the following commands:
ca65 loader.s
ld65 -C loader.cfg -o loader.system loader.o
Installation
------------
The file 'loader.system' as generated by the cc65 linker with the command above
does NOT include the 4-byte address/length header that is generated for Apple][
programs by default. This is because ProDOS 8 system programs are always loaded
into memory starting at location $2000.
The recommended way to transfer 'loader.system' from your native file system to
a ProDOS 8 file system disk image is to use AppleCommander which is available at
http://applecommander.sourceforge.net/
If you want to put the file 'loader.system' onto a disk image 'mydisk.dsk' as
system program MYPROGRAM.SYSTEM you can do so using the following command:
java -jar ac.jar -p mydisk.dsk MYPROGRAM.SYSTEM sys < loader.system

View File

@@ -0,0 +1,9 @@
../wrk/$(TARGET)/convert.o: TARGET = apple2enh
../wrk/$(TARGET)/convert.o: $(SRCDIR)/targetutil/convert.c | ../wrk/$(TARGET)
$(COMPILE_recipe)
../targetutil/convert.system: ../wrk/$(TARGET)/convert.o | ../targetutil
$(LD) -o $@ -C apple2enh-system.cfg $^ apple2enh.lib
$(TARGET): ../targetutil/convert.system

View File

@@ -0,0 +1,346 @@
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <dirent.h>
#include <device.h>
#include <dio.h>
unsigned char info_signature[3] = {3, 21, 63 | 0x80};
dhandle_t dhandle;
struct dir_entry_t {
struct {
unsigned name_length :4;
unsigned storage_type :4;
} storage_length;
char file_name[15];
unsigned char file_type;
unsigned key_pointer;
unsigned blocks_used;
unsigned char size[3];
unsigned long creation;
unsigned char version;
unsigned char min_version;
unsigned char access;
unsigned aux_type;
unsigned long last_mod;
unsigned header_pointer;
}* dir_entry;
union {
unsigned char bytes[512];
struct {
unsigned prev_block;
unsigned next_block;
unsigned char entries[1];
} content;
} dir_block;
union {
unsigned char bytes[512];
struct {
unsigned char addr_lo[254];
unsigned char size_lo[2];
unsigned char addr_hi[254];
unsigned char size_hi[2];
} content;
} index_block, master_block, vlir_block;
union {
unsigned char bytes[512];
struct {
unsigned reserved;
unsigned char info_block[254];
unsigned char vlir_records[128];
struct dir_entry_t dir_entry;
} content;
} header_block;
static void err_exit(char *operation, unsigned char oserr)
{
if (oserr) {
fprintf(stderr, "%s - err:%02x - %s",
operation, (int)_oserror, _stroserror(_oserror));
} else {
fprintf(stderr, "%s",
operation);
}
getchar();
exit(EXIT_FAILURE);
}
static unsigned get_dir_entry(char* p_name)
{
char* d_name;
char* f_name;
size_t f_namelen;
DIR* dir;
struct dirent* dirent;
unsigned cur_addr;
unsigned char entry_length;
unsigned char entries_per_block;
unsigned char cur_entry;
/* Split path name into directory name and file name */
f_name = strrchr(p_name, '/');
if (f_name) {
d_name = p_name;
*f_name++ = '\0';
} else {
d_name = ".";
f_name = p_name;
}
f_namelen = strlen(f_name);
/* Start with high level functions to get handling
of relative path and current drive for free */
dir = opendir(d_name);
if (!dir) {
err_exit("opendir", 1);
}
dirent = readdir(dir);
if (!dirent) {
err_exit("readdir", 1);
}
/* Field header_pointer directly follows field last_mod */
cur_addr = *(unsigned*)(&dirent->d_mtime.hour + 1);
dhandle = dio_open(getcurrentdevice());
if (!dhandle) {
err_exit("dio_open", 1);
}
if (dio_read(dhandle, cur_addr, &dir_block)) {
err_exit("dio_read.1", 1);
}
/* Get directory entry infos from directory header */
entry_length = dir_block.bytes[0x23];
entries_per_block = dir_block.bytes[0x24];
/* Skip directory header entry */
cur_entry = 1;
do {
/* Search for next active directory entry */
do {
/* Check if next directory block is necessary */
if (cur_entry == entries_per_block) {
/* Check if another directory block is present */
cur_addr = dir_block.content.next_block;
if (!cur_addr) {
_mappederrno(0x46);
err_exit("dio_read.2", 1);
}
/* Read next directory block */
if (dio_read(dhandle, cur_addr, &dir_block)) {
err_exit("dio_read.3", 1);
}
/* Start with first entry in next block */
cur_entry = 0;
}
/* Compute pointer to current entry */
dir_entry = (struct dir_entry_t*)(dir_block.content.entries +
cur_entry * entry_length);
/* Switch to next entry */
++cur_entry;
} while (!dir_entry->storage_length.storage_type);
} while (dir_entry->storage_length.name_length != f_namelen ||
strncasecmp(dir_entry->file_name, f_name, f_namelen));
return cur_addr;
}
int main(int argc, char* argv[])
{
char input[80];
char* p_name;
unsigned dir_addr;
unsigned header_addr;
unsigned char index;
unsigned long size;
if (argc > 1) {
p_name = argv[1];
} else {
printf("\n"
"Apple GEOS Convert 1.0\n"
"----------------------\n"
"\n"
"Pathname:");
p_name = gets(input);
}
dir_addr = get_dir_entry(p_name);
/* Read index block */
if (dio_read(dhandle, dir_entry->key_pointer, &index_block)) {
err_exit("dio_read.4", 1);
}
/* First pointer is header block */
header_addr = index_block.content.addr_lo[0] |
index_block.content.addr_hi[0] << 8;
/* Read header block */
if (dio_read(dhandle, header_addr, &header_block)) {
err_exit("dio_read.5", 1);
}
/* Do some sanity check */
for (index = 0; index < sizeof(info_signature); ++index) {
if (header_block.content.info_block[index] != info_signature[index]) {
err_exit("file signature mismatch", 0);
}
}
/* Check ProDOS storage type in directory entry template */
if (header_block.content.dir_entry.storage_length.storage_type == 2)
{
/* ProDOS sapling file means GEOS Sequential file*/
printf("\nSequential file\n");
/* Remove header block pointer from pointer list */
memmove(&index_block.content.addr_lo[0],
&index_block.content.addr_lo[1], sizeof(index_block.content.addr_lo) - 1);
memmove(&index_block.content.addr_hi[0],
&index_block.content.addr_hi[1], sizeof(index_block.content.addr_hi) - 1);
/* Get file size from ProDOS directory entry template */
size = (unsigned long)(header_block.content.dir_entry.size[0]) |
(unsigned long)(header_block.content.dir_entry.size[1]) << 8 |
(unsigned long)(header_block.content.dir_entry.size[2]) << 16;
} else {
/* ProDOS tree file means GEOS VLIR file */
unsigned vlir_addr;
unsigned long vlir_size;
unsigned char vlir_blocks;
unsigned char record = 0;
printf("\nVLIR file\n");
/* Skip header block pointer */
index = 1;
size = 0;
while (1) {
/* Get next VLIR index pointer from index block */
vlir_addr = index_block.content.addr_lo[index] |
index_block.content.addr_hi[index] << 8;
++index;
/* Check for end of pointer list */
if (vlir_addr == 0) {
break;
}
/* Check for empty VLIRs */
while (header_block.content.vlir_records[record] == 0xFF) {
/* Add empty VLIR index pointer to to master index block */
master_block.content.addr_lo[record] = 0xFF;
master_block.content.addr_hi[record] = 0xFF;
++record;
}
/* Add VLIR index pointer to master index block */
master_block.content.addr_lo[record] = (unsigned char)(vlir_addr );
master_block.content.addr_hi[record] = (unsigned char)(vlir_addr >> 8);
++record;
/* Read VLIR index block */
if (dio_read(dhandle, vlir_addr, &vlir_block)) {
err_exit("dio_read.6", 1);
}
/* Get VLIR size from VLIR index block */
vlir_size = (unsigned long)(vlir_block.content.size_lo[1]) |
(unsigned long)(vlir_block.content.size_hi[1]) << 8 |
(unsigned long)(vlir_block.content.size_lo[0]) << 16 |
(unsigned long)(vlir_block.content.size_hi[0]) << 24;
printf("VLIR %u size %lu bytes\n", record - 1, vlir_size);
/* Compute VLIR block size */
vlir_blocks = (unsigned char)((vlir_size + 511) / 512);
/* Copy VLIR block pointers from index block to VLIR index block */
memcpy(&vlir_block.content.addr_lo[0],
&index_block.content.addr_lo[index], vlir_blocks);
memcpy(&vlir_block.content.addr_hi[0],
&index_block.content.addr_hi[index], vlir_blocks);
index += vlir_blocks;
/* Write back VLIR index block */
if (dio_write(dhandle, vlir_addr, &vlir_block)) {
err_exit("dio_write.1", 1);
}
/* Add VLIR size to file size */
size += vlir_size;
}
/* Replace (by now completely read) index block with
(by now completely created) master index block */
index_block = master_block;
}
printf("File size %lu bytes\n\n", size);
/* Set file size in index block */
index_block.content.size_lo[1] = (unsigned char)(size );
index_block.content.size_hi[1] = (unsigned char)(size >> 8);
index_block.content.size_lo[0] = (unsigned char)(size >> 16);
index_block.content.size_hi[0] = (unsigned char)(size >> 24);
/* Write index block */
if (dio_write(dhandle, dir_entry->key_pointer, &index_block)) {
err_exit("dio_write.2", 1);
}
/* Copy selected fields from directory entry template to directory block */
dir_entry->storage_length = header_block.content.dir_entry.storage_length;
memcpy(dir_entry->file_name, header_block.content.dir_entry.file_name, 15);
dir_entry->file_type = header_block.content.dir_entry.file_type;
dir_entry->size[0] = (unsigned char)(size );
dir_entry->size[1] = (unsigned char)(size >> 8);
dir_entry->size[2] = (unsigned char)(size >> 16);
dir_entry->creation = header_block.content.dir_entry.creation;
dir_entry->version = header_block.content.dir_entry.version;
dir_entry->min_version = header_block.content.dir_entry.min_version;
dir_entry->aux_type = header_addr;
dir_entry->last_mod = header_block.content.dir_entry.last_mod;
/* Write directory block */
if (dio_write(dhandle, dir_addr, &dir_block)) {
err_exit("dio_write.3", 1);
}
/* We're done */
if (dio_close(dhandle)) {
err_exit("dio_close", 1);
}
printf("Convert to '%.*s' successful", dir_entry->storage_length.name_length,
dir_entry->file_name);
getchar();
return EXIT_SUCCESS;
}