NetBSD/dist/pdisk/deblock_media.c

335 lines
8.2 KiB
C

/*
* deblock_media.c -
*
* Written by Eryk Vershen
*/
/*
* Copyright 1997,1998 by Apple Computer, Inc.
* All Rights Reserved
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby granted,
* provided that the above copyright notice appears in all copies and
* that both the copyright notice and this permission notice appear in
* supporting documentation.
*
* APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE.
*
* IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
* NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
// for malloc() & free()
#include <stdlib.h>
// for memcpy()
#include <string.h>
#include "deblock_media.h"
/*
* Defines
*/
/*
* Types
*/
typedef struct deblock_media *DEBLOCK_MEDIA;
struct deblock_media {
struct media m;
long need_filtering;
MEDIA next_media;
unsigned long next_block_size;
unsigned char *buffer;
};
struct deblock_globals {
long exists;
long kind;
};
/*
* Global Constants
*/
/*
* Global Variables
*/
static long deblock_inited = 0;
static struct deblock_globals deblock_info;
/*
* Forward declarations
*/
void deblock_init(void);
DEBLOCK_MEDIA new_deblock_media(void);
long read_deblock_media(MEDIA m, long long offset, unsigned long count, void *address);
long write_deblock_media(MEDIA m, long long offset, unsigned long count, void *address);
long close_deblock_media(MEDIA m);
long os_reload_deblock_media(MEDIA m);
/*
* Routines
*/
void
deblock_init(void)
{
if (deblock_inited != 0) {
return;
}
deblock_inited = 1;
deblock_info.kind = allocate_media_kind();
}
DEBLOCK_MEDIA
new_deblock_media(void)
{
return (DEBLOCK_MEDIA) new_media(sizeof(struct deblock_media));
}
MEDIA
open_deblock_media(unsigned long new_block_size, MEDIA m)
{
DEBLOCK_MEDIA a;
unsigned long block_size;
if (deblock_inited == 0) {
deblock_init();
}
a = 0;
if (m != 0) {
block_size = media_granularity(m);
if (new_block_size == block_size) {
return m;
} else if (new_block_size > block_size) {
if ((new_block_size % block_size) == 0) {
/* no filtering necessary */
a = new_deblock_media();
if (a != 0) {
a->need_filtering = 0;
a->next_block_size = block_size;
a->buffer = 0;
}
} else {
/* too hard to bother with */
}
} else /* new_block_size < block_size */ {
if ((block_size % new_block_size) == 0) {
/* block & unblock */
a = new_deblock_media();
if (a != 0) {
a->need_filtering = 1;
a->next_block_size = block_size;
a->buffer = malloc(block_size);
}
} else {
/* too hard to bother with */
}
}
if (a != 0) {
a->m.kind = deblock_info.kind;
a->m.grain = new_block_size;
a->m.size_in_bytes = media_total_size(m);
a->m.do_read = read_deblock_media;
a->m.do_write = write_deblock_media;
a->m.do_close = close_deblock_media;
a->m.do_os_reload = os_reload_deblock_media;
a->next_media = m;
}
}
return (MEDIA) a;
}
long
read_deblock_media(MEDIA m, long long offset, unsigned long count, void *address)
{
DEBLOCK_MEDIA a;
long rtn_value;
unsigned long next_size;
unsigned long partial_offset;
unsigned long partial_count;
long long cur_offset;
unsigned long remainder;
unsigned char *addr;
a = (DEBLOCK_MEDIA) m;
rtn_value = 0;
if (a == 0) {
/* no media */
} else if (a->m.kind != deblock_info.kind) {
/* wrong kind - XXX need to error here - this is an internal problem */
} else if (count <= 0 || count % a->m.grain != 0) {
/* can't handle size */
} else if (offset < 0 || offset % a->m.grain != 0) {
/* can't handle offset */
} else if (a->need_filtering == 0) {
rtn_value = read_media(a->next_media, offset, count, address);
} else {
next_size = a->next_block_size;
addr = address;
cur_offset = offset;
remainder = count;
rtn_value = 1;
/* read partial */
partial_offset = cur_offset % next_size;
if (partial_offset != 0) {
partial_count = next_size - partial_offset;
if (partial_count > remainder) {
partial_count = remainder;
}
rtn_value = read_media(a->next_media, cur_offset - partial_offset, next_size, a->buffer);
if (rtn_value != 0) {
memcpy (addr, a->buffer + partial_offset, partial_count);
addr += partial_count;
cur_offset += partial_count;
remainder -= partial_count;
}
}
/* read fulls as long as needed */
if (rtn_value != 0 && remainder > next_size) {
partial_count = remainder - (remainder % next_size);
rtn_value = read_media(a->next_media, cur_offset, partial_count, addr);
addr += partial_count;
cur_offset += partial_count;
remainder -= partial_count;
}
/* read partial */
if (rtn_value != 0 && remainder > 0) {
partial_count = remainder;
rtn_value = read_media(a->next_media, cur_offset, next_size, a->buffer);
if (rtn_value != 0) {
memcpy (addr, a->buffer, partial_count);
}
}
}
return rtn_value;
}
long
write_deblock_media(MEDIA m, long long offset, unsigned long count, void *address)
{
DEBLOCK_MEDIA a;
long rtn_value;
unsigned long next_size;
unsigned long partial_offset;
unsigned long partial_count;
long long cur_offset;
unsigned long remainder;
unsigned char *addr;
a = (DEBLOCK_MEDIA) m;
rtn_value = 0;
if (a == 0) {
/* no media */
} else if (a->m.kind != deblock_info.kind) {
/* wrong kind - XXX need to error here - this is an internal problem */
} else if (count <= 0 || count % a->m.grain != 0) {
/* can't handle size */
} else if (offset < 0 || offset % a->m.grain != 0) {
/* can't handle offset */
} else if (a->need_filtering == 0) {
rtn_value = write_media(a->next_media, offset, count, address);
} else {
next_size = a->next_block_size;
addr = address;
cur_offset = offset;
remainder = count;
rtn_value = 1;
/* write partial */
partial_offset = cur_offset % next_size;
if (partial_offset != 0) {
partial_count = next_size - partial_offset;
if (partial_count > remainder) {
partial_count = remainder;
}
rtn_value = read_media(a->next_media, cur_offset - partial_offset, next_size, a->buffer);
if (rtn_value != 0) {
memcpy (a->buffer + partial_offset, addr, partial_count);
rtn_value = write_media(a->next_media, cur_offset - partial_offset, next_size, a->buffer);
addr += partial_count;
cur_offset += partial_count;
remainder -= partial_count;
}
}
/* write fulls as long as needed */
if (rtn_value != 0 && remainder > next_size) {
partial_count = remainder - (remainder % next_size);
rtn_value = write_media(a->next_media, cur_offset, partial_count, addr);
addr += partial_count;
cur_offset += partial_count;
remainder -= partial_count;
}
/* write partial */
if (rtn_value != 0 && remainder > 0) {
partial_count = remainder;
rtn_value = read_media(a->next_media, cur_offset, next_size, a->buffer);
if (rtn_value != 0) {
memcpy (a->buffer, addr, partial_count);
rtn_value = write_media(a->next_media, cur_offset, next_size, a->buffer);
}
}
}
/* recompute size to handle file media */
a->m.size_in_bytes = media_total_size(a->next_media);
return rtn_value;
}
long
close_deblock_media(MEDIA m)
{
DEBLOCK_MEDIA a;
a = (DEBLOCK_MEDIA) m;
if (a == 0) {
return 0;
} else if (a->m.kind != deblock_info.kind) {
/* XXX need to error here - this is an internal problem */
return 0;
}
close_media(a->next_media);
free(a->buffer);
return 1;
}
long
os_reload_deblock_media(MEDIA m)
{
DEBLOCK_MEDIA a;
a = (DEBLOCK_MEDIA) m;
if (a == 0) {
return 0;
} else if (a->m.kind != deblock_info.kind) {
/* XXX need to error here - this is an internal problem */
return 0;
}
os_reload_media(a->next_media);
return 1;
}