There were a variety of potential 64b problems due to the complete lack of prototype declarations. So, we add a file, isam_prototypes.h, generated mostly by the 'cproto' tool. We also fixed up some errors that having proper prototypes pointed out, mainly in passing ints where pointers were expected and vice versa. The iserase() function was supposed to accept a char *, but was defined as only accepting a char. Fun stuff like that.
567 lines
14 KiB
C
567 lines
14 KiB
C
/*
|
|
* CDE - Common Desktop Environment
|
|
*
|
|
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
|
|
*
|
|
* These libraries and programs are free software; you can
|
|
* redistribute them and/or modify them under the terms of the GNU
|
|
* Lesser General Public License as published by the Free Software
|
|
* Foundation; either version 2 of the License, or (at your option)
|
|
* any later version.
|
|
*
|
|
* These libraries and programs are distributed in the hope that
|
|
* they will be useful, but WITHOUT ANY WARRANTY; without even the
|
|
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
* PURPOSE. See the GNU Lesser General Public License for more
|
|
* details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with these libraries and programs; if not, write
|
|
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
|
|
* Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
/*%% (c) Copyright 1993, 1994 Hewlett-Packard Company */
|
|
/*%% (c) Copyright 1993, 1994 International Business Machines Corp. */
|
|
/*%% (c) Copyright 1993, 1994 Sun Microsystems, Inc. */
|
|
/*%% (c) Copyright 1993, 1994 Novell, Inc. */
|
|
/*%% $XConsortium: isvarrec.c /main/3 1995/10/23 11:45:36 rswiston $ */
|
|
/*
|
|
* Copyright (c) 1988 by Sun Microsystems, Inc.
|
|
*/
|
|
|
|
/*
|
|
* isvarrec.c
|
|
*
|
|
* Description:
|
|
* Fixed length record access (VLRA) module.
|
|
*/
|
|
|
|
#include "isam_impl.h"
|
|
|
|
/* Local functions */
|
|
long _vl_getpos(); /* Get offset in .rec file */
|
|
int _vl_deleted(); /* 0/1 returns 1 if record is deleted */
|
|
static void remove_from_chain2(); /* used by _vlrec_wrrec() */
|
|
long _istail_insert();
|
|
static void _istail_delete();
|
|
static int _istail_read();
|
|
|
|
/*
|
|
* _vlrec_write(fcb, record, recnum, reclen)
|
|
*
|
|
* Write a record.
|
|
*
|
|
* Input params:
|
|
* FCB File Control Block
|
|
* record record buffer
|
|
* reclen record length (NOT USED)
|
|
*
|
|
* Output params:
|
|
* recnum record number of the new record
|
|
*
|
|
* Returns 0 if record was written successfully, or -1 if any error.
|
|
*/
|
|
|
|
/*ARGSUSED*/
|
|
int
|
|
_vlrec_write(Fcb *fcb, char *record, Recno *recnum, int reclen)
|
|
{
|
|
Recno recnum2;
|
|
long rec_position;
|
|
long tailoff = VL_RECNOTAIL;
|
|
char recnobuf [RECNOSIZE];
|
|
char tailoffbuf[LONGSIZE];
|
|
|
|
/*
|
|
* Reuse a deleted record if one exits.
|
|
* Otherwise, extend .rec file by a record.
|
|
*/
|
|
if (fcb->freerecno != NULL_RECNO) {
|
|
recnum2 = fcb->freerecno;
|
|
|
|
/*
|
|
* Remove record from the chain of deleted records.
|
|
*/
|
|
rec_position = _vl_getpos(fcb, recnum2); /* Offset in .rec file */
|
|
_cp_fromfile(fcb, fcb->datfd, recnobuf, rec_position + LONGSIZE, RECNOSIZE);
|
|
fcb->freerecno = ldrecno(recnobuf);
|
|
}
|
|
else {
|
|
recnum2 = ++(fcb->lastrecno);
|
|
|
|
/*
|
|
* Extend .rec file size if necessary.
|
|
*/
|
|
while (_vl_getpos(fcb, recnum2 + 1) > fcb->datsize * ISPAGESIZE) {
|
|
fcb->datsize = _extend_file(fcb, fcb->datfd, fcb->datsize);
|
|
}
|
|
rec_position = _vl_getpos(fcb, recnum2); /* Offset in .rec file */
|
|
}
|
|
|
|
/*
|
|
* Store variable part of record (the 'tail') in .var file.
|
|
*/
|
|
tailoff = _istail_insert(fcb, record + fcb->minreclen,
|
|
reclen - fcb->minreclen);
|
|
|
|
/*
|
|
* Copy record to the .rec file. Mark record as undeleted.
|
|
*/
|
|
stlong(tailoff, tailoffbuf);
|
|
_cp_tofile(fcb, fcb->datfd, tailoffbuf, rec_position, LONGSIZE);
|
|
_cp_tofile(fcb, fcb->datfd, record, rec_position + LONGSIZE, fcb->minreclen);
|
|
|
|
*recnum = recnum2;
|
|
|
|
return (ISOK);
|
|
}
|
|
|
|
/*
|
|
* _vlrec_read(fcb, record, recnum, reclen)
|
|
*
|
|
* Read a record.
|
|
*
|
|
* Input params:
|
|
* FCB File Control Block
|
|
* recnum record number of the record
|
|
* reclen filled with the record size for compatibilty with
|
|
* variable length records
|
|
*
|
|
* Output params:
|
|
* record record buffer is filled with data
|
|
*
|
|
* Returns 0 if record was read successfully, or error code if any error.
|
|
*/
|
|
|
|
int
|
|
_vlrec_read(Fcb *fcb, char *record, Recno recnum, int *reclen)
|
|
{
|
|
long rec_position;
|
|
long tailoff;
|
|
char tailoffbuf[LONGSIZE];
|
|
|
|
/*
|
|
* Check that recnum is within the range of existing record numbers.
|
|
*/
|
|
if (recnum < 1 || recnum > fcb->lastrecno)
|
|
return (EENDFILE);
|
|
|
|
rec_position = _vl_getpos(fcb, recnum); /* Offset in .rec file */
|
|
|
|
/*
|
|
* Check that the record is not marked as deleted.
|
|
*/
|
|
_cp_fromfile(fcb, fcb->datfd, tailoffbuf, rec_position, LONGSIZE);
|
|
tailoff = ldlong(tailoffbuf);
|
|
if (tailoff == VL_RECDELETED) {
|
|
return (ENOREC);
|
|
}
|
|
|
|
/*
|
|
* Copy record from the .at file.
|
|
*/
|
|
_cp_fromfile(fcb, fcb->datfd, record, rec_position + LONGSIZE, fcb->minreclen);
|
|
|
|
*reclen = fcb->minreclen;
|
|
|
|
/*
|
|
* Get the 'tail' of the record if any.
|
|
*/
|
|
*reclen += _istail_read(fcb, tailoff, record + fcb->minreclen);
|
|
|
|
if (*reclen > fcb->maxreclen)
|
|
_isfatal_error("Corrupted file: too long variable length record");
|
|
|
|
return (ISOK);
|
|
}
|
|
|
|
/*
|
|
* pos = _vl_getpos(fcb, recnum)
|
|
*
|
|
* Calculate the position of record in .rec file.
|
|
*/
|
|
|
|
long
|
|
_vl_getpos(Fcb *fcb, Recno recnum)
|
|
{
|
|
return ((long)(ISCNTLSIZE + (fcb->minreclen + LONGSIZE) * (recnum -1)));
|
|
}
|
|
|
|
/*
|
|
* _vlrec_rewrite(fcb, record, recnum, reclen)
|
|
*
|
|
* Rewrite a record.
|
|
*
|
|
* Input params:
|
|
* FCB File Control Block
|
|
* recnum record number of the record
|
|
* record new record
|
|
* int reclen (NOT USED)
|
|
*
|
|
* Returns 0 if record was rewritten successfully, or error code if any error.
|
|
*/
|
|
|
|
/*ARGSUSED*/
|
|
int
|
|
_vlrec_rewrite(Fcb *fcb, char *record, Recno recnum, int reclen)
|
|
{
|
|
long rec_position;
|
|
long tailoff;
|
|
char tailoffbuf[LONGSIZE];
|
|
|
|
/*
|
|
* Check that recnum is within the range of existing record numbers.
|
|
*/
|
|
if (recnum < 1 || recnum > fcb->lastrecno)
|
|
return (EENDFILE);
|
|
|
|
rec_position = _vl_getpos(fcb, recnum); /* Offset in .rec file */
|
|
|
|
/*
|
|
* Check that the record is not marked as deleted.
|
|
*/
|
|
_cp_fromfile(fcb, fcb->datfd, tailoffbuf, rec_position, LONGSIZE);
|
|
tailoff = ldlong(tailoffbuf);
|
|
if (tailoff == VL_RECDELETED) {
|
|
return (ENOREC);
|
|
}
|
|
|
|
/*
|
|
* Store variable part of record (the 'tail') in .var file.
|
|
*/
|
|
tailoff = _istail_modify(fcb, tailoff, record + fcb->minreclen,
|
|
reclen - fcb->minreclen);
|
|
|
|
/*
|
|
* Copy new record to the .rec file.
|
|
*/
|
|
stlong(tailoff, tailoffbuf);
|
|
_cp_tofile(fcb, fcb->datfd, tailoffbuf, rec_position, LONGSIZE);
|
|
_cp_tofile(fcb, fcb->datfd, record, rec_position + LONGSIZE, fcb->minreclen);
|
|
|
|
return (ISOK);
|
|
}
|
|
|
|
/*
|
|
* _vlrec_delete;(fcb, recnum)
|
|
*
|
|
* Rewrite a record.
|
|
*
|
|
* Input params:
|
|
* FCB File Control Block
|
|
* recnum record number of the record
|
|
*
|
|
* Returns 0 if record was rewritten successfully, or error code if any error.
|
|
*/
|
|
|
|
int
|
|
_vlrec_delete(Fcb *fcb, Recno recnum)
|
|
{
|
|
long rec_position;
|
|
long tailoff;
|
|
char tailoffbuf[LONGSIZE];
|
|
char recnobuf [RECNOSIZE];
|
|
|
|
/*
|
|
* Check that recnum is within the range of existing record numbers.
|
|
*/
|
|
if (recnum < 1 || recnum > fcb->lastrecno)
|
|
return (EENDFILE);
|
|
|
|
rec_position = _vl_getpos(fcb, recnum); /* Offset in .rec file */
|
|
|
|
/*
|
|
* Check that the record is not marked as deleted.
|
|
*/
|
|
_cp_fromfile(fcb, fcb->datfd, tailoffbuf, rec_position, LONGSIZE);
|
|
tailoff = ldlong(tailoffbuf);
|
|
if (tailoff == VL_RECDELETED) {
|
|
return (ENOREC);
|
|
}
|
|
|
|
/*
|
|
* Set the delete flag to VL_RECDELETED.
|
|
*/
|
|
tailoff = VL_RECDELETED;
|
|
stlong(tailoff, tailoffbuf);
|
|
_cp_tofile(fcb, fcb->datfd, tailoffbuf, rec_position, LONGSIZE);
|
|
|
|
/*
|
|
* Insert record into chain of deleted records.
|
|
*/
|
|
strecno(fcb->freerecno, recnobuf);
|
|
_cp_tofile(fcb, fcb->datfd, recnobuf, rec_position + LONGSIZE, RECNOSIZE);
|
|
fcb->freerecno = recnum;
|
|
|
|
/*
|
|
* Delete tail from .var file.
|
|
*/
|
|
|
|
return (ISOK);
|
|
}
|
|
|
|
/*
|
|
* _vlrec_wrrec(fcb, record, recnum, reclen)
|
|
*
|
|
* Write a record by record number.
|
|
*
|
|
* Input params:
|
|
* FCB File Control Block
|
|
* recnum record number of the record
|
|
* record record buffer
|
|
* int reclen (NOT USED)
|
|
*
|
|
* Returns 0 if record was written successfully, or error code if any error.
|
|
*
|
|
* Note that _vlrec_wrrec() commits updates and syncs the FCB to avoid
|
|
* buffer pool overflow.
|
|
*/
|
|
|
|
/*ARGSUSED*/
|
|
int
|
|
_vlrec_wrrec(Fcb *fcb, char *record, Recno recnum, int reclen)
|
|
{
|
|
long rec_position;
|
|
long tailoff;
|
|
char tailoffbuf[LONGSIZE];
|
|
Recno recnum2;
|
|
char recnumbuf [RECNOSIZE];
|
|
|
|
/*
|
|
* Check that recnum is not negative.
|
|
*/
|
|
if (recnum < 1)
|
|
return (EBADARG);
|
|
|
|
rec_position = _vl_getpos(fcb, recnum); /* Offset in .rec file */
|
|
|
|
if (recnum > fcb->lastrecno) {
|
|
|
|
/*
|
|
* If the recnum is bigger than the highest record number in the .rec
|
|
* file, extend the .rec file.
|
|
*/
|
|
while (_vl_getpos(fcb, recnum + 1) > fcb->datsize * ISPAGESIZE) {
|
|
fcb->datsize = _extend_file(fcb, fcb->datfd, fcb->datsize);
|
|
|
|
/* Sync the updates to avoid buffer pool overflow. */
|
|
_isdisk_commit();
|
|
_isdisk_sync();
|
|
(void)_isfcb_cntlpg_w2(fcb);
|
|
}
|
|
|
|
/*
|
|
* Mark all records in the range <fcb->lastrecno+1, recnum> as
|
|
* deleted.
|
|
*/
|
|
tailoff = VL_RECDELETED;
|
|
stlong(tailoff, tailoffbuf);
|
|
for (recnum2 = fcb->lastrecno + 1; recnum2 <= recnum; recnum2++) {
|
|
_cp_tofile(fcb, fcb->datfd, tailoffbuf, _vl_getpos(fcb, recnum2), LONGSIZE);
|
|
strecno(fcb->freerecno, recnumbuf);
|
|
_cp_tofile(fcb, fcb->datfd, recnumbuf,
|
|
_vl_getpos(fcb, recnum2) + LONGSIZE, RECNOSIZE);
|
|
fcb->freerecno = recnum2;
|
|
|
|
/* Sync the updates to avoid buffer pool overflow. */
|
|
_isdisk_commit();
|
|
_isdisk_sync();
|
|
fcb->lastrecno = recnum;
|
|
(void)_isfcb_cntlpg_w2(fcb);
|
|
}
|
|
|
|
/*
|
|
* Note that the disk structures are in a consistent state now,
|
|
* the .rec was extended by a few records marked as 'deleted'.
|
|
* This is important for subsequent rollbacks.
|
|
*/
|
|
}
|
|
|
|
/*
|
|
* If recnum specifies a record that has existed, check whether it
|
|
* has been deleted. _vlrec_wrrec() does not override existing record.
|
|
*/
|
|
_cp_fromfile(fcb, fcb->datfd, tailoffbuf, rec_position, LONGSIZE);
|
|
tailoff = ldlong(tailoffbuf);
|
|
if (tailoff != VL_RECDELETED) {
|
|
return (EDUPL);
|
|
}
|
|
|
|
/*
|
|
* Remove the record from the chain of deleted records.
|
|
*/
|
|
remove_from_chain2(fcb, recnum);
|
|
|
|
/*
|
|
* Store variable part of record (the 'tail') in .var file.
|
|
*/
|
|
tailoff = _istail_insert(fcb, record + fcb->minreclen, reclen - fcb->minreclen);
|
|
|
|
/*
|
|
* Copy new record to the .rec file.
|
|
*/
|
|
stlong(tailoff, tailoffbuf);
|
|
_cp_tofile(fcb, fcb->datfd, tailoffbuf, rec_position, LONGSIZE);
|
|
_cp_tofile(fcb, fcb->datfd, record, rec_position + LONGSIZE, fcb->minreclen);
|
|
|
|
return (ISOK);
|
|
}
|
|
|
|
/*
|
|
* remove_from_chain(fcb, recnum)
|
|
*
|
|
* Remove record from the chain of deleted records.
|
|
*/
|
|
|
|
static void
|
|
remove_from_chain2(Fcb *fcb, Recno recnum)
|
|
{
|
|
char recnobuf1 [RECNOSIZE] , recnobuf2 [RECNOSIZE];
|
|
long pos1, pos2;
|
|
Recno recnum2;
|
|
|
|
pos1 = _vl_getpos(fcb, recnum);
|
|
_cp_fromfile(fcb, fcb->datfd, recnobuf1, pos1 + LONGSIZE, RECNOSIZE);
|
|
|
|
if (fcb->freerecno == recnum) {
|
|
fcb->freerecno = ldrecno(recnobuf1);
|
|
}
|
|
else {
|
|
recnum2 = fcb->freerecno;
|
|
do {
|
|
pos2 = _vl_getpos(fcb, recnum2);
|
|
_cp_fromfile(fcb, fcb->datfd, recnobuf2, pos2 + LONGSIZE, RECNOSIZE);
|
|
recnum2 = ldrecno(recnobuf2);
|
|
} while (recnum2 != recnum && recnum2 != NULL_RECNO);
|
|
|
|
_cp_tofile(fcb, fcb->datfd, recnobuf1, pos2 + LONGSIZE, RECNOSIZE);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* The following are functions that manipulate the 'tails' of variable
|
|
* records. The tail is the actual record with the fixed part removed
|
|
* (fixed part starts at offset zero and its length is minimum record
|
|
* length. The tails are stored in the .var file.
|
|
*/
|
|
|
|
|
|
/* Insert tail into .var file. Return offset in .var file */
|
|
|
|
long _istail_insert(Fcb *fcb, char *tailp, int taillen)
|
|
{
|
|
char frameheadbuf [2 * SHORTSIZE];
|
|
int framelen;
|
|
long offset;
|
|
|
|
/* printf ("_insert called, taillen %d\n", taillen); */
|
|
|
|
if (taillen == 0)
|
|
return (VL_RECNOTAIL);
|
|
|
|
framelen = taillen + 2 * SHORTSIZE;
|
|
|
|
/*
|
|
* Set up frame header.
|
|
*/
|
|
stshort((short)taillen, frameheadbuf + VR_FRAMELEN_OFF);
|
|
stshort((short)taillen, frameheadbuf + VR_TAILLEN_OFF);
|
|
|
|
offset = fcb->varend;
|
|
|
|
/*
|
|
* Extend .var file if that is necesary.
|
|
*/
|
|
while (offset + framelen > fcb->varsize * ISPAGESIZE)
|
|
fcb->varsize = _extend_file(fcb, fcb->varfd, fcb->varsize);
|
|
|
|
/*
|
|
* Copy frame head and tail to .var file.
|
|
*/
|
|
_cp_tofile(fcb, fcb->varfd, frameheadbuf, offset, 2 * SHORTSIZE);
|
|
_cp_tofile(fcb, fcb->varfd, tailp, offset + 2 * SHORTSIZE, taillen);
|
|
|
|
fcb->varend += taillen + 2 * SHORTSIZE;
|
|
|
|
return (offset);
|
|
}
|
|
|
|
/* Remove tail from .var file */
|
|
|
|
/* ARGSUSED */
|
|
Static void _istail_delete(Fcb *fcb, long offset)
|
|
{
|
|
/*
|
|
* Don't do anything in NetISAM 1.0. The tails are lost, the space
|
|
* will be re-used after next restructuring: "copy -c file" command
|
|
*/
|
|
return;
|
|
}
|
|
|
|
/* Read tail from .var file */
|
|
|
|
Static int _istail_read(Fcb *fcb, long offset, char *buffer)
|
|
{
|
|
char frameheadbuf [2 * SHORTSIZE];
|
|
int taillen;
|
|
|
|
/* printf ("_read called, offset %d\n", offset); */
|
|
|
|
if (offset == VL_RECNOTAIL)
|
|
return (0);
|
|
|
|
/*
|
|
* Read frame header.
|
|
*/
|
|
_cp_fromfile(fcb, fcb->varfd, frameheadbuf, offset, 2 * SHORTSIZE);
|
|
taillen = ldshort(frameheadbuf + VR_TAILLEN_OFF);
|
|
_cp_fromfile(fcb, fcb->varfd, buffer, offset + 2 * SHORTSIZE, taillen);
|
|
|
|
return (taillen);
|
|
}
|
|
|
|
/* Rewrite tail. Returns -1 if the new tail is longer than the original frame */
|
|
|
|
int _istail_modify(Fcb *fcb, long offset, char *tailp, int taillen)
|
|
{
|
|
char frameheadbuf [2 * SHORTSIZE];
|
|
int framelen;
|
|
|
|
/*
|
|
* Trivial case: no old frame, no new tail.
|
|
*/
|
|
if (offset == VL_RECNOTAIL && taillen == 0)
|
|
return (offset);
|
|
|
|
if (offset != VL_RECNOTAIL) {
|
|
/*
|
|
* Read frame header.
|
|
*/
|
|
_cp_fromfile(fcb, fcb->varfd, frameheadbuf, offset, 2 * SHORTSIZE);
|
|
framelen = ldshort(frameheadbuf + VR_FRAMELEN_OFF);
|
|
}
|
|
else
|
|
framelen = 0;
|
|
|
|
if (taillen > framelen) {
|
|
/*
|
|
* Delete the old frame if the new tail does not fit.
|
|
* Insert the new tail at the end of .var file.
|
|
*/
|
|
|
|
_istail_delete(fcb, offset);
|
|
return (_istail_insert(fcb, tailp, taillen));
|
|
}
|
|
else {
|
|
/*
|
|
* The new tail fits in the existing frame.
|
|
*/
|
|
stshort((short)taillen, frameheadbuf + VR_TAILLEN_OFF);
|
|
_cp_tofile(fcb, fcb->varfd, frameheadbuf, offset, 2 * SHORTSIZE);
|
|
_cp_tofile(fcb, fcb->varfd, tailp, offset + 2 * SHORTSIZE, taillen);
|
|
|
|
return (offset);
|
|
}
|
|
}
|