1/* Copyright 1994 NEC Corporation, Tokyo, Japan.
2 *
3 * Permission to use, copy, modify, distribute and sell this software
4 * and its documentation for any purpose is hereby granted without
5 * fee, provided that the above copyright notice appear in all copies
6 * and that both that copyright notice and this permission notice
7 * appear in supporting documentation, and that the name of NEC
8 * Corporation not be used in advertising or publicity pertaining to
9 * distribution of the software without specific, written prior
10 * permission.  NEC Corporation makes no representations about the
11 * suitability of this software for any purpose.  It is provided "as
12 * is" without express or implied warranty.
13 *
14 * NEC CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
16 * NO EVENT SHALL NEC CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
18 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
19 * OTHER TORTUOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20 * PERFORMANCE OF THIS SOFTWARE.
21 */
22
23#if !defined(lint) && !defined(__CODECENTER__)
24static char rcsid[]="$Id: fq.c 10525 2004-12-23 21:23:50Z korli $";
25#endif
26
27#include	"RKintern.h"
28
29#include <string.h>
30#include <unistd.h>
31#include <fcntl.h>
32
33#ifdef WIN
34#include <fcntl.h>
35#include <sys\types.h>
36#include <sys\stat.h>
37#endif
38
39#define dm_xdm	dm_extdata.ptr
40
41
42static int WrToRut(struct RUT *ruc, unsigned long csn, unsigned long tick);
43static unsigned long UpdateFrst(struct RUT *ruc);
44static struct WRT *allocWRT(unsigned long size);
45static int writeNV(int fd, struct NV *nv);
46static void freeRUT(struct RUT *ruc);
47static int SaveRUC(int fr, struct RUT *ruc);
48
49struct xqm {
50  off_t ex_boff;
51  long ex_bsiz;
52};
53
54struct RUT *
55allocRUT(unsigned long hn)
56{
57  struct RUT	*tempo;
58
59  if (!(tempo = (struct RUT *)calloc(1, sizeof(struct RUT))))
60    return((struct RUT *) 0);
61  if (!(tempo->dp = (struct CTdata **)calloc((size_t) hn, sizeof(struct CTdata *)))){
62    free(tempo);
63    return((struct RUT *) 0);
64  }
65  return tempo;
66}
67
68inline int
69WrToRut(struct RUT *ruc, unsigned long csn, unsigned long tick)
70{
71  unsigned long whn;
72  struct CTdata *wd, **pwd;
73
74  whn = HashFunc(csn);
75  for (pwd = ruc->dp+whn, wd = *pwd ; wd; pwd = &wd->next, wd = *pwd) {
76    if (wd->ct[0] == csn) {
77      WriteCT(csn, tick, wd->ct);
78      return 0;
79    }
80  }
81  if (!(wd = (struct CTdata *)calloc(1, sizeof(struct CTdata))))
82    return -1;
83  *pwd = wd;
84  WriteCT(csn, tick, wd->ct);
85  return 1;
86}
87
88static
89unsigned long
90UpdateFrst(struct RUT *ruc)
91{
92  unsigned long wmin, wtick, frst, lc;
93  struct CTdata *wd;
94
95  wmin = 0xffffffffL;
96  frst = 0xfffffL;
97
98  for (lc = 0; lc < HN; lc++) {
99    for (wd = *(ruc->dp+lc) ; wd; wd = wd->next) {
100      if (wmin > (wtick = wd->ct[1])) {
101	frst = wd->ct[0];
102	wmin = wtick;
103      }
104    }
105  }
106  if(frst == (unsigned long) 0xffffffff)
107    return (unsigned long) 0L;
108  return frst;
109}
110
111inline int
112deleteCT(struct RUT *ruc, unsigned long csn)
113{
114  unsigned long whn;
115  struct CTdata *wd, **pre;
116
117  whn = HashFunc(csn);
118
119  for (pre = ruc->dp+whn, wd = *pre; ; pre = &wd->next, wd = *pre){
120    if (!wd)
121      return 0;
122    if (wd->ct[0] == csn)
123      break;
124  }
125  *pre = wd->next;
126  free(wd);
127  return 1;
128}
129
130unsigned long
131searchRut(struct RUT *ruc, unsigned long csn)
132{
133  unsigned long whn;
134  struct CTdata *wd;
135
136  whn = HashFunc(csn);
137  for (wd = *(ruc->dp+whn) ; wd; wd = wd->next) {
138    if (wd->ct[0] == csn)
139      return wd->ct[1];
140  }
141  return (unsigned long) 0L;
142}
143
144inline
145struct CTdata *
146searchCTadd(struct RUT *ruc, unsigned long csn)
147{
148  unsigned long whn;
149  struct CTdata *wd;
150
151  whn = HashFunc(csn);
152  for (wd = *(ruc->dp+whn) ; wd; wd = wd->next) {
153    if (wd->ct[0] == csn)
154      return wd;
155  }
156  return (struct CTdata *) 0;
157}
158
159int
160entryRut(struct RUT *ruc, unsigned long csn, unsigned long tick)
161{
162  struct CTdata *wpadd;
163  int retval;
164
165  retval = 1;
166  if (ruc->cs < ruc->sz)
167    switch (WrToRut(ruc, csn, tick)) {
168    case  0:
169      break;
170    case  1:
171      if (++(ruc->cs) == ruc->sz)
172	ruc->frst = UpdateFrst(ruc);
173      break;
174    case -1:
175      return (int) 0;
176    }
177  else {
178    wpadd = searchCTadd(ruc, csn);
179    if (wpadd) {
180      WriteCT(csn, tick, wpadd->ct);
181      if (csn == ruc->frst)
182	ruc->frst = UpdateFrst(ruc);
183    }
184    else {
185      if (deleteCT(ruc, ruc->frst)){
186        if (WrToRut(ruc, csn, tick) < 0){
187          ruc->cs -= 1L;
188	  retval = 0;
189        }
190      }
191      else
192        retval = 0;
193      ruc->frst = UpdateFrst(ruc);
194    }
195  }
196  return retval;
197}
198
199static
200struct WRT *
201allocWRT(unsigned long size)
202{
203  struct WRT *tempo;
204
205  if (!(tempo = (struct WRT *)calloc(1, sizeof(struct WRT))))
206    return((struct WRT *) 0);
207  if (!(tempo->buf = (unsigned char *)calloc(1, (int) 5*size))){
208    free(tempo);
209    return((struct WRT *) 0);
210  }
211  tempo->sz = size;
212  return tempo;
213}
214
215inline
216struct WRT *
217readWRT(int fr)
218{
219  unsigned	long wsz, wcs, wfrst, wtm;
220  unsigned char	ll[4];
221  struct WRT	*wrt;
222#ifdef WIN
223  DWORD dummy;
224#endif
225
226#ifndef WIN
227  if (read(fr, (char *)ll, 4) != 4)
228    return (struct WRT *) 0;
229  wsz = (unsigned long) bst4_to_l(ll);
230  if (read(fr, (char *)ll, 4) != 4)
231    return (struct WRT *) 0;
232  wcs = (unsigned long) bst4_to_l(ll);
233  if (read(fr, (char *)ll, 4) != 4)
234    return (struct WRT *) 0;
235  wfrst = (unsigned long) bst4_to_l(ll);
236  if (read(fr, (char *)ll, 4) != 4)
237    return (struct WRT *) 0;
238  wtm  = (unsigned long) bst4_to_l(ll);
239  if (!(wrt = allocWRT(wsz)))
240    return (struct WRT *) 0;
241#else
242  if (!ReadFile(fr, (char *)ll, 4, &dummy, NULL) || dummy != 4)
243    return (struct WRT *) 0;
244  wsz = (unsigned long) bst4_to_l(ll);
245  if (!ReadFile(fr, (char *)ll, 4, &dummy, NULL) || dummy != 4)
246    return (struct WRT *) 0;
247  wcs = (unsigned long) bst4_to_l(ll);
248  if (!ReadFile(fr, (char *)ll, 4, &dummy, NULL) || dummy != 4)
249    return (struct WRT *) 0;
250  wfrst = (unsigned long) bst4_to_l(ll);
251  if (!ReadFile(fr, (char *)ll, 4, &dummy, NULL) || dummy != 4)
252    return (struct WRT *) 0;
253  wtm  = (unsigned long) bst4_to_l(ll);
254  if (!(wrt = allocWRT(wsz)))
255    return (struct WRT *) 0;
256#endif
257
258  wrt->cs = wcs;
259  wrt->frst = wfrst;
260  wrt->tm = wtm;
261  if (wsz) {
262    if
263#ifndef WIN
264      (read(fr, wrt->buf, (unsigned) 5*wsz) != 5*(int)wsz)
265#else
266      (!ReadFile(fr, wrt->buf, (unsigned) 5*wsz, &dummy, NULL) ||
267       dummy != (unsigned)5*(int)wsz)
268#endif
269    {
270      freeWRT(wrt);
271      return (struct WRT *) 0;
272    }
273  }
274  return wrt;
275}
276
277inline int
278writeToWRT(int fr, struct WRT *wrt)
279{
280  unsigned char ll[4];
281
282#ifndef WIN
283  l_to_bst4(wrt->sz, ll);
284  if (write(fr, (char *)ll, 4) != 4)
285    return 0;
286  l_to_bst4(wrt->cs, ll);
287  if (write(fr, (char *)ll, 4) != 4)
288    return 0;
289  l_to_bst4(wrt->frst, ll);
290  if (write(fr, (char *)ll, 4) != 4)
291    return 0;
292  l_to_bst4(wrt->tm, ll);
293  if (write(fr, (char *)ll, 4) != 4)
294    return 0;
295  if (wrt->sz) {
296    if (write(fr, wrt->buf, (unsigned) 5*wrt->sz) != 5*(int)wrt->sz)
297      return 0;
298  }
299  return 1;
300#else
301  DWORD written;
302
303  l_to_bst4(wrt->sz, ll);
304  if (WriteFile(fr, (char *)ll, 4, &written, NULL) && written == 4){
305    l_to_bst4(wrt->cs, ll);
306    if (WriteFile(fr, (char *)ll, 4, &written, NULL) && written == 4) {
307      l_to_bst4(wrt->frst, ll);
308      if (WriteFile(fr, (char *)ll, 4, &written, NULL) && written == 4) {
309	l_to_bst4(wrt->tm, ll);
310	if (WriteFile(fr, (char *)ll, 4, &written, NULL) && written == 4) {
311	  if (wrt->sz) {
312	    if (WriteFile(fr, wrt->buf, (unsigned)5*wrt->sz, &written, NULL) &&
313		written == 5*wrt->sz) {
314	      return 1;
315	    }
316	  }
317	}
318      }
319    }
320  }
321  return 0;
322#endif
323}
324
325inline void
326abolishNV(struct NV *nv)
327
328{
329  struct NVE	*p, **q, *r;
330  unsigned i;
331
332  if (nv && nv->tsz && nv->buf) {
333    for (i = 0, q = nv->buf + i; i < nv->tsz; i++, q = nv->buf + i) {
334      for (p = *q; p; p = r) {
335	r = p->next;
336	if (p->data)
337	  free(p->data);
338	free(p);
339      }
340    }
341    free(nv->buf);
342    free(nv);
343  }
344  return;
345}
346
347inline struct NV *
348readNV(int fd)
349{
350  struct NV	nv, *vn;
351  unsigned char	ll[4], *buf, *p;
352  long		i, cnt;
353
354  vn = (struct NV *)malloc(sizeof(struct NV));
355  if (vn) {
356#ifndef WIN
357    if (read(fd, (char *)ll, 4) == 4) {
358      nv.sz = bst4_to_l(ll);
359      if (read(fd, (char *)ll, 4) == 4) {
360	cnt = bst4_to_l(ll);
361	if (read(fd, (char *)ll, 4) == 4) {
362	  nv.tsz = bst4_to_l(ll);
363	  if (read(fd, (char *)ll, 4) == 4) {
364	    goto read_ok;
365	  }
366	}
367      }
368    }
369#else
370    if (ReadFile(fd, (char *)ll, 4, &dummy, NULL) && dummy == 4) {
371      nv.sz = bst4_to_l(ll);
372      if (ReadFile(fd, (char *)ll, 4, &dummy, NULL) && dummy == 4) {
373	cnt = bst4_to_l(ll);
374	if (ReadFile(fd, (char *)ll, 4, &dummy, NULL) && dummy == 4) {
375	  nv.tsz = bst4_to_l(ll);
376	  if (ReadFile(fd, (char *)ll, 4, &dummy, NULL) && dummy == 4) {
377	    goto read_ok;
378	  }
379	}
380      }
381    }
382#endif
383    free(vn);
384  }
385  return (struct NV *)0;
386
387 read_ok:
388
389  nv.cnt = nv.csz = 0L;
390  nv.head.left = nv.head.right = &nv.head;
391  if (nv.sz) {
392    if (!(nv.buf = (struct NVE **)calloc((size_t)nv.tsz, sizeof(struct NVE *)))) {
393      free(vn);
394      return((struct NV *)0);
395    }
396    if
397#ifndef WIN
398      (!(buf = (unsigned char *)malloc((size_t)nv.sz)) ||
399       read(fd, buf, (unsigned int)nv.sz) != (int)nv.sz)
400#else
401      (!(buf = (unsigned char *)malloc((size_t)nv.sz)) ||
402       !ReadFile(fd, buf, (unsigned int)nv.sz, &dummy, NULL) ||
403       dummy != (int)nv.sz)
404#endif
405    {
406      free(nv.buf);
407      if (buf)
408	free(buf);
409      free(vn);
410      return((struct NV *)0);
411    }
412    for (p = buf, i = 0L; i < cnt; i++, p += *p*2 + 2)
413      if ((unsigned long) (p - buf) + *p * 2 + 2 < nv.sz)
414	_RkRegisterNV(&nv, p + 2, (int)*p, (int)*(p + 1));
415    free(buf);
416  } else {
417    free(vn);
418    return((struct NV *)0);
419  }
420  *vn = nv;
421  vn->head.right->left = &vn->head;
422  vn->head.left->right = &vn->head;
423  return(vn);
424}
425
426static int
427writeNV(int fd, struct NV *nv)
428{
429  unsigned char	ll[4];
430  unsigned char	*buf = (unsigned char *)0, *r;
431  struct NVE	*p, **q;
432  unsigned long i;
433#ifdef WIN
434  DWORD dummy;
435#endif
436
437  if (!nv)
438    return(-1);
439  if (nv->buf) {
440    if (!(buf = (unsigned char *)malloc((size_t)nv->sz)))
441      return(-1);
442    for (r = buf, i = 0L, q = nv->buf; i < nv->tsz; i++, q = nv->buf + i) {
443      for (p = *q; p; q = &p->next, p = *q) {
444	if ((unsigned long) (r - buf) + *(p->data)*2 + 2 < nv->sz) {
445	  memcpy(r, p->data, *(p->data)*2+2);
446	  r += *(p->data)*2+2;
447	} else {
448	  i = nv->tsz;
449	  break;
450	}
451      }
452    }
453  }
454
455#ifndef WIN
456  l_to_bst4(nv->sz, ll);
457  if (write(fd, (char *)ll, 4) == 4) {
458    l_to_bst4(nv->cnt, ll);
459    if (write(fd, (char *)ll, 4) == 4) {
460      l_to_bst4(nv->tsz, ll);
461      if (write(fd, (char *)ll, 4) == 4) {
462	l_to_bst4((unsigned long)0, ll);
463	if (write(fd, (char *)ll, 4) == 4) {
464	  if (!nv->sz ||
465	      (buf && write(fd, buf, (int) nv->sz) == (int)nv->sz)) {
466	    goto write_ok;
467	  }
468	}
469      }
470    }
471  }
472#else
473  l_to_bst4(nv->sz, ll);
474  if (WriteFile(fd, (char *)ll, 4, &dummy, NULL) && dummy == 4) {
475    l_to_bst4(nv->cnt, ll);
476    if (WriteFile(fd, (char *)ll, 4, &dummy, NULL) && dummy == 4) {
477      l_to_bst4(nv->tsz, ll);
478      if (WriteFile(fd, (char *)ll, 4, &dummy, NULL) && dummy == 4) {
479	l_to_bst4((unsigned long)0, ll);
480	if (WriteFile(fd, (char *)ll, 4, &dummy, NULL) && dummy == 4) {
481	  if (!nv->sz ||
482	      (buf && WriteFile(fd, buf, (int) nv->sz, &dummy, NULL) &&
483	       dummy == (int)nv->sz)) {
484	    goto write_ok;
485	  }
486	}
487      }
488    }
489  }
490#endif
491  if (buf) free(buf);
492  return(-1);
493
494 write_ok:
495  if (buf) free(buf);
496  return(0);
497}
498
499static void
500freeRUT(struct RUT *ruc)
501{
502  struct CTdata *wd, *nex;
503  unsigned long lc;
504
505  for (lc = 0; lc < HN; lc++) {
506    for (wd = *(ruc->dp+lc); wd; wd = nex) {
507      nex = wd->next;
508      free(wd);
509    }
510  }
511  free(ruc->dp);
512  free(ruc);
513}
514
515struct RUT *
516LoadRUC(int fr)
517{
518  struct WRT *wruc;
519  struct RUT *ruc;
520  unsigned long lc, csn, tick;
521
522  if (!(wruc = readWRT(fr)))
523    return (struct RUT *) 0;
524
525  if (!(ruc = allocRUT(HN))) {
526    freeWRT(wruc);
527    return (struct RUT *) 0;
528  }
529
530  ruc->sz = wruc->sz;
531  ruc->cs = 0L;
532  ruc->frst = wruc->frst;
533  ruc->tm = wruc->tm;
534
535  for (lc = 0; lc < wruc->cs; lc++) {
536    unsigned char *tmp = wruc->buf + 5 * lc;
537    csn  = a_csn(tmp);
538    tick = _RkGetTick(0) - a_tick(wruc->buf+5*lc);
539    if (!entryRut(ruc, csn, tick)) {
540      freeRUT(ruc);
541      ruc = (struct RUT *) 0;
542    }
543  }
544  freeWRT(wruc);
545  return ruc;
546}
547
548#ifndef WIN
549static int SaveRUC (int, struct RUT *);
550#else
551static int SaveRUC (HANDLE, struct RUT *);
552#endif
553
554static int
555SaveRUC(int fr, struct RUT *ruc)
556{
557  struct WRT	*wruc;
558  struct CTdata	*wdp;
559  unsigned	long lc, count;
560  int		retval;
561
562  if (!ruc)
563    return (int) 0;
564  retval = 1;
565  if (!(wruc = allocWRT(ruc->sz))){
566    freeRUT(ruc);
567    return (int) 0;
568  }
569  wruc->sz = ruc->sz;
570  wruc->cs = ruc->cs;
571  wruc->frst = ruc->frst;
572  wruc->tm = ruc->tm;
573
574  count = 0L;
575  for (lc = 0L; lc < HN; lc++) {
576    for (wdp = *(ruc->dp+lc) ; wdp; wdp = wdp->next) {
577      WriteVal(wdp->ct[0], _RkGetTick(0) - wdp->ct[1], wruc->buf+5*count);
578      count ++;
579    }
580  }
581  if (count != ruc->cs) {
582    retval = (int) 0;
583  }
584  if (!writeToWRT(fr, wruc))
585    retval = 0;
586  freeWRT(wruc);
587  return retval;
588}
589
590inline int
591FQscan(struct DF *df, struct DM *codm, char *file, int *w)
592{
593  int count = 0;
594  struct HD	hd;
595  struct DM	*dm, *dmh;
596  unsigned char	ll[4];
597  unsigned long	bitsiz, bitoff;
598  off_t		off;
599  int		fd;
600
601  *w = 1;
602  if ((fd = open(file, 2)) < 0) {
603    *w = 0;
604    if ((fd = open(file, 0)) < 0)
605      return -1;
606  }
607
608  for (off = 0; _RkReadHeader(fd, &hd, off) >= 0;) {
609    long		start = off;
610
611    if (!hd.data[HD_DMNM].ptr ||
612	(strncmp(".fq",
613		 (char *)hd.data[HD_DMNM].ptr +
614		 strlen((char *)hd.data[HD_DMNM].ptr) - (sizeof(".fq") - 1),
615		 sizeof(".fq") - 1) &&
616	 strncmp(".cld",
617		 (char *)hd.data[HD_DMNM].ptr +
618		 strlen((char *)hd.data[HD_DMNM].ptr) - (sizeof(".cld") - 1),
619		 sizeof(".cld") - 1)) ) {
620      break;
621    }
622    if (!codm->dm_xdm
623	|| (long)((struct ND *)codm->dm_xdm)->time != hd.data[HD_TIME].var
624	|| (long)((struct ND *)codm->dm_xdm)->rec != hd.data[HD_REC].var
625	|| (long)((struct ND *)codm->dm_xdm)->can != hd.data[HD_CAN].var)
626      break;
627    off += hd.data[HD_HSZ].var;
628    (void)lseek(fd, off, 0);
629    (void)read(fd, (char *)ll, 4);
630    off += 4;
631    bitsiz = L4TOL(ll);
632    bitoff = off;
633    off += bitsiz;
634    (void)lseek(fd, off, 0);
635    dmh = &df->df_members;
636    for (dm = dmh->dm_next; dm != dmh; dm = dm->dm_next) {
637      if (!strcmp((char *)dm->dm_dicname, (char *)hd.data[HD_CODM].ptr)) {
638	struct xqm 		*xqm;
639
640	if (!(xqm = (struct xqm *)malloc(sizeof(struct xqm))))
641	  break;
642	dm->dm_extdata.ptr = (pointer)xqm;
643	xqm->ex_boff = bitoff;
644	xqm->ex_bsiz = bitsiz;
645	dm->dm_flags |= DM_EXIST;
646	dm->dm_offset = start;
647	count++;
648	break;
649      }
650    }
651    _RkClearHeader(&hd);
652  }
653  _RkClearHeader(&hd);
654  if (!count) {
655    (void)close(fd);
656    return -1;
657  }
658  df->df_size = off;
659  df->df_extdata.var = (long)fd;
660  return fd;
661}
662
663int
664FQopen(struct DM *dm, struct DM *qm, char *file, int mode)
665{
666  struct DF	*df;
667  struct DD	*dd;
668  struct xqm 	*xqm;
669  int		writable;
670#ifndef WIN
671  int		fd;
672#else
673  HANDLE fd;
674#endif
675
676  /* missing file info ? */
677    if (!(df = qm->dm_file) || !(dd = df->df_direct))
678	return -1;
679  /* initialize df */
680    if (!df->df_rcount) {
681        df->df_extdata.var = (long)FQscan(df, dm, file, &writable);
682	if (df->df_extdata.var < 0)
683	    return -1;
684	if (writable)
685	  df->df_flags |= DF_WRITABLE;
686	else
687	  df->df_flags &= ~DF_WRITABLE;
688	df->df_flags |= DF_EXIST;
689	dd->dd_rcount++;
690    }
691  /*
692   *  this member is not included.
693   */
694    if (!(qm->dm_flags & DM_EXIST))
695	return -1;
696  if (strcmp(dm->dm_dicname, qm->dm_dicname))
697    return -1;
698  /* */
699    xqm = (struct xqm *)qm->dm_extdata.ptr;
700#ifndef WIN
701    fd = df->df_extdata.var;
702#else
703    fd = df->df_extdata.hnd;
704#endif
705
706    qm->dm_rut = (struct RUT *)0;
707    qm->dm_nv = (struct NV *)0;
708  /* dispatch */
709    qm->dm_qbits = (unsigned char *)malloc((unsigned)xqm->ex_bsiz);
710    if (!qm->dm_qbits)
711      return -1;
712#ifndef WIN
713    (void)lseek(fd, xqm->ex_boff, 0);
714    (void)read(fd, (char *)qm->dm_qbits, (int)xqm->ex_bsiz);
715#else
716    {
717      DWORD dummy;
718
719      (void)SetFilePointer(fd, xqm->ex_boff, NULL, FILE_BEGIN);
720      (void)ReadFile(fd, (char *)qm->dm_qbits, (int)xqm->ex_bsiz,
721		     &dummy, NULL);
722    }
723#endif
724    qm->dm_rut = LoadRUC(fd);
725    qm->dm_nv = readNV(fd);
726    df->df_rcount++;
727    if ((mode & DM_WRITABLE) && (df->df_flags & DF_WRITABLE)) {
728      qm->dm_flags |= DM_WRITABLE;
729    }
730    return 0;
731}
732
733/*
734 * CLOSE
735 */
736/*ARGSUSED*/
737void
738FQclose(struct RkContext *cx, struct DM *dm, struct DM *qm, char *file)
739{
740  struct DF		*df = qm->dm_file;
741  struct xqm		*xqm;
742#ifndef WIN
743  int			fd = (int)df->df_extdata.var;
744#else
745  HANDLE		fd = df->df_extdata.hnd;
746#endif
747
748  xqm = (struct xqm *)qm->dm_extdata.ptr;
749  if (xqm) {
750    if (qm->dm_qbits) {
751      if (qm->dm_flags & DM_UPDATED) {
752#ifndef WIN
753	(void)lseek(fd, xqm->ex_boff, 0);
754	(void)write(fd, (char *)qm->dm_qbits, (int)xqm->ex_bsiz);
755#else
756	DWORD dummy;
757
758	(void)SetFilePointer(fd, xqm->ex_boff, NULL, FILE_BEGIN);
759	(void)ReadFile(fd, (char *)qm->dm_qbits, (int)xqm->ex_bsiz,
760		       &dummy, NULL);
761#endif
762      };
763      free(qm->dm_qbits);
764      qm->dm_qbits = (unsigned char *)0;
765    }
766  }
767  if (qm->dm_rut) {
768    if (qm->dm_flags & DM_UPDATED)
769      SaveRUC(fd, qm->dm_rut);
770    freeRUT(qm->dm_rut);
771    qm->dm_rut = (struct RUT *)0;
772  }
773  if (qm->dm_nv) {
774    if (qm-> dm_flags & DM_UPDATED)
775      writeNV(fd, qm->dm_nv);
776    abolishNV(qm->dm_nv);
777    qm->dm_nv = (struct NV *)0;
778  }
779  qm->dm_flags &= ~DM_UPDATED;
780  if (--df->df_rcount == 0)  {
781    struct DM	*dmh, *ddm;
782
783#ifndef WIN
784    (void)close(fd);
785#else
786    (void)CloseHandle(fd);
787#endif
788    dmh = &df->df_members;
789    for (ddm = dmh->dm_next; ddm != dmh; ddm = ddm->dm_next) {
790      xqm = (struct xqm *)ddm->dm_extdata.ptr;
791      if (xqm) {
792	free(xqm);
793	ddm->dm_extdata.ptr = (pointer)0;
794      }
795    }
796  }
797}
798
799int
800FQsync(struct RkContext *cx, struct DM *dm, struct DM *qm, char *file)
801/* ARGSUSED */
802{
803  struct DF		*df = qm->dm_file;
804  struct xqm		*xqm;
805  int rv;
806#ifndef WIN
807  int			fd = (int)df->df_extdata.var;
808#else
809  HANDLE		fd = df->df_extdata.hnd;
810#endif
811
812  rv = 0;
813  xqm = (struct xqm *)qm->dm_extdata.ptr;
814  if (xqm) {
815    if (qm->dm_qbits) {
816      if (qm->dm_flags & DM_UPDATED) {
817#ifndef WIN
818	(void)lseek(fd, xqm->ex_boff, 0);
819	if (write(fd, (char *)qm->dm_qbits, (int)xqm->ex_bsiz) !=
820	    (int) xqm->ex_bsiz)
821	  rv = -1;
822#else
823	DWORD dummy;
824
825	(void)SetFilePointer(fd, xqm->ex_boff, NULL, FILE_BEGIN);
826	if (!WriteFile(fd, (char *)qm->dm_qbits, (int)xqm->ex_bsiz,
827		       &dummy, NULL) || (DWORD)xqm->ex_bsiz != dummy) {
828	  rv = -1;
829	}
830#endif
831	if (qm->dm_rut)
832	  rv = SaveRUC(fd, qm->dm_rut) - 1;
833	if (qm->dm_nv)
834	  rv = writeNV(fd, qm->dm_nv);
835      }
836      if (!rv)
837	qm->dm_flags &= ~DM_UPDATED;
838    }
839  }
840  return (rv);
841}
842
843
844