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: isfcb.c /main/3 1995/10/23 11:38:34 rswiston $ */
29 static char sccsid[] = "@(#)isfcb.c 1.9 89/07/17 Copyr 1988 Sun Micro";
32 * Copyright (c) 1988 by Sun Microsystems, Inc.
38 * Description: _ambuild()
39 * File Control Block functions
44 #include "isam_impl.h"
47 static int _create_datfile(), _create_indfile(), _create_varfile();
48 static void _remove_datfile(), _remove_indfile(), _remove_varfile();
49 Static int _open_datfile(), _open_indfile(), _open_varfile();
52 * _isfcb_create(isfname, crdat, crind, crvar, owner, group, u_mask, errcode)
54 * Create ISAM file: create UNIX files (dat/ind/var),
55 * and initialize File Control Block.
57 * Return 0 if create is successful, or -1 if any error. In the case of
58 *an error, the errcode block is set.
66 _isfcb_create(char *isfname, int crdat, int crind, int crvar,
67 int owner, int group, int u_mask, struct errcode *errcode)
73 int oldumask = umask (u_mask); /* Change umask to client's */
76 * Create the UNIX file for .rec file.
78 if (crdat && (dat_fd = _create_datfile (isfname)) == -1) {
79 _amseterrcode(errcode, errno);
84 * If a primary is specified, create .ind file.
86 if (crind && (ind_fd = _create_indfile (isfname)) == -1) {
87 _amseterrcode(errcode, errno);
92 * If the ISAM file is for variable length records, create .var file.
94 if (crvar && (var_fd = _create_varfile (isfname)) == -1) {
95 _amseterrcode(errcode, errno);
100 * Change user and group onwer ship of the file.
101 * This has affect only when executed by the netisamd daemon.
104 (void) fchown(dat_fd, owner, group);
106 (void) fchown(ind_fd, owner, group);
108 (void) fchown(var_fd, owner, group);
111 * Allocate File Control Block.
113 fcb = (Fcb *) _ismalloc(sizeof(*fcb));
114 memset ((char *) fcb, 0, sizeof(*fcb));
116 fcb->isfname = _isallocstring(isfname);
122 fcb->datsize = N_CNTL_PAGES; /* Control Pages */
123 fcb->indfreelist = FREELIST_NOPAGE;
127 fcb->keys = (Keydesc2 *) _ismalloc(sizeof(fcb->keys[0]));
128 memset((char *)fcb->keys, 0, sizeof(fcb->keys[0]));
133 /* Undo whatever was done. */
135 (void) close(dat_fd);
136 _remove_datfile(isfname);
139 (void) close(ind_fd);
140 _remove_indfile(isfname);
143 (void) close(var_fd);
144 _remove_varfile(isfname);
147 (void) umask(oldumask);
153 * _isfcb_setlength(fcb, varflag, minreclen, maxreclen)
155 * Set FCB attributes pertaining to record length.
159 _isfcb_setreclength(Fcb *fcb, Bool varflag, int minreclen, int maxreclen)
161 fcb->varflag = varflag;
162 fcb->minreclen = minreclen;
163 fcb->maxreclen = maxreclen;
167 * _isfcb_open(isfname, errcode)
169 * Open ISAM file: open UNIX files and create File Control Block.
171 * Return 0 if open is successful, or -1 if any error. In the case of an error,
172 * the errcode block is set.
174 * Note that rdonly is not fuly implemented. Now, all ISAM files are assumed
175 * to have permissions set to 0666 and may be opened in RW mode.
176 * If read-only media are used then the _open_datfile() function would have to
177 * try first to open the file in RW mode, and of that failed, try to
178 * open it in RO mode. The rdonly flag is used to reject any isamopen() with
179 * INOUT or OUTPUT mode on such files.
183 _isfcb_open(char *isfname, struct errcode *errcode)
189 Bool rdonly; /* set to 1 if file is Read-Only */
192 * Open the UNIX file for .rec file.
194 if ((dat_fd = _open_datfile (isfname, &rdonly)) == -1 || errno == EMFILE) {
195 _amseterrcode(errcode, errno);
205 ind_fd = _open_indfile (isfname, rdonly);
210 var_fd = _open_varfile (isfname, rdonly);
214 * Allocate File Control Block.
216 fcb = (Fcb *) _ismalloc(sizeof(*fcb));
217 memset ((char *) fcb, 0, sizeof(*fcb));
219 fcb->isfname = _isallocstring(isfname);
220 fcb->rdonly = rdonly;
227 fcb->keys = (Keydesc2 *) _ismalloc(sizeof(fcb->keys[0]));
228 memset((char *)fcb->keys, 0, sizeof(fcb->keys[0]));
236 * Return the number of UNIX fd consumed by the fcb block.
240 _isfcb_nfds(Fcb *fcb)
244 if (fcb->datfd != -1)
247 if (fcb->indfd != -1)
250 if (fcb->varfd != -1)
260 * Remove UNIX files associated with an FCB.
264 _isfcb_remove(Fcb *fcb)
267 _remove_datfile(fcb->isfname);
270 _remove_indfile(fcb->isfname);
273 _remove_varfile(fcb->isfname);
279 * Close UNIX files associated with an FCB, deallocate the FCB block.
283 _isfcb_close(Fcb *fcb)
285 assert (fcb != NULL);
286 assert (fcb->isfname != NULL);
288 (void) close(fcb->datfd);
289 (void) close(fcb->indfd);
290 (void) close(fcb->varfd);
292 _isfreestring(fcb->isfname);
293 free((char *)fcb->keys);
298 * _isfcb_cntlpg_w(fcb)
300 * Write information from the control block to the disk.
301 * Note that the Control Page transfer bypasses the disk buffer manager.
303 * Return 0 if write was successful, return -1 if any error.
307 _isfcb_cntlpg_w(Fcb *fcb)
309 char cntl_page[ISCNTLSIZE];
310 int dat_fd = fcb->datfd;
313 /* Clear the page. */
314 memset (cntl_page, 0, sizeof(cntl_page));
316 /* Set Magic number. */
317 (void)strcpy(cntl_page + CP_MAGIC_OFF, ISMAGIC);
320 stshort(ISPAGESIZE, cntl_page + CP_BLOCKSIZE_OFF);
322 /* Set NetISAM version stamp. */
323 (void)strcpy(cntl_page + CP_VERSION_OFF, ISVERSION);
325 /* .rec file size in blocks. */
326 stlong((long)fcb->datsize, cntl_page + CP_DATSIZE_OFF);
328 /* .ind file size in blocks. */
329 stlong((long)fcb->indsize, cntl_page + CP_INDSIZE_OFF);
331 /* .var file size in blocks. */
332 stlong((long)fcb->varsize, cntl_page + CP_VARSIZE_OFF);
334 /* Variable length 0/1 flag. */
335 stshort((short)fcb->varflag, cntl_page + CP_VARFLAG_OFF);
337 /* Number of records. */
338 stlong((long)fcb->nrecords, cntl_page + CP_NRECORDS_OFF);
340 /* Minimum and maximum record length. */
341 stshort((short)fcb->minreclen, cntl_page + CP_MINRECLEN_OFF);
342 stshort((short)fcb->maxreclen, cntl_page + CP_MAXRECLEN_OFF);
344 /* Last record number. */
345 strecno(fcb->lastrecno, cntl_page + CP_LASTRECNO_OFF);
347 /* Free record number. */
348 strecno(fcb->freerecno, cntl_page + CP_FREERECNO_OFF);
351 stshort((short)fcb->nkeys, cntl_page + CP_NKEYS_OFF);
354 stlong((long)fcb->lastkeyid, cntl_page + CP_LASTKEYID_OFF);
356 /* ind. free list head */
357 stlong((long)fcb->indfreelist, cntl_page + CP_INDFREELIST_OFF);
359 /* offset of the end of .var file */
360 stlong((long)fcb->varend, cntl_page + CP_VAREND_OFF);
362 /* Key descriptors. */
363 for (i = 0; i < fcb->nkeys; i++) {
364 stkey(fcb->keys + i, cntl_page + CP_KEYS_OFF + i * K2_LEN);
367 /* Increment stamp1 and stamp2 to indicate change in the Control Page. */
371 stlong((long)fcb->changestamp1, cntl_page + CP_CHANGESTAMP1_OFF);
372 stlong((long)fcb->changestamp2, cntl_page + CP_CHANGESTAMP2_OFF);
375 * Write the buffer to the disk.
377 _isseekpg(dat_fd, ISCNTLPGOFF);
378 _iswritepg(dat_fd, cntl_page);
379 _iswritepg(dat_fd, cntl_page + ISPAGESIZE);
385 * _isfcb_cntlpg_w2(fcb)
387 * Write information from the control block to the disk.
388 * Write only selected fields of the control block to avoid the overhead
389 * of coding and decoding.
390 * Note that the Control Page transfer bypasses the disk buffer manager.
392 * Return 0 if write was successful, return -1 if any error.
396 _isfcb_cntlpg_w2(Fcb *fcb)
398 char cntl_page[CP_VAREND_OFF+CP_VAREND_LEN];
399 int dat_fd = fcb->datfd;
402 * Read the page from disk.
404 _isseekpg(dat_fd, ISCNTLPGOFF);
405 (void)read(dat_fd, cntl_page, sizeof(cntl_page));
407 /* .rec file size in blocks. */
408 stlong((long)fcb->datsize, cntl_page + CP_DATSIZE_OFF);
410 /* .ind file size in blocks. */
411 stlong((long)fcb->indsize, cntl_page + CP_INDSIZE_OFF);
413 /* .var file size in blocks. */
414 stlong((long)fcb->varsize, cntl_page + CP_VARSIZE_OFF);
416 /* Number of records. */
417 stlong((long)fcb->nrecords, cntl_page + CP_NRECORDS_OFF);
419 /* Last record number. */
420 strecno(fcb->lastrecno, cntl_page + CP_LASTRECNO_OFF);
422 /* Free record number. */
423 strecno(fcb->freerecno, cntl_page + CP_FREERECNO_OFF);
425 /* ind. free list head */
426 stlong((long)fcb->indfreelist, cntl_page + CP_INDFREELIST_OFF);
428 /* end of .var file */
429 stlong((long)fcb->varend, cntl_page + CP_VAREND_OFF);
431 /* Increment stamp2 to indicate change in the Control Page. */
433 stlong((long)fcb->changestamp2, cntl_page + CP_CHANGESTAMP2_OFF);
437 * Write the buffer to the disk.
439 _isseekpg(dat_fd, ISCNTLPGOFF);
440 (void)write(dat_fd, cntl_page, sizeof(cntl_page));
446 * _isfcb_cntlpg_r(fcb)
448 * Read information from control page and store it in the FCB.
449 * Note that the Control Page transfer bypasses the disk buffer manager.
451 * Return 0 if read was successful, return -1 if any error.
455 _isfcb_cntlpg_r(Fcb *fcb)
457 char cntl_page[ISCNTLSIZE];
458 int dat_fd = fcb->datfd;
462 * Read the page from the disk.
464 _isseekpg(dat_fd, ISCNTLPGOFF);
465 _isreadpg(dat_fd, cntl_page);
466 _isreadpg(dat_fd, cntl_page + ISPAGESIZE);
469 fcb->blocksize = ldshort(cntl_page + CP_BLOCKSIZE_OFF);
471 /* .rec file size in blocks. */
472 fcb->datsize = ldlong(cntl_page + CP_DATSIZE_OFF);
474 /* .ind file size in blocks. */
475 fcb->indsize = ldlong(cntl_page + CP_INDSIZE_OFF);
477 /* .var file size in blocks. */
478 fcb->varsize = ldlong(cntl_page + CP_VARSIZE_OFF);
480 /* Variable length 0/1 flag. */
481 fcb->varflag = (Bool)ldshort(cntl_page + CP_VARFLAG_OFF);
483 /* Number of records. */
484 fcb->nrecords = ldlong(cntl_page + CP_NRECORDS_OFF);
486 /* Minimum and maximum record length. */
487 fcb->minreclen = ldunshort(cntl_page + CP_MINRECLEN_OFF);
488 fcb->maxreclen = ldunshort(cntl_page + CP_MAXRECLEN_OFF);
490 /* Last record number. */
491 fcb->lastrecno = ldrecno(cntl_page + CP_LASTRECNO_OFF);
493 /* Free record number. */
494 fcb->freerecno = ldrecno(cntl_page + CP_FREERECNO_OFF);
497 fcb->lastkeyid = ldlong(cntl_page + CP_LASTKEYID_OFF);
499 /* .ind free list head. */
500 fcb->indfreelist = ldlong(cntl_page + CP_INDFREELIST_OFF);
502 /* end of .var file */
503 fcb->varend = ldlong(cntl_page + CP_VAREND_OFF);
506 fcb->nkeys = ldshort(cntl_page + CP_NKEYS_OFF);
509 * Read key descriptors.
511 fcb->keys = (Keydesc2 *)
512 _isrealloc((char *)fcb->keys,
513 (unsigned) (sizeof(Keydesc2) * fcb->nkeys));
514 memset((char *)fcb->keys, 0, sizeof(Keydesc2) * fcb->nkeys);
516 for (i = 0; i < fcb->nkeys; i++) {
517 ldkey(fcb->keys + i, cntl_page + CP_KEYS_OFF + i * K2_LEN);
521 fcb->changestamp1 = ldlong(cntl_page + CP_CHANGESTAMP1_OFF);
524 fcb->changestamp2 = ldlong(cntl_page + CP_CHANGESTAMP2_OFF);
527 * Open .ind file in situations when some other process has created
528 * keys and this process has just learned it now.
530 if (fcb->nkeys > 1 || !FCB_NOPRIMARY_KEY(fcb)) {
532 if (_open2_indfile(fcb) != ISOK)
533 _isfatal_error("_open2_indfile()");
535 (void)_open2_indfile(fcb);
544 * _isfcb_cntlpg_r2(fcb)
546 * Read information from the control block on the disk.
547 * Read only selected fields of the control block to avoid the overhead
548 * of coding and decoding.
549 * Note that the Control Page transfer bypasses the disk buffer manager.
551 * Return 0 if write was successful, return -1 if any error.
555 _isfcb_cntlpg_r2(Fcb *fcb)
557 char cntl_page[CP_VAREND_OFF+CP_VAREND_LEN];
558 int dat_fd = fcb->datfd;
561 * Read the page from disk.
563 _isseekpg(dat_fd, ISCNTLPGOFF);
564 (void)read(dat_fd, cntl_page, sizeof(cntl_page));
567 * Check changestamp1. If the stamp has changed, we must read the entire
568 * page and update the FCB.
570 if (ldlong(cntl_page + CP_CHANGESTAMP1_OFF) != fcb->changestamp1) {
571 (void)_isfcb_cntlpg_r(fcb);
575 *_isfcb_cntlpg_r2() is called if transaction is rolled back.
576 * We cannot test changestamp2; we must read the info into the FCB
582 * Check changestamp2. If the stamp has not changed, the FCB contains
583 * up-to-date information.
585 if (ldlong(cntl_page + CP_CHANGESTAMP2_OFF) == fcb->changestamp2) {
590 /* .rec file size in blocks. */
591 fcb->datsize = ldlong(cntl_page + CP_DATSIZE_OFF);
593 /* .ind file size in blocks. */
594 fcb->indsize = ldlong(cntl_page + CP_INDSIZE_OFF);
596 /* .var file size in blocks. */
597 fcb->varsize = ldlong(cntl_page + CP_VARSIZE_OFF);
599 /* Number of records. */
600 fcb->nrecords = ldlong(cntl_page + CP_NRECORDS_OFF);
602 /* Last record number. */
603 fcb->lastrecno = ldrecno(cntl_page + CP_LASTRECNO_OFF);
605 /* Free record number. */
606 fcb->freerecno = ldrecno(cntl_page + CP_FREERECNO_OFF);
608 /* .ind free list head. */
609 fcb->indfreelist = ldlong(cntl_page + CP_INDFREELIST_OFF);
611 /* end of .var file */
612 fcb->varend = ldlong(cntl_page + CP_VAREND_OFF);
615 fcb->changestamp2 = ldlong(cntl_page + CP_CHANGESTAMP2_OFF);
622 * _create_datfile(isfname)
624 * Create .rec file for ISAM file isfname.
628 _create_datfile(char *isfname)
631 char namebuf[MAXPATHLEN];
633 snprintf(namebuf, sizeof(namebuf), "%s", isfname);
634 _makedat_isfname(namebuf);
636 fd = open (namebuf, O_CREAT | O_EXCL | O_RDWR, 0666);
639 if(fcntl(fd, F_SETFD, 1) == -1) {
648 * _create_indfile(isfname)
650 * Create .ind file for ISAM file isfname.
654 _create_indfile(char *isfname)
657 char namebuf[MAXPATHLEN];
659 snprintf(namebuf, sizeof(namebuf), "%s", isfname);
660 _makeind_isfname(namebuf);
662 fd = open (namebuf, O_CREAT | O_EXCL | O_RDWR, 0666);
665 if(fcntl(fd, F_SETFD, 1) == -1) {
674 * _create_varfile(isfname)
676 * Create .var file for ISAM file isfname.
680 _create_varfile(char *isfname)
683 char namebuf[MAXPATHLEN];
685 snprintf(namebuf, sizeof(namebuf), "%s", isfname);
686 _makevar_isfname(namebuf);
688 fd = open (namebuf, O_CREAT | O_EXCL | O_RDWR, 0666);
691 if(fcntl(fd, F_SETFD, 1) == -1) {
701 * _remove_datfile(isfname)
703 * Remove .rec file for ISAM file isfname.
707 _remove_datfile(char *isfname)
709 char namebuf[MAXPATHLEN];
711 snprintf(namebuf, sizeof(namebuf), "%s", isfname);
712 _makedat_isfname(namebuf);
714 (void) unlink(namebuf);
718 * _remove_indfile(isfname)
720 * Remove .ind file for ISAM file isfname.
724 _remove_indfile(char *isfname)
726 char namebuf[MAXPATHLEN];
728 snprintf(namebuf, sizeof(namebuf), "%s", isfname);
729 _makeind_isfname(namebuf);
731 (void) unlink(namebuf);
735 * _remove_varfile(isfname)
737 * Remove .var file for ISAM file isfname.
741 _remove_varfile(char *isfname)
743 char namebuf[MAXPATHLEN];
745 snprintf(namebuf, sizeof(namebuf), "%s", isfname);
746 _makevar_isfname(namebuf);
748 (void) unlink(namebuf);
753 * _open_datfile(isfname)
755 * Open .rec file for ISAM file isfname.
759 _open_datfile(char *isfname, Bool *rdonly)
761 char namebuf[MAXPATHLEN];
764 snprintf(namebuf, sizeof(namebuf), "%s", isfname);
765 _makedat_isfname(namebuf);
767 if ((ret = open (namebuf, O_RDWR)) != -1) {
770 if(fcntl(ret, F_SETFD, 1) == -1) {
778 ret = open (namebuf, O_RDONLY);
781 if(fcntl(ret, F_SETFD, 1) == -1) {
790 * _open_indfile(isfname)
792 * Open .ind file for ISAM file isfname.
796 _open_indfile(char *isfname, Bool rdonly)
799 char namebuf[MAXPATHLEN];
801 snprintf(namebuf, sizeof(namebuf), "%s", isfname);
802 _makeind_isfname(namebuf);
804 fd = open (namebuf, (rdonly==TRUE)?O_RDONLY:O_RDWR);
807 if(fcntl(fd, F_SETFD, 1) == -1) {
816 * _open_varfile(isfname)
818 * Open .var file for ISAM file isfname.
822 _open_varfile(char *isfname, Bool rdonly)
825 char namebuf[MAXPATHLEN];
827 snprintf(namebuf, sizeof(namebuf), "%s", isfname);
828 _makevar_isfname(namebuf);
830 fd = open (namebuf, (rdonly==TRUE)?O_RDONLY:O_RDWR);
833 if(fcntl(fd, F_SETFD, 1) == -1) {
842 _check_isam_magic(Fcb *fcb)
844 char magicbuffer[CP_MAGIC_LEN];
846 (void)lseek(fcb->datfd, 0L, 0);
847 if (read(fcb->datfd, magicbuffer, CP_MAGIC_LEN) < CP_MAGIC_LEN ||
848 /* The following test for compatibilty with `SunISAM 1.0 Beta files. */
849 strncmp(magicbuffer, "SunISAM", strlen(ISMAGIC)) != 0 &&
850 strncmp(magicbuffer, ISMAGIC, strlen(ISMAGIC)) != 0) {
859 * _open2_indfile(fcb)
861 * Open (or create) .ind file for ISAM file if the .ind file
862 * is not open already (or does not exist).
866 _open2_indfile(Fcb *fcb)
868 char namebuf[MAXPATHLEN];
872 if (fcb->indfd != -1)
875 snprintf(namebuf, sizeof(namebuf), "%s", fcb->isfname);
876 _makeind_isfname(namebuf);
878 (void)fstat(fcb->datfd, &buf);
880 openmode = (fcb->rdonly) ? O_RDONLY : O_RDWR;
882 if (fcb->indsize == 0)
885 fcb->indfd = open(namebuf, openmode, buf.st_mode);
886 if (fcb->indfd > -1) {
888 if(fcntl(fcb->indfd, F_SETFD, 1) == -1) {
894 if(fcb->indfd == -1 && (openmode & O_CREAT)) {
895 _isfatal_error("Cannot create .ind file");
898 if (fcb->indfd != -1) {
899 (void) _watchfd_incr(1);
900 (void)fchown(fcb->indfd, buf.st_uid, buf.st_gid);
903 return ((fcb->indfd == -1) ? ISERROR : ISOK);