2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these libraries and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /*%% (c) Copyright 1993, 1994 Hewlett-Packard Company */
24 /*%% (c) Copyright 1993, 1994 International Business Machines Corp. */
25 /*%% (c) Copyright 1993, 1994 Sun Microsystems, Inc. */
26 /*%% (c) Copyright 1993, 1994 Novell, Inc. */
27 /*%% $XConsortium: isvarrec.c /main/3 1995/10/23 11:45:36 rswiston $ */
29 static char sccsid[] = "@(#)isvarrec.c 1.8 89/07/17 Copyr 1988 Sun Micro";
32 * Copyright (c) 1988 by Sun Microsystems, Inc.
39 * Fixed length record access (VLRA) module.
42 #include "isam_impl.h"
45 long _vl_getpos(); /* Get offset in .rec file */
46 int _vl_deleted(); /* 0/1 returns 1 if record is deleted */
47 static void remove_from_chain2(); /* used by _vlrec_wrrec() */
48 long _istail_insert();
49 static void _istail_delete();
50 static _istail_read();
53 * _vlrec_write(fcb, record, recnum, reclen)
58 * FCB File Control Block
59 * record record buffer
60 * reclen record length (NOT USED)
63 * recnum record number of the new record
65 * Returns 0 if record was written successfully, or -1 if any error.
70 _vlrec_write(Fcb *fcb, char *record, Recno *recnum, int reclen)
74 long tailoff = VL_RECNOTAIL;
75 char recnobuf [RECNOSIZE];
76 char tailoffbuf[LONGSIZE];
79 * Reuse a deleted record if one exits.
80 * Otherwise, extend .rec file by a record.
82 if (fcb->freerecno != NULL_RECNO) {
83 recnum2 = fcb->freerecno;
86 * Remove record from the chain of deleted records.
88 rec_position = _vl_getpos(fcb, recnum2); /* Offset in .rec file */
89 _cp_fromfile(fcb, fcb->datfd, recnobuf, rec_position + LONGSIZE, RECNOSIZE);
90 fcb->freerecno = ldrecno(recnobuf);
93 recnum2 = ++(fcb->lastrecno);
96 * Extend .rec file size if necessary.
98 while (_vl_getpos(fcb, recnum2 + 1) > fcb->datsize * ISPAGESIZE) {
99 fcb->datsize = _extend_file(fcb, fcb->datfd, fcb->datsize);
101 rec_position = _vl_getpos(fcb, recnum2); /* Offset in .rec file */
105 * Store variable part of record (the 'tail') in .var file.
107 tailoff = _istail_insert(fcb, record + fcb->minreclen,
108 reclen - fcb->minreclen);
111 * Copy record to the .rec file. Mark record as undeleted.
113 stlong(tailoff, tailoffbuf);
114 _cp_tofile(fcb, fcb->datfd, tailoffbuf, rec_position, LONGSIZE);
115 _cp_tofile(fcb, fcb->datfd, record, rec_position + LONGSIZE, fcb->minreclen);
123 * _vlrec_read(fcb, record, recnum, reclen)
128 * FCB File Control Block
129 * recnum record number of the record
130 * reclen filled with the record size for compatibilty with
131 * variable length records
134 * record record buffer is filled with data
136 * Returns 0 if record was read successfully, or error code if any error.
140 _vlrec_read(Fcb *fcb, char *record, Recno recnum, int *reclen)
144 char tailoffbuf[LONGSIZE];
147 * Check that recnum is within the range of existing record numbers.
149 if (recnum < 1 || recnum > fcb->lastrecno)
152 rec_position = _vl_getpos(fcb, recnum); /* Offset in .rec file */
155 * Check that the record is not marked as deleted.
157 _cp_fromfile(fcb, fcb->datfd, tailoffbuf, rec_position, LONGSIZE);
158 tailoff = ldlong(tailoffbuf);
159 if (tailoff == VL_RECDELETED) {
164 * Copy record from the .at file.
166 _cp_fromfile(fcb, fcb->datfd, record, rec_position + LONGSIZE, fcb->minreclen);
168 *reclen = fcb->minreclen;
171 * Get the 'tail' of the record if any.
173 *reclen += _istail_read(fcb, tailoff, record + fcb->minreclen);
175 if (*reclen > fcb->maxreclen)
176 _isfatal_error("Corrupted file: too long variable length record");
182 * pos = _vl_getpos(fcb, recnum)
184 * Calculate the position of record in .rec file.
188 _vl_getpos(Fcb *fcb, Recno recnum)
190 return ((long)(ISCNTLSIZE + (fcb->minreclen + LONGSIZE) * (recnum -1)));
194 * _vlrec_rewrite(fcb, record, recnum, reclen)
199 * FCB File Control Block
200 * recnum record number of the record
202 * int reclen (NOT USED)
204 * Returns 0 if record was rewritten successfully, or error code if any error.
209 _vlrec_rewrite(Fcb *fcb, char *record, Recno recnum, int reclen)
213 char tailoffbuf[LONGSIZE];
216 * Check that recnum is within the range of existing record numbers.
218 if (recnum < 1 || recnum > fcb->lastrecno)
221 rec_position = _vl_getpos(fcb, recnum); /* Offset in .rec file */
224 * Check that the record is not marked as deleted.
226 _cp_fromfile(fcb, fcb->datfd, tailoffbuf, rec_position, LONGSIZE);
227 tailoff = ldlong(tailoffbuf);
228 if (tailoff == VL_RECDELETED) {
233 * Store variable part of record (the 'tail') in .var file.
235 tailoff = _istail_modify(fcb, tailoff, record + fcb->minreclen,
236 reclen - fcb->minreclen);
239 * Copy new record to the .rec file.
241 stlong(tailoff, tailoffbuf);
242 _cp_tofile(fcb, fcb->datfd, tailoffbuf, rec_position, LONGSIZE);
243 _cp_tofile(fcb, fcb->datfd, record, rec_position + LONGSIZE, fcb->minreclen);
249 * _vlrec_delete;(fcb, recnum)
254 * FCB File Control Block
255 * recnum record number of the record
257 * Returns 0 if record was rewritten successfully, or error code if any error.
261 _vlrec_delete(Fcb *fcb, Recno recnum)
265 char tailoffbuf[LONGSIZE];
266 char recnobuf [RECNOSIZE];
269 * Check that recnum is within the range of existing record numbers.
271 if (recnum < 1 || recnum > fcb->lastrecno)
274 rec_position = _vl_getpos(fcb, recnum); /* Offset in .rec file */
277 * Check that the record is not marked as deleted.
279 _cp_fromfile(fcb, fcb->datfd, tailoffbuf, rec_position, LONGSIZE);
280 tailoff = ldlong(tailoffbuf);
281 if (tailoff == VL_RECDELETED) {
286 * Set the delete flag to VL_RECDELETED.
288 tailoff = VL_RECDELETED;
289 stlong(tailoff, tailoffbuf);
290 _cp_tofile(fcb, fcb->datfd, tailoffbuf, rec_position, LONGSIZE);
293 * Insert record into chain of deleted records.
295 strecno(fcb->freerecno, recnobuf);
296 _cp_tofile(fcb, fcb->datfd, recnobuf, rec_position + LONGSIZE, RECNOSIZE);
297 fcb->freerecno = recnum;
300 * Delete tail from .var file.
307 * _vlrec_wrrec(fcb, record, recnum, reclen)
309 * Write a record by record number.
312 * FCB File Control Block
313 * recnum record number of the record
314 * record record buffer
315 * int reclen (NOT USED)
317 * Returns 0 if record was written successfully, or error code if any error.
319 * Note that _vlrec_wrrec() commits updates and syncs the FCB to avoid
320 * buffer pool overflow.
325 _vlrec_wrrec(Fcb *fcb, char *record, Recno recnum, int reclen)
329 char tailoffbuf[LONGSIZE];
331 char recnumbuf [RECNOSIZE];
334 * Check that recnum is not negative.
339 rec_position = _vl_getpos(fcb, recnum); /* Offset in .rec file */
341 if (recnum > fcb->lastrecno) {
344 * If the recnum is bigger than the highest record number in the .rec
345 * file, extend the .rec file.
347 while (_vl_getpos(fcb, recnum + 1) > fcb->datsize * ISPAGESIZE) {
348 fcb->datsize = _extend_file(fcb, fcb->datfd, fcb->datsize);
350 /* Sync the updates to avoid buffer pool overflow. */
353 (void)_isfcb_cntlpg_w2(fcb);
357 * Mark all records in the range <fcb->lastrecno+1, recnum> as
360 tailoff = VL_RECDELETED;
361 stlong(tailoff, tailoffbuf);
362 for (recnum2 = fcb->lastrecno + 1; recnum2 <= recnum; recnum2++) {
363 _cp_tofile(fcb, fcb->datfd, tailoffbuf, _vl_getpos(fcb, recnum2), LONGSIZE);
364 strecno(fcb->freerecno, recnumbuf);
365 _cp_tofile(fcb, fcb->datfd, recnumbuf,
366 _vl_getpos(fcb, recnum2) + LONGSIZE, RECNOSIZE);
367 fcb->freerecno = recnum2;
369 /* Sync the updates to avoid buffer pool overflow. */
372 fcb->lastrecno = recnum;
373 (void)_isfcb_cntlpg_w2(fcb);
377 * Note that the disk structures are in a consistent state now,
378 * the .rec was extended by a few records marked as 'deleted'.
379 * This is important for subsequent rollbacks.
384 * If recnum specifies a record that has existed, check whether it
385 * has been deleted. _vlrec_wrrec() does not override existing record.
387 _cp_fromfile(fcb, fcb->datfd, tailoffbuf, rec_position, LONGSIZE);
388 tailoff = ldlong(tailoffbuf);
389 if (tailoff != VL_RECDELETED) {
394 * Remove the record from the chain of deleted records.
396 remove_from_chain2(fcb, recnum);
399 * Store variable part of record (the 'tail') in .var file.
401 tailoff = _istail_insert(fcb, record + fcb->minreclen, reclen - fcb->minreclen);
404 * Copy new record to the .rec file.
406 stlong(tailoff, tailoffbuf);
407 _cp_tofile(fcb, fcb->datfd, tailoffbuf, rec_position, LONGSIZE);
408 _cp_tofile(fcb, fcb->datfd, record, rec_position + LONGSIZE, fcb->minreclen);
414 * remove_from_chain(fcb, recnum)
416 * Remove record from the chain of deleted records.
420 remove_from_chain2(Fcb *fcb, Recno recnum)
422 char recnobuf1 [RECNOSIZE] , recnobuf2 [RECNOSIZE];
426 pos1 = _vl_getpos(fcb, recnum);
427 _cp_fromfile(fcb, fcb->datfd, recnobuf1, pos1 + LONGSIZE, RECNOSIZE);
429 if (fcb->freerecno == recnum) {
430 fcb->freerecno = ldrecno(recnobuf1);
433 recnum2 = fcb->freerecno;
435 pos2 = _vl_getpos(fcb, recnum2);
436 _cp_fromfile(fcb, fcb->datfd, recnobuf2, pos2 + LONGSIZE, RECNOSIZE);
437 recnum2 = ldrecno(recnobuf2);
438 } while (recnum2 != recnum && recnum2 != NULL_RECNO);
440 _cp_tofile(fcb, fcb->datfd, recnobuf1, pos2 + LONGSIZE, RECNOSIZE);
446 * The following are functions that manipulate the 'tails' of variable
447 * records. The tail is the actual record with the fixed part removed
448 * (fixed part starts at offset zero and its length is minimum record
449 * length. The tails are stored in the .var file.
453 /* Insert tail into .var file. Return offset in .var file */
455 long _istail_insert(Fcb *fcb, char *tailp, int taillen)
457 char frameheadbuf [2 * SHORTSIZE];
461 /* printf ("_insert called, taillen %d\n", taillen); */
464 return (VL_RECNOTAIL);
466 framelen = taillen + 2 * SHORTSIZE;
469 * Set up frame header.
471 stshort((short)taillen, frameheadbuf + VR_FRAMELEN_OFF);
472 stshort((short)taillen, frameheadbuf + VR_TAILLEN_OFF);
474 offset = fcb->varend;
477 * Extend .var file if that is necesary.
479 while (offset + framelen > fcb->varsize * ISPAGESIZE)
480 fcb->varsize = _extend_file(fcb, fcb->varfd, fcb->varsize);
483 * Copy frame head and tail to .var file.
485 _cp_tofile(fcb, fcb->varfd, frameheadbuf, offset, 2 * SHORTSIZE);
486 _cp_tofile(fcb, fcb->varfd, tailp, offset + 2 * SHORTSIZE, taillen);
488 fcb->varend += taillen + 2 * SHORTSIZE;
493 /* Remove tail from .var file */
496 Static void _istail_delete(Fcb *fcb, long offset)
499 * Don't do anything in NetISAM 1.0. The tails are lost, the space
500 * will be re-used after next restructuring: "copy -c file" command
505 /* Read tail from .var file */
507 Static _istail_read(Fcb *fcb, long offset, char *buffer)
509 char frameheadbuf [2 * SHORTSIZE];
512 /* printf ("_read called, offset %d\n", offset); */
514 if (offset == VL_RECNOTAIL)
520 _cp_fromfile(fcb, fcb->varfd, frameheadbuf, offset, 2 * SHORTSIZE);
521 taillen = ldshort(frameheadbuf + VR_TAILLEN_OFF);
522 _cp_fromfile(fcb, fcb->varfd, buffer, offset + 2 * SHORTSIZE, taillen);
527 /* Rewrite tail. Returns -1 if the new tail is longer than the original frame */
529 int _istail_modify(Fcb *fcb, long offset, char *tailp, int taillen)
531 char frameheadbuf [2 * SHORTSIZE];
535 * Trivial case: no old frame, no new tail.
537 if (offset == VL_RECNOTAIL && taillen == 0)
540 if (offset != VL_RECNOTAIL) {
544 _cp_fromfile(fcb, fcb->varfd, frameheadbuf, offset, 2 * SHORTSIZE);
545 framelen = ldshort(frameheadbuf + VR_FRAMELEN_OFF);
550 if (taillen > framelen) {
552 * Delete the old frame if the new tail does not fit.
553 * Insert the new tail at the end of .var file.
556 _istail_delete(fcb, offset);
557 return (_istail_insert(fcb, tailp, taillen));
561 * The new tail fits in the existing frame.
563 stshort((short)taillen, frameheadbuf + VR_TAILLEN_OFF);
564 _cp_tofile(fcb, fcb->varfd, frameheadbuf, offset, 2 * SHORTSIZE);
565 _cp_tofile(fcb, fcb->varfd, tailp, offset + 2 * SHORTSIZE, taillen);