1d3e5b52626bdfb77e1391cb7f0afd66f2747580
[oweals/cde.git] / cde / lib / DtSvc / DtUtil1 / MMDb.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
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)
10  * any later version.
11  *
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
16  * details.
17  *
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
22  */
23 /* $TOG: MMDb.c /main/19 1998/10/23 13:48:52 mgreess $ */
24 /*
25  * +SNOTICE
26  * 
27  * Copyright 1995 Sun Microsystems, Inc.  All rights reserved.
28  * 
29  * +ENOTICE
30  */
31 #include <stdio.h>
32 #include <sys/types.h>
33
34 #include <unistd.h>
35 #include <sys/utsname.h>
36 #include <stdlib.h>
37
38 #include <ctype.h>
39 #include <string.h>
40 #include <stdint.h>
41
42 #ifdef NLS16
43 #include <limits.h>
44 #endif
45
46 #include <sys/stat.h>
47 #include <sys/param.h>          /* MAXPATHLEN, MAXHOSTNAMELEN */
48 #define X_INCLUDE_DIRENT_H
49 #define XOS_USE_XT_LOCKING
50 #include <X11/Xos_r.h>
51 #include <Dt/DbReader.h>
52 #include <Dt/DtsDb.h>
53 #include <Dt/DtsMM.h>
54 #include <Dt/DtShmDb.h>
55 #include <Dt/Dts.h>
56 #include <Dt/ActionP.h>
57 #include <Dt/ActionDbP.h>
58 #include <Dt/ActionUtilP.h>
59 #include <Dt/DtNlUtils.h>
60 #include <Dt/UserMsg.h>
61 #include "myassertP.h"
62 #include "DtSvcLock.h"
63
64 static void build_file_list(DtShmProtoIntList, DtDirPaths *,
65                             DtDtsMMHeader *, const char *);
66 extern  int     cde_dc_field_compare(DtDtsDbField **, DtDtsDbField **);
67 extern  int     cde_dc_compare(DtDtsDbRecord **, DtDtsDbRecord **);
68 static void     _DtMMSortDataTypes(DtShmProtoStrtab str_handle);
69 static void     _DtMMAddActionsToDataAttribute(DtDtsDbDatabase *db_ptr);
70 static int      write_db(DtDtsMMHeader *header, void *index, int size,
71                          const char *CacheFile);
72 static int      build_new_db(DtShmProtoStrtab, DtShmProtoIntList, int, DtDtsDbDatabase **);
73 static int      build_name_list(DtDtsDbDatabase *, DtShmProtoIntList, DtDtsMMHeader *);
74
75 static  DtShmProtoStrtab        shm_handle = 0;
76 static  DtShmProtoIntList       int_handle = 0;
77
78 #define QtB(a)  _DtShmProtoAddStrtab(shm_handle, XrmQuarkToString(a), &isnew)
79
80 int
81 _MMWriteDb(DtDirPaths *dirs, int num_db, DtDtsDbDatabase **db_list,
82            const char *CacheFile)
83 {
84         DtDtsMMHeader           header;
85         char                    *suffix = ".dt";
86         int                     tbl_size;
87         void                    *tbl_data;
88         DtDtsDbDatabase         *db;
89         int                     returnCode;
90
91         _DtSvcProcessLock();
92         memset(&header, '\0', sizeof(header));
93         int_handle = _DtShmProtoInitIntLst(50000);
94         shm_handle = _DtShmProtoInitStrtab(10000);
95
96         build_file_list(int_handle, dirs, &header, suffix);
97
98         _DtMMSortDataTypes(shm_handle);
99         db = (DtDtsDbDatabase   *) _DtDtsDbGet(DtDTS_DA_NAME);
100         _DtMMAddActionsToDataAttribute(db);
101
102         header.pathhash = _DtDtsMMPathHash(dirs);
103         header.num_db = num_db;
104         header.db_offset = build_new_db(shm_handle, int_handle, num_db,
105 db_list);
106         db = (DtDtsDbDatabase   *) _DtDtsDbGet("DATA_CRITERIA");
107         build_name_list(db, int_handle, &header);
108
109         tbl_size = _DtShmProtoSizeStrtab(shm_handle);
110         tbl_data = (void *) _DtShmProtoAddIntLst(int_handle,
111                                 tbl_size/sizeof(int), &header.str_tbl_offset);
112         _DtShmProtoCopyStrtab(shm_handle, tbl_data);
113
114
115         tbl_size = _DtShmProtoSizeIntLst(int_handle);
116         tbl_data = (void *)malloc(tbl_size);
117         memset(tbl_data, '\0', tbl_size);
118         tbl_data = (void *)_DtShmProtoCopyIntLst(int_handle, tbl_data);
119
120         returnCode = write_db(&header, tbl_data, tbl_size, CacheFile);
121         _DtShmProtoDestroyStrtab(shm_handle);
122         _DtShmProtoDestroyIntLst(int_handle);
123         _DtSvcProcessUnlock();
124         free(tbl_data);
125
126         return returnCode;
127 }
128
129 static void
130 build_file_list(DtShmProtoIntList int_handle, DtDirPaths *dirs,
131                 DtDtsMMHeader *header, const char *suffix)
132 {
133         DIR                     *dirp;
134         struct dirent           *dp = NULL;
135         struct stat             buf;
136         char                    cur_path[MAXPATHLEN+1];
137         void                    *data;
138         int                     size = sizeof(buf.st_mtime);
139         int                     i;
140         int                     isnew;
141         DtShmBoson              *boson_list = 0;
142         time_t                  *mtime_list = 0;
143         int                     count = 0;
144         _Xreaddirparams         dirEntryBuf;
145         struct dirent           *result;
146
147         /* Theses here to make sure it gets into the string tables
148            because actions uses it in its "types" field. */
149         _DtShmProtoAddStrtab(shm_handle, DtDTS_DT_UNKNOWN, &isnew);
150         _DtShmProtoAddStrtab(shm_handle, DtDTS_DT_RECURSIVE_LINK, &isnew);
151         _DtShmProtoAddStrtab(shm_handle, DtDTS_DT_BROKEN_LINK, &isnew);
152
153         getcwd(cur_path, sizeof(cur_path));
154         for(i = 0; dirs->paths[i]; i++)
155         {
156                 chdir(dirs->paths[i]);
157                 stat(".", &buf);
158                 count++;
159                 boson_list = (int *)realloc(boson_list, count*sizeof(int));
160                 mtime_list = (time_t *)realloc(mtime_list, count*sizeof(time_t));
161
162                 mtime_list[count-1] = buf.st_mtime;
163                 boson_list[count-1] = _DtShmProtoAddStrtab(shm_handle, dirs->paths[i], &isnew);
164                 dirp = opendir(".");
165                 while ((result = _XReaddir(dirp, dirEntryBuf)) != NULL)
166                 {
167                         char    *c = strrchr(result->d_name, suffix[0]);
168                         if(c && strcmp(c, suffix) == 0)
169                         {
170                                 char    *pathname = malloc(MAXPATHLEN+1);
171                                 sprintf(pathname, "%s/%s", dirs->paths[i], result->d_name);
172                                 stat(result->d_name, &buf);
173                                 count++;
174                                 boson_list = (int *)realloc(boson_list, count*sizeof(int));
175                                 mtime_list = (time_t *)realloc(mtime_list, count*sizeof(time_t));
176                                 mtime_list[count-1] = buf.st_mtime;
177                                 boson_list[count-1] = _DtShmProtoAddStrtab(shm_handle,
178                                         pathname, &isnew);
179                                 free(pathname);
180                                 continue;
181                         }
182                 }
183                 (void)closedir( dirp );
184         }
185         chdir(cur_path);
186         data = _DtShmProtoAddIntLst(int_handle, count, &header->files_offset);
187         memcpy(data, boson_list, count*sizeof(int));
188         data = _DtShmProtoAddIntLst(int_handle, count*sizeof(time_t)/sizeof(int), &header->mtimes_offset);
189         memcpy(data, mtime_list, count*sizeof(time_t));
190         header->files_count = count;
191         free(boson_list);
192         free(mtime_list);
193         return;
194 }
195
196 static int
197 db_table_size(int num_db, DtDtsDbDatabase **db_list)
198 {
199         int                     db;
200         DtDtsDbDatabase         *db_ptr;
201         int                     rec;
202         DtDtsDbRecord           *rec_ptr;
203         int                     fld;
204         DtDtsDbField            *fld_ptr;
205         int                     size = 0;
206
207         size += num_db*sizeof(DtDtsMMDatabase);
208         for(db = 0; db < num_db; db++)
209         {
210                 db_ptr = db_list[db];
211                 size += db_ptr->recordCount * sizeof(DtDtsMMRecord);
212                 for(rec = 0; rec < db_ptr->recordCount; rec++)
213                 {
214                         rec_ptr = db_ptr->recordList[rec];
215                         size += rec_ptr->fieldCount * sizeof(DtDtsMMField);
216                 }
217         }
218         return(size/sizeof(int));
219 }
220 static void
221 _DtMMSortDataTypes(DtShmProtoStrtab str_handle)
222 {
223         DtDtsDbDatabase *dc;
224         DtDtsDbDatabase *da;
225         int             i;
226
227         _DtSvcProcessLock();       
228         dc = (DtDtsDbDatabase *) _DtDtsDbGet(DtDTS_DC_NAME);
229         da = (DtDtsDbDatabase *) _DtDtsDbGet(DtDTS_DA_NAME);
230
231 /*_DtDtsDbPrintRecords(dc, stdout);*/
232         for(i = 0; i < dc->recordCount; i++)
233         {
234                 if(dc->recordList[i]->compare != cde_dc_field_compare)
235                 {
236                         _DtDtsDbFieldSort(dc->recordList[i], 
237                                 cde_dc_field_compare);
238                 }
239         }
240         _DtDtsDbRecordSort(dc, cde_dc_compare);
241
242         for(i = 0; i < da->recordCount; i++)
243         {
244                 if(da->recordList[i]->compare !=
245                                 _DtDtsDbCompareFieldNames)
246                 {
247                         _DtDtsDbFieldSort(da->recordList[i], 
248                                 _DtDtsDbCompareFieldNames);
249                 }
250         }
251
252         _DtDtsDbRecordSort(da, _DtDtsDbCompareRecordNames);
253 /*_DtDtsDbPrintRecords(dc, stdout);*/
254         _DtSvcProcessUnlock();
255 }
256
257 static void
258 add_if_missing(DtDtsDbRecord *rec_ptr, XrmQuark name, char *value)
259 {
260         DtDtsDbField    *fld_ptr;
261         int             fld;
262         int             found = 0;
263
264         for(fld = 0; fld < rec_ptr->fieldCount; fld++)
265         {
266                 fld_ptr = rec_ptr->fieldList[fld];
267                 if(name == fld_ptr->fieldName)
268                 {
269                         found = 1;
270                         break;
271                 }
272         }
273         if(found)
274         {
275                 return;
276         }
277
278         fld_ptr = _DtDtsDbAddField(rec_ptr);
279         fld_ptr->fieldName = name;
280         fld_ptr->fieldValue = value;
281         _DtDtsDbFieldSort(rec_ptr, 0);
282
283         return;
284 }
285
286 static void
287 _DtMMAddActionsToDataAttribute(DtDtsDbDatabase *db_ptr)
288 {
289         int             rec;
290         DtDtsDbRecord   *rec_ptr;
291         int             action_flag = 0;
292         int             sort_flag = 0;
293         int             found_flag = 0;
294         int             n;
295         const   char    *tmp;
296         XrmQuark        desc_qrk = XrmStringToQuark(DtDTS_DA_DESCRIPTION);
297         XrmQuark        icon_qrk = XrmStringToQuark(DtDTS_DA_ICON);
298         XrmQuark        label_qrk = XrmStringToQuark(DtDTS_DA_LABEL);
299
300         for(rec = 0; rec < db_ptr->recordCount; rec++)
301         {
302                 int     found_des = 0;
303                 int     found_icon = 0;
304                 int     found_label = 0;
305                 char    *obj_type;
306
307                 rec_ptr = db_ptr->recordList[rec];
308                 obj_type = XrmQuarkToString(rec_ptr->recordName);
309
310                 if ( _DtDtsDbGetFieldByName(rec_ptr,
311                                 DtDTS_DA_IS_ACTION) == 0 )
312                 {
313                         continue;
314                 }
315                 add_if_missing(rec_ptr, desc_qrk, 
316                                 DtActionDescription(obj_type));
317                 add_if_missing(rec_ptr, icon_qrk, DtActionIcon(obj_type));
318                 add_if_missing(rec_ptr, label_qrk, DtActionLabel(obj_type));
319         }
320 }
321
322 static int
323 build_new_db(DtShmProtoStrtab shm_handle, DtShmProtoIntList int_handle, int num_db, DtDtsDbDatabase **db_list)
324 {
325         DtDtsMMDatabase         *new_db_list;
326         int                     db;
327         DtDtsDbDatabase         *db_ptr;
328         DtDtsMMDatabase         *new_db_ptr;
329         int                     rec;
330         DtDtsDbRecord           *rec_ptr;
331         DtDtsMMRecord           *new_rec_ptr;
332         DtDtsMMRecord           *new_rec_ptr_list;
333         int                     fld;
334         DtDtsDbField            *fld_ptr;
335         DtDtsMMField            *new_fld_ptr;
336         DtDtsMMField            *new_fld_ptr_list;
337         int                     index;
338         int                     db_index;
339         int                     isnew;
340         char                    *tmp;
341
342         /* create a space to hold the list of database structures */
343         new_db_list = (DtDtsMMDatabase *)_DtShmProtoAddIntLst(int_handle,
344                         num_db*sizeof(DtDtsMMDatabase)/sizeof(int),
345                         &db_index);
346         for(db = 0; db < num_db; db++)
347         {
348                 int     last_boson = -1;
349                 int     list_count = 0;
350                 DtShmProtoInttab        nameIndex;
351                 int             size;
352                 int             *idx;
353
354                 new_db_ptr = &new_db_list[db];
355                 db_ptr = db_list[db];
356
357                 new_db_ptr->databaseName = _DtShmProtoAddStrtab(shm_handle, db_ptr->databaseName, &isnew);
358                 new_db_ptr->recordCount = db_ptr->recordCount;
359                 /* create space to hold record list */
360                 new_rec_ptr_list = (DtDtsMMRecord *)_DtShmProtoAddIntLst(int_handle,
361                                 db_ptr->recordCount*sizeof(DtDtsMMRecord)/sizeof(int),
362                                 &index);
363
364                 new_db_ptr->recordList = index;
365                 /* create index to names list */
366                 nameIndex = _DtShmProtoInitInttab(db_ptr->recordCount);
367                 for(rec = 0; rec < db_ptr->recordCount; rec++)
368                 {
369                         new_rec_ptr = &new_rec_ptr_list[rec];
370                         rec_ptr = db_ptr->recordList[rec];
371                         new_rec_ptr->recordName = QtB(rec_ptr->recordName);
372
373                         if(new_rec_ptr->recordName != last_boson)
374                         {
375                                 /* save name position */
376                                 _DtShmProtoAddInttab(nameIndex, new_rec_ptr->recordName, rec);
377
378                                 last_boson = new_rec_ptr->recordName;
379                         }
380                         new_rec_ptr->pathId = _DtShmProtoAddStrtab(shm_handle,
381                                 tmp = _DtDbPathIdToString(rec_ptr->pathId),
382                                                  &isnew);
383                         XtFree(tmp);
384                         new_rec_ptr->seq = rec_ptr->seq;
385                         new_rec_ptr->fieldCount = rec_ptr->fieldCount;
386
387                         /* create space for field list */
388                         new_fld_ptr_list = (DtDtsMMField *)_DtShmProtoAddIntLst(int_handle,
389                                 rec_ptr->fieldCount*sizeof(DtDtsMMField)/sizeof(int),
390                                 &index);
391
392                         new_rec_ptr->fieldList = index;
393                         for(fld = 0; fld < rec_ptr->fieldCount; fld++)
394                         {
395                                 new_fld_ptr = &new_fld_ptr_list[fld];
396                                 fld_ptr = rec_ptr->fieldList[fld];
397
398                                 new_fld_ptr->fieldName  = QtB(fld_ptr->fieldName);
399                                 new_fld_ptr->fieldValue = fld_ptr->fieldValue?_DtShmProtoAddStrtab(shm_handle,
400                                         fld_ptr->fieldValue, &isnew):0;
401                         }
402                 }
403                 /* create table for index and save it */
404                 size = _DtShmProtoSizeInttab(nameIndex);
405                 idx = _DtShmProtoAddIntLst(int_handle, size/sizeof(int), &new_db_ptr->nameIndex);
406                 _DtShmProtoCopyInttab(nameIndex, (void *)idx);
407                 _DtShmProtoDestroyInttab(nameIndex);
408         }
409         return(db_index);
410 }
411
412 struct  list
413 {
414         DtShmBoson      boson;
415         int             rec;
416 };
417
418 static int
419 srch(const void *a, const void *b)
420 {
421         int results = ((struct list *)a)->boson - ((struct list *)b)->boson;
422
423         if(results == 0)
424         {
425                 results = ((struct list *)a)->rec - ((struct list *)b)->rec;
426         }
427         return(results);
428 }
429
430 static void
431 showtable(
432         DtDtsDbDatabase *db,
433         struct list *name_index, 
434         struct list *other, 
435         DtDtsMMHeader *head,
436         int other_break)
437 {
438         int     i;
439
440         printf("============== names =====================\n");
441         for(i = 0; name_index[i].boson; i++)
442         {
443                 printf("%20s -> %s\n",
444                         XrmQuarkToString(db->recordList[name_index[i].rec]->recordName),
445                         _DtShmProtoLookUpStrtab(shm_handle, 
446                                         name_index[i].boson));
447         }
448         printf("%d entries\n", i);
449         
450         printf("============= other ======================\n");
451         for(i = 0; i < other_break; i++)
452         {
453                 printf("%s\n",
454                         XrmQuarkToString(db->recordList[other[i].rec]->recordName));
455         }
456         printf("%d entries\n", i);                      
457 }
458
459 static int
460 build_name_list(DtDtsDbDatabase *db,
461                 DtShmProtoIntList int_handle,
462                 DtDtsMMHeader   *head)
463 {
464         struct list     *other;
465         int             i;
466         char            *c;
467         int             isnew;
468         struct list     *name_index;
469         int             next = 0;
470         int             other_break = 0;
471         DtShmProtoInttab        indexList = 0;
472         DtShmBoson      last_boson = -1;
473         int             *list_of_recs = 0;
474         int             list_count = 0;
475         int             index = 0;
476         int             size;
477         void            *space;
478
479         /* create tmp space for two lists */
480         name_index = (struct list *)calloc(db->recordCount*2,
481                                         sizeof(struct list));
482         other = (struct list *)calloc(db->recordCount, sizeof(struct list));
483
484         /* step through all records */
485         for(i = 0; i < db->recordCount; i++)
486         {
487                 DtShmBoson      boson;
488                 char    *attr;
489                 char    *t;
490
491                 /* see if a name pattern exist */
492                 attr = _DtDtsDbGetFieldByName(db->recordList[i],
493                                 DtDTS_NAME_PATTERN);
494                 if(!attr)
495                 {
496                         /* it didn't so check path pattern */
497                         attr = _DtDtsDbGetFieldByName(db->recordList[i],
498                                 DtDTS_PATH_PATTERN);
499                         if(!attr)
500                         {
501                                 /* neither exist so save it as plain buffer */
502                                 if(!head->buffer_start_index)
503                                 {
504                                         head->buffer_start_index = other_break;
505                                 }
506                                 other[other_break++].rec = i;
507                                 continue; /* go to next record */
508                         }
509                 }
510
511                 /* we have a name now find its final component */
512                 c = strrchr(attr, '/');
513                 if(c)
514                 {
515                         c++;
516                 }
517                 if(!c)
518                 {
519                         c = attr;
520                 }
521                 else
522                 {
523                         attr = c;
524                 }
525
526                 /* now see if that final component has any *,?,[ */
527                 while(c && *c &&
528                           !(*c == '*' ||
529                             *c == '[' ||
530                             *c == '?' ||
531                             *c == '$' ))
532                 {
533                         c++;
534                 }
535
536
537                 if(c && *c == '\0')
538                 {
539                         /* it doesn't so save it in the name index */
540                         name_index[next].boson = 
541                                 _DtShmProtoAddStrtab(shm_handle,
542                                         (const char *)attr, &isnew);
543                         name_index[next++].rec = i;
544                         continue; /* next record */
545                 }
546
547                 /* the name had something in it now lets get the suffix */
548                 c = strrchr(attr, '.');
549                 attr = c;
550
551                 /* lets see if the suffix has any  *,?,[ */
552                 while(c && *c &&
553                           !(*c == '*' ||
554                             *c == '[' ||
555                             *c == '?' ||
556                             *c == '$' ))
557                 {
558                         c++;
559                 }
560                 if(c && *c == '\0')
561                 {
562                         /* it doesn't so save it in the name index */
563                         name_index[next].boson = 
564                         _DtShmProtoAddStrtab(shm_handle,
565                                         (const char *)attr, &isnew);
566                         name_index[next++].rec = i;
567                 }
568                 else
569                 {
570                         /* couldn't find any thing so save it as other */
571                         other[other_break++].rec = i;
572                 }
573
574         }
575
576         if (next > 0)
577         {
578                 qsort(name_index, next, sizeof(struct list), srch);
579         }
580
581 /*
582 showtable(db, name_index, other, head, other_break);
583 printf("                    next = %d\n", next);
584 printf("             other_break = %d\n", other_break);
585 printf("head->buffer_start_index = %d\n", head->buffer_start_index);
586 */
587         /* create a table and add the records to it. However
588            duplicates need to be in separate lists.
589         */
590         indexList = _DtShmProtoInitInttab(next+3);
591         for(i = 0; i <= next; i++)
592         {
593                 if(i != next && (last_boson == -1 || name_index[i].boson == last_boson))
594                 {
595                         /* this a new list of records or an addition to one */
596                         list_of_recs = (int *)realloc(list_of_recs, 
597                                         ++list_count*sizeof(int));
598                         last_boson = name_index[i].boson;
599                         list_of_recs[list_count-1] = name_index[i].rec;
600                 }
601                 else
602                 {
603                         /* we reached the end of a list now we check how many
604                                 are in the list. 
605                         */
606                         if(list_count == 1)
607                         {
608                                 /* if just one just add it in the index */
609                                 _DtShmProtoAddInttab(indexList,
610                                                 last_boson, list_of_recs[0]);
611                         }
612                         else
613                         {
614                                 /* if there are multiple items in the list
615                                    create a table for them */
616                                 int     *list = _DtShmProtoAddIntLst(int_handle,
617                                                 list_count, &index);
618
619                                 /* write the list to the to the table */
620                                 memcpy(list, list_of_recs,
621                                                 list_count*sizeof(int));
622
623                                 /* then index on the negative of the boson
624                                    so that we know it is a list */
625                                 _DtShmProtoAddInttab(indexList,
626                                                 last_boson, -index);
627                                 list_count = 0;
628                                 list_of_recs = (int *)realloc(list_of_recs, 
629                                                 ++list_count*sizeof(int));
630                         }
631                         if ( i != next )
632                         {
633                                 /* reset for the next set */
634                                 last_boson = name_index[i].boson;
635                                 list_of_recs[list_count-1] = name_index[i].rec;
636                         }
637                 }
638
639         }
640
641         /* same thing but they all go into a separate list */
642         if(other_break > 0)
643         {
644                 /* create the space */
645                 int     *list = _DtShmProtoAddIntLst(int_handle,
646                                 other_break, &head->no_name_offset);
647
648                 /* copy it into the list */
649                 for(i = 0; i < other_break; i++)
650                 {
651                         list[i] = other[i].rec;
652                 }
653         }
654         else
655         {
656                 head->no_name_offset = -1;
657         }
658
659         /* make the real space */
660         size = _DtShmProtoSizeInttab(indexList);
661         space = _DtShmProtoAddIntLst(int_handle, size/sizeof(int), 
662                                 &head->name_list_offset);
663         _DtShmProtoCopyInttab(indexList, space);
664         _DtShmProtoDestroyInttab(indexList);
665         free(name_index);
666         free(list_of_recs);
667         free(other);
668         return(index);
669 }
670
671 static int
672 write_db(DtDtsMMHeader *header, void *index, int size, const char *CacheFile)
673 {
674         int     fd;
675         mode_t  cmask = umask((mode_t)077);
676         char    *tmpfile;
677
678         if ((tmpfile = malloc(sizeof(_DTDTSMMTEMPDIR) +
679             sizeof(_DTDTSMMTEMPFILE) + 7)) == NULL) {
680                 _DtSimpleError(DtProgName, DtError, NULL, tmpfile, NULL);
681                 return 0;
682         }
683
684         sprintf(tmpfile, "%s/%sXXXXXX", _DTDTSMMTEMPDIR, _DTDTSMMTEMPFILE);
685         fd = mkstemp(tmpfile);
686
687         umask(cmask);
688
689         if(fd ==  -1)
690         {
691                 _DtSimpleError(
692                         DtProgName, DtError, NULL,
693                         (char*) tmpfile, NULL);
694                 free(tmpfile);
695                 return(0);
696         }
697
698         /* Remove file on write failure - we don't */
699         /* want a partial dtdbcache file. */
700         if ((write(fd, header, sizeof(DtDtsMMHeader))
701              != sizeof(DtDtsMMHeader)) ||
702             (write(fd, index, size) != size))
703         {
704                 close(fd);
705                 unlink(tmpfile);
706                 free(tmpfile);
707                 return(0);
708         }
709
710         close(fd);
711
712         if(rename((const char *)tmpfile, CacheFile) == -1)
713         {
714                 _DtSimpleError(
715                         DtProgName, DtError, NULL,
716                         (char*) CacheFile, NULL);
717                 unlink(CacheFile); /* Just in case? */
718                 unlink(tmpfile);
719                 free(tmpfile);
720                 return(0);
721         }
722         free(tmpfile);
723         return(1);
724 }
725
726
727 _DtActionCompareRecordBoson(
728         DtDtsMMRecord *record1,
729         DtDtsMMRecord *record2 )
730 {
731         int results = (int)record1->recordName - (int)record2->recordName;
732
733         if (results)
734                 return(results);
735
736         return((intptr_t)record1 - (intptr_t)record2);
737 }