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 * Copyright (c) 1988 by Sun Microsystems, Inc.
35 * Description: _ambuild()
36 * File Control Block functions
41 #include "isam_impl.h"
44 static int _create_datfile(), _create_indfile(), _create_varfile();
45 static void _remove_datfile(), _remove_indfile(), _remove_varfile();
46 Static int _open_datfile(), _open_indfile(), _open_varfile();
49 * _isfcb_create(isfname, crdat, crind, crvar, owner, group, u_mask, errcode)
51 * Create ISAM file: create UNIX files (dat/ind/var),
52 * and initialize File Control Block.
54 * Return 0 if create is successful, or -1 if any error. In the case of
55 *an error, the errcode block is set.
63 _isfcb_create(char *isfname, int crdat, int crind, int crvar,
64 int owner, int group, int u_mask, struct errcode *errcode)
70 int oldumask = umask (u_mask); /* Change umask to client's */
73 * Create the UNIX file for .rec file.
75 if (crdat && (dat_fd = _create_datfile (isfname)) == -1) {
76 _amseterrcode(errcode, errno);
81 * If a primary is specified, create .ind file.
83 if (crind && (ind_fd = _create_indfile (isfname)) == -1) {
84 _amseterrcode(errcode, errno);
89 * If the ISAM file is for variable length records, create .var file.
91 if (crvar && (var_fd = _create_varfile (isfname)) == -1) {
92 _amseterrcode(errcode, errno);
97 * Change user and group onwer ship of the file.
98 * This has affect only when executed by the netisamd daemon.
101 (void) fchown(dat_fd, owner, group);
103 (void) fchown(ind_fd, owner, group);
105 (void) fchown(var_fd, owner, group);
108 * Allocate File Control Block.
110 fcb = (Fcb *) _ismalloc(sizeof(*fcb));
111 memset ((char *) fcb, 0, sizeof(*fcb));
113 fcb->isfname = _isallocstring(isfname);
119 fcb->datsize = N_CNTL_PAGES; /* Control Pages */
120 fcb->indfreelist = FREELIST_NOPAGE;
124 fcb->keys = (Keydesc2 *) _ismalloc(sizeof(fcb->keys[0]));
125 memset((char *)fcb->keys, 0, sizeof(fcb->keys[0]));
130 /* Undo whatever was done. */
132 (void) close(dat_fd);
133 _remove_datfile(isfname);
136 (void) close(ind_fd);
137 _remove_indfile(isfname);
140 (void) close(var_fd);
141 _remove_varfile(isfname);
144 (void) umask(oldumask);
150 * _isfcb_setlength(fcb, varflag, minreclen, maxreclen)
152 * Set FCB attributes pertaining to record length.
156 _isfcb_setreclength(Fcb *fcb, Bool varflag, int minreclen, int maxreclen)
158 fcb->varflag = varflag;
159 fcb->minreclen = minreclen;
160 fcb->maxreclen = maxreclen;
164 * _isfcb_open(isfname, errcode)
166 * Open ISAM file: open UNIX files and create File Control Block.
168 * Return 0 if open is successful, or -1 if any error. In the case of an error,
169 * the errcode block is set.
171 * Note that rdonly is not fuly implemented. Now, all ISAM files are assumed
172 * to have permissions set to 0666 and may be opened in RW mode.
173 * If read-only media are used then the _open_datfile() function would have to
174 * try first to open the file in RW mode, and of that failed, try to
175 * open it in RO mode. The rdonly flag is used to reject any isamopen() with
176 * INOUT or OUTPUT mode on such files.
180 _isfcb_open(char *isfname, struct errcode *errcode)
186 Bool rdonly; /* set to 1 if file is Read-Only */
189 * Open the UNIX file for .rec file.
191 if ((dat_fd = _open_datfile (isfname, &rdonly)) == -1 || errno == EMFILE) {
192 _amseterrcode(errcode, errno);
202 ind_fd = _open_indfile (isfname, rdonly);
207 var_fd = _open_varfile (isfname, rdonly);
211 * Allocate File Control Block.
213 fcb = (Fcb *) _ismalloc(sizeof(*fcb));
214 memset ((char *) fcb, 0, sizeof(*fcb));
216 fcb->isfname = _isallocstring(isfname);
217 fcb->rdonly = rdonly;
224 fcb->keys = (Keydesc2 *) _ismalloc(sizeof(fcb->keys[0]));
225 memset((char *)fcb->keys, 0, sizeof(fcb->keys[0]));
233 * Return the number of UNIX fd consumed by the fcb block.
237 _isfcb_nfds(Fcb *fcb)
241 if (fcb->datfd != -1)
244 if (fcb->indfd != -1)
247 if (fcb->varfd != -1)
257 * Remove UNIX files associated with an FCB.
261 _isfcb_remove(Fcb *fcb)
264 _remove_datfile(fcb->isfname);
267 _remove_indfile(fcb->isfname);
270 _remove_varfile(fcb->isfname);
276 * Close UNIX files associated with an FCB, deallocate the FCB block.
280 _isfcb_close(Fcb *fcb)
282 assert (fcb != NULL);
283 assert (fcb->isfname != NULL);
285 (void) close(fcb->datfd);
286 (void) close(fcb->indfd);
287 (void) close(fcb->varfd);
289 _isfreestring(fcb->isfname);
290 free((char *)fcb->keys);
295 * _isfcb_cntlpg_w(fcb)
297 * Write information from the control block to the disk.
298 * Note that the Control Page transfer bypasses the disk buffer manager.
300 * Return 0 if write was successful, return -1 if any error.
304 _isfcb_cntlpg_w(Fcb *fcb)
306 char cntl_page[ISCNTLSIZE];
307 int dat_fd = fcb->datfd;
310 /* Clear the page. */
311 memset (cntl_page, 0, sizeof(cntl_page));
313 /* Set Magic number. */
314 (void)strcpy(cntl_page + CP_MAGIC_OFF, ISMAGIC);
317 stshort(ISPAGESIZE, cntl_page + CP_BLOCKSIZE_OFF);
319 /* Set NetISAM version stamp. */
320 (void)strcpy(cntl_page + CP_VERSION_OFF, ISVERSION);
322 /* .rec file size in blocks. */
323 stlong((long)fcb->datsize, cntl_page + CP_DATSIZE_OFF);
325 /* .ind file size in blocks. */
326 stlong((long)fcb->indsize, cntl_page + CP_INDSIZE_OFF);
328 /* .var file size in blocks. */
329 stlong((long)fcb->varsize, cntl_page + CP_VARSIZE_OFF);
331 /* Variable length 0/1 flag. */
332 stshort((short)fcb->varflag, cntl_page + CP_VARFLAG_OFF);
334 /* Number of records. */
335 stlong((long)fcb->nrecords, cntl_page + CP_NRECORDS_OFF);
337 /* Minimum and maximum record length. */
338 stshort((short)fcb->minreclen, cntl_page + CP_MINRECLEN_OFF);
339 stshort((short)fcb->maxreclen, cntl_page + CP_MAXRECLEN_OFF);
341 /* Last record number. */
342 strecno(fcb->lastrecno, cntl_page + CP_LASTRECNO_OFF);
344 /* Free record number. */
345 strecno(fcb->freerecno, cntl_page + CP_FREERECNO_OFF);
348 stshort((short)fcb->nkeys, cntl_page + CP_NKEYS_OFF);
351 stlong((long)fcb->lastkeyid, cntl_page + CP_LASTKEYID_OFF);
353 /* ind. free list head */
354 stlong((long)fcb->indfreelist, cntl_page + CP_INDFREELIST_OFF);
356 /* offset of the end of .var file */
357 stlong((long)fcb->varend, cntl_page + CP_VAREND_OFF);
359 /* Key descriptors. */
360 for (i = 0; i < fcb->nkeys; i++) {
361 stkey(fcb->keys + i, cntl_page + CP_KEYS_OFF + i * K2_LEN);
364 /* Increment stamp1 and stamp2 to indicate change in the Control Page. */
368 stlong((long)fcb->changestamp1, cntl_page + CP_CHANGESTAMP1_OFF);
369 stlong((long)fcb->changestamp2, cntl_page + CP_CHANGESTAMP2_OFF);
372 * Write the buffer to the disk.
374 _isseekpg(dat_fd, ISCNTLPGOFF);
375 _iswritepg(dat_fd, cntl_page);
376 _iswritepg(dat_fd, cntl_page + ISPAGESIZE);
382 * _isfcb_cntlpg_w2(fcb)
384 * Write information from the control block to the disk.
385 * Write only selected fields of the control block to avoid the overhead
386 * of coding and decoding.
387 * Note that the Control Page transfer bypasses the disk buffer manager.
389 * Return 0 if write was successful, return -1 if any error.
393 _isfcb_cntlpg_w2(Fcb *fcb)
395 char cntl_page[CP_VAREND_OFF+CP_VAREND_LEN];
396 int dat_fd = fcb->datfd;
399 * Read the page from disk.
401 _isseekpg(dat_fd, ISCNTLPGOFF);
402 (void)read(dat_fd, cntl_page, sizeof(cntl_page));
404 /* .rec file size in blocks. */
405 stlong((long)fcb->datsize, cntl_page + CP_DATSIZE_OFF);
407 /* .ind file size in blocks. */
408 stlong((long)fcb->indsize, cntl_page + CP_INDSIZE_OFF);
410 /* .var file size in blocks. */
411 stlong((long)fcb->varsize, cntl_page + CP_VARSIZE_OFF);
413 /* Number of records. */
414 stlong((long)fcb->nrecords, cntl_page + CP_NRECORDS_OFF);
416 /* Last record number. */
417 strecno(fcb->lastrecno, cntl_page + CP_LASTRECNO_OFF);
419 /* Free record number. */
420 strecno(fcb->freerecno, cntl_page + CP_FREERECNO_OFF);
422 /* ind. free list head */
423 stlong((long)fcb->indfreelist, cntl_page + CP_INDFREELIST_OFF);
425 /* end of .var file */
426 stlong((long)fcb->varend, cntl_page + CP_VAREND_OFF);
428 /* Increment stamp2 to indicate change in the Control Page. */
430 stlong((long)fcb->changestamp2, cntl_page + CP_CHANGESTAMP2_OFF);
434 * Write the buffer to the disk.
436 _isseekpg(dat_fd, ISCNTLPGOFF);
437 (void)write(dat_fd, cntl_page, sizeof(cntl_page));
443 * _isfcb_cntlpg_r(fcb)
445 * Read information from control page and store it in the FCB.
446 * Note that the Control Page transfer bypasses the disk buffer manager.
448 * Return 0 if read was successful, return -1 if any error.
452 _isfcb_cntlpg_r(Fcb *fcb)
454 char cntl_page[ISCNTLSIZE];
455 int dat_fd = fcb->datfd;
459 * Read the page from the disk.
461 _isseekpg(dat_fd, ISCNTLPGOFF);
462 _isreadpg(dat_fd, cntl_page);
463 _isreadpg(dat_fd, cntl_page + ISPAGESIZE);
466 fcb->blocksize = ldshort(cntl_page + CP_BLOCKSIZE_OFF);
468 /* .rec file size in blocks. */
469 fcb->datsize = ldlong(cntl_page + CP_DATSIZE_OFF);
471 /* .ind file size in blocks. */
472 fcb->indsize = ldlong(cntl_page + CP_INDSIZE_OFF);
474 /* .var file size in blocks. */
475 fcb->varsize = ldlong(cntl_page + CP_VARSIZE_OFF);
477 /* Variable length 0/1 flag. */
478 fcb->varflag = (Bool)ldshort(cntl_page + CP_VARFLAG_OFF);
480 /* Number of records. */
481 fcb->nrecords = ldlong(cntl_page + CP_NRECORDS_OFF);
483 /* Minimum and maximum record length. */
484 fcb->minreclen = ldunshort(cntl_page + CP_MINRECLEN_OFF);
485 fcb->maxreclen = ldunshort(cntl_page + CP_MAXRECLEN_OFF);
487 /* Last record number. */
488 fcb->lastrecno = ldrecno(cntl_page + CP_LASTRECNO_OFF);
490 /* Free record number. */
491 fcb->freerecno = ldrecno(cntl_page + CP_FREERECNO_OFF);
494 fcb->lastkeyid = ldlong(cntl_page + CP_LASTKEYID_OFF);
496 /* .ind free list head. */
497 fcb->indfreelist = ldlong(cntl_page + CP_INDFREELIST_OFF);
499 /* end of .var file */
500 fcb->varend = ldlong(cntl_page + CP_VAREND_OFF);
503 fcb->nkeys = ldshort(cntl_page + CP_NKEYS_OFF);
506 * Read key descriptors.
508 fcb->keys = (Keydesc2 *)
509 _isrealloc((char *)fcb->keys,
510 (unsigned) (sizeof(Keydesc2) * fcb->nkeys));
511 memset((char *)fcb->keys, 0, sizeof(Keydesc2) * fcb->nkeys);
513 for (i = 0; i < fcb->nkeys; i++) {
514 ldkey(fcb->keys + i, cntl_page + CP_KEYS_OFF + i * K2_LEN);
518 fcb->changestamp1 = ldlong(cntl_page + CP_CHANGESTAMP1_OFF);
521 fcb->changestamp2 = ldlong(cntl_page + CP_CHANGESTAMP2_OFF);
524 * Open .ind file in situations when some other process has created
525 * keys and this process has just learned it now.
527 if (fcb->nkeys > 1 || !FCB_NOPRIMARY_KEY(fcb)) {
529 if (_open2_indfile(fcb) != ISOK)
530 _isfatal_error("_open2_indfile()");
532 (void)_open2_indfile(fcb);
541 * _isfcb_cntlpg_r2(fcb)
543 * Read information from the control block on the disk.
544 * Read only selected fields of the control block to avoid the overhead
545 * of coding and decoding.
546 * Note that the Control Page transfer bypasses the disk buffer manager.
548 * Return 0 if write was successful, return -1 if any error.
552 _isfcb_cntlpg_r2(Fcb *fcb)
554 char cntl_page[CP_VAREND_OFF+CP_VAREND_LEN];
555 int dat_fd = fcb->datfd;
558 * Read the page from disk.
560 _isseekpg(dat_fd, ISCNTLPGOFF);
561 (void)read(dat_fd, cntl_page, sizeof(cntl_page));
564 * Check changestamp1. If the stamp has changed, we must read the entire
565 * page and update the FCB.
567 if (ldlong(cntl_page + CP_CHANGESTAMP1_OFF) != fcb->changestamp1) {
568 (void)_isfcb_cntlpg_r(fcb);
572 *_isfcb_cntlpg_r2() is called if transaction is rolled back.
573 * We cannot test changestamp2; we must read the info into the FCB
579 * Check changestamp2. If the stamp has not changed, the FCB contains
580 * up-to-date information.
582 if (ldlong(cntl_page + CP_CHANGESTAMP2_OFF) == fcb->changestamp2) {
587 /* .rec file size in blocks. */
588 fcb->datsize = ldlong(cntl_page + CP_DATSIZE_OFF);
590 /* .ind file size in blocks. */
591 fcb->indsize = ldlong(cntl_page + CP_INDSIZE_OFF);
593 /* .var file size in blocks. */
594 fcb->varsize = ldlong(cntl_page + CP_VARSIZE_OFF);
596 /* Number of records. */
597 fcb->nrecords = ldlong(cntl_page + CP_NRECORDS_OFF);
599 /* Last record number. */
600 fcb->lastrecno = ldrecno(cntl_page + CP_LASTRECNO_OFF);
602 /* Free record number. */
603 fcb->freerecno = ldrecno(cntl_page + CP_FREERECNO_OFF);
605 /* .ind free list head. */
606 fcb->indfreelist = ldlong(cntl_page + CP_INDFREELIST_OFF);
608 /* end of .var file */
609 fcb->varend = ldlong(cntl_page + CP_VAREND_OFF);
612 fcb->changestamp2 = ldlong(cntl_page + CP_CHANGESTAMP2_OFF);
619 * _create_datfile(isfname)
621 * Create .rec file for ISAM file isfname.
625 _create_datfile(char *isfname)
628 char namebuf[MAXPATHLEN];
630 snprintf(namebuf, sizeof(namebuf), "%s", isfname);
631 _makedat_isfname(namebuf);
633 fd = open (namebuf, O_CREAT | O_EXCL | O_RDWR, 0666);
636 if(fcntl(fd, F_SETFD, 1) == -1) {
645 * _create_indfile(isfname)
647 * Create .ind file for ISAM file isfname.
651 _create_indfile(char *isfname)
654 char namebuf[MAXPATHLEN];
656 snprintf(namebuf, sizeof(namebuf), "%s", isfname);
657 _makeind_isfname(namebuf);
659 fd = open (namebuf, O_CREAT | O_EXCL | O_RDWR, 0666);
662 if(fcntl(fd, F_SETFD, 1) == -1) {
671 * _create_varfile(isfname)
673 * Create .var file for ISAM file isfname.
677 _create_varfile(char *isfname)
680 char namebuf[MAXPATHLEN];
682 snprintf(namebuf, sizeof(namebuf), "%s", isfname);
683 _makevar_isfname(namebuf);
685 fd = open (namebuf, O_CREAT | O_EXCL | O_RDWR, 0666);
688 if(fcntl(fd, F_SETFD, 1) == -1) {
698 * _remove_datfile(isfname)
700 * Remove .rec file for ISAM file isfname.
704 _remove_datfile(char *isfname)
706 char namebuf[MAXPATHLEN];
708 snprintf(namebuf, sizeof(namebuf), "%s", isfname);
709 _makedat_isfname(namebuf);
711 (void) unlink(namebuf);
715 * _remove_indfile(isfname)
717 * Remove .ind file for ISAM file isfname.
721 _remove_indfile(char *isfname)
723 char namebuf[MAXPATHLEN];
725 snprintf(namebuf, sizeof(namebuf), "%s", isfname);
726 _makeind_isfname(namebuf);
728 (void) unlink(namebuf);
732 * _remove_varfile(isfname)
734 * Remove .var file for ISAM file isfname.
738 _remove_varfile(char *isfname)
740 char namebuf[MAXPATHLEN];
742 snprintf(namebuf, sizeof(namebuf), "%s", isfname);
743 _makevar_isfname(namebuf);
745 (void) unlink(namebuf);
750 * _open_datfile(isfname)
752 * Open .rec file for ISAM file isfname.
756 _open_datfile(char *isfname, Bool *rdonly)
758 char namebuf[MAXPATHLEN];
761 snprintf(namebuf, sizeof(namebuf), "%s", isfname);
762 _makedat_isfname(namebuf);
764 if ((ret = open (namebuf, O_RDWR)) != -1) {
767 if(fcntl(ret, F_SETFD, 1) == -1) {
775 ret = open (namebuf, O_RDONLY);
778 if(fcntl(ret, F_SETFD, 1) == -1) {
787 * _open_indfile(isfname)
789 * Open .ind file for ISAM file isfname.
793 _open_indfile(char *isfname, Bool rdonly)
796 char namebuf[MAXPATHLEN];
798 snprintf(namebuf, sizeof(namebuf), "%s", isfname);
799 _makeind_isfname(namebuf);
801 fd = open (namebuf, (rdonly==TRUE)?O_RDONLY:O_RDWR);
804 if(fcntl(fd, F_SETFD, 1) == -1) {
813 * _open_varfile(isfname)
815 * Open .var file for ISAM file isfname.
819 _open_varfile(char *isfname, Bool rdonly)
822 char namebuf[MAXPATHLEN];
824 snprintf(namebuf, sizeof(namebuf), "%s", isfname);
825 _makevar_isfname(namebuf);
827 fd = open (namebuf, (rdonly==TRUE)?O_RDONLY:O_RDWR);
830 if(fcntl(fd, F_SETFD, 1) == -1) {
839 _check_isam_magic(Fcb *fcb)
841 char magicbuffer[CP_MAGIC_LEN];
843 (void)lseek(fcb->datfd, 0L, 0);
844 if (read(fcb->datfd, magicbuffer, CP_MAGIC_LEN) < CP_MAGIC_LEN ||
845 /* The following test for compatibilty with `SunISAM 1.0 Beta files. */
846 strncmp(magicbuffer, "SunISAM", strlen(ISMAGIC)) != 0 &&
847 strncmp(magicbuffer, ISMAGIC, strlen(ISMAGIC)) != 0) {
856 * _open2_indfile(fcb)
858 * Open (or create) .ind file for ISAM file if the .ind file
859 * is not open already (or does not exist).
863 _open2_indfile(Fcb *fcb)
865 char namebuf[MAXPATHLEN];
869 if (fcb->indfd != -1)
872 snprintf(namebuf, sizeof(namebuf), "%s", fcb->isfname);
873 _makeind_isfname(namebuf);
875 (void)fstat(fcb->datfd, &buf);
877 openmode = (fcb->rdonly) ? O_RDONLY : O_RDWR;
879 if (fcb->indsize == 0)
882 fcb->indfd = open(namebuf, openmode, buf.st_mode);
883 if (fcb->indfd > -1) {
885 if(fcntl(fcb->indfd, F_SETFD, 1) == -1) {
891 if(fcb->indfd == -1 && (openmode & O_CREAT)) {
892 _isfatal_error("Cannot create .ind file");
895 if (fcb->indfd != -1) {
896 (void) _watchfd_incr(1);
897 (void)fchown(fcb->indfd, buf.st_uid, buf.st_gid);
900 return ((fcb->indfd == -1) ? ISERROR : ISOK);