mirror of
https://github.com/digarok/gsplus.git
synced 2024-12-01 07:50:18 +00:00
906 lines
20 KiB
C
906 lines
20 KiB
C
|
/*
|
||
|
GSport - an Apple //gs Emulator
|
||
|
Copyright (C) 2010 by GSport contributors
|
||
|
|
||
|
Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey
|
||
|
|
||
|
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 program is distributed in the hope that it will be useful, but
|
||
|
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||
|
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||
|
for more details.
|
||
|
|
||
|
You should have received a copy of the GNU General Public License along
|
||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||
|
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||
|
*/
|
||
|
|
||
|
#include "defc.h"
|
||
|
#include <ctype.h>
|
||
|
|
||
|
#include "prodos.h"
|
||
|
|
||
|
#include <errno.h>
|
||
|
|
||
|
|
||
|
#define DEF_DISK_SIZE (800*1024)
|
||
|
#define MAX_FILE_NAMES 51
|
||
|
|
||
|
char out_name[] = "POOF1";
|
||
|
|
||
|
int g_def_file_type = -1;
|
||
|
int g_def_aux_type = -1;
|
||
|
|
||
|
void make_legal_prodos_name(char *new_name, char *old_name);
|
||
|
|
||
|
int
|
||
|
main(int argc, char **argv)
|
||
|
{
|
||
|
char *files[MAX_FILE_NAMES];
|
||
|
char *name;
|
||
|
char *new_name_end;
|
||
|
int new_name_len;
|
||
|
struct stat stat_buf;
|
||
|
int in;
|
||
|
int in_size;
|
||
|
int ret;
|
||
|
ProDisk *disk;
|
||
|
char new_name[128];
|
||
|
byte in_buf[1024];
|
||
|
int disk_size;
|
||
|
int i;
|
||
|
int done;
|
||
|
int pos;
|
||
|
int size;
|
||
|
int num_files;
|
||
|
int file_type;
|
||
|
int aux_type;
|
||
|
|
||
|
disk_size = DEF_DISK_SIZE;
|
||
|
if(argc < 2) {
|
||
|
fprintf(stderr, "%s: {-[size in K]} {unix_files}\n",
|
||
|
argv[0]);
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
num_files = 0;
|
||
|
for(i = 1; i < argc; i++) {
|
||
|
if(argv[i][0] == '-') {
|
||
|
/* I smell a -size_in_K */
|
||
|
disk_size = strtoul(&(argv[i][1]), 0, 10) * 1024;
|
||
|
printf("disk_size: %d, 0x%x\n", disk_size, disk_size);
|
||
|
if(disk_size < 40*1024) {
|
||
|
printf("Too small!\n");
|
||
|
exit(1);
|
||
|
}
|
||
|
} else {
|
||
|
files[num_files] = argv[i];
|
||
|
num_files++;
|
||
|
if(num_files >= MAX_FILE_NAMES) {
|
||
|
printf("Too many filenames: %d\n", num_files);
|
||
|
exit(2);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
disk = allocate_memdisk(out_name, disk_size);
|
||
|
format_memdisk(disk, out_name);
|
||
|
|
||
|
for(i = 0; i < num_files; i++) {
|
||
|
name = files[i];
|
||
|
in = open(name, O_RDONLY | O_BINARY);
|
||
|
if(in < 0) {
|
||
|
fprintf(stderr, "opening %s returned %d, errno: %d\n",
|
||
|
name, in, errno);
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
ret = fstat(in, &stat_buf);
|
||
|
if(ret != 0) {
|
||
|
fprintf(stderr, "fstat returned %d, errno: %d\n",
|
||
|
ret, errno);
|
||
|
}
|
||
|
|
||
|
in_size = stat_buf.st_size;
|
||
|
printf("in size: %d\n", in_size);
|
||
|
|
||
|
if(in_size > disk->disk_bytes_left) {
|
||
|
printf("File bigger than %d, too big!\n", disk_size);
|
||
|
exit(2);
|
||
|
}
|
||
|
|
||
|
make_legal_prodos_name(new_name, name);
|
||
|
|
||
|
new_name_len = strlen(new_name);
|
||
|
new_name_end = new_name + new_name_len;
|
||
|
|
||
|
file_type = g_def_file_type;
|
||
|
aux_type = g_def_aux_type;
|
||
|
while(g_def_file_type < 0) {
|
||
|
/* choose file type */
|
||
|
if(new_name_len >= 5) {
|
||
|
if(strcmp(new_name_end - 4, ".SHK") == 0) {
|
||
|
file_type = 0xe0;
|
||
|
aux_type = 0x8002;
|
||
|
break;
|
||
|
}
|
||
|
if(strcmp(new_name_end - 4, ".SDK") == 0) {
|
||
|
file_type = 0xe0;
|
||
|
aux_type = 0x8002;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
file_type = 0x04; /* TXT */
|
||
|
aux_type = 0;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
create_new_file(disk, 2, 1, new_name, file_type,
|
||
|
0, 0, 0, 0xc3, aux_type, 0, in_size);
|
||
|
|
||
|
|
||
|
done = 0;
|
||
|
pos = 0;
|
||
|
while(pos < in_size) {
|
||
|
size = 512;
|
||
|
if(pos + size > in_size) {
|
||
|
size = in_size - pos;
|
||
|
}
|
||
|
ret = read(in, in_buf, size);
|
||
|
if(ret != size || ret <= 0) {
|
||
|
fprintf(stderr, "read returned %d, errno: %d\n",
|
||
|
ret, errno);
|
||
|
exit(2);
|
||
|
}
|
||
|
ret = pro_write_file(disk, in_buf, pos, size);
|
||
|
if(ret != 0) {
|
||
|
printf("pro_write returned %d!\n", ret);
|
||
|
exit(3);
|
||
|
}
|
||
|
pos += size;
|
||
|
}
|
||
|
|
||
|
close_file(disk);
|
||
|
|
||
|
close(in);
|
||
|
}
|
||
|
|
||
|
flush_disk(disk);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
make_legal_prodos_name(char *new_name, char *old_name)
|
||
|
{
|
||
|
char *ptr;
|
||
|
int start_len, start_char;
|
||
|
int len;
|
||
|
int pos;
|
||
|
int c;
|
||
|
int j;
|
||
|
|
||
|
for(j = 0; j < 16; j++) {
|
||
|
/* make sure it ends with null == 15 + 1 */
|
||
|
new_name[j] = 0;
|
||
|
}
|
||
|
|
||
|
start_char = 0;
|
||
|
start_len = strlen(old_name);
|
||
|
len = 0;
|
||
|
ptr = &old_name[start_len - 1];
|
||
|
for(j = start_len - 1; j >= 0; j--) {
|
||
|
if(*ptr == '/' || *ptr == ':') {
|
||
|
break;
|
||
|
}
|
||
|
ptr--;
|
||
|
len++;
|
||
|
}
|
||
|
ptr++;
|
||
|
|
||
|
if(len <= 0) {
|
||
|
printf("Filename: %s has len: %d!\n", old_name, len);
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
printf("mid_name: %s, len:%d\n", ptr, len);
|
||
|
|
||
|
pos = 0;
|
||
|
for(j = 0; j < 15; j++) {
|
||
|
c = ptr[pos];
|
||
|
if(isalnum(c)) {
|
||
|
c = toupper(c);
|
||
|
} else if(c != 0) {
|
||
|
c = '.';
|
||
|
}
|
||
|
|
||
|
if(j == 0 && !isalpha(c)) {
|
||
|
c = 'A';
|
||
|
}
|
||
|
|
||
|
new_name[j] = c;
|
||
|
|
||
|
pos++;
|
||
|
if(pos == 7 && len > 15) {
|
||
|
pos = len - 8;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
printf("new_name: %s\n", new_name);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
flush_disk(ProDisk *disk)
|
||
|
{
|
||
|
disk_write_data(disk, 6, disk->bitmap_ptr,
|
||
|
disk->size_bitmap_blocks * 512);
|
||
|
close(disk->fd);
|
||
|
disk->fd = -1;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
close_file(ProDisk *disk)
|
||
|
{
|
||
|
write_ind_block(disk);
|
||
|
write_master_ind_block(disk);
|
||
|
disk_write_data(disk, disk->dir_blk_num, &(disk->dir_blk_data[0]), 512);
|
||
|
disk->file_ptr = 0;
|
||
|
}
|
||
|
|
||
|
ProDisk *
|
||
|
allocate_memdisk(char *out_name, int size)
|
||
|
{
|
||
|
ProDisk *disk;
|
||
|
int out;
|
||
|
|
||
|
out = open(out_name, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0x1b6);
|
||
|
if(out < 0) {
|
||
|
fprintf(stderr, "opening %s returned %d, errno: %d\n",
|
||
|
out_name, out, errno);
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
disk = (ProDisk *)malloc(sizeof(ProDisk));
|
||
|
if(disk == 0) {
|
||
|
printf("allocate_memdisk failed, errno: %d\n", errno);
|
||
|
}
|
||
|
|
||
|
disk->fd = out;
|
||
|
disk->total_blocks = (size + 511) / 512;
|
||
|
disk->bitmap_ptr = 0;
|
||
|
disk->disk_bytes_left = 0;
|
||
|
disk->size_bitmap_blocks = 0;
|
||
|
disk->dir_blk_num = -1;
|
||
|
disk->ind_blk_num = -1;
|
||
|
disk->master_ind_blk_num = -1;
|
||
|
|
||
|
return disk;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
format_memdisk(ProDisk *disk, char *name)
|
||
|
{
|
||
|
byte zero_buf[1024];
|
||
|
int total_blocks;
|
||
|
byte *bitmap_ptr;
|
||
|
Vol_hdr *vol_hdr;
|
||
|
Directory *dir;
|
||
|
int size_bitmap_bytes;
|
||
|
int size_bitmap_blocks;
|
||
|
int disk_blocks_left;
|
||
|
int i, j;
|
||
|
|
||
|
total_blocks = disk->total_blocks;
|
||
|
|
||
|
/* Zero out blocks 0 and 1 */
|
||
|
for(i = 0; i < 2*512; i++) {
|
||
|
zero_buf[i] = 0;
|
||
|
}
|
||
|
disk_write_data(disk, 0x00000, zero_buf, 2*512);
|
||
|
|
||
|
/* and make the image the right size */
|
||
|
disk_write_data(disk, total_blocks - 1, zero_buf, 512);
|
||
|
|
||
|
dir = disk_read_dir(disk, 2);
|
||
|
set_l2byte(&(dir->prev_blk), 0);
|
||
|
set_l2byte(&(dir->next_blk), 3);
|
||
|
vol_hdr = (Vol_hdr *)&(dir->file_entries[0]);
|
||
|
vol_hdr->storage_type_name_len = 0xf0 + strlen(name);
|
||
|
strncpy((char *)vol_hdr->vol_name, name, strlen(name));
|
||
|
vol_hdr->version = 0;
|
||
|
vol_hdr->min_version = 0;
|
||
|
vol_hdr->access = 0xc3;
|
||
|
vol_hdr->entry_length = 0x27;
|
||
|
vol_hdr->entries_per_block = 0x0d;
|
||
|
set_l2byte(&(vol_hdr->file_count), 0);
|
||
|
vol_hdr->entries_per_block = 0x0d;
|
||
|
set_l2byte(&(vol_hdr->bit_map), 6);
|
||
|
set_l2byte(&(vol_hdr->total_blocks), total_blocks);
|
||
|
for(i = 1; i < 13; i++) {
|
||
|
set_file_entry(&(dir->file_entries[i]), 0, "", 0, 0, 0,
|
||
|
0, 0, 0, 0, 0, 0, 0, 0);
|
||
|
}
|
||
|
disk_write_dir(disk, 2);
|
||
|
|
||
|
|
||
|
for(i = 3; i < 6; i++) {
|
||
|
dir = disk_read_dir(disk, i);
|
||
|
set_l2byte(&(dir->prev_blk), i - 1);
|
||
|
set_l2byte(&(dir->next_blk), i + 1);
|
||
|
if(i == 5) {
|
||
|
set_l2byte(&(dir->next_blk), 0);
|
||
|
}
|
||
|
for(j = 0; j < 13; j++) {
|
||
|
set_file_entry(&(dir->file_entries[j]), 0, "", 0, 0, 0,
|
||
|
0, 0, 0, 0, 0, 0, 0, 0);
|
||
|
}
|
||
|
|
||
|
disk_write_dir(disk, i);
|
||
|
}
|
||
|
|
||
|
size_bitmap_bytes = (total_blocks + 7)/ 8;
|
||
|
size_bitmap_blocks = (size_bitmap_bytes + 511)/ 512;
|
||
|
bitmap_ptr = (byte *)malloc(size_bitmap_blocks * 512);
|
||
|
for(i = 0; i < 6+size_bitmap_blocks; i++) {
|
||
|
set_bitmap_used(bitmap_ptr, i);
|
||
|
}
|
||
|
for(i = 6+size_bitmap_blocks; i < total_blocks; i++) {
|
||
|
set_bitmap_free(bitmap_ptr, i);
|
||
|
}
|
||
|
for(i = total_blocks; i < size_bitmap_blocks*512*8; i++) {
|
||
|
set_bitmap_used(bitmap_ptr, i);
|
||
|
}
|
||
|
|
||
|
disk_write_data(disk, 6, bitmap_ptr, size_bitmap_blocks * 512);
|
||
|
disk->bitmap_ptr = bitmap_ptr;
|
||
|
disk->size_bitmap_blocks = size_bitmap_blocks;
|
||
|
disk->bitmap_bytes = size_bitmap_blocks * 512;
|
||
|
disk->bitmap_cur_pos = 0;
|
||
|
|
||
|
disk_blocks_left = total_blocks - 6 - size_bitmap_blocks;
|
||
|
disk->disk_bytes_left = disk_blocks_left * 512;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
disk_write_data(ProDisk *disk, int blk_num, byte *buf, int size)
|
||
|
{
|
||
|
int size_in_blocks;
|
||
|
int ret;
|
||
|
|
||
|
#if 0
|
||
|
printf("Writing blk %04x from buf: %08x, %03x\n", blk_num, buf, size);
|
||
|
#endif
|
||
|
|
||
|
size_in_blocks = size >> 9;
|
||
|
if(size_in_blocks * 512 != size) {
|
||
|
printf("disk_write: blk: %04x, buf: %08x, size: %08x\n",
|
||
|
blk_num, (word32)buf, size);
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
ret = lseek(disk->fd, 512*blk_num, SEEK_SET);
|
||
|
if(ret != 512*blk_num) {
|
||
|
printf("disk_write: seek: %d, errno: %d, blk: %04x, buf: "
|
||
|
"%08x, sz: %08x\n", ret, errno, blk_num,
|
||
|
(word32)buf, size);
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
ret = write(disk->fd, buf, size);
|
||
|
if(ret != size) {
|
||
|
printf("disk_write: write: %d, errno: %d, blk: %04x, buf: "
|
||
|
"%08x, sz: %08x\n", ret, errno, blk_num,
|
||
|
(word32)buf, size);
|
||
|
exit(1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
disk_read_data(ProDisk *disk, int blk_num, byte *buf, int size)
|
||
|
{
|
||
|
int size_in_blocks;
|
||
|
int ret;
|
||
|
int i;
|
||
|
|
||
|
size_in_blocks = size >> 9;
|
||
|
if(size_in_blocks * 512 != size) {
|
||
|
printf("disk_read: blk: %04x, buf: %08x, size: %08x\n",
|
||
|
blk_num, (word32)buf, size);
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
ret = lseek(disk->fd, 512*blk_num, SEEK_SET);
|
||
|
if(ret != 512*blk_num) {
|
||
|
printf("disk_read: seek: %d, errno: %d, blk: %04x, buf: "
|
||
|
"%08x, sz: %08x\n", ret, errno, blk_num,
|
||
|
(word32)buf, size);
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
ret = read(disk->fd, buf, size);
|
||
|
if(ret != size) {
|
||
|
printf("disk_read: read: %d, errno: %d, blk: %04x, buf: "
|
||
|
"%08x, sz: %08x\n", ret, errno, blk_num,
|
||
|
(word32)buf, size);
|
||
|
for(i = 0; i < size; i++) {
|
||
|
buf[i] = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Directory *
|
||
|
disk_read_dir(ProDisk *disk, int blk_num)
|
||
|
{
|
||
|
disk_write_dir(disk, blk_num);
|
||
|
|
||
|
disk->dir_blk_num = blk_num;
|
||
|
disk_read_data(disk, blk_num, &(disk->dir_blk_data[0]), 512);
|
||
|
|
||
|
return (Directory *)&(disk->dir_blk_data[0]);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
disk_write_dir(ProDisk *disk, int blk_num)
|
||
|
{
|
||
|
if(disk->dir_blk_num >= 0) {
|
||
|
if(disk->dir_blk_num != blk_num) {
|
||
|
printf("disk_write_dir: %04x != %04x\n",
|
||
|
disk->dir_blk_num, blk_num);
|
||
|
}
|
||
|
disk_write_data(disk, disk->dir_blk_num,
|
||
|
&(disk->dir_blk_data[0]), 512);
|
||
|
disk->dir_blk_num = -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
create_new_file(ProDisk *disk, int dir_block, int storage_type, char *name,
|
||
|
int file_type, word32 creation_time, int version, int min_version,
|
||
|
int access, int aux_type, word32 last_mod, word32 eof)
|
||
|
{
|
||
|
Vol_hdr *vol_ptr;
|
||
|
int val;
|
||
|
Directory *dir_ptr;
|
||
|
File_entry *file_ptr;
|
||
|
int file_count;
|
||
|
int pos;
|
||
|
int last_pos;
|
||
|
int done;
|
||
|
int next_blk;
|
||
|
int name_len;
|
||
|
|
||
|
name_len = strlen(name);
|
||
|
dir_ptr = disk_read_dir(disk, dir_block);
|
||
|
next_blk = dir_block;
|
||
|
val = dir_ptr->file_entries[0].storage_type_name_len;
|
||
|
last_pos = 13;
|
||
|
pos = 0;
|
||
|
if(((val & 0xf0) == 0xf0) || ((val & 0xf0) == 0xe0)) {
|
||
|
/* vol dir or subdir header */
|
||
|
vol_ptr = (Vol_hdr *)&(dir_ptr->file_entries[0]);
|
||
|
file_count = get_l2byte(&(vol_ptr->file_count));
|
||
|
pos = 1;
|
||
|
last_pos = vol_ptr->entries_per_block;
|
||
|
} else {
|
||
|
printf("dir_block: %04x not subdir or voldir\n", dir_block);
|
||
|
exit(6);
|
||
|
}
|
||
|
|
||
|
vol_ptr = 0;
|
||
|
|
||
|
done = 0;
|
||
|
while(!done) {
|
||
|
file_ptr = &(dir_ptr->file_entries[pos]);
|
||
|
if(((file_ptr->storage_type_name_len) & 0xf0) == 0) {
|
||
|
/* Got it! */
|
||
|
file_ptr->storage_type_name_len =
|
||
|
(storage_type << 4) | name_len;
|
||
|
strncpy((char *)file_ptr->file_name, name, 15);
|
||
|
file_ptr->file_type = file_type;
|
||
|
set_l2byte(&(file_ptr->key_pointer),
|
||
|
find_next_free_block(disk));
|
||
|
set_l2byte(&(file_ptr->blocks_used), 0);
|
||
|
set_pro_time(&(file_ptr->creation_time),
|
||
|
creation_time);
|
||
|
file_ptr->version = version;
|
||
|
file_ptr->min_version = min_version;
|
||
|
file_ptr->access = access;
|
||
|
set_l2byte(&(file_ptr->aux_type), aux_type);
|
||
|
set_pro_time(&(file_ptr->last_mod), last_mod);
|
||
|
set_l2byte(&(file_ptr->header_pointer),
|
||
|
dir_block);
|
||
|
set_l3byte(&(file_ptr->eof), eof);
|
||
|
disk_write_dir(disk, next_blk);
|
||
|
|
||
|
dir_ptr = disk_read_dir(disk, dir_block);
|
||
|
vol_ptr = (Vol_hdr *)&(dir_ptr->file_entries[0]);
|
||
|
set_l2byte(&(vol_ptr->file_count), file_count+1);
|
||
|
disk_write_dir(disk, dir_block);
|
||
|
|
||
|
disk_read_dir(disk, next_blk);
|
||
|
/* re-read dir so that ptrs are set up right */
|
||
|
disk->file_ptr = file_ptr;
|
||
|
disk->file_open = 1;
|
||
|
disk->ind_blk_num = -1;
|
||
|
disk->master_ind_blk_num = -1;
|
||
|
done = 1;
|
||
|
break;
|
||
|
} else {
|
||
|
/* check to make sure name is unique */
|
||
|
if((file_ptr->storage_type_name_len & 0x0f)== name_len){
|
||
|
if(!memcmp(file_ptr->file_name, name,name_len)){
|
||
|
printf("Name %s already on disk!\n",
|
||
|
name);
|
||
|
exit(8);
|
||
|
}
|
||
|
}
|
||
|
pos++;
|
||
|
if(pos >= last_pos) {
|
||
|
/* Go to next block */
|
||
|
next_blk = get_l2byte(&(dir_ptr->next_blk));
|
||
|
if(next_blk) {
|
||
|
dir_ptr = disk_read_dir(disk, next_blk);
|
||
|
pos = 0;
|
||
|
} else {
|
||
|
printf("Top directory full!\n");
|
||
|
exit(2);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int
|
||
|
pro_write_file(ProDisk *disk, byte *in_buf, int pos, int size)
|
||
|
{
|
||
|
int block;
|
||
|
int i;
|
||
|
|
||
|
block = get_disk_block(disk, pos, 1);
|
||
|
if(block < 7) {
|
||
|
printf("pro_write_file, get_disk_block: %d\n", block);
|
||
|
exit(3);
|
||
|
}
|
||
|
if(size < 512) {
|
||
|
for(i = size; i < 512; i++) {
|
||
|
in_buf[i] = 0;
|
||
|
}
|
||
|
} else if(size > 512) {
|
||
|
printf("error, pro_write_file size: %d too big\n", size);
|
||
|
exit(4);
|
||
|
}
|
||
|
|
||
|
disk_write_data(disk, block, in_buf, 512);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
int
|
||
|
get_disk_block(ProDisk *disk, int pos, int create)
|
||
|
{
|
||
|
File_entry *file_ptr;
|
||
|
int storage_type;
|
||
|
word32 eof;
|
||
|
int lo, hi;
|
||
|
int offset;
|
||
|
int master_ind_block, ind_block;
|
||
|
int ret_block;
|
||
|
int key_block;
|
||
|
|
||
|
if(pos >= 128*256*512) {
|
||
|
printf("offset too big\n");
|
||
|
exit(3);
|
||
|
}
|
||
|
|
||
|
file_ptr = disk->file_ptr;
|
||
|
|
||
|
eof = get_l3byte(&(file_ptr->eof));
|
||
|
storage_type = (file_ptr->storage_type_name_len) >> 4;
|
||
|
|
||
|
key_block = get_l2byte(&(file_ptr->key_pointer));
|
||
|
|
||
|
if(storage_type == 1 && pos >= 512) {
|
||
|
/* make it sapling */
|
||
|
get_new_ind_block(disk);
|
||
|
inc_l2byte(&(file_ptr->blocks_used));
|
||
|
disk->ind_blk_data[0] = key_block & 0xff;
|
||
|
disk->ind_blk_data[0x100] = key_block >> 8;
|
||
|
key_block = disk->ind_blk_num;
|
||
|
set_l2byte(&(file_ptr->key_pointer), key_block);
|
||
|
file_ptr->storage_type_name_len += 0x10;
|
||
|
storage_type++;
|
||
|
}
|
||
|
if(storage_type == 2 && pos >= 256*512) {
|
||
|
/* make it tree */
|
||
|
get_new_master_ind_block(disk);
|
||
|
inc_l2byte(&(file_ptr->blocks_used));
|
||
|
disk->master_ind_blk_data[0] = key_block & 0xff;
|
||
|
disk->master_ind_blk_data[0x100] = key_block >> 8;
|
||
|
key_block = disk->master_ind_blk_num;
|
||
|
set_l2byte(&(file_ptr->key_pointer), key_block);
|
||
|
file_ptr->storage_type_name_len += 0x10;
|
||
|
storage_type++;
|
||
|
}
|
||
|
|
||
|
switch(storage_type) {
|
||
|
case 1:
|
||
|
if(pos >= 512) {
|
||
|
printf("Error1!\n");
|
||
|
exit(3);
|
||
|
}
|
||
|
ret_block = key_block;
|
||
|
if(ret_block == 0) {
|
||
|
ret_block = find_next_free_block(disk);
|
||
|
inc_l2byte(&(file_ptr->blocks_used));
|
||
|
set_l2byte(&(file_ptr->key_pointer), ret_block);
|
||
|
}
|
||
|
return ret_block;
|
||
|
case 2:
|
||
|
ind_block = key_block;
|
||
|
if(ind_block <= 0) {
|
||
|
printf("write failure, ind_block: %d!\n", ind_block);
|
||
|
exit(3);
|
||
|
}
|
||
|
offset = pos >> 9;
|
||
|
if(offset >= 256) {
|
||
|
printf("pos too big!\n");
|
||
|
exit(3);
|
||
|
}
|
||
|
|
||
|
lo = disk->ind_blk_data[offset];
|
||
|
hi = disk->ind_blk_data[offset + 0x100];
|
||
|
ret_block = hi*256 + lo;
|
||
|
if(ret_block == 0) {
|
||
|
/* Need to alloc a block for this guy */
|
||
|
ret_block = find_next_free_block(disk);
|
||
|
inc_l2byte(&(file_ptr->blocks_used));
|
||
|
disk->ind_blk_data[offset] = ret_block & 0xff;
|
||
|
disk->ind_blk_data[offset + 0x100] =
|
||
|
((ret_block >> 8) & 0xff);
|
||
|
}
|
||
|
return ret_block;
|
||
|
case 3:
|
||
|
/* tree */
|
||
|
master_ind_block = key_block;
|
||
|
if(master_ind_block <= 0) {
|
||
|
printf("write failure, master_ind_block: %d!\n",
|
||
|
master_ind_block);
|
||
|
exit(3);
|
||
|
}
|
||
|
offset = pos >> 17;
|
||
|
if(offset >= 128) {
|
||
|
printf("master too big!\n");
|
||
|
exit(4);
|
||
|
}
|
||
|
lo = disk->master_ind_blk_data[offset];
|
||
|
hi = disk->master_ind_blk_data[offset + 0x100];
|
||
|
ind_block = hi*256 + lo;
|
||
|
if(ind_block == 0) {
|
||
|
/* Need to alloc an ind block */
|
||
|
get_new_ind_block(disk);
|
||
|
ind_block = disk->ind_blk_num;
|
||
|
inc_l2byte(&(file_ptr->blocks_used));
|
||
|
disk->master_ind_blk_data[offset] = ind_block & 0xff;
|
||
|
disk->master_ind_blk_data[offset + 0x100] =
|
||
|
((ind_block >> 8) & 0xff);
|
||
|
}
|
||
|
|
||
|
offset = (pos >> 9) & 0xff;
|
||
|
lo = disk->ind_blk_data[offset];
|
||
|
hi = disk->ind_blk_data[offset + 0x100];
|
||
|
ret_block = hi*256 + lo;
|
||
|
|
||
|
if(ret_block == 0) {
|
||
|
/* Need to alloc a block for this guy */
|
||
|
ret_block = find_next_free_block(disk);
|
||
|
inc_l2byte(&(file_ptr->blocks_used));
|
||
|
disk->ind_blk_data[offset] = ret_block & 0xff;
|
||
|
disk->ind_blk_data[offset + 0x100] =
|
||
|
((ret_block >> 8) & 0xff);
|
||
|
}
|
||
|
return ret_block;
|
||
|
default:
|
||
|
printf("unknown storage type: %d\n", storage_type);
|
||
|
exit(4);
|
||
|
}
|
||
|
|
||
|
printf("Can't get here!\n");
|
||
|
exit(5);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
get_new_ind_block(ProDisk *disk)
|
||
|
{
|
||
|
int ind_blk_num;
|
||
|
int i;
|
||
|
|
||
|
write_ind_block(disk);
|
||
|
|
||
|
ind_blk_num = find_next_free_block(disk);
|
||
|
for(i = 0; i < 512; i++) {
|
||
|
disk->ind_blk_data[i] = 0;
|
||
|
}
|
||
|
|
||
|
disk->ind_blk_num = ind_blk_num;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
write_ind_block(ProDisk *disk)
|
||
|
{
|
||
|
int ind_blk_num;
|
||
|
|
||
|
ind_blk_num = disk->ind_blk_num;
|
||
|
if(ind_blk_num > 0) {
|
||
|
printf("Write ind block: %04x\n", ind_blk_num);
|
||
|
disk_write_data(disk, ind_blk_num, &(disk->ind_blk_data[0]),
|
||
|
512);
|
||
|
disk->ind_blk_num = -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
get_new_master_ind_block(ProDisk *disk)
|
||
|
{
|
||
|
int master_ind_blk_num;
|
||
|
int i;
|
||
|
|
||
|
write_master_ind_block(disk);
|
||
|
|
||
|
master_ind_blk_num = find_next_free_block(disk);
|
||
|
for(i = 0; i < 512; i++) {
|
||
|
disk->master_ind_blk_data[i] = 0;
|
||
|
}
|
||
|
|
||
|
disk->master_ind_blk_num = master_ind_blk_num;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
write_master_ind_block(ProDisk *disk)
|
||
|
{
|
||
|
int master_ind_blk_num;
|
||
|
|
||
|
master_ind_blk_num = disk->master_ind_blk_num;
|
||
|
if(master_ind_blk_num > 0) {
|
||
|
printf("Write master_ind block: %04x\n", master_ind_blk_num);
|
||
|
disk_write_data(disk, master_ind_blk_num,
|
||
|
&(disk->master_ind_blk_data[0]), 512);
|
||
|
disk->master_ind_blk_num = -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int
|
||
|
find_next_free_block(ProDisk *disk)
|
||
|
{
|
||
|
byte *bitmap_ptr;
|
||
|
int pos;
|
||
|
int bitmap_bytes;
|
||
|
int i, j;
|
||
|
word32 val;
|
||
|
|
||
|
bitmap_ptr = disk->bitmap_ptr;
|
||
|
bitmap_bytes = disk->bitmap_bytes;
|
||
|
pos = disk->bitmap_cur_pos;
|
||
|
|
||
|
for(i = pos; i < bitmap_bytes; i++) {
|
||
|
val = bitmap_ptr[i];
|
||
|
if(val == 0) {
|
||
|
continue;
|
||
|
}
|
||
|
for(j = 0; j < 8; j++) {
|
||
|
if(val & (0x80 >> j)) {
|
||
|
set_bitmap_used(bitmap_ptr, 8*i+j);
|
||
|
disk->bitmap_cur_pos = i;
|
||
|
return 8*i + j;
|
||
|
}
|
||
|
}
|
||
|
return -1;
|
||
|
}
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
void
|
||
|
set_bitmap_used(byte *ptr, int i)
|
||
|
{
|
||
|
word32 offset, bit;
|
||
|
word32 val;
|
||
|
|
||
|
offset = i >> 3;
|
||
|
bit = i & 7;
|
||
|
|
||
|
val = ~(0x80 >> bit);
|
||
|
ptr[offset] &= val;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
set_bitmap_free(byte *ptr, int i)
|
||
|
{
|
||
|
int offset, bit;
|
||
|
int val;
|
||
|
|
||
|
offset = i >> 3;
|
||
|
bit = i & 7;
|
||
|
|
||
|
val = (0x80 >> bit);
|
||
|
ptr[offset] |= val;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
set_file_entry(File_entry *entry, int storage_type_name_len, char *file_name,
|
||
|
int file_type, int key_pointer, int blocks_used, int eof,
|
||
|
word32 creation_time, int version, int min_version, int access,
|
||
|
int aux_type, word32 last_mod, int header_pointer)
|
||
|
{
|
||
|
|
||
|
entry->storage_type_name_len = storage_type_name_len;
|
||
|
strncpy((char *)entry->file_name, file_name, 15);
|
||
|
entry->file_type = file_type;
|
||
|
set_l2byte(&(entry->key_pointer), key_pointer);
|
||
|
set_l2byte(&(entry->blocks_used), blocks_used);
|
||
|
set_l3byte(&(entry->eof), eof);
|
||
|
set_pro_time(&(entry->creation_time), creation_time);
|
||
|
entry->version = version;
|
||
|
entry->min_version = min_version;
|
||
|
entry->access = access;
|
||
|
set_l2byte(&(entry->aux_type), aux_type);
|
||
|
set_pro_time(&(entry->last_mod), last_mod);
|
||
|
set_l2byte(&(entry->aux_type), header_pointer);
|
||
|
|
||
|
}
|
||
|
|
||
|
void
|
||
|
set_l2byte(L2byte *ptr, int val)
|
||
|
{
|
||
|
ptr->low = (val & 0xff);
|
||
|
ptr->hi = ((val >> 8) & 0xff);
|
||
|
|
||
|
}
|
||
|
|
||
|
void
|
||
|
set_l3byte(L3byte *ptr, int val)
|
||
|
{
|
||
|
ptr->low = (val & 0xff);
|
||
|
ptr->hi = ((val >> 8) & 0xff);
|
||
|
ptr->higher = ((val >> 16) & 0xff);
|
||
|
|
||
|
}
|
||
|
|
||
|
void
|
||
|
set_pro_time(Pro_time *ptr, word32 val)
|
||
|
{
|
||
|
ptr->times[0] = ((val >> 24) & 0xff);
|
||
|
ptr->times[1] = ((val >> 16) & 0xff);
|
||
|
ptr->times[2] = ((val >> 8) & 0xff);
|
||
|
ptr->times[3] = ((val) & 0xff);
|
||
|
}
|
||
|
|
||
|
int
|
||
|
get_l2byte(L2byte *ptr)
|
||
|
{
|
||
|
int val;
|
||
|
|
||
|
val = ((ptr->hi) * 256) + ptr->low;
|
||
|
return val;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
get_l3byte(L3byte *ptr)
|
||
|
{
|
||
|
int val;
|
||
|
|
||
|
val = ((ptr->higher) * 65536) + ((ptr->hi) * 256) + ptr->low;
|
||
|
return val;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
inc_l2byte(L2byte *ptr)
|
||
|
{
|
||
|
set_l2byte(ptr, get_l2byte(ptr) + 1);
|
||
|
}
|