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 librararies 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>
36 #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 _MMWriteDb(DtDirPaths *dirs, int num_db, DtDtsDbDatabase **db_list,
82 const char *CacheFile)
92 memset(&header, '\0', sizeof(header));
93 int_handle = _DtShmProtoInitIntLst(50000);
94 shm_handle = _DtShmProtoInitStrtab(10000);
96 build_file_list(int_handle, dirs, &header, suffix);
98 _DtMMSortDataTypes(shm_handle);
99 db = (DtDtsDbDatabase *) _DtDtsDbGet(DtDTS_DA_NAME);
100 _DtMMAddActionsToDataAttribute(db);
102 header.pathhash = _DtDtsMMPathHash(dirs);
103 header.num_db = num_db;
104 header.db_offset = build_new_db(shm_handle, int_handle, num_db,
106 db = (DtDtsDbDatabase *) _DtDtsDbGet("DATA_CRITERIA");
107 build_name_list(db, int_handle, &header);
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);
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);
120 returnCode = write_db(&header, tbl_data, tbl_size, CacheFile);
121 _DtShmProtoDestroyStrtab(shm_handle);
122 _DtShmProtoDestroyIntLst(int_handle);
123 _DtSvcProcessUnlock();
130 build_file_list(DtShmProtoIntList int_handle, DtDirPaths *dirs,
131 DtDtsMMHeader *header, const char *suffix)
134 struct dirent *dp = NULL;
136 char cur_path[MAXPATHLEN+1];
138 int size = sizeof(buf.st_mtime);
141 DtShmBoson *boson_list = 0;
142 time_t *mtime_list = 0;
144 _Xreaddirparams dirEntryBuf;
145 struct dirent *result;
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);
153 getcwd(cur_path, sizeof(cur_path));
154 for(i = 0; dirs->paths[i]; i++)
156 chdir(dirs->paths[i]);
159 boson_list = (int *)realloc(boson_list, count*sizeof(int));
160 mtime_list = (time_t *)realloc(mtime_list, count*sizeof(time_t));
162 mtime_list[count-1] = buf.st_mtime;
163 boson_list[count-1] = _DtShmProtoAddStrtab(shm_handle, dirs->paths[i], &isnew);
165 while ((result = _XReaddir(dirp, dirEntryBuf)) != NULL)
167 char *c = strrchr(result->d_name, suffix[0]);
168 if(c && strcmp(c, suffix) == 0)
170 char *pathname = malloc(MAXPATHLEN+1);
171 sprintf(pathname, "%s/%s", dirs->paths[i], result->d_name);
172 stat(result->d_name, &buf);
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,
179 if (pathname) free(pathname);
183 (void)closedir( dirp );
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 if(boson_list)free(boson_list);
192 if(mtime_list)free(mtime_list);
197 db_table_size(int num_db, DtDtsDbDatabase **db_list)
200 DtDtsDbDatabase *db_ptr;
202 DtDtsDbRecord *rec_ptr;
204 DtDtsDbField *fld_ptr;
207 size += num_db*sizeof(DtDtsMMDatabase);
208 for(db = 0; db < num_db; db++)
210 db_ptr = db_list[db];
211 size += db_ptr->recordCount * sizeof(DtDtsMMRecord);
212 for(rec = 0; rec < db_ptr->recordCount; rec++)
214 rec_ptr = db_ptr->recordList[rec];
215 size += rec_ptr->fieldCount * sizeof(DtDtsMMField);
218 return(size/sizeof(int));
221 _DtMMSortDataTypes(DtShmProtoStrtab str_handle)
228 dc = (DtDtsDbDatabase *) _DtDtsDbGet(DtDTS_DC_NAME);
229 da = (DtDtsDbDatabase *) _DtDtsDbGet(DtDTS_DA_NAME);
231 /*_DtDtsDbPrintRecords(dc, stdout);*/
232 for(i = 0; i < dc->recordCount; i++)
234 if(dc->recordList[i]->compare != cde_dc_field_compare)
236 _DtDtsDbFieldSort(dc->recordList[i],
237 cde_dc_field_compare);
240 _DtDtsDbRecordSort(dc, cde_dc_compare);
242 for(i = 0; i < da->recordCount; i++)
244 if(da->recordList[i]->compare !=
245 _DtDtsDbCompareFieldNames)
247 _DtDtsDbFieldSort(da->recordList[i],
248 _DtDtsDbCompareFieldNames);
252 _DtDtsDbRecordSort(da, _DtDtsDbCompareRecordNames);
253 /*_DtDtsDbPrintRecords(dc, stdout);*/
254 _DtSvcProcessUnlock();
258 add_if_missing(DtDtsDbRecord *rec_ptr, XrmQuark name, char *value)
260 DtDtsDbField *fld_ptr;
264 for(fld = 0; fld < rec_ptr->fieldCount; fld++)
266 fld_ptr = rec_ptr->fieldList[fld];
267 if(name == fld_ptr->fieldName)
278 fld_ptr = _DtDtsDbAddField(rec_ptr);
279 fld_ptr->fieldName = name;
280 fld_ptr->fieldValue = value;
281 _DtDtsDbFieldSort(rec_ptr, 0);
287 _DtMMAddActionsToDataAttribute(DtDtsDbDatabase *db_ptr)
290 DtDtsDbRecord *rec_ptr;
296 XrmQuark desc_qrk = XrmStringToQuark(DtDTS_DA_DESCRIPTION);
297 XrmQuark icon_qrk = XrmStringToQuark(DtDTS_DA_ICON);
298 XrmQuark label_qrk = XrmStringToQuark(DtDTS_DA_LABEL);
300 for(rec = 0; rec < db_ptr->recordCount; rec++)
307 rec_ptr = db_ptr->recordList[rec];
308 obj_type = XrmQuarkToString(rec_ptr->recordName);
310 if ( _DtDtsDbGetFieldByName(rec_ptr,
311 DtDTS_DA_IS_ACTION) == 0 )
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));
323 build_new_db(DtShmProtoStrtab shm_handle, DtShmProtoIntList int_handle, int num_db, DtDtsDbDatabase **db_list)
325 DtDtsMMDatabase *new_db_list;
327 DtDtsDbDatabase *db_ptr;
328 DtDtsMMDatabase *new_db_ptr;
330 DtDtsDbRecord *rec_ptr;
331 DtDtsMMRecord *new_rec_ptr;
332 DtDtsMMRecord *new_rec_ptr_list;
334 DtDtsDbField *fld_ptr;
335 DtDtsMMField *new_fld_ptr;
336 DtDtsMMField *new_fld_ptr_list;
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),
346 for(db = 0; db < num_db; db++)
350 DtShmProtoInttab nameIndex;
354 new_db_ptr = &new_db_list[db];
355 db_ptr = db_list[db];
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),
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++)
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);
373 if(new_rec_ptr->recordName != last_boson)
375 /* save name position */
376 _DtShmProtoAddInttab(nameIndex, new_rec_ptr->recordName, rec);
378 last_boson = new_rec_ptr->recordName;
380 new_rec_ptr->pathId = _DtShmProtoAddStrtab(shm_handle,
381 tmp = _DtDbPathIdToString(rec_ptr->pathId),
384 new_rec_ptr->seq = rec_ptr->seq;
385 new_rec_ptr->fieldCount = rec_ptr->fieldCount;
387 /* create space for field list */
388 new_fld_ptr_list = (DtDtsMMField *)_DtShmProtoAddIntLst(int_handle,
389 rec_ptr->fieldCount*sizeof(DtDtsMMField)/sizeof(int),
392 new_rec_ptr->fieldList = index;
393 for(fld = 0; fld < rec_ptr->fieldCount; fld++)
395 new_fld_ptr = &new_fld_ptr_list[fld];
396 fld_ptr = rec_ptr->fieldList[fld];
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;
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);
419 srch(const void *a, const void *b)
421 int results = ((struct list *)a)->boson - ((struct list *)b)->boson;
425 results = ((struct list *)a)->rec - ((struct list *)b)->rec;
433 struct list *name_index,
440 printf("============== names =====================\n");
441 for(i = 0; name_index[i].boson; i++)
443 printf("%20s -> %s\n",
444 XrmQuarkToString(db->recordList[name_index[i].rec]->recordName),
445 _DtShmProtoLookUpStrtab(shm_handle,
446 name_index[i].boson));
448 printf("%d entries\n", i);
450 printf("============= other ======================\n");
451 for(i = 0; i < other_break; i++)
454 XrmQuarkToString(db->recordList[other[i].rec]->recordName));
456 printf("%d entries\n", i);
460 build_name_list(DtDtsDbDatabase *db,
461 DtShmProtoIntList int_handle,
468 struct list *name_index;
471 DtShmProtoInttab indexList = 0;
472 DtShmBoson last_boson = -1;
473 int *list_of_recs = 0;
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));
484 /* step through all records */
485 for(i = 0; i < db->recordCount; i++)
491 /* see if a name pattern exist */
492 attr = _DtDtsDbGetFieldByName(db->recordList[i],
496 /* it didn't so check path pattern */
497 attr = _DtDtsDbGetFieldByName(db->recordList[i],
501 /* neither exist so save it as plain buffer */
502 if(!head->buffer_start_index)
504 head->buffer_start_index = other_break;
506 other[other_break++].rec = i;
507 continue; /* go to next record */
511 /* we have a name now find its final component */
512 c = strrchr(attr, '/');
526 /* now see if that final component has any *,?,[ */
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 */
547 /* the name had something in it now lets get the suffix */
548 c = strrchr(attr, '.');
551 /* lets see if the suffix has any *,?,[ */
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;
570 /* couldn't find any thing so save it as other */
571 other[other_break++].rec = i;
578 qsort(name_index, next, sizeof(struct list), srch);
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);
587 /* create a table and add the records to it. However
588 duplicates need to be in separate lists.
590 indexList = _DtShmProtoInitInttab(next+3);
591 for(i = 0; i <= next; i++)
593 if(i != next && (last_boson == -1 || name_index[i].boson == last_boson))
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;
603 /* we reached the end of a list now we check how many
608 /* if just one just add it in the index */
609 _DtShmProtoAddInttab(indexList,
610 last_boson, list_of_recs[0]);
614 /* if there are multiple items in the list
615 create a table for them */
616 int *list = _DtShmProtoAddIntLst(int_handle,
619 /* write the list to the to the table */
620 memcpy(list, list_of_recs,
621 list_count*sizeof(int));
623 /* then index on the negative of the boson
624 so that we know it is a list */
625 _DtShmProtoAddInttab(indexList,
628 list_of_recs = (int *)realloc(list_of_recs,
629 ++list_count*sizeof(int));
633 /* reset for the next set */
634 last_boson = name_index[i].boson;
635 list_of_recs[list_count-1] = name_index[i].rec;
641 /* same thing but they all go into a separate list */
644 /* create the space */
645 int *list = _DtShmProtoAddIntLst(int_handle,
646 other_break, &head->no_name_offset);
648 /* copy it into the list */
649 for(i = 0; i < other_break; i++)
651 list[i] = other[i].rec;
656 head->no_name_offset = -1;
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 if(name_index)free(name_index);
666 if(list_of_recs)free(list_of_recs);
667 if(other)free(other);
672 write_db(DtDtsMMHeader *header, void *index, int size, const char *CacheFile)
675 mode_t cmask = umask((mode_t)077);
677 /* tempnam(3) is affected by the TMPDIR environment variable. */
678 /* This creates problems for rename() is "tmpfile" and "cacheFile" */
679 /* are on different file systems. Use tmpnam(3) to create the */
680 /* unique file name instead. */
681 char tmpnam_buf[L_tmpnam + 1];
683 tmpfile = (char *)malloc(sizeof(_DTDTSMMTEMPDIR) +
684 sizeof(_DTDTSMMTEMPFILE) + L_tmpnam + 3);
686 sprintf(tmpfile, "%s/%s%s", _DTDTSMMTEMPDIR, _DTDTSMMTEMPFILE,
687 basename(tmpnam_buf));
689 fd = open(tmpfile, O_RDWR|O_CREAT, 0600);
695 DtProgName, DtError, NULL,
696 (char*) tmpfile, NULL);
700 /* Remove file on write failure - we don't */
701 /* want a partial dtdbcache file. */
702 if ((write(fd, header, sizeof(DtDtsMMHeader))
703 != sizeof(DtDtsMMHeader)) ||
704 (write(fd, index, size) != size))
714 if(rename((const char *)tmpfile, CacheFile) == -1)
717 DtProgName, DtError, NULL,
718 (char*) CacheFile, NULL);
719 unlink(CacheFile); /* Just in case? */
729 _DtActionCompareRecordBoson(
730 DtDtsMMRecord *record1,
731 DtDtsMMRecord *record2 )
733 int results = (int)record1->recordName - (int)record2->recordName;
738 return((int)record1 - (int)record2);