/* * 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: isread.c /main/3 1995/10/23 11:43:35 rswiston $ */ /* * Copyright (c) 1988 by Sun Microsystems, Inc. */ /* * isread.c * * Description: * Read a record from ISAM file. */ #include "isam_impl.h" #include static int _amread(); /* * err = isread(isfd, record, mode) * * Isread() reads a new record from an ISAM file. * * Current record position is set. * isrecnum is set to indicate the read record. * * If the ISAM file is for variable length records, the isreclen variable * is set to indicate the actual length of the record. * * Returns 0 if successful, or -1 of any error. * * Errors: * ELOCKED The record or the entire file is locked by another process. * ENOTOPEN isfd does not correspond to an open ISAM file, or the * ISAM file was opened with ISOUTPUT mode. * EBADARG Bad mode parameter. * ENOCURR Mode is ISCURR and the current record position is not set. * ENOREC Specified record cannot be found (random access read) * EENDFILE The end file of is reached (sequential read). * EBADKEY Index was deleted by other process (can happen only * when lock file is purged). */ int isread(int isfd, char *record, int mode) { Fab *fab; int reclen; Recno recnum; int ret; enum readmode readmode; /* * Get File Access Block. */ if ((fab = _isfd_find(isfd)) == NULL) { _setiserrno2(ENOTOPEN, '9', '0'); return (ISERROR); } /* * Check that the open mode was ISINPUT, or ISINOUT. */ if (fab->openmode != OM_INPUT && fab->openmode != OM_INOUT) { _setiserrno2(ENOTOPEN, '9', '0'); return (ISERROR); } /* * Extract read mode. */ if ((readmode = _getreadmode(mode)) == RM_BADMODE) { _setiserrno2(EBADARG, '9', '0'); return (ISERROR); } /* * All keys must be in the minimum record length. * So send just the minimum length part of the record. */ reclen = fab->minreclen; /* * Call the Access Method */ recnum = isrecnum; if ((ret = _amread(&fab->isfhandle, record, &reclen, readmode, &fab->curpos, &recnum, &fab->errcode)) == ISOK) { isrecnum = recnum; /* Set isrecnum */ } isreclen = reclen; _seterr_errcode(&fab->errcode); return (ret); /* Successful read */ } /* * _amread(isfhandle, record, reclen, readmode, curpos, recnum, errcode) * * _amread() reads a record from ISAM file * * Input params: * isfhandle Handle of ISAM file * readmode Specifies access mode (random or sequential) * curpos current record position * recnum copy if isrecnum * * Output params: * curpos new current position * recnum record number * errcode error status of the operation * reclen actual length of the record * record filled with data * */ static int _amread(Bytearray *isfhandle, char *record, int *reclen, enum readmode readmode, Bytearray *curpos, Recno *recnum, struct errcode *errcode) { Fcb *fcb = NULL; Recno recnum2 = 0; int err; Crp *crp; Btree *btree = NULL; Keydesc2 *pkeydesc2; char keybuf1[MAXKEYSIZE], keybuf2[MAXKEYSIZE]; char *pkey = NULL, *pkeynext; int skipbytes; int ret; Bytearray oldcurpos; int (*rec_read)(); _isam_entryhook(); /* * Get FCB corresponding to the isfhandle handle. */ if ((fcb = _openfcb(isfhandle, errcode)) == NULL) { _isam_exithook(); return (ISERROR); } rec_read = (fcb->varflag?_vlrec_read:_flrec_read); /* * Update information in FCB from CNTL page on the disk */ (void)_isfcb_cntlpg_r2(fcb); /* * Save the old record position. */ oldcurpos = _bytearr_dup(curpos); /* * Get info from current record position structure. */ crp = (Crp *) curpos->data; if (crp->keyid == PHYS_ORDER) { /* * Physical order in use. */ switch (readmode) { case RM_EQUAL: recnum2 = *recnum; /* passed from isrecnum */ if ((err = rec_read(fcb, record, recnum2, reclen)) != ISOK) { _amseterrcode(errcode, ENOREC); goto ERROR; } break; case RM_GREAT: recnum2 = *recnum + 1; if (recnum2 < 1) recnum2 = 1; /* * Skip deleted records. */ while ((err = rec_read(fcb, record, recnum2, reclen)) != ISOK && err == ENOREC) recnum2++; if (err != ISOK) { _amseterrcode(errcode, ENOREC); goto ERROR; } break; case RM_GTEQ: recnum2 = *recnum; if (recnum2 < 1) recnum2 = 1; /* * Skip deleted records. */ while ((err = rec_read(fcb, record, recnum2, reclen)) != ISOK && err == ENOREC) recnum2++; if (err != ISOK) { _amseterrcode(errcode, ENOREC); goto ERROR; } break; case RM_LESS: recnum2 = *recnum - 1; if (recnum2 > fcb->lastrecno) recnum2 = fcb->lastrecno; /* * Skip deleted records. */ while ((err = rec_read(fcb, record, recnum2, reclen)) != ISOK && err == ENOREC) recnum2--; if (err != ISOK) { _amseterrcode(errcode, ENOREC); goto ERROR; } break; case RM_LTEQ: recnum2 = *recnum; if (recnum2 > fcb->lastrecno) recnum2 = fcb->lastrecno; /* * Skip deleted records. */ while ((err = rec_read(fcb, record, recnum2, reclen)) != ISOK && err == ENOREC) recnum2--; if (err != ISOK) { _amseterrcode(errcode, ENOREC); goto ERROR; } break; case RM_FIRST: recnum2 = 1; /* * Skip deleted records. */ while ((err = rec_read(fcb, record, recnum2, reclen)) != ISOK && err == ENOREC) recnum2++; if (err != ISOK) { _amseterrcode(errcode, EENDFILE); goto ERROR; } break; case RM_CURR: switch (crp->flag) { case CRP_ON: case CRP_BEFORE: case CRP_AFTER: recnum2 = crp->recno; break; case CRP_BEFOREANY: recnum2 = 1; break; default: _amseterrcode(errcode, ENOCURR); goto ERROR; } if( rec_read(fcb, record, recnum2, reclen) != ISOK) { _amseterrcode(errcode, ENOCURR); goto ERROR; } break; case RM_NEXT: switch (crp->flag) { case CRP_ON: case CRP_AFTER: recnum2 = crp->recno + 1; break; case CRP_BEFOREANY: recnum2 = 1; break; case CRP_BEFORE: recnum2 = crp->recno; break; case CRP_AFTERANY: _amseterrcode(errcode, EENDFILE); goto ERROR; default: _amseterrcode(errcode, ENOCURR); goto ERROR; } /* * Skip deleted records. */ while ((err = rec_read(fcb, record, recnum2, reclen)) != ISOK && err == ENOREC) recnum2++; if (err != ISOK) { _amseterrcode(errcode, EENDFILE); goto ERROR; } break; case RM_PREV: switch (crp->flag) { case CRP_ON: case CRP_BEFORE: recnum2 = crp->recno - 1; break; case CRP_AFTER: recnum2 = crp->recno; break; case CRP_BEFOREANY: _amseterrcode(errcode, EENDFILE); goto ERROR; default: _amseterrcode(errcode, ENOCURR); goto ERROR; } /* * Skip deleted records. */ while ((err = rec_read(fcb, record, recnum2, reclen)) != ISOK && err == ENOREC) recnum2--; if (err != ISOK) { _amseterrcode(errcode, EENDFILE); goto ERROR; } break; case RM_LAST: recnum2 = fcb->lastrecno; /* * Skip deleted records. */ while ((err = rec_read(fcb, record, recnum2, reclen)) != ISOK && err == ENOREC) recnum2--; if (err != ISOK) { _amseterrcode(errcode, EENDFILE); goto ERROR; } break; default: _isfatal_error("Invalid readmode"); } *recnum = recnum2; /* * Set new current record position. */ crp->recno = recnum2; crp->flag = CRP_ON; } /* physical order */ else { /* * Find key descriptor in FCB */ if ((pkeydesc2 = _isfcb_indfindkey(fcb, crp->keyid)) == NULL) { _amseterrcode(errcode, EBADKEY); goto ERROR; } /* * skipkeybytes is set to the number of bytes in the beginning * of the key: * RECNOSIZE for ISNODUPS keys to skip recno part * RECNOSIZE + DUPIDSIZE to skip recno and duplicate serial number */ skipbytes = RECNOSIZE; if (ALLOWS_DUPS2(pkeydesc2)) skipbytes += DUPIDSIZE; /* * Create B tree object. */ btree = _isbtree_create(fcb, pkeydesc2); switch (readmode) { case RM_EQUAL: case RM_GTEQ: /* * Make sure that you will read the first duplicate. */ _iskey_fillmin(pkeydesc2, keybuf1); /* * Extract key fields from record. */ _iskey_extract(pkeydesc2, record, keybuf2); memcpy((void *)(keybuf1 + skipbytes), (const void *)(keybuf2 + skipbytes), crp->matchkeylen); /* * Position pointer in the B-tree in before the searched value. */ _isbtree_search(btree, keybuf1); if ((pkey = _isbtree_next(btree)) == NULL) { _amseterrcode(errcode, ENOREC); goto ERROR; } if (readmode == RM_EQUAL && memcmp(keybuf1 + skipbytes, pkey + skipbytes, crp->matchkeylen) != 0) { _amseterrcode(errcode, ENOREC); goto ERROR; } crp->recno = ldrecno(pkey + KEY_RECNO_OFF); memcpy((void *)crp->key, (const void *)pkey, pkeydesc2->k2_len); if( rec_read(fcb, record, crp->recno, reclen) != ISOK) { _amseterrcode(errcode, ENOCURR); goto ERROR; } recnum2 = crp->recno; break; case RM_GREAT: /* * Make sure that you will read past all matching records. */ _iskey_fillmax(pkeydesc2, keybuf1); /* * Extract key fields from record. */ _iskey_extract(pkeydesc2, record, keybuf2); memcpy((void *)(keybuf1 + skipbytes), (const void *)(keybuf2 + skipbytes), crp->matchkeylen); /* * Position pointer in the B-tree in before the searched value. */ _isbtree_search(btree, keybuf1); if ((pkey = _isbtree_next(btree)) == NULL) { _amseterrcode(errcode, ENOREC); goto ERROR; } crp->recno = ldrecno(pkey + KEY_RECNO_OFF); memcpy((void *)crp->key, (const void *)pkey, pkeydesc2->k2_len); if( rec_read(fcb, record, crp->recno, reclen) != ISOK) { _amseterrcode(errcode, ENOCURR); goto ERROR; } recnum2 = crp->recno; break; case RM_LESS: /* * Make sure that you will read before all matching records. */ _iskey_fillmin(pkeydesc2, keybuf1); /* * Extract key fields from record. */ _iskey_extract(pkeydesc2, record, keybuf2); memcpy((void *)(keybuf1 + skipbytes), (const void *)(keybuf2 + skipbytes), crp->matchkeylen); /* * Position pointer in the B-tree in before the searched value. */ _isbtree_search(btree, keybuf1); if ((pkey = _isbtree_current(btree)) == NULL) { _amseterrcode(errcode, ENOREC); goto ERROR; } crp->recno = ldrecno(pkey + KEY_RECNO_OFF); memcpy((void *)crp->key, (const void *)pkey, pkeydesc2->k2_len); if( rec_read(fcb, record, crp->recno, reclen) != ISOK) { _amseterrcode(errcode, ENOCURR); goto ERROR; } recnum2 = crp->recno; break; case RM_LTEQ: /* * Make sure that you will read the last duplicate. */ _iskey_fillmax(pkeydesc2, keybuf1); /* * Extract key fields from record. */ _iskey_extract(pkeydesc2, record, keybuf2); memcpy((void *)(keybuf1 + skipbytes), (const void *)(keybuf2 + skipbytes), crp->matchkeylen); /* * Position pointer in the B-tree in before the searched value. */ _isbtree_search(btree, keybuf1); if ((pkey = _isbtree_current(btree)) == NULL) { _amseterrcode(errcode, ENOREC); goto ERROR; } crp->recno = ldrecno(pkey + KEY_RECNO_OFF); memcpy((void *)crp->key, (const void *)pkey, pkeydesc2->k2_len); if( rec_read(fcb, record, crp->recno, reclen) != ISOK) { _amseterrcode(errcode, ENOCURR); goto ERROR; } recnum2 = crp->recno; break; case RM_CURR: switch (crp->flag) { case CRP_ON: case CRP_BEFORE: case CRP_AFTER: /* * We have check if the record has not been deleted * since the current record position was set up. */ _isbtree_search(btree, crp->key); pkey = _isbtree_current(btree); if (pkey == NULL || ldrecno(pkey + KEY_RECNO_OFF) != crp->recno) { _amseterrcode(errcode, ENOCURR); goto ERROR; } break; case CRP_BEFOREANY: _isbtree_search(btree, crp->key); pkey = _isbtree_next(btree); if (pkey == NULL) { _amseterrcode(errcode, EENDFILE); goto ERROR; } crp->recno = ldrecno(pkey + KEY_RECNO_OFF); memcpy((void *)crp->key, (const void *)pkey, pkeydesc2->k2_len); break; default: _amseterrcode(errcode, ENOCURR); goto ERROR; } if( rec_read(fcb, record, crp->recno, reclen) != ISOK) { _amseterrcode(errcode, ENOCURR); goto ERROR; } recnum2 = crp->recno; break; case RM_NEXT: /* * Validate that current position has been set. */ switch (crp->flag) { case CRP_ON: case CRP_BEFORE: case CRP_BEFOREANY: break; case CRP_AFTERANY: _amseterrcode(errcode, EENDFILE); goto ERROR; default: _amseterrcode(errcode, ENOCURR); goto ERROR; } /* * Position pointer to current position. */ _isbtree_search(btree, crp->key); if (crp->flag == CRP_BEFORE) pkey = _isbtree_current(btree); else /* crp->flag == CRP_ON || crp->flag == CRP_BEFOREANY */ pkey = _isbtree_next(btree); if (pkey == NULL) { _amseterrcode(errcode, EENDFILE); goto ERROR; } crp->recno = ldrecno(pkey + KEY_RECNO_OFF); memcpy((void *)crp->key, (const void *)pkey, pkeydesc2->k2_len); if( rec_read(fcb, record, crp->recno, reclen) != ISOK) { _amseterrcode(errcode, ENOCURR); goto ERROR; } recnum2 = crp->recno; break; case RM_PREV: /* * Validate that current position has been set. */ switch (crp->flag) { case CRP_ON: case CRP_BEFORE: /* * To get to the previous record, we must decrement * the TID part for unique keys, or duplicate serial number * for non-unique keys. */ memcpy((void *)keybuf1, (const void *)crp->key, pkeydesc2->k2_len); if (ALLOWS_DUPS2(pkeydesc2)) { stlong(ldlong(keybuf1 + KEY_DUPS_OFF) - 1, keybuf1 + KEY_DUPS_OFF); } else { strecno(ldrecno(keybuf1 + KEY_RECNO_OFF) - 1, keybuf1 + KEY_RECNO_OFF); } break; case CRP_AFTER: memcpy((void *)keybuf1, (const void *)crp->key, pkeydesc2->k2_len); break; case CRP_BEFOREANY: _amseterrcode(errcode, EENDFILE); goto ERROR; default: _amseterrcode(errcode, ENOCURR); goto ERROR; } /* * Position pointer to current position. */ _isbtree_search(btree, keybuf1); pkey = _isbtree_current(btree); if (pkey == NULL) { _amseterrcode(errcode, EENDFILE); goto ERROR; } crp->recno = ldrecno(pkey + KEY_RECNO_OFF); memcpy((void *)crp->key, (const void *)pkey, pkeydesc2->k2_len); if( rec_read(fcb, record, crp->recno, reclen) != ISOK) { _amseterrcode(errcode, ENOCURR); goto ERROR; } recnum2 = crp->recno; break; case RM_FIRST: /* * Fill key buffer with -infinity. */ _iskey_fillmin(pkeydesc2, keybuf1); /* * Position pointer in the B-tree before any key entry. */ _isbtree_search(btree, keybuf1); if ((pkey = _isbtree_next(btree)) == NULL) { _amseterrcode(errcode, EENDFILE); goto ERROR; } crp->recno = ldrecno(pkey + KEY_RECNO_OFF); memcpy((void *)crp->key, (const void *)pkey, pkeydesc2->k2_len); if( rec_read(fcb, record, crp->recno, reclen) != ISOK) { _amseterrcode(errcode, EENDFILE); goto ERROR; } recnum2 = crp->recno; break; case RM_LAST: /* * Fill key buffer with +infinity. */ _iskey_fillmax(pkeydesc2, keybuf1); /* * Position pointer in the B-tree before any key entry. */ _isbtree_search(btree, keybuf1); if ((pkey = _isbtree_current(btree)) == NULL) { _amseterrcode(errcode, EENDFILE); goto ERROR; } crp->recno = ldrecno(pkey + KEY_RECNO_OFF); memcpy((void *)crp->key, (const void *)pkey, pkeydesc2->k2_len); if( rec_read(fcb, record, crp->recno, reclen) != ISOK) { _amseterrcode(errcode, EENDFILE); goto ERROR; } recnum2 = crp->recno; break; default: _isfatal_error("Invalid readmode"); } *recnum = recnum2; crp->flag = CRP_ON; /* * Set up isdupl to handle isstat2 value for keys that allow * duplicate values. */ if (ALLOWS_DUPS2(pkeydesc2) && (pkeynext = _isbtree_next(btree)) && memcmp(pkey + skipbytes, pkeynext + skipbytes, crp->matchkeylen) == 0) { isdupl = 1; } _isbtree_destroy(btree); } _amseterrcode(errcode, ISOK); ret = ISOK; /* Clean-up work. */ _isdisk_commit(); /* This will only check * that we unfixed all fixed * buffers */ _isdisk_inval(); _bytearr_free(&oldcurpos); _isam_exithook(); return (ret); ERROR: *reclen = 0; _isdisk_inval(); _bytearr_free(&oldcurpos); /* * If error is ENOREC, set the current record position undefined. */ if (errcode->iserrno == ENOREC || errcode->iserrno == EENDFILE) { ((Crp *)curpos->data)->flag = CRP_UNDEF; } if (btree != NULL) _isbtree_destroy(btree); _isam_exithook(); return (ISERROR); }