8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-23 14:03:07 +01:00

Introduce isc_dpb_version2 - format is WideTagged.

This commit is contained in:
alexpeshkoff 2009-12-30 15:24:16 +00:00
parent db5dc212ff
commit 443f261abf
11 changed files with 246 additions and 89 deletions

View File

@ -121,6 +121,32 @@ ClumpletReader::ClumpletReader(MemoryPool& pool, Kind k, const UCHAR* buffer, si
rewind(); // this will set cur_offset and spbState
}
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)
{
if (buffLen)
{
while (kl->kind != EndOfList)
{
kind = kl->kind;
if (getBufferTag() == kl->tag)
{
break;
}
++kl;
}
if (kl->kind == EndOfList)
{
if (raise)
{
raise();
}
invalid_structure("Unknown tag value - missing in the list of possible");
}
}
rewind(); // this will set cur_offset and spbState
}
const UCHAR* ClumpletReader::getBuffer() const
{
return static_buffer;
@ -672,5 +698,20 @@ bool ClumpletReader::getBoolean() const
return length && ptr[0];
}
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}
};
} // namespace

View File

@ -45,11 +45,24 @@ namespace Firebird {
class ClumpletReader : protected AutoStorage
{
public:
enum Kind {Tagged, UnTagged, SpbAttach, SpbStart, Tpb/*, SpbInfo*/, WideTagged, WideUnTagged, SpbItems};
enum Kind {EndOfList, Tagged, UnTagged, SpbAttach, SpbStart, Tpb/*, SpbInfo*/, WideTagged, WideUnTagged, SpbItems};
struct KindList
{
Kind kind;
UCHAR tag;
};
struct SingleClumplet
{
UCHAR tag;
size_t size;
const UCHAR* data;
};
// Constructor prepares an object from plain PB
ClumpletReader(Kind k, const UCHAR* buffer, size_t buffLen);
ClumpletReader(MemoryPool& pool, Kind k, const UCHAR* buffer, size_t buffLen);
// Different versions of clumplets may have different kinds
ClumpletReader(const KindList* kl, const UCHAR* buffer, size_t buffLen, FPTR_VOID raise = NULL);
virtual ~ClumpletReader() { }
// Navigation in clumplet buffer
@ -108,7 +121,7 @@ protected:
void adjustSpbState();
size_t cur_offset;
const Kind kind;
Kind kind;
UCHAR spbState; // Reflects state of spb parser/writer
// Methods are virtual so writer can override 'em
@ -125,6 +138,9 @@ protected:
// This is called when passed buffer appears invalid
virtual void invalid_structure(const char* what) const;
// get the most generic representation of clumplet
SingleClumplet getClumplet() const;
private:
// Assignment and copy constructor not implemented.
ClumpletReader(const ClumpletReader& from);
@ -134,6 +150,10 @@ private:
const UCHAR* static_buffer_end;
static SINT64 fromVaxInteger(const UCHAR* ptr, size_t length);
// Some frequently used kind lists
public:
static const KindList dpbList[];
};
} // namespace Firebird

View File

