cdesktopenv/cde/lib/tt/mini_isam/isfcb.c

903 lines
20 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: isfcb.c /main/3 1995/10/23 11:38:34 rswiston $ */
/*
* Copyright (c) 1988 by Sun Microsystems, Inc.
*/
/*
* isfcb.c
*
* Description: _ambuild()
* File Control Block functions
*
*
*/
#include <unistd.h>
#include <stdlib.h>
#include "isam_impl.h"
#include <sys/stat.h>
static int _create_datfile(), _create_indfile(), _create_varfile();
static void _remove_datfile(), _remove_indfile(), _remove_varfile();
Static int _open_datfile(), _open_indfile(), _open_varfile();
/*
* _isfcb_create(isfname, crdat, crind, crvar, owner, group, u_mask, errcode)
*
* Create ISAM file: create UNIX files (dat/ind/var),
* and initialize File Control Block.
*
* Return 0 if create is successful, or -1 if any error. In the case of
*an error, the errcode block is set.
*
* crdat, 0/1 flag
* crind, 0/1 flag
* crvar, 0/1 flag
*/
Fcb *
_isfcb_create(char *isfname, int crdat, int crind, int crvar,
int owner, int group, int u_mask, struct errcode *errcode)
{
Fcb *fcb;
int dat_fd = -1;
int ind_fd = -1;
int var_fd = -1;
int oldumask = umask (u_mask); /* Change umask to client's */
/*
* Create the UNIX file for .rec file.
*/
if (crdat && (dat_fd = _create_datfile (isfname)) == -1) {
_amseterrcode(errcode, errno);
goto ERROR;
}
/*
* If a primary is specified, create .ind file.
*/
if (crind && (ind_fd = _create_indfile (isfname)) == -1) {
_amseterrcode(errcode, errno);
goto ERROR;
}
/*
* If the ISAM file is for variable length records, create .var file.
*/
if (crvar && (var_fd = _create_varfile (isfname)) == -1) {
_amseterrcode(errcode, errno);
goto ERROR;
}
/*
* Change user and group onwer ship of the file.
* This has affect only when executed by the netisamd daemon.
*/
if (dat_fd != -1)
(void) fchown(dat_fd, owner, group);
if (ind_fd != -1)
(void) fchown(ind_fd, owner, group);
if (var_fd != -1)
(void) fchown(var_fd, owner, group);
/*
* Allocate File Control Block.
*/
fcb = (Fcb *) _ismalloc(sizeof(*fcb));
memset ((char *) fcb, 0, sizeof(*fcb));
fcb->isfname = _isallocstring(isfname);
fcb->rdonly = FALSE;
fcb->datfd = dat_fd;
fcb->indfd = ind_fd;
fcb->varfd = var_fd;
fcb->datsize = N_CNTL_PAGES; /* Control Pages */
fcb->indfreelist = FREELIST_NOPAGE;
/* Key descriptor */
fcb->nkeys = 1;
fcb->keys = (Keydesc2 *) _ismalloc(sizeof(fcb->keys[0]));
memset((char *)fcb->keys, 0, sizeof(fcb->keys[0]));
return (fcb);
ERROR:
/* Undo whatever was done. */
if (dat_fd != -1) {
(void) close(dat_fd);
_remove_datfile(isfname);
}
if (ind_fd != -1) {
(void) close(ind_fd);
_remove_indfile(isfname);
}
if (var_fd != -1) {
(void) close(var_fd);
_remove_varfile(isfname);
}
(void) umask(oldumask);
return (NULL);
}
/*
* _isfcb_setlength(fcb, varflag, minreclen, maxreclen)
*
* Set FCB attributes pertaining to record length.
*/
void
_isfcb_setreclength(Fcb *fcb, Bool varflag, int minreclen, int maxreclen)
{
fcb->varflag = varflag;
fcb->minreclen = minreclen;
fcb->maxreclen = maxreclen;
}
/*
* _isfcb_open(isfname, errcode)
*
* Open ISAM file: open UNIX files and create File Control Block.
*
* Return 0 if open is successful, or -1 if any error. In the case of an error,
* the errcode block is set.
*
* Note that rdonly is not fuly implemented. Now, all ISAM files are assumed
* to have permissions set to 0666 and may be opened in RW mode.
* If read-only media are used then the _open_datfile() function would have to
* try first to open the file in RW mode, and of that failed, try to
* open it in RO mode. The rdonly flag is used to reject any isamopen() with
* INOUT or OUTPUT mode on such files.
*/
Fcb *
_isfcb_open(char *isfname, struct errcode *errcode)
{
Fcb *fcb;
int dat_fd = -1;
int ind_fd = -1;
int var_fd = -1;
Bool rdonly; /* set to 1 if file is Read-Only */
/*
* Open the UNIX file for .rec file.
*/
if ((dat_fd = _open_datfile (isfname, &rdonly)) == -1 || errno == EMFILE) {
_amseterrcode(errcode, errno);
if(dat_fd != -1) {
close(dat_fd);
}
return (NULL);
}
/*
* Open .ind file.
*/
ind_fd = _open_indfile (isfname, rdonly);
/*
* Open .var file.
*/
var_fd = _open_varfile (isfname, rdonly);
/*
* Allocate File Control Block.
*/
fcb = (Fcb *) _ismalloc(sizeof(*fcb));
memset ((char *) fcb, 0, sizeof(*fcb));
fcb->isfname = _isallocstring(isfname);
fcb->rdonly = rdonly;
fcb->datfd = dat_fd;
fcb->indfd = ind_fd;
fcb->varfd = var_fd;
/* Key descriptor */
fcb->nkeys = 1;
fcb->keys = (Keydesc2 *) _ismalloc(sizeof(fcb->keys[0]));
memset((char *)fcb->keys, 0, sizeof(fcb->keys[0]));
return (fcb);
}
/*
* _isfcb_nfds(fcb)
*
* Return the number of UNIX fd consumed by the fcb block.
*/
int
_isfcb_nfds(Fcb *fcb)
{
int count = 0;
if (fcb->datfd != -1)
count++;
if (fcb->indfd != -1)
count++;
if (fcb->varfd != -1)
count++;
return (count);
}
/*
* _isfcb_remove(fcb)
*
* Remove UNIX files associated with an FCB.
*/
void
_isfcb_remove(Fcb *fcb)
{
if (fcb->datfd)
_remove_datfile(fcb->isfname);
if (fcb->indfd)
_remove_indfile(fcb->isfname);
if (fcb->varfd)
_remove_varfile(fcb->isfname);
}
/*
* _isfcb_close(fcb)
*
* Close UNIX files associated with an FCB, deallocate the FCB block.
*/
void
_isfcb_close(Fcb *fcb)
{
assert (fcb != NULL);
assert (fcb->isfname != NULL);
(void) close(fcb->datfd);
(void) close(fcb->indfd);
(void) close(fcb->varfd);
_isfreestring(fcb->isfname);
free((char *)fcb->keys);
free((char *)fcb);
}
/*
* _isfcb_cntlpg_w(fcb)
*
* Write information from the control block to the disk.
* Note that the Control Page transfer bypasses the disk buffer manager.
*
* Return 0 if write was successful, return -1 if any error.
*/
int
_isfcb_cntlpg_w(Fcb *fcb)
{
char cntl_page[ISCNTLSIZE];
int dat_fd = fcb->datfd;
int i;
/* Clear the page. */
memset (cntl_page, 0, sizeof(cntl_page));
/* Set Magic number. */
(void)strcpy(cntl_page + CP_MAGIC_OFF, ISMAGIC);
/* Set Block size */
stshort(ISPAGESIZE, cntl_page + CP_BLOCKSIZE_OFF);
/* Set NetISAM version stamp. */
(void)strcpy(cntl_page + CP_VERSION_OFF, ISVERSION);
/* .rec file size in blocks. */
stlong((long)fcb->datsize, cntl_page + CP_DATSIZE_OFF);
/* .ind file size in blocks. */
stlong((long)fcb->indsize, cntl_page + CP_INDSIZE_OFF);
/* .var file size in blocks. */
stlong((long)fcb->varsize, cntl_page + CP_VARSIZE_OFF);
/* Variable length 0/1 flag. */
stshort((short)fcb->varflag, cntl_page + CP_VARFLAG_OFF);
/* Number of records. */
stlong((long)fcb->nrecords, cntl_page + CP_NRECORDS_OFF);
/* Minimum and maximum record length. */
stshort((short)fcb->minreclen, cntl_page + CP_MINRECLEN_OFF);
stshort((short)fcb->maxreclen, cntl_page + CP_MAXRECLEN_OFF);
/* Last record number. */
strecno(fcb->lastrecno, cntl_page + CP_LASTRECNO_OFF);
/* Free record number. */
strecno(fcb->freerecno, cntl_page + CP_FREERECNO_OFF);
/* Number of keys */
stshort((short)fcb->nkeys, cntl_page + CP_NKEYS_OFF);
/* Last key id */
stlong((long)fcb->lastkeyid, cntl_page + CP_LASTKEYID_OFF);
/* ind. free list head */
stlong((long)fcb->indfreelist, cntl_page + CP_INDFREELIST_OFF);
/* offset of the end of .var file */
stlong((long)fcb->varend, cntl_page + CP_VAREND_OFF);
/* Key descriptors. */
for (i = 0; i < fcb->nkeys; i++) {
stkey(fcb->keys + i, cntl_page + CP_KEYS_OFF + i * K2_LEN);
}
/* Increment stamp1 and stamp2 to indicate change in the Control Page. */
fcb->changestamp1++;
fcb->changestamp2++;
stlong((long)fcb->changestamp1, cntl_page + CP_CHANGESTAMP1_OFF);
stlong((long)fcb->changestamp2, cntl_page + CP_CHANGESTAMP2_OFF);
/*
* Write the buffer to the disk.
*/
_isseekpg(dat_fd, ISCNTLPGOFF);
_iswritepg(dat_fd, cntl_page);
_iswritepg(dat_fd, cntl_page + ISPAGESIZE);
return (ISOK);
}
/*
* _isfcb_cntlpg_w2(fcb)
*
* Write information from the control block to the disk.
* Write only selected fields of the control block to avoid the overhead
* of coding and decoding.
* Note that the Control Page transfer bypasses the disk buffer manager.
*
* Return 0 if write was successful, return -1 if any error.
*/
int
_isfcb_cntlpg_w2(Fcb *fcb)
{
char cntl_page[CP_VAREND_OFF+CP_VAREND_LEN];
int dat_fd = fcb->datfd;
/*
* Read the page from disk.
*/
_isseekpg(dat_fd, ISCNTLPGOFF);
(void)read(dat_fd, cntl_page, sizeof(cntl_page));
/* .rec file size in blocks. */
stlong((long)fcb->datsize, cntl_page + CP_DATSIZE_OFF);
/* .ind file size in blocks. */
stlong((long)fcb->indsize, cntl_page + CP_INDSIZE_OFF);
/* .var file size in blocks. */
stlong((long)fcb->varsize, cntl_page + CP_VARSIZE_OFF);
/* Number of records. */
stlong((long)fcb->nrecords, cntl_page + CP_NRECORDS_OFF);
/* Last record number. */
strecno(fcb->lastrecno, cntl_page + CP_LASTRECNO_OFF);
/* Free record number. */
strecno(fcb->freerecno, cntl_page + CP_FREERECNO_OFF);
/* ind. free list head */
stlong((long)fcb->indfreelist, cntl_page + CP_INDFREELIST_OFF);
/* end of .var file */
stlong((long)fcb->varend, cntl_page + CP_VAREND_OFF);
/* Increment stamp2 to indicate change in the Control Page. */
fcb->changestamp2++;
stlong((long)fcb->changestamp2, cntl_page + CP_CHANGESTAMP2_OFF);
/*
* Write the buffer to the disk.
*/
_isseekpg(dat_fd, ISCNTLPGOFF);
(void)write(dat_fd, cntl_page, sizeof(cntl_page));
return (ISOK);
}
/*
* _isfcb_cntlpg_r(fcb)
*
* Read information from control page and store it in the FCB.
* Note that the Control Page transfer bypasses the disk buffer manager.
*
* Return 0 if read was successful, return -1 if any error.
*/
int
_isfcb_cntlpg_r(Fcb *fcb)
{
char cntl_page[ISCNTLSIZE];
int dat_fd = fcb->datfd;
int i;
/*
* Read the page from the disk.
*/
_isseekpg(dat_fd, ISCNTLPGOFF);
_isreadpg(dat_fd, cntl_page);
_isreadpg(dat_fd, cntl_page + ISPAGESIZE);
/* block size */
fcb->blocksize = ldshort(cntl_page + CP_BLOCKSIZE_OFF);
/* .rec file size in blocks. */
fcb->datsize = ldlong(cntl_page + CP_DATSIZE_OFF);
/* .ind file size in blocks. */
fcb->indsize = ldlong(cntl_page + CP_INDSIZE_OFF);
/* .var file size in blocks. */
fcb->varsize = ldlong(cntl_page + CP_VARSIZE_OFF);
/* Variable length 0/1 flag. */
fcb->varflag = (Bool)ldshort(cntl_page + CP_VARFLAG_OFF);
/* Number of records. */
fcb->nrecords = ldlong(cntl_page + CP_NRECORDS_OFF);
/* Minimum and maximum record length. */
fcb->minreclen = ldunshort(cntl_page + CP_MINRECLEN_OFF);
fcb->maxreclen = ldunshort(cntl_page + CP_MAXRECLEN_OFF);
/* Last record number. */
fcb->lastrecno = ldrecno(cntl_page + CP_LASTRECNO_OFF);
/* Free record number. */
fcb->freerecno = ldrecno(cntl_page + CP_FREERECNO_OFF);
/* Last key id */
fcb->lastkeyid = ldlong(cntl_page + CP_LASTKEYID_OFF);
/* .ind free list head. */
fcb->indfreelist = ldlong(cntl_page + CP_INDFREELIST_OFF);
/* end of .var file */
fcb->varend = ldlong(cntl_page + CP_VAREND_OFF);
/* Number of keys */
fcb->nkeys = ldshort(cntl_page + CP_NKEYS_OFF);
/*
* Read key descriptors.
*/
fcb->keys = (Keydesc2 *)
_isrealloc((char *)fcb->keys,
(unsigned) (sizeof(Keydesc2) * fcb->nkeys));
memset((char *)fcb->keys, 0, sizeof(Keydesc2) * fcb->nkeys);
for (i = 0; i < fcb->nkeys; i++) {
ldkey(fcb->keys + i, cntl_page + CP_KEYS_OFF + i * K2_LEN);
}
/* Changestamp1 */
fcb->changestamp1 = ldlong(cntl_page + CP_CHANGESTAMP1_OFF);
/* Changestamp2 */
fcb->changestamp2 = ldlong(cntl_page + CP_CHANGESTAMP2_OFF);
/*
* Open .ind file in situations when some other process has created
* keys and this process has just learned it now.
*/
if (fcb->nkeys > 1 || !FCB_NOPRIMARY_KEY(fcb)) {
/*
if (_open2_indfile(fcb) != ISOK)
_isfatal_error("_open2_indfile()");
*/
(void)_open2_indfile(fcb);
}
return (ISOK);
}
/*
* _isfcb_cntlpg_r2(fcb)
*
* Read information from the control block on the disk.
* Read only selected fields of the control block to avoid the overhead
* of coding and decoding.
* Note that the Control Page transfer bypasses the disk buffer manager.
*
* Return 0 if write was successful, return -1 if any error.
*/
int
_isfcb_cntlpg_r2(Fcb *fcb)
{
char cntl_page[CP_VAREND_OFF+CP_VAREND_LEN];
int dat_fd = fcb->datfd;
/*
* Read the page from disk.
*/
_isseekpg(dat_fd, ISCNTLPGOFF);
(void)read(dat_fd, cntl_page, sizeof(cntl_page));
/*
* Check changestamp1. If the stamp has changed, we must read the entire
* page and update the FCB.
*/
if (ldlong(cntl_page + CP_CHANGESTAMP1_OFF) != fcb->changestamp1) {
(void)_isfcb_cntlpg_r(fcb);
}
/*
*_isfcb_cntlpg_r2() is called if transaction is rolled back.
* We cannot test changestamp2; we must read the info into the FCB
* always.
*/
#if 0
/*
* Check changestamp2. If the stamp has not changed, the FCB contains
* up-to-date information.
*/
if (ldlong(cntl_page + CP_CHANGESTAMP2_OFF) == fcb->changestamp2) {
return (ISOK);
}
#endif
/* .rec file size in blocks. */
fcb->datsize = ldlong(cntl_page + CP_DATSIZE_OFF);
/* .ind file size in blocks. */
fcb->indsize = ldlong(cntl_page + CP_INDSIZE_OFF);
/* .var file size in blocks. */
fcb->varsize = ldlong(cntl_page + CP_VARSIZE_OFF);
/* Number of records. */
fcb->nrecords = ldlong(cntl_page + CP_NRECORDS_OFF);
/* Last record number. */
fcb->lastrecno = ldrecno(cntl_page + CP_LASTRECNO_OFF);
/* Free record number. */
fcb->freerecno = ldrecno(cntl_page + CP_FREERECNO_OFF);
/* .ind free list head. */
fcb->indfreelist = ldlong(cntl_page + CP_INDFREELIST_OFF);
/* end of .var file */
fcb->varend = ldlong(cntl_page + CP_VAREND_OFF);
/* Changestamp2 */
fcb->changestamp2 = ldlong(cntl_page + CP_CHANGESTAMP2_OFF);
return (ISOK);
}
/*
* _create_datfile(isfname)
*
* Create .rec file for ISAM file isfname.
*/
Static int
_create_datfile(char *isfname)
{
int fd;
char namebuf[MAXPATHLEN];
snprintf(namebuf, sizeof(namebuf), "%s", isfname);
_makedat_isfname(namebuf);
fd = open (namebuf, O_CREAT | O_EXCL | O_RDWR, 0666);
if (fd > -1) {
/* Close on exec */
if(fcntl(fd, F_SETFD, 1) == -1) {
close(fd);
return(-1);
}
}
return (fd);
}
/*
* _create_indfile(isfname)
*
* Create .ind file for ISAM file isfname.
*/
Static int
_create_indfile(char *isfname)
{
int fd;
char namebuf[MAXPATHLEN];
snprintf(namebuf, sizeof(namebuf), "%s", isfname);
_makeind_isfname(namebuf);
fd = open (namebuf, O_CREAT | O_EXCL | O_RDWR, 0666);
if (fd > -1) {
/* Close on exec */
if(fcntl(fd, F_SETFD, 1) == -1) {
close(fd);
return(-1);
}
}
return (fd);
}
/*
* _create_varfile(isfname)
*
* Create .var file for ISAM file isfname.
*/
Static int
_create_varfile(char *isfname)
{
int fd;
char namebuf[MAXPATHLEN];
snprintf(namebuf, sizeof(namebuf), "%s", isfname);
_makevar_isfname(namebuf);
fd = open (namebuf, O_CREAT | O_EXCL | O_RDWR, 0666);
if (fd > -1) {
/* Close on exec */
if(fcntl(fd, F_SETFD, 1) == -1) {
close(fd);
return(-1);
}
}
return (fd);
}
/*
* _remove_datfile(isfname)
*
* Remove .rec file for ISAM file isfname.
*/
Static void
_remove_datfile(char *isfname)
{
char namebuf[MAXPATHLEN];
snprintf(namebuf, sizeof(namebuf), "%s", isfname);
_makedat_isfname(namebuf);
(void) unlink(namebuf);
}
/*
* _remove_indfile(isfname)
*
* Remove .ind file for ISAM file isfname.
*/
Static void
_remove_indfile(char *isfname)
{
char namebuf[MAXPATHLEN];
snprintf(namebuf, sizeof(namebuf), "%s", isfname);
_makeind_isfname(namebuf);
(void) unlink(namebuf);
}
/*
* _remove_varfile(isfname)
*
* Remove .var file for ISAM file isfname.
*/
Static void
_remove_varfile(char *isfname)
{
char namebuf[MAXPATHLEN];
snprintf(namebuf, sizeof(namebuf), "%s", isfname);
_makevar_isfname(namebuf);
(void) unlink(namebuf);
}
/*
* _open_datfile(isfname)
*
* Open .rec file for ISAM file isfname.
*/
Static int
_open_datfile(char *isfname, Bool *rdonly)
{
char namebuf[MAXPATHLEN];
int ret;
snprintf(namebuf, sizeof(namebuf), "%s", isfname);
_makedat_isfname(namebuf);
if ((ret = open (namebuf, O_RDWR)) != -1) {
*rdonly = FALSE;
/* Close on exec */
if(fcntl(ret, F_SETFD, 1) == -1) {
close(ret);
ret = -1;
}
return (ret);
}
*rdonly = TRUE;
ret = open (namebuf, O_RDONLY);
if (ret > -1) {
/* Close on exec */
if(fcntl(ret, F_SETFD, 1) == -1) {
close(ret);
return(-1);
}
}
return (ret);
}
/*
* _open_indfile(isfname)
*
* Open .ind file for ISAM file isfname.
*/
Static int
_open_indfile(char *isfname, Bool rdonly)
{
int fd;
char namebuf[MAXPATHLEN];
snprintf(namebuf, sizeof(namebuf), "%s", isfname);
_makeind_isfname(namebuf);
fd = open (namebuf, (rdonly==TRUE)?O_RDONLY:O_RDWR);
if (fd > -1) {
/* Close on exec */
if(fcntl(fd, F_SETFD, 1) == -1) {
close(fd);
return(-1);
}
}
return (fd);
}
/*
* _open_varfile(isfname)
*
* Open .var file for ISAM file isfname.
*/
Static int
_open_varfile(char *isfname, Bool rdonly)
{
int fd;
char namebuf[MAXPATHLEN];
snprintf(namebuf, sizeof(namebuf), "%s", isfname);
_makevar_isfname(namebuf);
fd = open (namebuf, (rdonly==TRUE)?O_RDONLY:O_RDWR);
if (fd > -1) {
/* Close on exec */
if(fcntl(fd, F_SETFD, 1) == -1) {
close(fd);
return(-1);
}
}
return (fd);
}
int
_check_isam_magic(Fcb *fcb)
{
char magicbuffer[CP_MAGIC_LEN];
(void)lseek(fcb->datfd, 0L, 0);
if ((read(fcb->datfd, magicbuffer, CP_MAGIC_LEN) < CP_MAGIC_LEN) ||
/* The following test for compatibilty with `SunISAM 1.0 Beta files. */
((strncmp(magicbuffer, "SunISAM", strlen(ISMAGIC)) != 0) &&
(strncmp(magicbuffer, ISMAGIC, strlen(ISMAGIC))) != 0)) {
return ISERROR;
}
else
return ISOK;
}
/*
* _open2_indfile(fcb)
*
* Open (or create) .ind file for ISAM file if the .ind file
* is not open already (or does not exist).
*/
int
_open2_indfile(Fcb *fcb)
{
char namebuf[MAXPATHLEN];
struct stat buf;
int openmode;
if (fcb->indfd != -1)
return (ISOK);
snprintf(namebuf, sizeof(namebuf), "%s", fcb->isfname);
_makeind_isfname(namebuf);
(void)fstat(fcb->datfd, &buf);
openmode = (fcb->rdonly) ? O_RDONLY : O_RDWR;
if (fcb->indsize == 0)
openmode |= O_CREAT;
fcb->indfd = open(namebuf, openmode, buf.st_mode);
if (fcb->indfd > -1) {
/* Close on exec */
if(fcntl(fcb->indfd, F_SETFD, 1) == -1) {
close(fcb->indfd);
fcb->indfd = -1;
}
}
if(fcb->indfd == -1 && (openmode & O_CREAT)) {
_isfatal_error("Cannot create .ind file");
}
if (fcb->indfd != -1) {
(void) _watchfd_incr(1);
(void)fchown(fcb->indfd, buf.st_uid, buf.st_gid);
}
return ((fcb->indfd == -1) ? ISERROR : ISOK);
}