123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566 |
- /*
- * 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);
- }
- }
|