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 /* $TOG: MMDb.c /main/19 1998/10/23 13:48:52 mgreess $ */
27 * Copyright 1995 Sun Microsystems, Inc. All rights reserved.
32 #include <sys/types.h>
35 #include <sys/utsname.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>
54 #include <Dt/DtShmDb.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"
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 *);
75 static DtShmProtoStrtab shm_handle = 0;
76 static DtShmProtoIntList int_handle = 0;
78 #define QtB(a) _DtShmProtoAddStrtab(shm_handle, XrmQuarkToString(a), &isnew)
81 extern int _DtDtsMMPathHash(DtDirPaths *dirs);
85 _MMWriteDb(DtDirPaths *dirs, int num_db, DtDtsDbDatabase **db_list,
86 const char *CacheFile)
96 memset(&header, '\0', sizeof(header));
97 int_handle = _DtShmProtoInitIntLst(50000);
98 shm_handle = _DtShmProtoInitStrtab(10000);
100 build_file_list(int_handle, dirs, &header, suffix);
102 _DtMMSortDataTypes(shm_handle);
103 db = (DtDtsDbDatabase *) _DtDtsDbGet(DtDTS_DA_NAME);
104 _DtMMAddActionsToDataAttribute(db);
106 header.pathhash = _DtDtsMMPathHash(dirs);
107 header.num_db = num_db;
108 header.db_offset = build_new_db(shm_handle, int_handle, num_db,
110 db = (DtDtsDbDatabase *) _DtDtsDbGet("DATA_CRITERIA");
111 build_name_list(db, int_handle, &header);
113 tbl_size = _DtShmProtoSizeStrtab(shm_handle);
114 tbl_data = (void *) _DtShmProtoAddIntLst(int_handle,
115 tbl_size/sizeof(int), &header.str_tbl_offset);
116 _DtShmProtoCopyStrtab(shm_handle, tbl_data);
119 tbl_size = _DtShmProtoSizeIntLst(int_handle);
120 tbl_data = (void *)malloc(tbl_size);
121 memset(tbl_data, '\0', tbl_size);
122 tbl_data = (void *)_DtShmProtoCopyIntLst(int_handle, tbl_data);
124 returnCode = write_db(&header, tbl_data, tbl_size, CacheFile);
125 _DtShmProtoDestroyStrtab(shm_handle);
126 _DtShmProtoDestroyIntLst(int_handle);
127 _DtSvcProcessUnlock();
134 build_file_list(DtShmProtoIntList int_handle, DtDirPaths *dirs,
135 DtDtsMMHeader *header, const char *suffix)
138 struct dirent *dp = NULL;
140 char cur_path[MAXPATHLEN+1];
142 int size = sizeof(buf.st_mtime);
145 DtShmBoson *boson_list = 0;
146 time_t *mtime_list = 0;
148 _Xreaddirparams dirEntryBuf;
149 struct dirent *result;
151 /* Theses here to make sure it gets into the string tables
152 because actions uses it in its "types" field. */
153 _DtShmProtoAddStrtab(shm_handle, DtDTS_DT_UNKNOWN, &isnew);
154 _DtShmProtoAddStrtab(shm_handle, DtDTS_DT_RECURSIVE_LINK, &isnew);
155 _DtShmProtoAddStrtab(shm_handle, DtDTS_DT_BROKEN_LINK, &isnew);
157 getcwd(cur_path, sizeof(cur_path));
158 for(i = 0; dirs->paths[i]; i++)
160 chdir(dirs->paths[i]);
163 boson_list = (int *)realloc(boson_list, count*sizeof(int));
164 mtime_list = (time_t *)realloc(mtime_list, count*sizeof(time_t));
166 mtime_list[count-1] = buf.st_mtime;
167 boson_list[count-1] = _DtShmProtoAddStrtab(shm_handle, dirs->paths[i], &isnew);
169 while ((result = _XReaddir(dirp, dirEntryBuf)) != NULL)
171 char *c = strrchr(result->d_name, suffix[0]);
172 if(c && strcmp(c, suffix) == 0)
174 char *pathname = malloc(MAXPATHLEN+1);
175 sprintf(pathname, "%s/%s", dirs->paths[i], result->d_name);
176 stat(result->d_name, &buf);
178 boson_list = (int *)realloc(boson_list, count*sizeof(int));
179 mtime_list = (time_t *)realloc(mtime_list, count*sizeof(time_t));
180 mtime_list[count-1] = buf.st_mtime;
181 boson_list[count-1] = _DtShmProtoAddStrtab(shm_handle,
187 (void)closedir( dirp );
190 data = _DtShmProtoAddIntLst(int_handle, count, &header->files_offset);
191 memcpy(data, boson_list, count*sizeof(int));
192 data = _DtShmProtoAddIntLst(int_handle, count*sizeof(time_t)/sizeof(int), &header->mtimes_offset);
193 memcpy(data, mtime_list, count*sizeof(time_t));
194 header->files_count = count;
201 db_table_size(int num_db, DtDtsDbDatabase **db_list)
204 DtDtsDbDatabase *db_ptr;
206 DtDtsDbRecord *rec_ptr;
208 DtDtsDbField *fld_ptr;
211 size += num_db*sizeof(DtDtsMMDatabase);
212 for(db = 0; db < num_db; db++)
214 db_ptr = db_list[db];
215 size += db_ptr->recordCount * sizeof(DtDtsMMRecord);
216 for(rec = 0; rec < db_ptr->recordCount; rec++)
218 rec_ptr = db_ptr->recordList[rec];
219 size += rec_ptr->fieldCount * sizeof(DtDtsMMField);
222 return(size/sizeof(int));
225 _DtMMSortDataTypes(DtShmProtoStrtab str_handle)
232 dc = (DtDtsDbDatabase *) _DtDtsDbGet(DtDTS_DC_NAME);
233 da = (DtDtsDbDatabase *) _DtDtsDbGet(DtDTS_DA_NAME);
235 /*_DtDtsDbPrintRecords(dc, stdout);*/
236 for(i = 0; i < dc->recordCount; i++)
238 if(dc->recordList[i]->compare != cde_dc_field_compare)
240 _DtDtsDbFieldSort(dc->recordList[i],
241 cde_dc_field_compare);
244 _DtDtsDbRecordSort(dc, cde_dc_compare);
246 for(i = 0; i < da->recordCount; i++)
248 if(da->recordList[i]->compare !=
249 _DtDtsDbCompareFieldNames)
251 _DtDtsDbFieldSort(da->recordList[i],
252 _DtDtsDbCompareFieldNames);
256 _DtDtsDbRecordSort(da, _DtDtsDbCompareRecordNames);
257 /*_DtDtsDbPrintRecords(dc, stdout);*/
258 _DtSvcProcessUnlock();
262 add_if_missing(DtDtsDbRecord *rec_ptr, XrmQuark name, char *value)
264 DtDtsDbField *fld_ptr;
268 for(fld = 0; fld < rec_ptr->fieldCount; fld++)
270 fld_ptr = rec_ptr->fieldList[fld];
271 if(name == fld_ptr->fieldName)
282 fld_ptr = _DtDtsDbAddField(rec_ptr);
283 fld_ptr->fieldName = name;
284 fld_ptr->fieldValue = value;
285 _DtDtsDbFieldSort(rec_ptr, 0);
291 _DtMMAddActionsToDataAttribute(DtDtsDbDatabase *db_ptr)
294 DtDtsDbRecord *rec_ptr;
300 XrmQuark desc_qrk = XrmStringToQuark(DtDTS_DA_DESCRIPTION);
301 XrmQuark icon_qrk = XrmStringToQuark(DtDTS_DA_ICON);
302 XrmQuark label_qrk = XrmStringToQuark(DtDTS_DA_LABEL);
304 for(rec = 0; rec < db_ptr->recordCount; rec++)
311 rec_ptr = db_ptr->recordList[rec];
312 obj_type = XrmQuarkToString(rec_ptr->recordName);
314 if ( _DtDtsDbGetFieldByName(rec_ptr,
315 DtDTS_DA_IS_ACTION) == 0 )
319 add_if_missing(rec_ptr, desc_qrk,
320 DtActionDescription(obj_type));
321 add_if_missing(rec_ptr, icon_qrk, DtActionIcon(obj_type));
322 add_if_missing(rec_ptr, label_qrk, DtActionLabel(obj_type));
327 build_new_db(DtShmProtoStrtab shm_handle, DtShmProtoIntList int_handle, int num_db, DtDtsDbDatabase **db_list)
329 DtDtsMMDatabase *new_db_list;
331 DtDtsDbDatabase *db_ptr;
332 DtDtsMMDatabase *new_db_ptr;
334 DtDtsDbRecord *rec_ptr;
335 DtDtsMMRecord *new_rec_ptr;
336 DtDtsMMRecord *new_rec_ptr_list;
338 DtDtsDbField *fld_ptr;
339 DtDtsMMField *new_fld_ptr;
340 DtDtsMMField *new_fld_ptr_list;
346 /* create a space to hold the list of database structures */
347 new_db_list = (DtDtsMMDatabase *)_DtShmProtoAddIntLst(int_handle,
348 num_db*sizeof(DtDtsMMDatabase)/sizeof(int),
350 for(db = 0; db < num_db; db++)
354 DtShmProtoInttab nameIndex;
358 new_db_ptr = &new_db_list[db];
359 db_ptr = db_list[db];
361 new_db_ptr->databaseName = _DtShmProtoAddStrtab(shm_handle, db_ptr->databaseName, &isnew);
362 new_db_ptr->recordCount = db_ptr->recordCount;
363 /* create space to hold record list */
364 new_rec_ptr_list = (DtDtsMMRecord *)_DtShmProtoAddIntLst(int_handle,
365 db_ptr->recordCount*sizeof(DtDtsMMRecord)/sizeof(int),
368 new_db_ptr->recordList = index;
369 /* create index to names list */
370 nameIndex = _DtShmProtoInitInttab(db_ptr->recordCount);
371 for(rec = 0; rec < db_ptr->recordCount; rec++)
373 new_rec_ptr = &new_rec_ptr_list[rec];
374 rec_ptr = db_ptr->recordList[rec];
375 new_rec_ptr->recordName = QtB(rec_ptr->recordName);
377 if(new_rec_ptr->recordName != last_boson)
379 /* save name position */
380 _DtShmProtoAddInttab(nameIndex, new_rec_ptr->recordName, rec);
382 last_boson = new_rec_ptr->recordName;
384 new_rec_ptr->pathId = _DtShmProtoAddStrtab(shm_handle,
385 tmp = _DtDbPathIdToString(rec_ptr->pathId),
388 new_rec_ptr->seq = rec_ptr->seq;
389 new_rec_ptr->fieldCount = rec_ptr->fieldCount;
391 /* create space for field list */
392 new_fld_ptr_list = (DtDtsMMField *)_DtShmProtoAddIntLst(int_handle,
393 rec_ptr->fieldCount*sizeof(DtDtsMMField)/sizeof(int),
396 new_rec_ptr->fieldList = index;
397 for(fld = 0; fld < rec_ptr->fieldCount; fld++)
399 new_fld_ptr = &new_fld_ptr_list[fld];
400 fld_ptr = rec_ptr->fieldList[fld];
402 new_fld_ptr->fieldName = QtB(fld_ptr->fieldName);
403 new_fld_ptr->fieldValue = fld_ptr->fieldValue?_DtShmProtoAddStrtab(shm_handle,
404 fld_ptr->fieldValue, &isnew):0;
407 /* create table for index and save it */
408 size = _DtShmProtoSizeInttab(nameIndex);
409 idx = _DtShmProtoAddIntLst(int_handle, size/sizeof(int), &new_db_ptr->nameIndex);
410 _DtShmProtoCopyInttab(nameIndex, (void *)idx);
411 _DtShmProtoDestroyInttab(nameIndex);
423 srch(const void *a, const void *b)
425 int results = ((struct list *)a)->boson - ((struct list *)b)->boson;
429 results = ((struct list *)a)->rec - ((struct list *)b)->rec;
437 struct list *name_index,
444 printf("============== names =====================\n");
445 for(i = 0; name_index[i].boson; i++)
447 printf("%20s -> %s\n",
448 XrmQuarkToString(db->recordList[name_index[i].rec]->recordName),
449 _DtShmProtoLookUpStrtab(shm_handle,
450 name_index[i].boson));
452 printf("%d entries\n", i);
454 printf("============= other ======================\n");
455 for(i = 0; i < other_break; i++)
458 XrmQuarkToString(db->recordList[other[i].rec]->recordName));
460 printf("%d entries\n", i);
464 build_name_list(DtDtsDbDatabase *db,
465 DtShmProtoIntList int_handle,
472 struct list *name_index;
475 DtShmProtoInttab indexList = 0;
476 DtShmBoson last_boson = -1;
477 int *list_of_recs = 0;
483 /* create tmp space for two lists */
484 name_index = (struct list *)calloc(db->recordCount*2,
485 sizeof(struct list));
486 other = (struct list *)calloc(db->recordCount, sizeof(struct list));
488 /* step through all records */
489 for(i = 0; i < db->recordCount; i++)
495 /* see if a name pattern exist */
496 attr = _DtDtsDbGetFieldByName(db->recordList[i],
500 /* it didn't so check path pattern */
501 attr = _DtDtsDbGetFieldByName(db->recordList[i],
505 /* neither exist so save it as plain buffer */
506 if(!head->buffer_start_index)
508 head->buffer_start_index = other_break;
510 other[other_break++].rec = i;
511 continue; /* go to next record */
515 /* we have a name now find its final component */
516 c = strrchr(attr, '/');
530 /* now see if that final component has any *,?,[ */
543 /* it doesn't so save it in the name index */
544 name_index[next].boson =
545 _DtShmProtoAddStrtab(shm_handle,
546 (const char *)attr, &isnew);
547 name_index[next++].rec = i;
548 continue; /* next record */
551 /* the name had something in it now lets get the suffix */
552 c = strrchr(attr, '.');
555 /* lets see if the suffix has any *,?,[ */
566 /* it doesn't so save it in the name index */
567 name_index[next].boson =
568 _DtShmProtoAddStrtab(shm_handle,
569 (const char *)attr, &isnew);
570 name_index[next++].rec = i;
574 /* couldn't find any thing so save it as other */
575 other[other_break++].rec = i;
582 qsort(name_index, next, sizeof(struct list), srch);
586 showtable(db, name_index, other, head, other_break);
587 printf(" next = %d\n", next);
588 printf(" other_break = %d\n", other_break);
589 printf("head->buffer_start_index = %d\n", head->buffer_start_index);
591 /* create a table and add the records to it. However
592 duplicates need to be in separate lists.
594 indexList = _DtShmProtoInitInttab(next+3);
595 for(i = 0; i <= next; i++)
597 if(i != next && (last_boson == -1 || name_index[i].boson == last_boson))
599 /* this a new list of records or an addition to one */
600 list_of_recs = (int *)realloc(list_of_recs,
601 ++list_count*sizeof(int));
602 last_boson = name_index[i].boson;
603 list_of_recs[list_count-1] = name_index[i].rec;
607 /* we reached the end of a list now we check how many
612 /* if just one just add it in the index */
613 _DtShmProtoAddInttab(indexList,
614 last_boson, list_of_recs[0]);
618 /* if there are multiple items in the list
619 create a table for them */
620 int *list = _DtShmProtoAddIntLst(int_handle,
623 /* write the list to the to the table */
624 memcpy(list, list_of_recs,
625 list_count*sizeof(int));
627 /* then index on the negative of the boson
628 so that we know it is a list */
629 _DtShmProtoAddInttab(indexList,
632 list_of_recs = (int *)realloc(list_of_recs,
633 ++list_count*sizeof(int));
637 /* reset for the next set */
638 last_boson = name_index[i].boson;
639 list_of_recs[list_count-1] = name_index[i].rec;
645 /* same thing but they all go into a separate list */
648 /* create the space */
649 int *list = _DtShmProtoAddIntLst(int_handle,
650 other_break, &head->no_name_offset);
652 /* copy it into the list */
653 for(i = 0; i < other_break; i++)
655 list[i] = other[i].rec;
660 head->no_name_offset = -1;
663 /* make the real space */
664 size = _DtShmProtoSizeInttab(indexList);
665 space = _DtShmProtoAddIntLst(int_handle, size/sizeof(int),
666 &head->name_list_offset);
667 _DtShmProtoCopyInttab(indexList, space);
668 _DtShmProtoDestroyInttab(indexList);
676 write_db(DtDtsMMHeader *header, void *index, int size, const char *CacheFile)
679 mode_t cmask = umask((mode_t)077);
682 if ((tmpfile = malloc(sizeof(_DTDTSMMTEMPDIR) +
683 sizeof(_DTDTSMMTEMPFILE) + 7)) == NULL) {
684 _DtSimpleError(DtProgName, DtError, NULL, tmpfile, NULL);
688 sprintf(tmpfile, "%s/%sXXXXXX", _DTDTSMMTEMPDIR, _DTDTSMMTEMPFILE);
689 fd = mkstemp(tmpfile);
696 DtProgName, DtError, NULL,
697 (char*) tmpfile, NULL);
702 /* Remove file on write failure - we don't */
703 /* want a partial dtdbcache file. */
704 if ((write(fd, header, sizeof(DtDtsMMHeader))
705 != sizeof(DtDtsMMHeader)) ||
706 (write(fd, index, size) != size))
716 if(rename((const char *)tmpfile, CacheFile) == -1)
719 DtProgName, DtError, NULL,
720 (char*) CacheFile, NULL);
721 unlink(CacheFile); /* Just in case? */
731 intptr_t _DtActionCompareRecordBoson(
732 DtDtsMMRecord *record1,
733 DtDtsMMRecord *record2 )
735 int results = (int)record1->recordName - (int)record2->recordName;
740 return((intptr_t)record1 - (intptr_t)record2);