@ -93,6 +93,19 @@ ClumpletWriter::ClumpletWriter(Kind k, size_t limit, const UCHAR* buffer, size_t
rewind();
}
ClumpletWriter::ClumpletWriter(const KindList* kl, size_t limit, const UCHAR* buffer, size_t buffLen) :
ClumpletReader(kl, buffer, buffLen), sizeLimit(limit), kindList(kl), dynamic_buffer(getPool())
{
if (buffer && buffLen) {
dynamic_buffer.push(buffer, buffLen);
}
else {
initNewBuffer(kl->tag);
}
rewind();
}
/*
ClumpletWriter::ClumpletWriter(MemoryPool& given_pool, Kind k, size_t limit,
const UCHAR* buffer, size_t buffLen, UCHAR tag) :
ClumpletReader(given_pool, k, NULL, 0), sizeLimit(limit), dynamic_buffer(getPool())
@ -105,9 +118,27 @@ ClumpletWriter::ClumpletWriter(MemoryPool& given_pool, Kind k, size_t limit,
}
rewind();
}
*/
void ClumpletWriter::reset(UCHAR tag)
{
if (kindList)
{
for (const KindList* kl = kindList; kl->kind != EndOfList; ++kl)
{
if (tag == kl->tag)
{
kind = kl->kind;
dynamic_buffer.shrink(0);
initNewBuffer(tag);
rewind();
return;
}
}
invalid_structure("Unknown tag value - missing in the list of possible");
}
dynamic_buffer.shrink(0);
initNewBuffer(tag);
rewind();
@ -218,66 +249,75 @@ void ClumpletWriter::insertBytesLengthCheck(UCHAR tag, const UCHAR* bytes, const
return;
}
// Check length according to clumplet type
const ClumpletType t = getClumpletType(tag);
UCHAR lenSize = 0;
switch (t)
// Check length according to clumplet type
// Perform structure upgrade when needed and possible
for(;;)
{
case Wide:
if (length > MAX_ULONG)
const ClumpletType t = getClumpletType(tag);
string m;
switch (t)
{
string m;
m.printf("attempt to store %d bytes in a clumplet", length);
case Wide:
if (length > MAX_ULONG)
{
m.printf("attempt to store %d bytes in a clumplet", length);
break;
}
lenSize = 4;
break;
case TraditionalDpb:
if (length > MAX_UCHAR)
{
m.printf("attempt to store %d bytes in a clumplet with maximum size 255 bytes", length);
break;
}
lenSize = 1;
break;
case SingleTpb:
if (length > 0)
{
m.printf("attempt to store data in dataless clumplet");
break;
}
break;
case StringSpb:
if (length > MAX_USHORT)
{
m.printf("attempt to store %d bytes in a clumplet", length);
break;
}
lenSize = 2;
break;
case IntSpb:
if (length != 4)
{
m.printf("attempt to store %d bytes in a clumplet, need 4", length);
break;
}
break;
case ByteSpb:
if (length != 1)
{
m.printf("attempt to store %d bytes in a clumplet, need 1", length);
break;
}
break;
}
if (m.isEmpty())
{
// OK, no errors
break;
}
if (!upgradeVersion())
{
// can't uprgade - report failure
usage_mistake(m.c_str());
return;
}
lenSize = 4;
break;
case TraditionalDpb:
if (length > MAX_UCHAR)
{
string m;
m.printf("attempt to store %d bytes in a clumplet with maximum size 255 bytes", length);
usage_mistake(m.c_str());
return;
}
lenSize = 1;
break;
case SingleTpb:
if (length > 0)
{
usage_mistake("attempt to store data in dataless clumplet");
return;
}
break;
case StringSpb:
if (length > MAX_USHORT)
{
string m;
m.printf("attempt to store %d bytes in a clumplet", length);
usage_mistake(m.c_str());
return;
}
lenSize = 2;
break;
case IntSpb:
if (length != 4)
{
string m;
m.printf("attempt to store %d bytes in a clumplet, need 4", length);
usage_mistake(m.c_str());
return;
}
break;
case ByteSpb:
if (length != 1)
{
string m;
m.printf("attempt to store %d bytes in a clumplet, need 1", length);
usage_mistake(m.c_str());
return;
}
break;
}
// Check that resulting data doesn't overflow size limit
@ -378,4 +418,63 @@ bool ClumpletWriter::deleteWithTag(UCHAR tag)
return rc;
}
bool ClumpletWriter::upgradeVersion()
{
// Sanity check
if (!kindList)
{
return false;
}
// Check for required version - use highmost one
const KindList* newest = kindList;
for (const KindList* itr = kindList; itr->tag != EndOfList; ++itr)
{
if (itr->tag > newest->tag)
{
newest = itr;
}
}
if (getBufferLength() && newest->tag <= getBufferTag())
{
return false;
}
// Copy data to new clumplet writer
size_t newPos = 0;
ClumpletWriter newPb(newest->kind, sizeLimit, newest->tag);
size_t currentPosition = cur_offset;
for(rewind(); !isEof(); moveNext())
{
if (currentPosition == cur_offset)
{
newPos = newPb.cur_offset;
}
newPb.insertClumplet(getClumplet());
newPb.moveNext();
}
// Return it to current clumplet writer in new format
dynamic_buffer.clear();
kind = newest->kind;
dynamic_buffer.push(newPb.dynamic_buffer.begin(), newPb.dynamic_buffer.getCount());
// Set pointer to correct position
if (newPos)
{
cur_offset = newPos;
}
else
{
rewind();
}
return true;
}
void ClumpletWriter::insertClumplet(const SingleClumplet& clumplet)
{
insertBytes(clumplet.tag, clumplet.data, clumplet.size);
}
} // namespace

