/* * PROGRAM: JRD Backup and Restore Program * MODULE: canonical.c * DESCRIPTION: * * The contents of this file are subject to the Interbase Public * License Version 1.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy * of the License at http://www.Inprise.com/IPL.html * * Software distributed under the License is distributed on an * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express * or implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code was created by Inprise Corporation * and its predecessors. Portions created by Inprise Corporation are * Copyright (C) Inprise Corporation. * * All Rights Reserved. * Contributor(s): ______________________________________. * * 2002.10.27 Sean Leyne - Code Cleanup, removed obsolete "Ultrix/MIPS" port * * 2002.10.29 Sean Leyne - Removed obsolete "Netware" port * * 2002.10.30 Sean Leyne - Removed support for obsolete "PC_PLATFORM" define * */ /* $Id: canonical.cpp,v 1.17 2003-03-18 01:35:11 brodsom Exp $ */ #include "firebird.h" #include "../jrd/ib_stdio.h" #include #include "../burp/burp.h" #include "../jrd/align.h" #include "../jrd/sdl.h" #include "../burp/canon_proto.h" #include "../jrd/sdl_proto.h" #include "../remote/xdr_proto.h" #include "../jrd/gdsassert.h" #include "../include/fb_types.h" // TMN: Currently we can't include remote/remote.h because we'd get // conflicting blk_t definitions (we are gonna fix this, in due time). // Because this file needs the remote definition of VARY, which // coincidentally is different from _all_ other modules in the code, // we have to make the type definition here. typedef vary* VARY; extern "C" { static XDR_INT burp_destroy(XDR*); static bool_t burp_getbytes(XDR*, SCHAR *, u_int); static bool_t burp_getlong(XDR*, SLONG *); static u_int burp_getpostn(XDR*); static caddr_t burp_inline(XDR*, u_int); static bool_t burp_putbytes(XDR*, SCHAR *, u_int); static bool_t burp_putlong(XDR*, SLONG *); static bool_t burp_setpostn(XDR*, u_int); static bool_t expand_buffer(XDR*); static bool_t xdr_datum(XDR*, DSC*, UCHAR*); static bool_t xdr_quad(XDR*, SLONG*); static int xdr_init(XDR*, LSTRING*, enum xdr_op); static bool_t xdr_slice(XDR*, LSTRING*, USHORT, UCHAR*); static xdr_t::xdr_ops burp_ops = { burp_getlong, burp_putlong, burp_getbytes, burp_putbytes, burp_getpostn, burp_setpostn, burp_inline, burp_destroy }; #define INCREMENT 1024 ULONG CAN_encode_decode(BURP_REL relation, LSTRING * buffer, UCHAR * data, bool_t direction) { /************************************** * * C A N _ e n c o d e _ d e c o d e * ************************************** * * Functional description * encode and decode canonical backup. * **************************************/ XDR xdr, *xdrs; BURP_FLD field; FLD_LENGTH length; SSHORT dtype, n; UCHAR *p; RCRD_OFFSET offset; USHORT array_fld; xdrs = &xdr; xdr_init(xdrs, buffer, (direction) ? XDR_ENCODE : XDR_DECODE); offset = 0; for (field = relation->rel_fields; field; field = field->fld_next) { if (field->fld_flags & FLD_computed) continue; p = data + field->fld_offset; if (array_fld = field->fld_flags & FLD_array) length = 8; else length = field->fld_length; if (field->fld_offset >= offset) offset = field->fld_offset + length; if (field->fld_type == blr_varying && !array_fld) offset += sizeof(SSHORT); if (field->fld_type == blr_blob || array_fld) dtype = dtype_blob; else dtype = (SSHORT) gds_cvt_blr_dtype[field->fld_type]; switch (dtype) { case dtype_text: if (!xdr_opaque(xdrs, reinterpret_cast(p), length)) { return FALSE; } break; case dtype_varying: { VARY pVary = reinterpret_cast(p); if (!xdr_short( xdrs, reinterpret_cast(&pVary->vary_length))) { return FALSE; } if (!xdr_opaque(xdrs, reinterpret_cast(pVary->vary_string), pVary->vary_length)) { return FALSE; } } break; case dtype_cstring: if (xdrs->x_op == XDR_ENCODE) n = (strlen(reinterpret_cast(p))); if (!xdr_short(xdrs, &n)) return FALSE; if (!xdr_opaque(xdrs, reinterpret_cast(p), n)) return FALSE; if (xdrs->x_op == XDR_DECODE) p[n] = 0; break; case dtype_short: if (!xdr_short(xdrs, (SSHORT *) p)) return FALSE; break; case dtype_long: case dtype_sql_time: case dtype_sql_date: if (!xdr_long(xdrs, (SLONG *) p)) return FALSE; break; case dtype_real: if (!xdr_float(xdrs, (float *) p)) return FALSE; break; case dtype_double: if (!xdr_double(xdrs, (double *) p)) return FALSE; break; case dtype_timestamp: if (!xdr_long(xdrs, &((SLONG *) p)[0])) return FALSE; if (!xdr_long(xdrs, &((SLONG *) p)[1])) return FALSE; break; case dtype_quad: case dtype_blob: if (!xdr_quad(xdrs, (SLONG *) p)) return FALSE; break; case dtype_int64: if (!xdr_hyper(xdrs, (SINT64 *) p)) return FALSE; break; default: assert(FALSE); return FALSE; } } /* Next, get null flags */ for (field = relation->rel_fields; field; field = field->fld_next) { if (field->fld_flags & FLD_computed) continue; offset = FB_ALIGN(offset, sizeof(SSHORT)); p = data + offset; if (!xdr_short(xdrs, (SSHORT *) p)) return FALSE; offset += sizeof(SSHORT); } return (xdrs->x_private - xdrs->x_base); } ULONG CAN_slice(LSTRING * buffer, LSTRING * slice, bool_t direction, USHORT sdl_length, UCHAR * sdl) { /************************************** * * C A N _ s l i c e * ************************************** * * Functional description * encode and decode canonical backup. * **************************************/ XDR xdr, *xdrs; xdrs = &xdr; xdr_init(xdrs, buffer, (direction) ? XDR_ENCODE : XDR_DECODE); xdr_slice(xdrs, slice, sdl_length, sdl); return (xdrs->x_private - xdrs->x_base); } static XDR_INT burp_destroy( XDR * xdrs) { /************************************** * * b u r p _ d e s t r o y * ************************************** * * Functional description * Destroy a stream. A no-op. * **************************************/ return 0; } static bool_t burp_getbytes(XDR* xdrs, SCHAR* buff, u_int bytecount) { /************************************** * * b u r p _ g e t b y t e s * ************************************** * * Functional description * Fetch a bunch of bytes into a memory stream if it fits. * **************************************/ if (bytecount && xdrs->x_handy >= bytecount) { xdrs->x_handy -= bytecount; do { *buff++ = *xdrs->x_private++; } while (--bytecount); return TRUE; } while (bytecount) { if (!xdrs->x_handy && !expand_buffer(xdrs)) return FALSE; *buff++ = *xdrs->x_private++; --xdrs->x_handy; --bytecount; } return TRUE; } static bool_t burp_getlong( XDR * xdrs, SLONG * lp) { /************************************** * * b u r p _ g e t l o n g * ************************************** * * Functional description * Fetch a longword into a memory stream if it fits. * **************************************/ SLONG l; if (!(*xdrs->x_ops->x_getbytes) (xdrs, reinterpret_cast(&l), 4)) return FALSE; *lp = ntohl(l); return TRUE; } static u_int burp_getpostn( XDR * xdrs) { /************************************** * * b u r p _ g e t p o s t n * ************************************** * * Functional description * Get the current position (which is also current length) from stream. * **************************************/ return xdrs->x_private - xdrs->x_base; } static caddr_t burp_inline( XDR * xdrs, u_int bytecount) { /************************************** * * b u r p _ i n l i n e * ************************************** * * Functional description * Return a pointer to somewhere in the buffer. * **************************************/ if (bytecount > (u_int) xdrs->x_handy) return FALSE; return xdrs->x_base + bytecount; } static bool_t burp_putbytes(XDR* xdrs, SCHAR* buff, u_int bytecount) { /************************************** * * b u r p _ p u t b y t e s * ************************************** * * Functional description * Fetch a bunch of bytes into a memory stream if it fits. * **************************************/ if (bytecount && xdrs->x_handy >= bytecount) { xdrs->x_handy -= bytecount; do { *xdrs->x_private++ = *buff++; } while (--bytecount); return TRUE; } while (bytecount) { if (xdrs->x_handy <= 0 && !expand_buffer(xdrs)) { return FALSE; } --xdrs->x_handy; *xdrs->x_private++ = *buff++; --bytecount; } return TRUE; } static bool_t burp_putlong( XDR * xdrs, SLONG * lp) { /************************************** * * b u r p _ p u t l o n g * ************************************** * * Functional description * Fetch a longword into a memory stream if it fits. * **************************************/ SLONG l; l = htonl(*lp); return (*xdrs->x_ops->x_putbytes) (xdrs, reinterpret_cast(AOF32L(l)), 4); } static bool_t burp_setpostn( XDR * xdrs, u_int bytecount) { /************************************** * * b u r p _ s e t p o s t n * ************************************** * * Functional description * Set the current position (which is also current length) from stream. * **************************************/ if (bytecount > (u_int) xdrs->x_handy) return FALSE; xdrs->x_private = xdrs->x_base + bytecount; return TRUE; } static bool_t expand_buffer( XDR * xdrs) { /************************************** * * e x p a n d _ b u f f e r * ************************************** * * Functional description * Allocate a new, larger buffer, copy * everything we've got, and release the * old one. * **************************************/ caddr_t p, q; SSHORT length; LSTRING *buffer; buffer = (LSTRING *) xdrs->x_public; length = (xdrs->x_private - xdrs->x_base) + xdrs->x_handy + INCREMENT; buffer->lstr_allocated = buffer->lstr_length = length; caddr_t new_ = (caddr_t) BURP_ALLOC(length); for (p = new_, q = xdrs->x_base; q < xdrs->x_private; *p++ = *q++) ; BURP_FREE(xdrs->x_base); xdrs->x_base = new_; xdrs->x_private = p; xdrs->x_handy += INCREMENT; buffer->lstr_address = (UCHAR *) new_; return TRUE; } static bool_t xdr_datum( XDR * xdrs, DSC * desc, UCHAR * buffer) { /************************************** * * x d r _ d a t u m * ************************************** * * Functional description * Handle a data item by relative descriptor and buffer. * **************************************/ UCHAR *p; SSHORT n; p = buffer + (int) desc->dsc_address; switch (desc->dsc_dtype) { case dtype_text: if (!xdr_opaque(xdrs, reinterpret_cast(p), desc->dsc_length)) { return FALSE; } break; case dtype_varying: { VARY pVary = reinterpret_cast(p); if (!xdr_short(xdrs, reinterpret_cast(&pVary->vary_length))) { return FALSE; } if (!xdr_opaque(xdrs, reinterpret_cast(pVary->vary_string), MIN(desc->dsc_length - 2, pVary->vary_length))) { return FALSE; } } break; case dtype_cstring: if (xdrs->x_op == XDR_ENCODE) n = MIN(strlen(reinterpret_cast(p)), (size_t) (desc->dsc_length - 1)); if (!xdr_short(xdrs, &n)) return FALSE; if (!xdr_opaque(xdrs, reinterpret_cast(p), n)) return FALSE; if (xdrs->x_op == XDR_DECODE) p[n] = 0; break; case dtype_short: if (!xdr_short(xdrs, (SSHORT *) p)) return FALSE; break; case dtype_sql_date: case dtype_sql_time: case dtype_long: if (!xdr_long(xdrs, (SLONG *) p)) return FALSE; break; case dtype_real: if (!xdr_float(xdrs, (float *) p)) return FALSE; break; case dtype_double: if (!xdr_double(xdrs, (double *) p)) return FALSE; break; case dtype_timestamp: if (!xdr_long(xdrs, &((SLONG *) p)[0])) return FALSE; if (!xdr_long(xdrs, &((SLONG *) p)[1])) return FALSE; break; case dtype_quad: case dtype_blob: if (!xdr_quad(xdrs, (SLONG *) p)) return FALSE; break; case dtype_int64: if (!xdr_hyper(xdrs, (SINT64 *) p)) return FALSE; break; default: assert(FALSE); return FALSE; } return TRUE; } static bool_t xdr_quad(XDR* xdrs, SLONG* ip) { /************************************** * * x d r _ q u a d * ************************************** * * Functional description * Map from external to internal representation (or vice versa). * **************************************/ switch (xdrs->x_op) { case XDR_ENCODE: if ((*xdrs->x_ops->x_putlong) (xdrs, &ip[0]) && (*xdrs->x_ops->x_putlong) (xdrs, &ip[1])) return TRUE; return FALSE; case XDR_DECODE: if (!(*xdrs->x_ops->x_getlong) (xdrs, &ip[0])) return FALSE; return (*xdrs->x_ops->x_getlong) (xdrs, &ip[1]); case XDR_FREE: return TRUE; default: assert(FALSE); return FALSE; } } static int xdr_init( XDR * xdrs, LSTRING * buffer, enum xdr_op x_op) { /************************************** * * x d r _ i n i t * ************************************** * * Functional description * Initialize an XDR stream for Apollo mailboxes. * **************************************/ xdrs->x_public = (caddr_t) buffer; xdrs->x_base = xdrs->x_private = (caddr_t) buffer->lstr_address; xdrs->x_handy = buffer->lstr_length; xdrs->x_ops = &burp_ops; xdrs->x_op = x_op; return TRUE; } static bool_t xdr_slice(XDR* xdrs, LSTRING* slice, USHORT sdl_length, UCHAR* sdl) { /************************************** * * x d r _ s l i c e * ************************************** * * Functional description * Move a slice of an array under * **************************************/ STATUS status_vector[ISC_STATUS_LENGTH]; ULONG n; UCHAR *p, *end; DSC *desc; struct sdl_info info; if (!xdr_long(xdrs, reinterpret_cast(&slice->lstr_length))) return FALSE; /* Handle operation specific stuff, particularly memory allocation/deallocation */ switch (xdrs->x_op) { case XDR_ENCODE: break; case XDR_DECODE: if (!slice->lstr_length) return TRUE; if (slice->lstr_length > slice->lstr_allocated && slice->lstr_allocated) { BURP_FREE(slice->lstr_address); slice->lstr_address = NULL; } if (!slice->lstr_address) { slice->lstr_address = BURP_ALLOC((SLONG) slice->lstr_length); if (!slice->lstr_address) { return FALSE; } slice->lstr_allocated = slice->lstr_length; } break; case XDR_FREE: if (slice->lstr_allocated) BURP_FREE(slice->lstr_address); slice->lstr_address = NULL; slice->lstr_allocated = 0; return TRUE; default: assert(FALSE); return FALSE; } /* Get descriptor of array element */ if (SDL_info(status_vector, sdl, &info, 0)) return FALSE; desc = &info.sdl_info_element; n = slice->lstr_length / desc->dsc_length; p = slice->lstr_address; for (end = p + n * desc->dsc_length; p < end; p += desc->dsc_length) { if (!xdr_datum(xdrs, desc, p)) { return FALSE; } } return TRUE; } } // extern "C"