2004-12-10 23:54:16 +01:00
|
|
|
/*
|
|
|
|
* PROGRAM: Client/Server Common Code
|
|
|
|
* MODULE: ClumpletReader.cpp
|
|
|
|
* DESCRIPTION: Secure handling of clumplet buffers
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Initial
|
|
|
|
* Developer's 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.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed AS IS,
|
|
|
|
* 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 Nickolay Samofatov
|
|
|
|
* for the Firebird Open Source RDBMS project.
|
|
|
|
*
|
|
|
|
* Copyright (c) 2004 Nickolay Samofatov <nickolay@broadviewsoftware.com>
|
|
|
|
* and all contributors signed below.
|
|
|
|
*
|
|
|
|
* All Rights Reserved.
|
|
|
|
* Contributor(s): ______________________________________.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2004-10-22 08:24:40 +02:00
|
|
|
#include "firebird.h"
|
|
|
|
|
|
|
|
#include "../common/classes/ClumpletReader.h"
|
|
|
|
#include "fb_exception.h"
|
|
|
|
|
2005-11-27 21:53:09 +01:00
|
|
|
#include "../jrd/ibase.h"
|
|
|
|
|
|
|
|
#ifdef DEBUG_CLUMPLETS
|
2010-10-12 10:02:57 +02:00
|
|
|
#include "../yvalve/gds_proto.h"
|
2005-11-27 21:53:09 +01:00
|
|
|
#include <ctype.h>
|
|
|
|
|
2005-11-30 18:11:23 +01:00
|
|
|
namespace Firebird {
|
|
|
|
|
2006-07-26 12:00:26 +02:00
|
|
|
class ClumpletDump : public ClumpletReader
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
ClumpletDump(Kind k, const UCHAR* buffer, size_t buffLen)
|
2009-01-03 10:14:29 +01:00
|
|
|
: ClumpletReader(k, buffer, buffLen)
|
|
|
|
{ }
|
2006-07-26 12:00:26 +02:00
|
|
|
static string hexString(const UCHAR* b, size_t len)
|
|
|
|
{
|
|
|
|
string t1, t2;
|
2009-06-28 13:59:30 +02:00
|
|
|
for (; len > 0; --len, ++b)
|
|
|
|
{
|
2006-07-26 12:00:26 +02:00
|
|
|
if (isprint(*b))
|
|
|
|
t2 += *b;
|
2009-06-28 13:59:30 +02:00
|
|
|
else
|
|
|
|
{
|
2006-07-26 12:00:26 +02:00
|
|
|
t1.printf("<%02x>", *b);
|
|
|
|
t2 += t1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return t2;
|
|
|
|
}
|
|
|
|
protected:
|
2008-12-05 02:20:14 +01:00
|
|
|
virtual void usage_mistake(const char* what) const
|
2006-07-26 12:00:26 +02:00
|
|
|
{
|
2008-12-13 10:26:00 +01:00
|
|
|
fatal_exception::raiseFmt("Internal error when using clumplet API: %s", what);
|
2006-07-26 12:00:26 +02:00
|
|
|
}
|
2008-12-05 02:20:14 +01:00
|
|
|
virtual void invalid_structure(const char* what) const
|
2006-07-26 12:00:26 +02:00
|
|
|
{
|
2008-12-13 10:26:00 +01:00
|
|
|
fatal_exception::raiseFmt("Invalid clumplet buffer structure: %s", what);
|
2006-07-26 12:00:26 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2005-11-30 18:11:23 +01:00
|
|
|
void ClumpletReader::dump() const
|
2005-11-27 21:53:09 +01:00
|
|
|
{
|
2005-11-30 18:11:23 +01:00
|
|
|
static int dmp = 0;
|
|
|
|
gds__log("*** DUMP ***");
|
2009-06-28 13:59:30 +02:00
|
|
|
if (dmp)
|
|
|
|
{
|
2006-07-26 12:00:26 +02:00
|
|
|
// Avoid infinite recursion during dump
|
2005-11-30 18:11:23 +01:00
|
|
|
gds__log("recursion");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
dmp++;
|
2008-12-05 02:20:14 +01:00
|
|
|
|
2005-11-30 18:11:23 +01:00
|
|
|
try {
|
|
|
|
ClumpletDump d(kind, getBuffer(), getBufferLength());
|
2006-09-26 17:09:46 +02:00
|
|
|
int t = (kind == SpbStart || kind == UnTagged || kind == WideUnTagged) ? -1 : d.getBufferTag();
|
2005-12-02 17:54:04 +01:00
|
|
|
gds__log("Tag=%d Offset=%d Length=%d Eof=%d\n", t, getCurOffset(), getBufferLength(), isEof());
|
2005-11-30 18:11:23 +01:00
|
|
|
for (d.rewind(); !(d.isEof()); d.moveNext())
|
|
|
|
{
|
|
|
|
gds__log("Clump %d at offset %d: %s", d.getClumpTag(), d.getCurOffset(),
|
|
|
|
ClumpletDump::hexString(d.getBytes(), d.getClumpLength()).c_str());
|
2005-11-27 21:53:09 +01:00
|
|
|
}
|
|
|
|
}
|
2009-06-28 13:59:30 +02:00
|
|
|
catch (const fatal_exception& x)
|
|
|
|
{
|
2005-11-27 21:53:09 +01:00
|
|
|
gds__log("Fatal exception during clumplet dump: %s", x.what());
|
2005-11-30 18:11:23 +01:00
|
|
|
size_t l = getBufferLength() - getCurOffset();
|
|
|
|
const UCHAR *p = getBuffer() + getCurOffset();
|
|
|
|
gds__log("Plain dump starting with offset %d: %s", getCurOffset(),
|
|
|
|
ClumpletDump::hexString(p, l).c_str());
|
2005-11-27 21:53:09 +01:00
|
|
|
}
|
2005-11-30 18:11:23 +01:00
|
|
|
dmp--;
|
|
|
|
}
|
|
|
|
|
2005-11-27 21:53:09 +01:00
|
|
|
}
|
|
|
|
#endif //DEBUG_CLUMPLETS
|
|
|
|
|
2004-10-22 08:24:40 +02:00
|
|
|
namespace Firebird {
|
|
|
|
|
2005-11-27 21:53:09 +01:00
|
|
|
ClumpletReader::ClumpletReader(Kind k, const UCHAR* buffer, size_t buffLen) :
|
2008-12-05 02:20:14 +01:00
|
|
|
kind(k), static_buffer(buffer), static_buffer_end(buffer + buffLen)
|
2004-11-03 09:38:09 +01:00
|
|
|
{
|
2005-11-27 21:53:09 +01:00
|
|
|
rewind(); // this will set cur_offset and spbState
|
2004-11-03 09:38:09 +01:00
|
|
|
}
|
|
|
|
|
2006-09-26 17:09:46 +02:00
|
|
|
ClumpletReader::ClumpletReader(MemoryPool& pool, Kind k, const UCHAR* buffer, size_t buffLen) :
|
2008-12-05 02:20:14 +01:00
|
|
|
AutoStorage(pool), kind(k), static_buffer(buffer), static_buffer_end(buffer + buffLen)
|
2006-09-26 17:09:46 +02:00
|
|
|
{
|
|
|
|
rewind(); // this will set cur_offset and spbState
|
|
|
|
}
|
|
|
|
|
2010-01-24 16:18:43 +01:00
|
|
|
ClumpletReader::ClumpletReader(MemoryPool& pool, const KindList* kl,
|
2010-01-22 15:55:11 +01:00
|
|
|
const UCHAR* buffer, size_t buffLen, FPTR_VOID raise) :
|
|
|
|
AutoStorage(pool), kind(kl->kind), static_buffer(buffer), static_buffer_end(buffer + buffLen)
|
|
|
|
{
|
|
|
|
create(kl, buffLen, raise);
|
|
|
|
}
|
|
|
|
|
2009-12-30 16:24:16 +01:00
|
|
|
ClumpletReader::ClumpletReader(const KindList* kl, const UCHAR* buffer, size_t buffLen, FPTR_VOID raise) :
|
|
|
|
kind(kl->kind), static_buffer(buffer), static_buffer_end(buffer + buffLen)
|
2010-01-22 15:55:11 +01:00
|
|
|
{
|
|
|
|
create(kl, buffLen, raise);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ClumpletReader::create(const KindList* kl, size_t buffLen, FPTR_VOID raise)
|
2009-12-30 16:24:16 +01:00
|
|
|
{
|
2011-06-08 11:27:04 +02:00
|
|
|
cur_offset = 0;
|
|
|
|
|
2009-12-30 16:24:16 +01:00
|
|
|
if (buffLen)
|
|
|
|
{
|
|
|
|
while (kl->kind != EndOfList)
|
|
|
|
{
|
|
|
|
kind = kl->kind;
|
|
|
|
if (getBufferTag() == kl->tag)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
++kl;
|
|
|
|
}
|
2010-01-01 21:23:52 +01:00
|
|
|
|
2009-12-30 16:24:16 +01:00
|
|
|
if (kl->kind == EndOfList)
|
|
|
|
{
|
|
|
|
if (raise)
|
|
|
|
{
|
|
|
|
raise();
|
|
|
|
}
|
|
|
|
invalid_structure("Unknown tag value - missing in the list of possible");
|
|
|
|
}
|
|
|
|
}
|
2010-01-01 21:23:52 +01:00
|
|
|
|
2009-12-30 16:24:16 +01:00
|
|
|
rewind(); // this will set cur_offset and spbState
|
|
|
|
}
|
|
|
|
|
2009-07-23 02:56:28 +02:00
|
|
|
const UCHAR* ClumpletReader::getBuffer() const
|
|
|
|
{
|
|
|
|
return static_buffer;
|
2009-07-21 15:59:45 +02:00
|
|
|
}
|
|
|
|
|
2009-07-23 02:56:28 +02:00
|
|
|
const UCHAR* ClumpletReader::getBufferEnd() const
|
|
|
|
{
|
|
|
|
return static_buffer_end;
|
2009-07-21 15:59:45 +02:00
|
|
|
}
|
|
|
|
|
2008-04-18 12:03:04 +02:00
|
|
|
void ClumpletReader::usage_mistake(const char* what) const
|
|
|
|
{
|
2005-11-27 21:53:09 +01:00
|
|
|
#ifdef DEBUG_CLUMPLETS
|
|
|
|
dump();
|
|
|
|
#endif
|
2008-12-13 10:26:00 +01:00
|
|
|
fatal_exception::raiseFmt("Internal error when using clumplet API: %s", what);
|
2004-10-22 08:24:40 +02:00
|
|
|
}
|
|
|
|
|
2008-04-18 12:03:04 +02:00
|
|
|
void ClumpletReader::invalid_structure(const char* what) const
|
|
|
|
{
|
2005-11-27 21:53:09 +01:00
|
|
|
#ifdef DEBUG_CLUMPLETS
|
|
|
|
dump();
|
|
|
|
#endif
|
2008-12-13 10:26:00 +01:00
|
|
|
fatal_exception::raiseFmt("Invalid clumplet buffer structure: %s", what);
|
2004-10-22 08:24:40 +02:00
|
|
|
}
|
|
|
|
|
2004-12-12 07:50:10 +01:00
|
|
|
UCHAR ClumpletReader::getBufferTag() const
|
|
|
|
{
|
2008-04-18 12:03:04 +02:00
|
|
|
const UCHAR* const buffer_end = getBufferEnd();
|
2005-11-27 21:53:09 +01:00
|
|
|
const UCHAR* buffer_start = getBuffer();
|
2008-12-05 02:20:14 +01:00
|
|
|
|
|
|
|
switch (kind)
|
2005-11-27 21:53:09 +01:00
|
|
|
{
|
|
|
|
case Tpb:
|
|
|
|
case Tagged:
|
2006-09-26 17:09:46 +02:00
|
|
|
case WideTagged:
|
2008-12-05 02:20:14 +01:00
|
|
|
if (buffer_end - buffer_start == 0)
|
2005-11-27 21:53:09 +01:00
|
|
|
{
|
2005-11-30 18:11:23 +01:00
|
|
|
invalid_structure("empty buffer");
|
2005-11-27 21:53:09 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return buffer_start[0];
|
2005-11-30 18:11:23 +01:00
|
|
|
case SpbStart:
|
2005-11-27 21:53:09 +01:00
|
|
|
case UnTagged:
|
2006-09-26 17:09:46 +02:00
|
|
|
case WideUnTagged:
|
2007-04-19 11:16:38 +02:00
|
|
|
case SpbItems:
|
2004-11-03 09:38:09 +01:00
|
|
|
usage_mistake("buffer is not tagged");
|
|
|
|
return 0;
|
2005-11-27 21:53:09 +01:00
|
|
|
case SpbAttach:
|
2008-12-05 02:20:14 +01:00
|
|
|
if (buffer_end - buffer_start == 0)
|
2005-11-27 21:53:09 +01:00
|
|
|
{
|
2005-11-30 18:11:23 +01:00
|
|
|
invalid_structure("empty buffer");
|
2005-11-27 21:53:09 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
switch (buffer_start[0])
|
|
|
|
{
|
|
|
|
case isc_spb_version1:
|
2008-12-05 02:20:14 +01:00
|
|
|
// This is old SPB format, it's almost like DPB -
|
2005-11-27 21:53:09 +01:00
|
|
|
// buffer's tag is the first byte.
|
|
|
|
return buffer_start[0];
|
|
|
|
case isc_spb_version:
|
|
|
|
// Buffer's tag is the second byte
|
2008-12-05 02:20:14 +01:00
|
|
|
if (buffer_end - buffer_start == 1)
|
2005-11-27 21:53:09 +01:00
|
|
|
{
|
2005-11-30 18:11:23 +01:00
|
|
|
invalid_structure("buffer too short (1 byte)");
|
2005-11-27 21:53:09 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return buffer_start[1];
|
|
|
|
default:
|
2005-11-30 18:11:23 +01:00
|
|
|
invalid_structure("spb in service attach should begin with isc_spb_version1 or isc_spb_version");
|
2005-11-27 21:53:09 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2005-11-30 18:11:23 +01:00
|
|
|
default:
|
|
|
|
fb_assert(false);
|
|
|
|
return 0;
|
2004-11-03 09:38:09 +01:00
|
|
|
}
|
2005-11-27 21:53:09 +01:00
|
|
|
}
|
2004-11-03 09:38:09 +01:00
|
|
|
|
2005-11-27 21:53:09 +01:00
|
|
|
ClumpletReader::ClumpletType ClumpletReader::getClumpletType(UCHAR tag) const
|
|
|
|
{
|
|
|
|
switch (kind)
|
|
|
|
{
|
|
|
|
case Tagged:
|
|
|
|
case UnTagged:
|
|
|
|
case SpbAttach:
|
|
|
|
return TraditionalDpb;
|
2006-09-26 17:09:46 +02:00
|
|
|
case WideTagged:
|
|
|
|
case WideUnTagged:
|
|
|
|
return Wide;
|
2005-11-27 21:53:09 +01:00
|
|
|
case Tpb:
|
|
|
|
switch (tag)
|
|
|
|
{
|
|
|
|
case isc_tpb_lock_write:
|
|
|
|
case isc_tpb_lock_read:
|
2010-08-07 23:18:23 +02:00
|
|
|
case isc_tpb_lock_timeout:
|
2005-11-27 21:53:09 +01:00
|
|
|
return TraditionalDpb;
|
|
|
|
}
|
|
|
|
return SingleTpb;
|
2007-04-19 11:16:38 +02:00
|
|
|
case SpbItems:
|
|
|
|
return SingleTpb;
|
2005-11-30 18:11:23 +01:00
|
|
|
case SpbStart:
|
2009-02-03 12:02:00 +01:00
|
|
|
switch (spbState)
|
|
|
|
{
|
2005-11-27 21:53:09 +01:00
|
|
|
case 0:
|
|
|
|
return SingleTpb;
|
|
|
|
case isc_action_svc_backup:
|
|
|
|
case isc_action_svc_restore:
|
2008-12-05 02:20:14 +01:00
|
|
|
switch (tag)
|
2005-11-27 21:53:09 +01:00
|
|
|
{
|
|
|
|
case isc_spb_bkp_file:
|
|
|
|
case isc_spb_dbname:
|
2009-10-05 12:26:59 +02:00
|
|
|
case isc_spb_res_fix_fss_data:
|
|
|
|
case isc_spb_res_fix_fss_metadata:
|
2005-11-27 21:53:09 +01:00
|
|
|
return StringSpb;
|
2005-12-03 11:22:22 +01:00
|
|
|
case isc_spb_bkp_factor:
|
2005-12-03 10:48:35 +01:00
|
|
|
case isc_spb_bkp_length:
|
|
|
|
case isc_spb_res_length:
|
2005-11-27 21:53:09 +01:00
|
|
|
case isc_spb_res_buffers:
|
|
|
|
case isc_spb_res_page_size:
|
|
|
|
case isc_spb_options:
|
2009-11-05 10:03:41 +01:00
|
|
|
case isc_spb_verbint:
|
2005-11-27 21:53:09 +01:00
|
|
|
return IntSpb;
|
|
|
|
case isc_spb_verbose:
|
|
|
|
return SingleTpb;
|
|
|
|
case isc_spb_res_access_mode:
|
|
|
|
return ByteSpb;
|
|
|
|
}
|
2005-11-30 18:11:23 +01:00
|
|
|
invalid_structure("unknown parameter for backup/restore");
|
2005-11-27 21:53:09 +01:00
|
|
|
break;
|
|
|
|
case isc_action_svc_repair:
|
2008-12-05 02:20:14 +01:00
|
|
|
switch (tag)
|
2005-11-27 21:53:09 +01:00
|
|
|
{
|
|
|
|
case isc_spb_dbname:
|
|
|
|
return StringSpb;
|
|
|
|
case isc_spb_options:
|
|
|
|
case isc_spb_rpr_commit_trans:
|
|
|
|
case isc_spb_rpr_rollback_trans:
|
|
|
|
case isc_spb_rpr_recover_two_phase:
|
2006-04-16 18:13:58 +02:00
|
|
|
return IntSpb;
|
2005-11-27 21:53:09 +01:00
|
|
|
}
|
2005-11-30 18:11:23 +01:00
|
|
|
invalid_structure("unknown parameter for repair");
|
2005-11-27 21:53:09 +01:00
|
|
|
break;
|
2008-12-05 02:20:14 +01:00
|
|
|
case isc_action_svc_add_user:
|
2005-11-27 21:53:09 +01:00
|
|
|
case isc_action_svc_delete_user:
|
|
|
|
case isc_action_svc_modify_user:
|
|
|
|
case isc_action_svc_display_user:
|
2009-12-16 14:40:26 +01:00
|
|
|
case isc_action_svc_display_user_adm:
|
2009-02-13 14:05:50 +01:00
|
|
|
case isc_action_svc_set_mapping:
|
|
|
|
case isc_action_svc_drop_mapping:
|
2008-12-05 02:20:14 +01:00
|
|
|
switch (tag)
|
2005-11-27 21:53:09 +01:00
|
|
|
{
|
|
|
|
case isc_spb_dbname:
|
|
|
|
case isc_spb_sql_role_name:
|
|
|
|
case isc_spb_sec_username:
|
|
|
|
case isc_spb_sec_password:
|
|
|
|
case isc_spb_sec_groupname:
|
|
|
|
case isc_spb_sec_firstname:
|
|
|
|
case isc_spb_sec_middlename:
|
|
|
|
case isc_spb_sec_lastname:
|
|
|
|
return StringSpb;
|
|
|
|
case isc_spb_sec_userid:
|
|
|
|
case isc_spb_sec_groupid:
|
2009-11-13 20:00:09 +01:00
|
|
|
case isc_spb_sec_admin:
|
2005-11-27 21:53:09 +01:00
|
|
|
return IntSpb;
|
|
|
|
}
|
2005-11-30 18:11:23 +01:00
|
|
|
invalid_structure("unknown parameter for security database operation");
|
2005-11-27 21:53:09 +01:00
|
|
|
break;
|
|
|
|
case isc_action_svc_properties:
|
2008-12-05 02:20:14 +01:00
|
|
|
switch (tag)
|
2005-11-27 21:53:09 +01:00
|
|
|
{
|
|
|
|
case isc_spb_dbname:
|
|
|
|
return StringSpb;
|
|
|
|
case isc_spb_prp_page_buffers:
|
|
|
|
case isc_spb_prp_sweep_interval:
|
|
|
|
case isc_spb_prp_shutdown_db:
|
|
|
|
case isc_spb_prp_deny_new_attachments:
|
|
|
|
case isc_spb_prp_deny_new_transactions:
|
|
|
|
case isc_spb_prp_set_sql_dialect:
|
|
|
|
case isc_spb_options:
|
2008-09-16 16:19:09 +02:00
|
|
|
case isc_spb_prp_force_shutdown:
|
|
|
|
case isc_spb_prp_attachments_shutdown:
|
|
|
|
case isc_spb_prp_transactions_shutdown:
|
2005-11-27 21:53:09 +01:00
|
|
|
return IntSpb;
|
|
|
|
case isc_spb_prp_reserve_space:
|
|
|
|
case isc_spb_prp_write_mode:
|
|
|
|
case isc_spb_prp_access_mode:
|
2008-09-16 16:19:09 +02:00
|
|
|
case isc_spb_prp_shutdown_mode:
|
|
|
|
case isc_spb_prp_online_mode:
|
2005-12-10 11:15:10 +01:00
|
|
|
return ByteSpb;
|
2005-11-27 21:53:09 +01:00
|
|
|
}
|
2005-11-30 18:11:23 +01:00
|
|
|
invalid_structure("unknown parameter for setting database properties");
|
2005-11-27 21:53:09 +01:00
|
|
|
break;
|
|
|
|
// case isc_action_svc_add_license:
|
|
|
|
// case isc_action_svc_remove_license:
|
|
|
|
case isc_action_svc_db_stats:
|
2008-12-05 02:20:14 +01:00
|
|
|
switch (tag)
|
2005-11-27 21:53:09 +01:00
|
|
|
{
|
|
|
|
case isc_spb_dbname:
|
2006-04-16 18:13:58 +02:00
|
|
|
case isc_spb_command_line:
|
2005-11-27 21:53:09 +01:00
|
|
|
return StringSpb;
|
|
|
|
case isc_spb_options:
|
|
|
|
return IntSpb;
|
|
|
|
}
|
2005-11-30 18:11:23 +01:00
|
|
|
invalid_structure("unknown parameter for getting statistics");
|
2005-11-27 21:53:09 +01:00
|
|
|
break;
|
|
|
|
case isc_action_svc_get_ib_log:
|
2005-11-30 18:11:23 +01:00
|
|
|
invalid_structure("unknown parameter for getting log");
|
2005-11-27 21:53:09 +01:00
|
|
|
break;
|
2008-11-20 18:29:38 +01:00
|
|
|
case isc_action_svc_nbak:
|
|
|
|
case isc_action_svc_nrest:
|
2008-12-05 02:20:14 +01:00
|
|
|
switch (tag)
|
2008-11-20 18:29:38 +01:00
|
|
|
{
|
|
|
|
case isc_spb_nbk_file:
|
2009-12-18 15:06:28 +01:00
|
|
|
case isc_spb_nbk_direct:
|
2008-11-20 18:29:38 +01:00
|
|
|
case isc_spb_dbname:
|
|
|
|
return StringSpb;
|
|
|
|
case isc_spb_nbk_level:
|
|
|
|
case isc_spb_options:
|
|
|
|
return IntSpb;
|
|
|
|
}
|
|
|
|
invalid_structure("unknown parameter for nbackup");
|
|
|
|
break;
|
2009-02-01 23:10:12 +01:00
|
|
|
case isc_action_svc_trace_start:
|
|
|
|
case isc_action_svc_trace_stop:
|
|
|
|
case isc_action_svc_trace_suspend:
|
|
|
|
case isc_action_svc_trace_resume:
|
|
|
|
switch(tag)
|
|
|
|
{
|
|
|
|
case isc_spb_trc_cfg:
|
|
|
|
case isc_spb_trc_name:
|
|
|
|
return StringSpb;
|
|
|
|
case isc_spb_trc_id:
|
|
|
|
return IntSpb;
|
|
|
|
}
|
|
|
|
break;
|
2005-11-27 21:53:09 +01:00
|
|
|
}
|
2005-11-30 18:11:23 +01:00
|
|
|
invalid_structure("wrong spb state");
|
2005-11-27 21:53:09 +01:00
|
|
|
break;
|
2004-10-22 08:24:40 +02:00
|
|
|
}
|
2005-11-30 18:11:23 +01:00
|
|
|
invalid_structure("unknown reason");
|
2005-11-27 21:53:09 +01:00
|
|
|
return SingleTpb;
|
2004-10-22 08:24:40 +02:00
|
|
|
}
|
|
|
|
|
2005-11-27 21:53:09 +01:00
|
|
|
void ClumpletReader::adjustSpbState()
|
|
|
|
{
|
|
|
|
switch (kind)
|
|
|
|
{
|
2005-11-30 18:11:23 +01:00
|
|
|
case SpbStart:
|
|
|
|
if (spbState == 0) { // Just started with service start block
|
2005-11-27 21:53:09 +01:00
|
|
|
spbState = getClumpTag();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t ClumpletReader::getClumpletSize(bool wTag, bool wLength, bool wData) const
|
2004-12-12 07:50:10 +01:00
|
|
|
{
|
2004-11-15 17:34:47 +01:00
|
|
|
const UCHAR* clumplet = getBuffer() + cur_offset;
|
2008-04-18 12:03:04 +02:00
|
|
|
const UCHAR* const buffer_end = getBufferEnd();
|
2004-10-22 08:24:40 +02:00
|
|
|
|
|
|
|
// Check for EOF
|
2009-06-28 13:59:30 +02:00
|
|
|
if (clumplet >= buffer_end)
|
|
|
|
{
|
2004-11-03 09:38:09 +01:00
|
|
|
usage_mistake("read past EOF");
|
2005-11-27 21:53:09 +01:00
|
|
|
return 0;
|
2004-10-22 08:24:40 +02:00
|
|
|
}
|
|
|
|
|
2005-11-27 21:53:09 +01:00
|
|
|
size_t rc = wTag ? 1 : 0;
|
|
|
|
size_t lengthSize = 0;
|
|
|
|
size_t dataSize = 0;
|
2008-12-05 02:20:14 +01:00
|
|
|
|
2005-11-27 21:53:09 +01:00
|
|
|
switch (getClumpletType(clumplet[0]))
|
|
|
|
{
|
2006-09-26 17:09:46 +02:00
|
|
|
|
|
|
|
// This form allows clumplets of virtually any size
|
|
|
|
case Wide:
|
|
|
|
// Check did we receive length component for clumplet
|
2009-06-28 13:59:30 +02:00
|
|
|
if (buffer_end - clumplet < 5)
|
|
|
|
{
|
2006-09-26 17:09:46 +02:00
|
|
|
invalid_structure("buffer end before end of clumplet - no length component");
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
lengthSize = 4;
|
|
|
|
dataSize = clumplet[4];
|
|
|
|
dataSize <<= 8;
|
|
|
|
dataSize += clumplet[3];
|
|
|
|
dataSize <<= 8;
|
|
|
|
dataSize += clumplet[2];
|
|
|
|
dataSize <<= 8;
|
|
|
|
dataSize += clumplet[1];
|
|
|
|
break;
|
|
|
|
|
2005-11-27 21:53:09 +01:00
|
|
|
// This is the most widely used form
|
|
|
|
case TraditionalDpb:
|
|
|
|
// Check did we receive length component for clumplet
|
2009-06-28 13:59:30 +02:00
|
|
|
if (buffer_end - clumplet < 2)
|
|
|
|
{
|
2005-11-30 18:11:23 +01:00
|
|
|
invalid_structure("buffer end before end of clumplet - no length component");
|
2005-11-27 21:53:09 +01:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
lengthSize = 1;
|
|
|
|
dataSize = clumplet[1];
|
|
|
|
break;
|
2006-09-26 17:09:46 +02:00
|
|
|
|
2005-11-27 21:53:09 +01:00
|
|
|
// Almost all TPB parameters are single bytes
|
|
|
|
case SingleTpb:
|
|
|
|
break;
|
|
|
|
|
|
|
|
// Used in SPB for long strings
|
|
|
|
case StringSpb:
|
|
|
|
// Check did we receive length component for clumplet
|
2009-06-28 13:59:30 +02:00
|
|
|
if (buffer_end - clumplet < 3)
|
|
|
|
{
|
2005-11-30 18:11:23 +01:00
|
|
|
invalid_structure("buffer end before end of clumplet - no length component");
|
2005-11-27 21:53:09 +01:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
lengthSize = 2;
|
2005-11-30 18:11:23 +01:00
|
|
|
dataSize = clumplet[2];
|
2005-11-27 21:53:09 +01:00
|
|
|
dataSize <<= 8;
|
2005-11-30 18:11:23 +01:00
|
|
|
dataSize += clumplet[1];
|
2005-11-27 21:53:09 +01:00
|
|
|
break;
|
2006-09-26 17:09:46 +02:00
|
|
|
|
2005-11-27 21:53:09 +01:00
|
|
|
// Used in SPB for 4-byte integers
|
|
|
|
case IntSpb:
|
|
|
|
dataSize = 4;
|
|
|
|
break;
|
|
|
|
|
|
|
|
// Used in SPB for single byte
|
|
|
|
case ByteSpb:
|
|
|
|
dataSize = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2008-04-18 12:03:04 +02:00
|
|
|
const size_t total = 1 + lengthSize + dataSize;
|
2009-06-28 13:59:30 +02:00
|
|
|
if (clumplet + total > buffer_end)
|
|
|
|
{
|
2005-11-30 18:11:23 +01:00
|
|
|
invalid_structure("buffer end before end of clumplet - clumplet too long");
|
2005-11-27 21:53:09 +01:00
|
|
|
size_t delta = total - (buffer_end - clumplet);
|
|
|
|
if (delta > dataSize)
|
|
|
|
dataSize = 0;
|
|
|
|
else
|
|
|
|
dataSize -= delta;
|
|
|
|
}
|
2006-09-26 17:09:46 +02:00
|
|
|
|
2005-11-27 21:53:09 +01:00
|
|
|
if (wLength) {
|
|
|
|
rc += lengthSize;
|
|
|
|
}
|
|
|
|
if (wData) {
|
|
|
|
rc += dataSize;
|
2004-10-22 08:24:40 +02:00
|
|
|
}
|
2005-11-27 21:53:09 +01:00
|
|
|
return rc;
|
|
|
|
}
|
2004-10-22 08:24:40 +02:00
|
|
|
|
2005-11-27 21:53:09 +01:00
|
|
|
void ClumpletReader::moveNext()
|
|
|
|
{
|
|
|
|
if (isEof())
|
|
|
|
return; // no need to raise useless exceptions
|
2005-11-30 18:11:23 +01:00
|
|
|
size_t cs = getClumpletSize(true, true, true);
|
2005-11-27 21:53:09 +01:00
|
|
|
adjustSpbState();
|
2005-11-30 18:11:23 +01:00
|
|
|
cur_offset += cs;
|
2004-10-22 08:24:40 +02:00
|
|
|
}
|
|
|
|
|
2004-12-09 20:19:47 +01:00
|
|
|
void ClumpletReader::rewind()
|
|
|
|
{
|
2009-06-28 13:59:30 +02:00
|
|
|
if (! getBuffer())
|
|
|
|
{
|
2005-11-27 21:53:09 +01:00
|
|
|
cur_offset = 0;
|
|
|
|
spbState = 0;
|
|
|
|
return;
|
|
|
|
}
|
2009-02-03 12:02:00 +01:00
|
|
|
switch (kind)
|
|
|
|
{
|
|
|
|
case UnTagged:
|
|
|
|
case WideUnTagged:
|
|
|
|
case SpbStart:
|
|
|
|
case SpbItems:
|
2005-11-27 21:53:09 +01:00
|
|
|
cur_offset = 0;
|
2009-02-03 12:02:00 +01:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if (kind == SpbAttach && getBufferLength() > 0 && getBuffer()[0] != isc_spb_version1)
|
|
|
|
cur_offset = 2;
|
|
|
|
else
|
|
|
|
cur_offset = 1;
|
|
|
|
}
|
2005-11-27 21:53:09 +01:00
|
|
|
spbState = 0;
|
2004-12-09 20:19:47 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool ClumpletReader::find(UCHAR tag)
|
|
|
|
{
|
2004-12-10 23:54:16 +01:00
|
|
|
const size_t co = getCurOffset();
|
2004-12-09 20:19:47 +01:00
|
|
|
for (rewind(); !isEof(); moveNext())
|
|
|
|
{
|
|
|
|
if (tag == getClumpTag())
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
setCurOffset(co);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2004-10-22 08:24:40 +02:00
|
|
|
// Methods which work with currently selected clumplet
|
2004-12-12 07:50:10 +01:00
|
|
|
UCHAR ClumpletReader::getClumpTag() const
|
|
|
|
{
|
2004-11-15 17:34:47 +01:00
|
|
|
const UCHAR* clumplet = getBuffer() + cur_offset;
|
2008-04-18 12:03:04 +02:00
|
|
|
const UCHAR* const buffer_end = getBufferEnd();
|
2004-10-22 08:24:40 +02:00
|
|
|
|
|
|
|
// Check for EOF
|
2009-06-28 13:59:30 +02:00
|
|
|
if (clumplet >= buffer_end)
|
|
|
|
{
|
2004-11-03 09:38:09 +01:00
|
|
|
usage_mistake("read past EOF");
|
2004-10-23 03:21:11 +02:00
|
|
|
return 0;
|
2004-10-22 08:24:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return clumplet[0];
|
|
|
|
}
|
|
|
|
|
2004-12-12 07:50:10 +01:00
|
|
|
size_t ClumpletReader::getClumpLength() const
|
|
|
|
{
|
2005-11-27 21:53:09 +01:00
|
|
|
return getClumpletSize(false, false, true);
|
|
|
|
}
|
2004-10-23 03:21:11 +02:00
|
|
|
|
2005-11-27 21:53:09 +01:00
|
|
|
const UCHAR* ClumpletReader::getBytes() const
|
|
|
|
{
|
|
|
|
return getBuffer() + cur_offset + getClumpletSize(true, true, false);
|
2004-10-22 08:24:40 +02:00
|
|
|
}
|
|
|
|
|
2008-06-24 15:07:12 +02:00
|
|
|
SINT64 ClumpletReader::fromVaxInteger(const UCHAR* ptr, size_t length)
|
|
|
|
{
|
2009-08-05 08:27:57 +02:00
|
|
|
// We can't handle numbers bigger than int64. Some cases use length == 0.
|
2009-08-06 03:06:05 +02:00
|
|
|
fb_assert(ptr && length >= 0 && length < 9);
|
2008-06-24 15:07:12 +02:00
|
|
|
// This code is taken from gds__vax_integer
|
|
|
|
SINT64 value = 0;
|
|
|
|
int shift = 0;
|
2009-06-28 13:59:30 +02:00
|
|
|
while (length > 0)
|
|
|
|
{
|
2008-06-24 15:07:12 +02:00
|
|
|
--length;
|
2009-02-01 22:55:26 +01:00
|
|
|
value += ((SINT64) *ptr++) << shift;
|
2008-06-24 15:07:12 +02:00
|
|
|
shift += 8;
|
|
|
|
}
|
|
|
|
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
2004-12-12 07:50:10 +01:00
|
|
|
SLONG ClumpletReader::getInt() const
|
|
|
|
{
|
2008-06-26 13:03:53 +02:00
|
|
|
const size_t length = getClumpLength();
|
2004-10-22 08:24:40 +02:00
|
|
|
|
2009-06-28 13:59:30 +02:00
|
|
|
if (length > 4)
|
|
|
|
{
|
2005-11-30 18:11:23 +01:00
|
|
|
invalid_structure("length of integer exceeds 4 bytes");
|
2005-11-27 21:53:09 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2004-10-22 08:24:40 +02:00
|
|
|
|
2008-06-24 15:07:12 +02:00
|
|
|
return fromVaxInteger(getBytes(), length);
|
|
|
|
}
|
|
|
|
|
|
|
|
double ClumpletReader::getDouble() const
|
|
|
|
{
|
|
|
|
|
2009-06-28 13:59:30 +02:00
|
|
|
if (getClumpLength() != sizeof(double))
|
|
|
|
{
|
2008-06-24 15:07:12 +02:00
|
|
|
invalid_structure("length of double must be equal 8 bytes");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// based on XDR code
|
|
|
|
union {
|
|
|
|
double temp_double;
|
|
|
|
SLONG temp_long[2];
|
|
|
|
} temp;
|
|
|
|
|
|
|
|
fb_assert(sizeof(double) == sizeof(temp));
|
|
|
|
|
|
|
|
const UCHAR* ptr = getBytes();
|
|
|
|
temp.temp_long[FB_LONG_DOUBLE_FIRST] = fromVaxInteger(ptr, sizeof(SLONG));
|
|
|
|
temp.temp_long[FB_LONG_DOUBLE_SECOND] = fromVaxInteger(ptr + sizeof(SLONG), sizeof(SLONG));
|
|
|
|
|
|
|
|
return temp.temp_double;
|
|
|
|
}
|
|
|
|
|
|
|
|
ISC_TIMESTAMP ClumpletReader::getTimeStamp() const
|
|
|
|
{
|
|
|
|
ISC_TIMESTAMP value;
|
|
|
|
|
2009-06-28 13:59:30 +02:00
|
|
|
if (getClumpLength() != sizeof(ISC_TIMESTAMP))
|
|
|
|
{
|
2008-06-24 15:07:12 +02:00
|
|
|
invalid_structure("length of ISC_TIMESTAMP must be equal 8 bytes");
|
|
|
|
value.timestamp_date = 0;
|
|
|
|
value.timestamp_time = 0;
|
|
|
|
return value;
|
2004-10-22 08:24:40 +02:00
|
|
|
}
|
|
|
|
|
2008-06-24 15:07:12 +02:00
|
|
|
const UCHAR* ptr = getBytes();
|
|
|
|
value.timestamp_date = fromVaxInteger(ptr, sizeof(SLONG));
|
|
|
|
value.timestamp_time = fromVaxInteger(ptr + sizeof(SLONG), sizeof(SLONG));
|
2004-10-22 08:24:40 +02:00
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
2004-12-12 07:50:10 +01:00
|
|
|
SINT64 ClumpletReader::getBigInt() const
|
|
|
|
{
|
2008-06-26 13:03:53 +02:00
|
|
|
const size_t length = getClumpLength();
|
2004-10-22 08:24:40 +02:00
|
|
|
|
2009-06-28 13:59:30 +02:00
|
|
|
if (length > 8)
|
|
|
|
{
|
2005-11-30 18:11:23 +01:00
|
|
|
invalid_structure("length of BigInt exceeds 8 bytes");
|
2005-11-27 21:53:09 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2004-10-22 08:24:40 +02:00
|
|
|
|
2008-06-24 15:07:12 +02:00
|
|
|
return fromVaxInteger(getBytes(), length);
|
2004-10-22 08:24:40 +02:00
|
|
|
}
|
|
|
|
|
2004-12-12 07:50:10 +01:00
|
|
|
string& ClumpletReader::getString(string& str) const
|
|
|
|
{
|
2005-11-27 21:53:09 +01:00
|
|
|
const UCHAR* ptr = getBytes();
|
2008-04-18 12:03:04 +02:00
|
|
|
const size_t length = getClumpLength();
|
2005-11-27 21:53:09 +01:00
|
|
|
str.assign(reinterpret_cast<const char*>(ptr), length);
|
2006-06-27 13:07:06 +02:00
|
|
|
str.recalculate_length();
|
|
|
|
if (str.length() + 1 < length)
|
|
|
|
{
|
|
|
|
invalid_structure("string length doesn't match with clumplet");
|
|
|
|
}
|
2004-11-15 17:34:47 +01:00
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
2004-12-12 07:50:10 +01:00
|
|
|
PathName& ClumpletReader::getPath(PathName& str) const
|
2004-11-24 19:26:24 +01:00
|
|
|
{
|
2005-11-27 21:53:09 +01:00
|
|
|
const UCHAR* ptr = getBytes();
|
2008-04-18 12:03:04 +02:00
|
|
|
const size_t length = getClumpLength();
|
2005-11-27 21:53:09 +01:00
|
|
|
str.assign(reinterpret_cast<const char*>(ptr), length);
|
2006-06-27 13:07:06 +02:00
|
|
|
str.recalculate_length();
|
|
|
|
if (str.length() + 1 < length)
|
|
|
|
{
|
2006-06-29 06:19:11 +02:00
|
|
|
invalid_structure("path length doesn't match with clumplet");
|
2006-06-27 13:07:06 +02:00
|
|
|
}
|
2004-10-22 08:24:40 +02:00
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
2004-12-12 07:50:10 +01:00
|
|
|
bool ClumpletReader::getBoolean() const
|
2004-11-24 19:26:24 +01:00
|
|
|
{
|
2005-11-27 21:53:09 +01:00
|
|
|
const UCHAR* ptr = getBytes();
|
2008-04-18 12:03:04 +02:00
|
|
|
const size_t length = getClumpLength();
|
2009-06-28 13:59:30 +02:00
|
|
|
if (length > 1)
|
|
|
|
{
|
2005-11-30 18:11:23 +01:00
|
|
|
invalid_structure("length of boolean exceeds 1 byte");
|
2005-11-27 21:53:09 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return length && ptr[0];
|
2004-11-24 19:26:24 +01:00
|
|
|
}
|
2004-10-22 08:24:40 +02:00
|
|
|
|
2009-12-30 16:24:16 +01:00
|
|
|
ClumpletReader::SingleClumplet ClumpletReader::getClumplet() const
|
|
|
|
{
|
|
|
|
SingleClumplet rc;
|
|
|
|
rc.tag = getClumpTag();
|
|
|
|
rc.size = getClumpletSize(false, false, true);
|
|
|
|
rc.data = getBytes();
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
const ClumpletReader::KindList ClumpletReader::dpbList[] = {
|
|
|
|
{ClumpletReader::Tagged, isc_dpb_version1},
|
|
|
|
{ClumpletReader::WideTagged, isc_dpb_version2},
|
|
|
|
{ClumpletReader::EndOfList, 0}
|
|
|
|
};
|
|
|
|
|
2010-01-22 15:55:11 +01:00
|
|
|
const ClumpletReader::KindList ClumpletReader::spbList[] = {
|
|
|
|
{ClumpletReader::SpbAttach, isc_spb_current_version},
|
|
|
|
{ClumpletReader::SpbAttach, isc_spb_version1},
|
|
|
|
{ClumpletReader::WideTagged, isc_spb_version3},
|
|
|
|
{ClumpletReader::EndOfList, 0}
|
|
|
|
};
|
|
|
|
|
2010-01-24 16:18:43 +01:00
|
|
|
AuthReader::AuthReader(const AuthBlock& authBlock)
|
2010-01-22 15:55:11 +01:00
|
|
|
: ClumpletReader(ClumpletReader::WideUnTagged, authBlock.begin(), authBlock.getCount())
|
|
|
|
{
|
|
|
|
rewind();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AuthReader::getInfo(string* name, string* method, string* details)
|
|
|
|
{
|
|
|
|
if (isEof())
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (name)
|
|
|
|
{
|
|
|
|
*name = "";
|
|
|
|
}
|
|
|
|
if (method)
|
|
|
|
{
|
|
|
|
*method = "";
|
|
|
|
}
|
|
|
|
if (details)
|
|
|
|
{
|
|
|
|
*details = "";
|
|
|
|
}
|
|
|
|
|
|
|
|
ClumpletReader internal(WideUnTagged, getBytes(), getClumpLength());
|
|
|
|
for (internal.rewind(); !internal.isEof(); internal.moveNext())
|
|
|
|
{
|
|
|
|
switch(internal.getClumpTag())
|
|
|
|
{
|
|
|
|
case AUTH_NAME:
|
|
|
|
if (name)
|
|
|
|
{
|
|
|
|
internal.getString(*name);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case AUTH_METHOD:
|
|
|
|
if (method)
|
|
|
|
{
|
|
|
|
internal.getString(*method);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case AUTH_DETAILS:
|
|
|
|
if (details)
|
|
|
|
{
|
|
|
|
internal.getString(*details);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2004-12-12 07:50:10 +01:00
|
|
|
} // namespace
|