View File

@ -49,7 +49,10 @@ public:
// Create writer from a given buffer
ClumpletWriter(Kind k, size_t limit, const UCHAR* buffer, size_t buffLen, UCHAR tag);
ClumpletWriter(MemoryPool& pool, Kind k, size_t limit, const UCHAR* buffer, size_t buffLen, UCHAR tag);
// ClumpletWriter(MemoryPool& pool, Kind k, size_t limit, const UCHAR* buffer, size_t buffLen, UCHAR tag);
// Create writer from a given buffer with possibly different clumplet version
ClumpletWriter(const KindList* kl, size_t limit, const UCHAR* buffer = NULL, size_t buffLen = 0);
void reset(UCHAR tag);
void reset(const UCHAR* buffer, const size_t buffLen);
@ -68,6 +71,7 @@ public:
void insertTime(UCHAR tag, ISC_TIME value) { insertInt(tag, value); }
void insertDate(UCHAR tag, ISC_DATE value) { insertInt(tag, value); }
void insertEndMarker(UCHAR tag);
void insertClumplet(const SingleClumplet& clumplet);
// Delete currently selected clumplet from buffer
void deleteClumplet();
@ -81,8 +85,11 @@ protected:
virtual const UCHAR* getBufferEnd() const;
virtual void size_overflow();
void insertBytesLengthCheck(UCHAR tag, const UCHAR* bytes, const size_t length);
// upgrade clumplet version - obtain newest from kindList
bool upgradeVersion();
private:
size_t sizeLimit;
const KindList* kindList;
// Assignment and copy constructor not implemented.
ClumpletWriter(const ClumpletWriter& from);

View File

@ -31,6 +31,8 @@
/**********************************/
#define isc_dpb_version1 1
#define isc_dpb_version2 2
#define isc_dpb_cdd_pathname 1
#define isc_dpb_allocation 2
#define isc_dpb_journal 3

View File

@ -43,7 +43,7 @@ UserManagement::UserManagement(jrd_tra* tra)
ISC_STATUS_ARRAY status;
Attachment* att = tra->tra_attachment;
ClumpletWriter dpb(ClumpletReader::Tagged, MAX_DPB_SIZE, isc_dpb_version1);
ClumpletWriter dpb(ClumpletReader::dpbList, MAX_DPB_SIZE);
dpb.insertByte(isc_dpb_gsec_attach, TRUE);
dpb.insertString(isc_dpb_trusted_auth, att->att_user->usr_user_name);
if (att->att_user->usr_flags & USR_trole)

View File

@ -356,7 +356,7 @@ bool Connection::isSameDatabase(thread_db* tdbb, const string& dbName,
if (m_dbName != dbName)
return false;
ClumpletWriter dpb(ClumpletReader::Tagged, MAX_DPB_SIZE, isc_dpb_version1);
ClumpletWriter dpb(ClumpletReader::dpbList, MAX_DPB_SIZE);
generateDPB(tdbb, dpb, user, pwd, role);
return m_dpb.simpleCompare(dpb);

View File

@ -4752,6 +4752,13 @@ static void find_intl_charset(thread_db* tdbb, Jrd::Attachment* attachment, cons
}
}
namespace {
void dpbErrorRaise()
{
ERR_post(Arg::Gds(isc_bad_dpb_form) <<
Arg::Gds(isc_wrodpbver));
}
} // anonymous
void DatabaseOptions::get(const UCHAR* dpb, USHORT dpb_length, bool& invalid_client_SQL_dialect)
{
@ -4788,13 +4795,7 @@ void DatabaseOptions::get(const UCHAR* dpb, USHORT dpb_length, bool& invalid_cli
ERR_post(Arg::Gds(isc_bad_dpb_form));
}
ClumpletReader rdr(ClumpletReader::Tagged, dpb, dpb_length);
if (rdr.getBufferTag() != isc_dpb_version1)
{
ERR_post(Arg::Gds(isc_bad_dpb_form) <<
Arg::Gds(isc_wrodpbver));
}
ClumpletReader rdr(ClumpletReader::dpbList, dpb, dpb_length, dpbErrorRaise);
dpb_utf8_filename = rdr.find(isc_dpb_utf8_filename);

View File

@ -1383,8 +1383,8 @@ ISC_STATUS API_ROUTINE GDS_ATTACH_DATABASE(ISC_STATUS* user_status,
// copy the file name to a temp buffer, since some of the following utilities can modify it
PathName org_filename(file_name, file_length ? file_length : strlen(file_name));
ClumpletWriter newDpb(ClumpletReader::Tagged, MAX_DPB_SIZE,
reinterpret_cast<const UCHAR*>(dpb), dpb_length, isc_dpb_version1);
ClumpletWriter newDpb(ClumpletReader::dpbList, MAX_DPB_SIZE,
reinterpret_cast<const UCHAR*>(dpb), dpb_length);
bool utfFilename = newDpb.find(isc_dpb_utf8_filename);
@ -1989,8 +1989,7 @@ ISC_STATUS API_ROUTINE GDS_CREATE_DATABASE(ISC_STATUS* user_status,
// copy the file name to a temp buffer, since some of the following utilities can modify it
PathName org_filename(file_name, file_length ? file_length : strlen(file_name));
ClumpletWriter newDpb(ClumpletReader::Tagged, MAX_DPB_SIZE,
dpb, dpb_length, isc_dpb_version1);
ClumpletWriter newDpb(ClumpletReader::dpbList, MAX_DPB_SIZE, dpb, dpb_length);
bool utfFilename = newDpb.find(isc_dpb_utf8_filename);

View File

@ -285,8 +285,8 @@ ISC_STATUS GDS_ATTACH_DATABASE(ISC_STATUS* user_status,
Rdb* rdb = 0;
try {
ClumpletWriter newDpb(ClumpletReader::Tagged, MAX_DPB_SIZE,
reinterpret_cast<const UCHAR*>(dpb), dpb_length, isc_dpb_version1);
ClumpletWriter newDpb(ClumpletReader::dpbList, MAX_DPB_SIZE,
reinterpret_cast<const UCHAR*>(dpb), dpb_length);
#ifdef UNIX
// If single user, return
@ -813,8 +813,8 @@ ISC_STATUS GDS_CREATE_DATABASE(ISC_STATUS* user_status,
try
{
ClumpletWriter newDpb(ClumpletReader::Tagged, MAX_DPB_SIZE,
reinterpret_cast<const UCHAR*>(dpb), dpb_length, isc_dpb_version1);
ClumpletWriter newDpb(ClumpletReader::dpbList, MAX_DPB_SIZE,
reinterpret_cast<const UCHAR*>(dpb), dpb_length);
#ifdef UNIX
// If single user, return
@ -5458,9 +5458,6 @@ static bool get_single_user(ClumpletReader& dpb)
* otherwise.
*
******************************************/
if (dpb.getBufferTag() != isc_dpb_version1)
return false;
string su;
if (dpb.find(isc_dpb_reserved)) {
dpb.getString(su);

View File

@ -1057,12 +1057,7 @@ static void attach_database(rem_port* port, P_OP operation, P_ATCH* attach, PACK
const UCHAR* dpb = attach->p_atch_dpb.cstr_address;
const USHORT dl = attach->p_atch_dpb.cstr_length;
Firebird::ClumpletWriter dpb_buffer(Firebird::ClumpletReader::Tagged, MAX_SSHORT);
if (dl)
dpb_buffer.reset(dpb, dl);
else
dpb_buffer.reset(isc_dpb_version1);
Firebird::ClumpletWriter dpb_buffer(Firebird::ClumpletReader::dpbList, MAX_SSHORT, dpb, dl);
// remove trusted role if present (security measure)
dpb_buffer.deleteWithTag(isc_dpb_trusted_role);
@ -1131,11 +1126,7 @@ static void attach_database2(rem_port* port,
send->p_operation = op_accept;
FB_API_HANDLE handle = 0;
Firebird::ClumpletWriter dpb_buffer(Firebird::ClumpletReader::Tagged, MAX_SSHORT);
if (dl)
dpb_buffer.reset(dpb, dl);
else
dpb_buffer.reset(isc_dpb_version1);
Firebird::ClumpletWriter dpb_buffer(Firebird::ClumpletReader::dpbList, MAX_SSHORT, dpb, dl);
#ifdef TRUSTED_AUTH
// If we have trusted authentication, append it to database parameter block