b2e694f061a17f868c460b2912065b6c96979329
[oweals/cde.git] / cde / lib / tt / bin / ttdbserverd / db_server_functions.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 //%%  (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 //%%  $TOG: db_server_functions.C /main/6 1999/10/14 18:38:12 mgreess $                                                         
28 /*
29  * @(#)db_server_functions.C    1.35 95/06/07
30  *
31  * Copyright (c) 1992 by Sun Microsystems, Inc.
32  *
33  * This file contains the functions that connect the DB server RPC
34  * interface to the DB server classes.
35  *
36  * As a function is implemented, it should commented
37  * out of the db_server_stubs.cc file.
38  */
39
40 #include <dirent.h>
41 #include <sys/stat.h>
42 #include <sys/param.h>
43 #include <errno.h>
44 #include <stdint.h>
45 #include <unistd.h>
46 #include <nl_types.h>
47
48 #include "api/c/tt_c.h"
49 #include "util/tt_file_system.h"
50 #include "util/tt_file_system_entry.h"
51 #include "util/tt_path.h"
52 #include "util/tt_port.h"
53 #include "util/tt_xdr_utils.h"
54 #include "util/tt_gettext.h"
55 #include "db/db_server.h"
56 #include "db/tt_db_access.h"
57 #include "db/tt_db_property.h"
58 #include "db/tt_db_access_utils.h"
59 #include "db/tt_db_property_utils.h"
60 #include "db/tt_db_rpc_routines.h"
61 #include "db_server_globals.h"
62 #include "tt_db_message_info_utils.h"
63 #include "tt_db_partition_global_map_ref.h"
64 #include "tt_db_server_consts.h"
65 #include "tt_db_server_db_utils.h"
66 #include "dm_access_cache.h"
67 #include "dm/dm_recfmts.h"
68
69
70 #if !defined(OPT_GARBAGE_THREADS)
71 #include <db/tt_db_client.h>
72 #include <db/tt_db_client_utils.h>
73
74 char                            **global_argv;
75 char                            **global_envp;
76
77 #endif
78
79 //
80 // This is the PID or TID of the procedure that is
81 // performing the garbage collection.
82 //
83 #if defined(USL) || defined(__uxp__)
84 int             _tt_garbage_id = 0;     // TID or PID.
85 #else
86 int             _tt_garbage_id = -1;    // TID or PID.
87 #endif
88
89 int             _tt_run_garbage_collect(int in_parallel);
90
91 static  const char              * sesProp = _TT_FILEJOIN_PROPNAME;
92 static  const char              * modDate = _MP_NODE_MOD_PROP;
93 static  const char              * propTable = "property_table";
94
95 extern _Tt_db_info      _tt_db_table[_TT_MAX_ISFD];
96
97 static bool_t _tt_is_file_a_directory (const _Tt_string&);
98 static _Tt_string _tt_make_equivalent_object_id(const _Tt_string &objid,
99                                                 const _Tt_string &partition);
100 static _Tt_db_results _tt_get_partition_db (const _Tt_string&,
101                                             _Tt_db_server_db_ptr&);
102 static _Tt_db_access_ptr
103        _tt_get_real_rpc_access (const _tt_access &rpc_access);
104 static _Tt_db_access_ptr _tt_get_file_access (const _Tt_string &file,
105                                               const _tt_access &rpc_access);
106 static _Tt_db_access_ptr _tt_get_unix_file_access (const _Tt_string &file);
107 static _Tt_string _tt_get_file_partition (const _Tt_string &file);
108 static _Tt_db_results
109        _tt_increment_file_properties_cache_level (const _Tt_db_server_db_ptr&,
110                                                   const _Tt_string&,
111                                                   const _Tt_db_access_ptr&,
112                                                   int&);
113 static _Tt_db_results
114        _tt_get_file_properties_cache_level (const _Tt_db_server_db_ptr&,
115                                             const _Tt_string&,
116                                             const _Tt_db_access_ptr&,
117                                             int&);
118 static _Tt_string _tt_get_object_partition (const _Tt_string &objid);
119 static _Tt_db_results
120 _tt_increment_object_properties_cache_level (const _Tt_db_server_db_ptr&,
121                                              const _Tt_string&,
122                                              const _Tt_db_access_ptr&,
123                                              int&);
124 static _Tt_db_results
125        _tt_get_object_properties_cache_level (const _Tt_db_server_db_ptr&,
126                                               const _Tt_string&,
127                                               const _Tt_db_access_ptr&,
128                                               int&);
129 static void _tt_screen_object_properties (_Tt_db_property_list_ptr&);
130
131 static _Tt_string _tt_get_local_path (const _Tt_string &network_path,
132                                       _Tt_string       &hostname,
133                                       _Tt_string       &partition);
134
135 _tt_auth_level_results *_tt_get_min_auth_level_1 (void * /* dummy_arg */,
136                                                   SVCXPRT * /* transp */)
137 {
138   static _tt_auth_level_results results;
139   results.auth_level = _tt_auth_level;
140   results.results = TT_DB_OK;
141   return &results;
142 }
143
144 _tt_file_partition_results *_tt_get_file_partition_1 (char **file,
145                                                       SVCXPRT * /* transp */)
146 {
147   static _tt_file_partition_results results;
148
149   _Tt_string hostname = _tt_gethostname();
150
151   _Tt_string file_hostname;
152   _Tt_string network_path = *file;
153   _Tt_string partition;
154   _Tt_string local_path = _tt_get_local_path (network_path,
155                                               file_hostname,
156                                               partition);
157   results.partition = strdup((char *)partition);
158
159   if (file_hostname == hostname) {
160     network_path = file_hostname.cat(":").cat(local_path);
161   }
162   results.network_path = strdup((char *)network_path);
163
164   results.results = TT_DB_OK;
165
166   return &results;
167 }
168
169 _tt_db_cache_results *_tt_create_file_1 (_tt_create_file_args *args,
170                                          SVCXPRT * /* transp */)
171 {
172   static _tt_db_cache_results results;
173   results.cache_level = -1;
174
175   _Tt_string real_file = args->file;
176   _Tt_string partition = _tt_get_file_partition(args->file);
177   _Tt_db_server_db_ptr db;
178   results.results = _tt_get_partition_db(partition, db);
179
180   _Tt_db_access_ptr access = _tt_get_file_access(real_file, args->access);
181
182   if (results.results == TT_DB_OK) {
183     // See if the file already exists by trying to get its access info
184     _Tt_db_access_ptr temp_access;
185     _Tt_db_results temp_results = db->getFileAccess(real_file,
186                                                     access,
187                                                     temp_access);
188
189     // If the file exists...
190     if ((temp_results == TT_DB_OK) ||
191         (temp_results == TT_DB_ERR_ACCESS_DENIED)) {
192       results.results = TT_DB_ERR_FILE_EXISTS;
193     }
194     // Else, if the file does not exist...
195     else if (temp_results == TT_DB_ERR_NO_SUCH_FILE) {
196       results.results = TT_DB_OK;
197     }
198     else {
199       results.results = temp_results;
200     }
201   }
202
203   if (results.results == TT_DB_OK) {
204     results.results = db->createFile(real_file, access);
205
206     if (results.results == TT_DB_OK) {
207       _Tt_db_property_list_ptr properties;
208       _tt_get_rpc_properties(args->properties, properties);
209
210       if (!properties.is_null()) {
211         results.results = db->setFileProperties(real_file,
212                                                 properties,
213                                                 access);
214       }
215
216       if (results.results == TT_DB_OK) {
217         results.results =
218           _tt_increment_file_properties_cache_level(db,
219                                                     real_file,
220                                                     access,
221                                                     results.cache_level);
222       }
223     }
224   }
225
226   return &results;
227 }
228
229 _tt_db_cache_results *_tt_create_obj_1 (_tt_create_obj_args *args,
230                                         SVCXPRT * /* transp */)
231 {
232   static _tt_db_cache_results results;
233   results.cache_level = -1;
234
235   _Tt_string partition = _tt_get_object_partition(args->objid);
236   _Tt_db_server_db_ptr db;
237   results.results = _tt_get_partition_db(partition, db);
238
239   _Tt_string        real_file = args->file;
240   _Tt_db_access_ptr object_access = _tt_get_real_rpc_access(args->access);
241
242   if (results.results == TT_DB_OK) {
243     // See if the object already exists by trying to get the forward
244     // pointer property
245     _Tt_db_property_ptr temp_property;
246     _Tt_db_results temp_results =
247       db->getObjectProperty(args->objid,
248                             TT_DB_FORWARD_POINTER_PROPERTY,
249                             object_access,
250                             temp_property);
251
252     // If the property exists, remove the object
253     if (temp_results == TT_DB_OK) {
254       (void)db->removeObject(args->objid, object_access);
255     }
256     // Else if the object exists without a forward pointer...
257     else if (temp_results == TT_DB_ERR_NO_SUCH_PROPERTY) {
258       results.results = TT_DB_ERR_OBJECT_EXISTS;
259     }
260     // Else if the object does not exist...
261     else if (temp_results == TT_DB_ERR_NO_SUCH_OBJECT) {
262       results.results = TT_DB_OK;
263     }
264     else {
265       results.results = temp_results;
266     }
267   }
268
269   if (results.results == TT_DB_OK) {
270     _Tt_db_access_ptr file_access = _tt_get_file_access(real_file,
271                                                         args->access);
272     results.results = db->createObject(real_file,
273                                        args->objid,
274                                        object_access,
275                                        file_access);
276     
277     if (results.results == TT_DB_OK) {
278       _Tt_db_property_list_ptr properties;
279       _tt_get_rpc_properties(args->properties, properties);
280       
281       if (!properties.is_null()) {
282         _tt_screen_object_properties (properties);
283       }
284
285       if (!properties.is_null()) {
286         results.results = db->setObjectProperties(args->objid,
287                                                   properties,
288                                                   object_access);
289       }
290
291       // Set the otype of the object
292       if (results.results == TT_DB_OK) {
293         _Tt_db_property_ptr property = new _Tt_db_property;
294         property->name = TT_DB_OBJECT_TYPE_PROPERTY;
295         property->values->append(_Tt_string(args->otype));
296
297         results.results = db->setObjectProperty(args->objid,
298                                                 property,
299                                                 object_access);
300       }
301
302       if (results.results == TT_DB_OK) {
303         results.results =
304           _tt_increment_object_properties_cache_level(db,
305                                                       args->objid,
306                                                       object_access,
307                                                       results.cache_level);
308       }
309     }
310   }
311
312   return &results;
313 }
314
315 _tt_db_results *_tt_remove_file_1 (_tt_remove_file_args *args,
316                                    SVCXPRT * /* transp */)
317 {
318   static _tt_db_results results;
319
320   _Tt_db_access_ptr accessPtr = _tt_get_real_rpc_access(args->access);
321
322   _Tt_string real_file = args->file;
323   _Tt_string partition = _tt_get_file_partition(args->file);
324   _Tt_db_server_db_ptr db;
325   results = _tt_get_partition_db(partition, db);
326
327   if (results == TT_DB_OK) {
328     // Get the list of children under the file to remove along with
329     // the file.  The list includes the file itself.
330     _Tt_string_list_ptr children;
331     results = db->getFileChildren(real_file, children);
332
333     if (children->is_empty()) {
334       results = TT_DB_ERR_NO_SUCH_FILE;
335     }
336     else {
337       _Tt_string_list_cursor children_cursor(children);
338       while ((results == TT_DB_OK) && children_cursor.next()) {
339         results = db->removeFile(*children_cursor, accessPtr);
340       }
341     }
342   }
343
344   return &results;
345 }
346
347 _tt_db_results *_tt_remove_obj_1 (_tt_remove_obj_args *args,
348                                   SVCXPRT * /* transp */)
349 {
350   static _tt_db_results results;
351
352   _Tt_db_access_ptr accessPtr = _tt_get_real_rpc_access(args->access);
353
354   _Tt_string partition = _tt_get_object_partition(args->objid);
355   _Tt_db_server_db_ptr db;
356   results = _tt_get_partition_db(partition, db);
357
358   if (results == TT_DB_OK) {
359     results = db->removeObject(args->objid, accessPtr);
360
361     if (results == TT_DB_OK) {
362       if (args->forward_pointer && strlen(args->forward_pointer)) {
363         // Allow everyone to read and delete the forward pointer
364         _Tt_db_access_ptr new_access = new _Tt_db_access;
365         new_access->user = (uid_t)-1;
366         new_access->group = (gid_t)-1;
367         new_access->mode = (mode_t)-1;
368
369         // Create a special forward pointer object with no file...
370         results = db->createObject((char *)NULL,
371                                    args->objid,
372                                    new_access,
373                                    new_access);
374
375         if (results == TT_DB_OK) {
376           _Tt_db_property_ptr property = new _Tt_db_property;
377           property->name = TT_DB_FORWARD_POINTER_PROPERTY;
378           property->values->append(_Tt_string(args->forward_pointer));
379
380           results = db->setObjectProperty(args->objid, property, accessPtr);
381         }
382       }
383     }
384   }
385
386   return &results;
387 }
388
389 _tt_db_results *_tt_move_file_1 (_tt_move_file_args *args,
390                                  SVCXPRT * /* transp */)
391 {
392   static _tt_db_results results;
393
394   _Tt_db_access_ptr accessPtr = _tt_get_real_rpc_access(args->access);
395
396   _Tt_string real_file = args->file;
397   _Tt_string real_new_file = args->new_file;
398
399   // Make sure we really need to do a move
400   if (real_file != real_new_file) {
401     _Tt_file_system           fs;
402     _Tt_file_system_entry_ptr entry = fs.bestMatchToPath(real_file);
403     _Tt_file_system_entry_ptr new_entry = fs.bestMatchToPath(real_new_file);
404     
405     _Tt_string partition = entry->getMountPoint();
406     _Tt_string new_partition = new_entry->getMountPoint();
407     
408     if (partition == new_partition) {
409       // Get a connection to the partition DB
410       _Tt_db_server_db_ptr db;
411       results = _tt_get_partition_db(partition, db);
412
413       _Tt_string_list_ptr children;
414       if (results == TT_DB_OK) {
415         // Get a list of the files to move
416         results = db->getFileChildren(real_file, children);
417       }
418
419       if (results == TT_DB_OK) {
420         if (children->is_empty ()) {
421           results = TT_DB_ERR_NO_SUCH_FILE;
422         }
423         else {
424           _Tt_string_list_cursor children_cursor(children);
425           while ((results == TT_DB_OK) && children_cursor.next()) {
426             // Construct the new file name by replacing the part
427             // that equals the "real_file" with the "real_new_file".
428             int length = (*children_cursor).len() - real_file.len();
429             _Tt_string new_child = real_new_file.cat("/");
430             new_child = new_child.cat((*children_cursor).right(length));
431
432             // Change the file name in the database
433             db->setFileFile(*children_cursor, new_child, accessPtr);
434           }
435         }
436       }
437     }
438     // Else, different partitions, therefore we can only move one
439     // non-directory file
440     else if (!_tt_is_file_a_directory(real_file)) {
441       // Get a connections to both partition DBs
442       _Tt_db_server_db_ptr db;
443       results = _tt_get_partition_db(partition, db);
444
445       _Tt_db_server_db_ptr new_db;
446       if (results == TT_DB_OK) {
447         results = _tt_get_partition_db(new_partition, new_db);
448       }
449
450       if (results == TT_DB_OK) {
451         _Tt_db_property_list_ptr properties;
452         _Tt_db_access_ptr        current_access;
453         _Tt_string_list_ptr      objids;
454
455         // Get all of the file's possesions
456         results = db->getFileProperties(real_file, accessPtr, properties);
457         if (results == TT_DB_OK) {
458           results = db->getFileAccess(real_file, accessPtr, current_access);
459         }
460         if (results == TT_DB_OK) {
461           results = db->getFileObjects(real_file, accessPtr, objids);
462         }
463
464         // Create the new file
465         if (results == TT_DB_OK) {
466           results = new_db->createFile(real_new_file, current_access);
467         }
468
469         // Copy the old file's properties to the new file
470         if (results == TT_DB_OK) {
471           results = new_db->setFileProperties(real_new_file,
472                                               properties,
473                                               accessPtr);
474         }
475
476         // Create the new objects with equivalent objids on the new partition
477         _Tt_string_list_ptr new_objids;
478         if (results == TT_DB_OK  && (!objids->is_empty())) {
479           new_objids = new _Tt_string_list;
480
481           // Loop through the file's objects
482           _Tt_string_list_cursor objids_cursor(objids);
483           while ((results == TT_DB_OK) && objids_cursor.next()) {
484             _Tt_string new_objid =
485               _tt_make_equivalent_object_id(*objids_cursor, new_partition);
486             new_objids->append(new_objid);
487
488             _Tt_db_property_list_ptr properties;
489             _Tt_db_access_ptr        current_access;
490
491             // Get all of the object's possesions
492             results = db->getObjectProperties(*objids_cursor,
493                                               accessPtr,
494                                               properties);
495             if (results == TT_DB_OK) {
496               results = db->getObjectAccess(*objids_cursor,
497                                             accessPtr,
498                                             current_access);
499             }
500
501             // Create the new object
502             if (results == TT_DB_OK) {
503               results = new_db->createObject(real_new_file,
504                                              new_objid,
505                                              current_access,
506                                              current_access);
507             }
508
509             // Copy the old object's properties to the new object
510             if (results == TT_DB_OK) {
511               results = new_db->setObjectProperties(new_objid,
512                                                     properties,
513                                                     accessPtr);
514             }
515           }
516         }
517
518         // Remove the old file and all of its objects
519         if (results == TT_DB_OK) {
520           results = db->removeFile(real_file, accessPtr);
521         }
522
523         // Create the forwarding pointers for all of the objects on
524         // the old file
525         if ((results == TT_DB_OK) && (!objids->is_empty())) {
526           _Tt_string_list_cursor objids_cursor(objids);
527           _Tt_string_list_cursor new_objids_cursor(new_objids);
528
529           while ((results == TT_DB_OK) &&
530                  objids_cursor.next() &&
531                  new_objids_cursor.next()) {
532             // Allow everyone to read and delete the forward pointer
533             _Tt_db_access_ptr new_access = new _Tt_db_access;
534             new_access->user = (uid_t)-1;
535             new_access->group = (gid_t)-1;
536             new_access->mode = (mode_t)-1;
537
538             // Create a special forward pointer object with no file...
539             results = db->createObject((char *)NULL,
540                                        *objids_cursor,
541                                        new_access,
542                                        new_access);
543
544             if (results == TT_DB_OK) {
545               _Tt_db_property_ptr property = new _Tt_db_property;
546               property->name = TT_DB_FORWARD_POINTER_PROPERTY;
547               property->values->append(*new_objids_cursor);
548
549               results = db->setObjectProperty(*objids_cursor,
550                                               property,
551                                               accessPtr);
552             }
553           }
554         }
555       }
556     }
557     else {
558       results = TT_DB_ERR_ILLEGAL_FILE;
559     }
560   }
561   else {
562     results = TT_DB_ERR_SAME_FILE;
563   }
564
565   return &results;
566 }
567
568 _tt_db_cache_results *_tt_set_file_props_1 (_tt_set_file_props_args *args,
569                                             SVCXPRT * /* transp */)
570 {
571   static _tt_db_cache_results results;
572   results.cache_level = -1;
573
574   _Tt_db_access_ptr accessPtr = _tt_get_real_rpc_access(args->access);
575
576   _Tt_string real_file = args->file;
577   _Tt_string partition = _tt_get_file_partition(args->file);
578   _Tt_db_server_db_ptr db;
579   results.results = _tt_get_partition_db(partition, db);
580
581   if (results.results == TT_DB_OK) {
582     _Tt_db_property_list_ptr properties;
583     _tt_get_rpc_properties(args->properties, properties);
584
585     if (!properties.is_null()) {
586       results.results = db->setFileProperties(real_file,
587                                               properties,
588                                               accessPtr);
589     }
590     else {
591       results.results = TT_DB_ERR_ILLEGAL_PROPERTY;
592     }
593
594     if (results.results == TT_DB_OK) {
595       results.results =
596         _tt_increment_file_properties_cache_level(db,
597                                                   real_file,
598                                                   accessPtr,
599                                                   results.cache_level);
600     }
601   }
602
603   return &results;
604 }
605
606 _tt_db_cache_results *_tt_set_file_prop_1 (_tt_set_file_prop_args *args,
607                                            SVCXPRT * /* transp */)
608 {
609   static _tt_db_cache_results results;
610   results.cache_level = -1;
611
612   _Tt_db_access_ptr accessPtr = _tt_get_real_rpc_access(args->access);
613
614   _Tt_string real_file = args->file;
615   _Tt_string partition = _tt_get_file_partition(args->file);
616   _Tt_db_server_db_ptr db;
617   results.results = _tt_get_partition_db(partition, db);
618
619   if (results.results == TT_DB_OK) {
620     _Tt_db_property_ptr property;
621     _tt_get_rpc_property(args->property, property);
622
623     if (!property.is_null()) {
624       results.results = db->setFileProperty(real_file,
625                                             property,
626                                             accessPtr);
627     }
628     else {
629       results.results = TT_DB_ERR_ILLEGAL_PROPERTY;
630     }
631
632     if (results.results == TT_DB_OK) {
633       results.results =
634         _tt_increment_file_properties_cache_level(db,
635                                                   real_file,
636                                                   accessPtr,
637                                                   results.cache_level);
638     }
639   }
640
641   return &results;
642 }
643
644 _tt_db_cache_results *_tt_add_file_prop_1 (_tt_add_file_prop_args *args,
645                                            SVCXPRT * /* transp */)
646 {
647   static _tt_db_cache_results results;
648   results.cache_level = -1;
649
650   _Tt_db_access_ptr accessPtr = _tt_get_real_rpc_access(args->access);
651
652   _Tt_string real_file = args->file;
653   _Tt_string partition = _tt_get_file_partition(args->file);
654   _Tt_db_server_db_ptr db;
655   results.results = _tt_get_partition_db(partition, db);
656
657   if (results.results == TT_DB_OK) {
658     _Tt_db_property_ptr property;
659     _tt_get_rpc_property(args->property, property);
660
661     if (!property.is_null()) {
662       results.results = db->addFileProperty(real_file,
663                                             property,
664                                             args->unique,
665                                             accessPtr);
666     }
667     else {
668       results.results = TT_DB_ERR_ILLEGAL_PROPERTY;
669     }
670
671     if (results.results == TT_DB_OK) {
672       results.results =
673         _tt_increment_file_properties_cache_level(db,
674                                                   real_file,
675                                                   accessPtr,
676                                                   results.cache_level);
677     }
678   }
679
680   return &results;
681 }
682
683 _tt_db_cache_results *_tt_delete_file_prop_1 (_tt_del_file_prop_args *args,
684                                               SVCXPRT * /* transp */)
685 {
686   static _tt_db_cache_results results;
687   results.cache_level = -1;
688
689   _Tt_db_access_ptr accessPtr = _tt_get_real_rpc_access(args->access);
690
691   _Tt_string real_file = args->file;
692   _Tt_string partition = _tt_get_file_partition(args->file);
693   _Tt_db_server_db_ptr db;
694   results.results = _tt_get_partition_db(partition, db);
695
696   if (results.results == TT_DB_OK) {
697     _Tt_db_property_ptr property;
698     _tt_get_rpc_property(args->property, property);
699
700     if (!property.is_null()) {
701       results.results = db->deleteFileProperty(real_file,
702                                                property,
703                                                accessPtr);
704     }
705     else {
706       results.results = TT_DB_ERR_ILLEGAL_PROPERTY;
707     }
708
709     if (results.results == TT_DB_OK) {
710       results.results =
711         _tt_increment_file_properties_cache_level(db,
712                                                   real_file,
713                                                   accessPtr,
714                                                   results.cache_level);
715     }
716   }
717
718   return &results;
719 }
720
721 _tt_file_prop_results *_tt_get_file_prop_1 (_tt_get_file_prop_args *args,
722                                             SVCXPRT * /* transp */)
723 {
724   static _tt_file_prop_results results;
725   results.cache_level = -1;
726
727   _Tt_db_access_ptr accessPtr = _tt_get_real_rpc_access(args->access);
728
729   _Tt_string real_file = args->file;
730   _Tt_string partition = _tt_get_file_partition(args->file);
731   _Tt_db_server_db_ptr db;
732   results.results = _tt_get_partition_db(partition, db);
733
734   if (results.results == TT_DB_OK) {
735     results.results = _tt_get_file_properties_cache_level(db,
736                                                           real_file,
737                                                           accessPtr,
738                                                           results.cache_level);
739   }
740
741   _Tt_db_property_ptr property;
742   if ((results.cache_level > args->cache_level) &&
743       (results.results == TT_DB_OK)) {
744     results.results = db->getFileProperty(real_file,
745                                           args->name,
746                                           accessPtr,
747                                           property);
748   }
749   _tt_set_rpc_property(property, results.property);
750
751   return &results;
752 }
753
754 _tt_file_props_results *
755 _tt_get_file_props_1 (_tt_get_file_props_args *args,
756                       SVCXPRT * /* transp */)
757 {
758   static _tt_file_props_results results;
759   results.cache_level = -1;
760
761   _Tt_db_access_ptr accessPtr = _tt_get_real_rpc_access(args->access);
762
763   _Tt_string real_file = args->file;
764   _Tt_string partition = _tt_get_file_partition(args->file);
765   _Tt_db_server_db_ptr db;
766   results.results = _tt_get_partition_db(partition, db);
767
768   if (results.results == TT_DB_OK) {
769     results.results = _tt_get_file_properties_cache_level(db,
770                                                           real_file,
771                                                           accessPtr,
772                                                           results.cache_level);
773   }
774
775   _Tt_db_property_list_ptr properties;
776   if ((results.cache_level > args->cache_level) &&
777       (results.results == TT_DB_OK)) {
778     results.results = db->getFileProperties(real_file,
779                                             accessPtr,
780                                             properties);
781   }
782   _tt_set_rpc_properties(properties, results.properties);
783
784   return &results;
785 }
786
787 _tt_file_objs_results *_tt_get_file_objs_1 (_tt_get_file_objs_args *args,
788                                             SVCXPRT * /* transp */)
789 {
790   static _tt_file_objs_results results;
791
792   // Make sure the returned cache level is higher then the callers
793   // cache level, so that the caller will use the returned data
794   results.cache_level = args->cache_level + 1;
795
796   _Tt_db_access_ptr accessPtr = _tt_get_real_rpc_access(args->access);
797
798   _Tt_string real_file = args->file;
799   _Tt_string partition = _tt_get_file_partition(args->file);
800   _Tt_db_server_db_ptr db;
801   results.results = _tt_get_partition_db(partition, db);
802
803   _Tt_string_list_ptr objids;
804   if ((results.cache_level > args->cache_level) &&
805       (results.results == TT_DB_OK)) {
806     results.results = db->getFileObjects(real_file,
807                                          accessPtr,
808                                          objids);
809   }
810   _tt_set_rpc_strings(objids, results.objids);
811
812   return &results;
813 }
814
815 _tt_db_results *_tt_set_file_access_1 (_tt_set_file_access_args *args,
816                                        SVCXPRT * /* transp */)
817 {
818   static _tt_db_results results;
819
820   _Tt_db_access_ptr accessPtr = _tt_get_real_rpc_access(args->access);
821
822   _Tt_string real_file = args->file;
823   _Tt_string partition = _tt_get_file_partition(args->file);
824   _Tt_db_server_db_ptr db;
825   results = _tt_get_partition_db(partition, db);
826
827   _Tt_db_access_ptr new_access;
828   if (results == TT_DB_OK) {
829     _tt_get_rpc_access(args->new_access, new_access);
830
831     if ((new_access->user == (uid_t)-1) ||
832         (new_access->group == (gid_t)-1) ||
833         (new_access->mode == (mode_t)-1)) { 
834       _Tt_db_access_ptr current_access;   
835       results = db->getFileAccess(real_file, 
836                                   accessPtr,
837                                   current_access);
838  
839       if (results == TT_DB_OK) { 
840         if (new_access->user == (uid_t)-1) {
841           new_access->user = current_access->user;
842         }
843  
844         if (new_access->group == (gid_t)-1) {
845           new_access->group = current_access->group;
846         }
847  
848         if (new_access->mode == (mode_t)-1) { 
849           new_access->mode = current_access->mode; 
850         } 
851       }  
852     }  
853  
854     if (results == TT_DB_OK) { 
855       results = db->setFileAccess(real_file, new_access, accessPtr);
856     }
857   }
858
859   return &results;
860 }
861
862 _tt_file_access_results *_tt_get_file_access_1 (_tt_get_file_access_args *args,
863                                                 SVCXPRT * /* transp */)
864 {
865   static _tt_file_access_results results;
866
867   _Tt_string real_file = args->file;
868   _Tt_string partition = _tt_get_file_partition(args->file);
869   _Tt_db_server_db_ptr db;
870   results.results = _tt_get_partition_db(partition, db);
871
872   _Tt_db_access_ptr accessPtr = _tt_get_real_rpc_access(args->access);
873
874   _Tt_db_access_ptr current_access;
875   if (results.results == TT_DB_OK) {
876     results.results = db->getFileAccess(real_file,
877                                         accessPtr,
878                                         current_access);
879   }
880   _tt_set_rpc_access(current_access, results.access);
881
882   return &results;
883 }
884
885 _tt_obj_props_results *_tt_set_obj_props_1 (_tt_set_obj_props_args *args,
886                                             SVCXPRT * /* transp */)
887 {
888   static _tt_obj_props_results results;
889   results.cache_level = -1;
890
891   _Tt_string partition = _tt_get_object_partition(args->objid);
892   _Tt_db_server_db_ptr db;
893   results.results = _tt_get_partition_db(partition, db);
894
895   _Tt_db_access_ptr accessPtr = _tt_get_real_rpc_access(args->access);
896
897   if (results.results == TT_DB_OK) {
898     results.results =
899       _tt_get_object_properties_cache_level(db,
900                                             args->objid,
901                                             accessPtr,
902                                             results.cache_level);
903   }
904
905   _Tt_db_property_list_ptr properties;
906
907   // If the cache level in the DB is higher then the passed in
908   // cache level, then someone else must have updated before
909   // the callers last read from the DB --> update conflict...
910   if ((results.results == TT_DB_OK) &&
911       (results.cache_level > args->cache_level)) {
912     results.results = TT_DB_ERR_UPDATE_CONFLICT;
913     
914     _Tt_db_results temp_results = db->getObjectProperties(args->objid,
915                                                           accessPtr,
916                                                           properties);
917     
918     if (results.results != TT_DB_OK) {
919       properties = (_Tt_db_property_list *)NULL;
920       results.results = temp_results;
921     }
922   }
923   _tt_set_rpc_properties(properties, results.properties);
924   
925   // No update conflicts or any other weirdness...
926   if (results.results == TT_DB_OK) {
927     _tt_get_rpc_properties(args->properties, properties);
928     
929     if (!properties.is_null()) {
930       _tt_screen_object_properties (properties);
931     }
932
933     if (!properties.is_null()) {
934       results.results = db->setObjectProperties(args->objid,
935                                                 properties,
936                                                 accessPtr);
937     }
938     else {
939       results.results = TT_DB_ERR_ILLEGAL_PROPERTY;
940     }
941   
942     if (results.results == TT_DB_OK) {
943       results.results =
944         _tt_increment_object_properties_cache_level(db,
945                                                     args->objid,
946                                                     accessPtr,
947                                                     results.cache_level);
948     }
949   }
950
951   return &results;
952 }
953
954 _tt_obj_props_results *_tt_set_obj_prop_1 (_tt_set_obj_prop_args *args,
955                                            SVCXPRT * /* transp */)
956 {
957   static _tt_obj_props_results results;
958   results.cache_level = -1;
959
960   _Tt_string partition = _tt_get_object_partition(args->objid);
961   _Tt_db_server_db_ptr db;
962   results.results = _tt_get_partition_db(partition, db);
963
964   _Tt_db_access_ptr accessPtr = _tt_get_real_rpc_access(args->access);
965
966   if (results.results == TT_DB_OK) {
967     results.results =
968       _tt_get_object_properties_cache_level(db,
969                                             args->objid,
970                                             accessPtr,
971                                             results.cache_level);
972   }
973
974   _Tt_db_property_list_ptr properties;
975
976   // If the cache level in the DB is higher then the passed in
977   // cache level, then someone else must have updated before
978   // the callers last read from the DB --> update conflict...
979   if ((results.results == TT_DB_OK) &&
980       (results.cache_level > args->cache_level)) {
981     results.results = TT_DB_ERR_UPDATE_CONFLICT;
982     
983     _Tt_db_results temp_results = db->getObjectProperties(args->objid,
984                                                           accessPtr,
985                                                           properties);
986     
987     if (results.results != TT_DB_OK) {
988       properties = (_Tt_db_property_list *)NULL;
989       results.results = temp_results;
990     }
991   }
992   _tt_set_rpc_properties(properties, results.properties);
993   
994   // No update conflicts or any other weirdness...
995   if (results.results == TT_DB_OK) {
996     _Tt_db_property_ptr property;
997     _tt_get_rpc_property(args->property, property);
998       
999     if (!property.is_null()) {
1000       results.results = db->setObjectProperty(args->objid,
1001                                               property,
1002                                               accessPtr);
1003     }
1004     else {
1005       results.results = TT_DB_ERR_ILLEGAL_PROPERTY;
1006     }
1007     
1008     if (results.results == TT_DB_OK) {
1009       results.results =
1010         _tt_increment_object_properties_cache_level(db,
1011                                                     args->objid,
1012                                                     accessPtr,
1013                                                     results.cache_level);
1014     }
1015   }
1016
1017   return &results;
1018 }
1019
1020 _tt_obj_props_results *_tt_add_obj_prop_1 (_tt_add_obj_prop_args *args,
1021                                            SVCXPRT * /* transp */)
1022 {
1023   static _tt_obj_props_results results;
1024   results.cache_level = -1;
1025
1026   _Tt_string partition = _tt_get_object_partition(args->objid);
1027   _Tt_db_server_db_ptr db;
1028   results.results = _tt_get_partition_db(partition, db);
1029
1030   _Tt_db_access_ptr accessPtr = _tt_get_real_rpc_access(args->access);
1031
1032   if (results.results == TT_DB_OK) {
1033     results.results =
1034       _tt_get_object_properties_cache_level(db,
1035                                             args->objid,
1036                                             accessPtr,
1037                                             results.cache_level);
1038   }
1039
1040   _Tt_db_property_list_ptr properties;
1041
1042   // If the cache level in the DB is higher then the passed in
1043   // cache level, then someone else must have updated before
1044   // the callers last read from the DB --> update conflict...
1045   if ((results.results == TT_DB_OK) &&
1046       (results.cache_level > args->cache_level)) {
1047     results.results = TT_DB_ERR_UPDATE_CONFLICT;
1048     
1049     _Tt_db_results temp_results = db->getObjectProperties(args->objid,
1050                                                           accessPtr,
1051                                                           properties);
1052     
1053     if (results.results != TT_DB_OK) {
1054       properties = (_Tt_db_property_list *)NULL;
1055       results.results = temp_results;
1056     }
1057   }
1058   _tt_set_rpc_properties(properties, results.properties);
1059   
1060   // No update conflicts or any other weirdness...
1061   if (results.results == TT_DB_OK) {
1062     _Tt_db_property_ptr property;
1063     _tt_get_rpc_property(args->property, property);
1064
1065     if (!property.is_null()) {
1066       results.results = db->addObjectProperty(args->objid,
1067                                               property,
1068                                               args->unique,
1069                                               accessPtr);
1070     }
1071     else {
1072       results.results = TT_DB_ERR_ILLEGAL_PROPERTY;
1073     }
1074     
1075     if (results.results == TT_DB_OK) {
1076       results.results =
1077         _tt_increment_object_properties_cache_level(db,
1078                                                     args->objid,
1079                                                     accessPtr,
1080                                                     results.cache_level);
1081     }
1082   }
1083
1084   return &results;
1085 }
1086
1087 _tt_obj_props_results *_tt_delete_obj_prop_1 (_tt_del_obj_prop_args *args,
1088                                               SVCXPRT * /* transp */)
1089 {
1090   static _tt_obj_props_results results;
1091   results.cache_level = -1;
1092
1093   _Tt_string partition = _tt_get_object_partition(args->objid);
1094   _Tt_db_server_db_ptr db;
1095   results.results = _tt_get_partition_db(partition, db);
1096
1097   _Tt_db_access_ptr accessPtr = _tt_get_real_rpc_access(args->access);
1098
1099   if (results.results == TT_DB_OK) {
1100     results.results =
1101       _tt_get_object_properties_cache_level(db,
1102                                             args->objid,
1103                                             accessPtr,
1104                                             results.cache_level);
1105   }
1106
1107   // If the cache level in the DB is higher then the passed in
1108   // cache level, then someone else must have updated before
1109   // the callers last read from the DB --> update conflict...
1110   if ((results.results == TT_DB_OK) &&
1111       (results.cache_level > args->cache_level)) {
1112     results.results = TT_DB_ERR_UPDATE_CONFLICT;
1113   }
1114     
1115   // No update conflicts or any other weirdness...
1116
1117   if (results.results == TT_DB_OK) {
1118     _Tt_db_property_ptr property;
1119     _tt_get_rpc_property(args->property, property);
1120
1121     if (!property.is_null()) {
1122       results.results = db->deleteObjectProperty(args->objid,
1123                                                  property,
1124                                                  accessPtr);
1125     }
1126     else {
1127       results.results = TT_DB_ERR_ILLEGAL_PROPERTY;
1128     }
1129     
1130     if (results.results == TT_DB_OK) {
1131       results.results =
1132         _tt_increment_object_properties_cache_level(db,
1133                                                     args->objid,
1134                                                     accessPtr,
1135                                                     results.cache_level);
1136     }
1137   }
1138
1139   // The delete object prop function is the only object function that always
1140   // returns that latest object properties.  The cache level passed in
1141   // is only used for update conflict detection.
1142   _Tt_db_property_list_ptr properties;
1143   if ((results.results == TT_DB_OK) ||
1144       (results.results == TT_DB_ERR_UPDATE_CONFLICT)) {
1145     _Tt_db_results temp_results = db->getObjectProperties(args->objid,
1146                                                           accessPtr,
1147                                                           properties);
1148     
1149     if (results.results != TT_DB_OK) {
1150       properties = (_Tt_db_property_list *)NULL;
1151       results.results = temp_results;
1152     }
1153   }
1154   _tt_set_rpc_properties(properties, results.properties);
1155   
1156   return &results;
1157 }
1158
1159 _tt_obj_prop_results *_tt_get_obj_prop_1 (_tt_get_obj_prop_args *args,
1160                                           SVCXPRT * /* transp */)
1161 {
1162   static _tt_obj_prop_results results;
1163   results.cache_level = -1;
1164
1165   _Tt_string partition = _tt_get_object_partition(args->objid);
1166   _Tt_db_server_db_ptr db;
1167   results.results = _tt_get_partition_db(partition, db);
1168
1169   _Tt_db_access_ptr accessPtr = _tt_get_real_rpc_access(args->access);
1170
1171   if (results.results == TT_DB_OK) {
1172     results.results =
1173       _tt_get_object_properties_cache_level(db,
1174                                             args->objid,
1175                                             accessPtr,
1176                                             results.cache_level);
1177   }
1178
1179   _Tt_db_property_ptr property;
1180
1181   // Only return values if the DB cache level is higher then the
1182   // callers cache level
1183   if ((results.results == TT_DB_OK) &&
1184       (results.cache_level > args->cache_level)) {
1185     results.results = db->getObjectProperty(args->objid,
1186                                             args->name,
1187                                             accessPtr,
1188                                             property);
1189   }
1190   _tt_set_rpc_property(property, results.property);
1191     
1192   return &results;
1193 }
1194
1195 _tt_obj_props_results *_tt_get_obj_props_1 (_tt_get_obj_props_args *args,
1196                                             SVCXPRT * /* transp */)
1197 {
1198   static _tt_obj_props_results results;
1199   results.cache_level = -1;
1200
1201   _Tt_string partition = _tt_get_object_partition(args->objid);
1202   _Tt_db_server_db_ptr db;
1203   results.results = _tt_get_partition_db(partition, db);
1204
1205   _Tt_db_access_ptr accessPtr = _tt_get_real_rpc_access(args->access);
1206
1207   if (results.results == TT_DB_OK) {
1208     results.results =
1209       _tt_get_object_properties_cache_level(db,
1210                                             args->objid,
1211                                             accessPtr,
1212                                             results.cache_level);
1213   }
1214
1215   _Tt_db_property_list_ptr properties;
1216
1217   // Only return values if the DB cache level is higher then the
1218   // callers cache level
1219   if ((results.results == TT_DB_OK) &&
1220       (results.cache_level > args->cache_level)) {
1221     results.results = db->getObjectProperties(args->objid,
1222                                               accessPtr,
1223                                               properties);
1224   }
1225   _tt_set_rpc_properties(properties, results.properties);
1226
1227   return &results;
1228 }
1229
1230 _tt_db_results *_tt_set_obj_type_1 (_tt_set_obj_type_args *args,
1231                                     SVCXPRT * /* transp */)
1232 {
1233   static _tt_db_results results;
1234
1235   _Tt_string partition = _tt_get_object_partition(args->objid);
1236   _Tt_db_server_db_ptr db;
1237   results = _tt_get_partition_db(partition, db);
1238
1239   _Tt_db_access_ptr accessPtr = _tt_get_real_rpc_access(args->access);
1240
1241   if (results == TT_DB_OK) {
1242     _Tt_db_property_ptr property = new _Tt_db_property;
1243     property->name = TT_DB_OBJECT_TYPE_PROPERTY;
1244     property->values->append(_Tt_string(args->otype));
1245
1246     results = db->setObjectProperty(args->objid, property, accessPtr);
1247   }
1248
1249   return &results;
1250 }
1251
1252 _tt_obj_type_results *_tt_get_obj_type_1 (_tt_get_obj_type_args *args,
1253                                           SVCXPRT * /* transp */)
1254 {
1255   static _tt_obj_type_results results;
1256
1257   _Tt_string partition = _tt_get_object_partition(args->objid);
1258   _Tt_db_server_db_ptr db;
1259   results.results = _tt_get_partition_db(partition, db);
1260
1261   _Tt_db_access_ptr accessPtr = _tt_get_real_rpc_access(args->access);
1262
1263   if (results.results == TT_DB_OK) {
1264     _Tt_db_property_ptr property;
1265     results.results = db->getObjectProperty(args->objid,
1266                                             TT_DB_OBJECT_TYPE_PROPERTY,
1267                                             accessPtr,
1268                                             property);
1269
1270     results.otype = (char *)NULL;
1271     if (results.results == TT_DB_OK) {
1272       if (!property.is_null() && !property->is_empty()) {
1273         _Tt_string otype = (*property->values) [0];
1274         int length = otype.len();
1275
1276         results.otype = (char *)malloc(length+1);
1277         memcpy(results.otype, (char *)otype, length);
1278         results.otype [length] = '\0';
1279       }
1280     }
1281     else if (results.results == TT_DB_ERR_NO_SUCH_PROPERTY) {
1282       results.results = TT_DB_ERR_NO_OTYPE;
1283     }
1284   }
1285
1286   return &results;
1287 }
1288
1289 _tt_db_results *_tt_set_obj_file_1 (_tt_set_obj_file_args *args,
1290                                     SVCXPRT * /* transp */)
1291 {
1292   static _tt_db_results results;
1293
1294   _Tt_string partition = _tt_get_object_partition(args->objid);
1295   _Tt_db_server_db_ptr db;
1296   results = _tt_get_partition_db(partition, db);
1297
1298   _Tt_db_access_ptr accessPtr = _tt_get_real_rpc_access(args->access);
1299
1300   if (results == TT_DB_OK) {
1301     results = db->setObjectFile(args->objid, args->file, accessPtr);
1302   }
1303
1304   return &results;
1305 }
1306
1307 _tt_obj_file_results *_tt_get_obj_file_1 (_tt_get_obj_file_args *args,
1308                                           SVCXPRT * /* transp */)
1309 {
1310   static _tt_obj_file_results results;
1311
1312   _Tt_string partition = _tt_get_object_partition(args->objid);
1313   _Tt_db_server_db_ptr db;
1314   results.results = _tt_get_partition_db(partition, db);
1315
1316   _Tt_db_access_ptr accessPtr = _tt_get_real_rpc_access(args->access);
1317
1318   if (results.results == TT_DB_OK) {
1319     _Tt_string file;
1320     results.results = db->getObjectFile(args->objid,
1321                                         accessPtr,
1322                                         file);
1323
1324     results.file = (char *)NULL;
1325     if (results.results == TT_DB_OK) {
1326       if (file.len()) {
1327         results.file = strdup((char *)file);
1328       }
1329     }
1330   }
1331
1332   return &results;
1333 }
1334
1335 _tt_db_results *_tt_set_obj_access_1 (_tt_set_obj_access_args *args,
1336                                       SVCXPRT * /* transp */)
1337 {
1338   static _tt_db_results results;
1339
1340   _Tt_string partition = _tt_get_object_partition(args->objid);
1341   _Tt_db_server_db_ptr db;
1342   results = _tt_get_partition_db(partition, db);
1343
1344   _Tt_db_access_ptr accessPtr = _tt_get_real_rpc_access(args->access);
1345
1346   _Tt_db_access_ptr new_access;
1347   if (results == TT_DB_OK) {
1348     _tt_get_rpc_access(args->new_access, new_access);
1349
1350     if ((new_access->user == (uid_t)-1) ||
1351         (new_access->group == (gid_t)-1) ||
1352         (new_access->mode == (mode_t)-1)) {
1353       _Tt_db_access_ptr current_access;
1354       results = db->getObjectAccess(args->objid,
1355                                     accessPtr,
1356                                     current_access);
1357
1358       if (results == TT_DB_OK) {
1359         if (new_access->user == (uid_t)-1) {
1360           new_access->user = current_access->user;
1361         }
1362
1363         if (new_access->group == (gid_t)-1) {
1364           new_access->group = current_access->group;
1365         }
1366
1367         if (new_access->mode == (mode_t)-1) {
1368           new_access->mode = current_access->mode;
1369         }
1370       }
1371     }
1372
1373     if (results == TT_DB_OK) {
1374       results = db->setObjectAccess(args->objid, new_access, accessPtr);
1375     }
1376   }
1377
1378   return &results;
1379 }
1380
1381 _tt_obj_access_results *_tt_get_obj_access_1 (_tt_get_obj_access_args *args,
1382                                               SVCXPRT * /* transp */)
1383 {
1384   static _tt_obj_access_results results;
1385
1386   _Tt_string partition = _tt_get_object_partition(args->objid);
1387   _Tt_db_server_db_ptr db;
1388   results.results = _tt_get_partition_db(partition, db);
1389
1390   _Tt_db_access_ptr accessPtr = _tt_get_real_rpc_access(args->access);
1391
1392   _Tt_db_access_ptr current_access;
1393   if (results.results == TT_DB_OK) {
1394     results.results = db->getObjectAccess(args->objid,
1395                                           accessPtr,
1396                                           current_access);
1397   }
1398   _tt_set_rpc_access(current_access, results.access);
1399
1400   return &results;
1401 }
1402
1403 _tt_is_file_in_db_results *_tt_is_file_in_db_1 (_tt_is_file_in_db_args *args,
1404                                                 SVCXPRT * /* transp */)
1405 {
1406   static _tt_is_file_in_db_results results;
1407   
1408   _Tt_db_access_ptr accessPtr = _tt_get_real_rpc_access(args->access);
1409
1410   _Tt_string real_file = args->file;
1411   _Tt_string partition = _tt_get_file_partition(args->file);
1412   _Tt_db_server_db_ptr db;
1413   results.results = _tt_get_partition_db(partition, db);
1414
1415   if (results.results == TT_DB_OK) {
1416     // See if the file already exists by trying to get its access info
1417     _Tt_db_access_ptr temp_access;
1418     _Tt_db_results temp_results = db->getFileAccess(real_file,
1419                                                     accessPtr,
1420                                                     temp_access);
1421
1422     // If the file exists...
1423     if ((temp_results == TT_DB_OK) ||
1424         (temp_results == TT_DB_ERR_ACCESS_DENIED)) {
1425       results.results = TT_DB_OK;
1426     }
1427     else {
1428       results.results = temp_results;
1429     }
1430
1431     // See if the file is a directory
1432     results.directory_flag = _tt_is_file_a_directory(real_file);
1433   }
1434
1435   return &results;
1436 }
1437
1438 _tt_is_obj_in_db_results *_tt_is_obj_in_db_1 (_tt_is_obj_in_db_args *args,
1439                                               SVCXPRT * /* transp */)
1440 {
1441   static _tt_is_obj_in_db_results results;
1442   results.forward_pointer = (char *)NULL;
1443   
1444   _Tt_string partition = _tt_get_object_partition(args->objid);
1445   _Tt_db_server_db_ptr db;
1446   results.results = _tt_get_partition_db(partition, db);
1447
1448   _Tt_db_access_ptr accessPtr = _tt_get_real_rpc_access(args->access);
1449
1450   if (results.results == TT_DB_OK) {
1451     _Tt_string file;
1452
1453     // See if the object has an entry in the file-object map
1454     results.results = db->getObjectFile(args->objid,
1455                                         accessPtr,
1456                                         file);
1457
1458     // If no entry in the file-object map...
1459     if (results.results != TT_DB_OK) {
1460       _Tt_db_property_ptr property;
1461
1462       // See if there is a forward pointer
1463       _Tt_db_results temp_results =
1464         db->getObjectProperty(args->objid,
1465                               TT_DB_FORWARD_POINTER_PROPERTY,
1466                               accessPtr,
1467                               property);
1468
1469       // If there is a forward pointer...
1470       if (temp_results == TT_DB_OK) {
1471         _Tt_string forward_pointer = (*property->values) [0];
1472         int length = forward_pointer.len();
1473         results.forward_pointer = (char *)malloc(length+1);
1474
1475         memcpy(results.forward_pointer, (char *)forward_pointer, length);
1476         results.forward_pointer [length] = '\0';
1477         results.results = TT_DB_WRN_FORWARD_POINTER;
1478       }
1479     }
1480   }
1481
1482   return &results;
1483 }
1484
1485 _tt_db_results *_tt_queue_message_1 (_tt_queue_msg_args *args,
1486                                      SVCXPRT * /* transp */)
1487 {
1488   static _tt_db_results results;
1489
1490   bool_t property_written = FALSE;
1491
1492   _Tt_db_server_db_ptr db;
1493   _Tt_string           real_file = args->file;
1494   if (!args->message.body.body_len) {
1495     results = TT_DB_ERR_ILLEGAL_MESSAGE;
1496   }
1497   else {
1498     _Tt_string partition = _tt_get_file_partition(args->file);
1499     results = _tt_get_partition_db(partition, db);
1500   }
1501
1502   if (results == TT_DB_OK) {
1503     _Tt_db_access_ptr accessPtr = _tt_get_unix_file_access(real_file);
1504
1505     // Set the DB file access to be the same as the actual file.  This
1506     // allows an easy method of controlled message security
1507     if (!accessPtr.is_null()) {
1508       results = db->setFileAccess(real_file, accessPtr, accessPtr);
1509     }
1510   }
1511   
1512   _Tt_db_access_ptr accessPtr = new _Tt_db_access;
1513   accessPtr->user = _tt_uid;
1514   accessPtr->group = _tt_gid;
1515
1516   // Create a new message info structure for the new message
1517   _Tt_db_message_info_ptr message_info = new _Tt_db_message_info;
1518   if (results == TT_DB_OK) {
1519     XDR  xdrs;
1520
1521     // Get the current information on queued messages
1522     _Tt_db_property_ptr property;
1523     _Tt_string name = TT_DB_MESSAGE_INFO_PROPERTY;
1524     results = db->getFileProperty(real_file, name, accessPtr, property);
1525
1526     // Default new message ID if there are none in the queue
1527     int message_id = 1;
1528
1529     if (results == TT_DB_OK) {
1530       // Calculate the index for the last message info structure in
1531       // the property
1532       int index = property->values->count() - 1;
1533
1534       if (index > -1) {
1535         // Un-XDR the message info into the "last_message_info" object
1536         // and set the new message ID to the message ID in in
1537         // "last_message_info" + 1.
1538         _Tt_string message_info_bytes = (*property->values) [index];
1539         xdrmem_create(&xdrs,
1540                       (char *)message_info_bytes,
1541                       (u_int)message_info_bytes.len(),
1542                       XDR_DECODE);
1543         _Tt_db_message_info_ptr last_message_info = new _Tt_db_message_info;
1544         (void)last_message_info->xdr(&xdrs);
1545         message_id = last_message_info->messageID + 1;
1546       }
1547     }
1548
1549     // It doesn't matter if there were no queued messages, as long as
1550     // there were no fatal errors
1551     if ((results == TT_DB_OK) ||
1552         (results == TT_DB_ERR_NO_SUCH_PROPERTY)) {
1553       results = TT_DB_OK;
1554
1555       // Put the new message info into the message info structure
1556       message_info->messageID = message_id;
1557       message_info->numParts = (args->message.body.body_len / ISMAXRECLEN) + 1;
1558       message_info->messageSize = args->message.body.body_len;
1559       _tt_get_rpc_strings(args->ptypes, message_info->ptypes);
1560
1561       // Get the XDR size of the new message info structure
1562       u_int length;
1563       _Tt_xdr_size_stream xdrsz;
1564       if (!message_info->xdr((XDR *)xdrsz)) {
1565         results = TT_DB_ERR_ILLEGAL_MESSAGE;
1566       } else {
1567         length = (unsigned int) xdrsz.getsize();
1568       }
1569
1570       // XDR the message info structure into "temp_string"
1571       _Tt_string temp_string((int)length);
1572       if (results != TT_DB_ERR_ILLEGAL_MESSAGE) {
1573         xdrmem_create(&xdrs, (char *)temp_string, length, XDR_ENCODE);
1574         if (!message_info->xdr(&xdrs)) {
1575           results = TT_DB_ERR_ILLEGAL_MESSAGE;
1576         }
1577       }
1578
1579       if (results != TT_DB_ERR_ILLEGAL_MESSAGE) {
1580         // Add the XDR'd message info to the message info property
1581         _Tt_db_property_ptr property = new _Tt_db_property;
1582         property->name = TT_DB_MESSAGE_INFO_PROPERTY;
1583         property->values->append(temp_string);
1584
1585         results = db->addFileProperty(real_file, property, FALSE, accessPtr);
1586         property_written = TRUE;
1587       }
1588     }
1589   }
1590   
1591   if (results == TT_DB_OK) {
1592     int length = ISMAXRECLEN;
1593
1594     // Break up the message into ISMAXRECLEN sized parts and store
1595     // as separate properties
1596     for (int i=0;
1597          (results == TT_DB_OK) && (i < message_info->numParts);
1598          i++) {
1599       // If this is the last part, it is probably shorter then
1600       // ISMAXRECLEN, so calculate the exact length
1601       if (i == message_info->numParts-1) {
1602         length = message_info->messageSize - (i * ISMAXRECLEN);
1603       }
1604
1605       // Copy the message part into a buffer
1606       _Tt_string message_part(length);
1607       memcpy((char *)message_part,
1608              args->message.body.body_val+i*ISMAXRECLEN,
1609              length);
1610
1611       // Construct a property name of the form:
1612       //
1613       //           _TT_MSG_<ID#>_<PART#>
1614       //
1615       char name [64];
1616       sprintf(name, TT_DB_MESSAGE_PROPERTY, message_info->messageID, i);
1617
1618       // Store the property
1619       _Tt_db_property_ptr property = new _Tt_db_property;
1620       property->name = name;
1621       property->values->append(message_part);
1622
1623       results = db->setFileProperty(real_file, property, accessPtr);
1624       property_written = TRUE;
1625     }
1626   }
1627
1628   if (property_written && (results == TT_DB_OK)) {
1629     int cache_level;
1630     results = _tt_increment_file_properties_cache_level(db,
1631                                                         real_file,
1632                                                         accessPtr,
1633                                                         cache_level);
1634   }
1635
1636   return &results;
1637 }
1638
1639 _tt_dequeue_msgs_results *
1640 _tt_dequeue_messages_1 (_tt_dequeue_msgs_args *args,
1641                         SVCXPRT * /* transp */)
1642 {
1643   static _tt_dequeue_msgs_results results;
1644   results.messages.messages_val = (_tt_message *)NULL;
1645   results.messages.messages_len = 0;
1646
1647   bool_t property_written = FALSE;
1648
1649   _Tt_string real_file = args->file;
1650   _Tt_string partition = _tt_get_file_partition(args->file);
1651   _Tt_db_server_db_ptr db;
1652   results.results = _tt_get_partition_db(partition, db);
1653
1654   if (results.results == TT_DB_OK) {
1655     _Tt_db_access_ptr accessPtr = _tt_get_unix_file_access(real_file);
1656
1657     // Set the DB file access to be the same as the actual file.  This
1658     // allows an easy method of control for queued message security
1659     if (!accessPtr.is_null()) {
1660       results.results = db->setFileAccess(real_file,
1661                                           accessPtr,
1662                                           accessPtr);
1663     }
1664   }
1665   
1666   _Tt_db_access_ptr accessPtr = new _Tt_db_access;
1667   accessPtr->user = _tt_uid;
1668   accessPtr->group = _tt_gid;
1669
1670   // Get the message info property
1671   _Tt_db_property_ptr property;
1672   if (results.results == TT_DB_OK) {
1673     _Tt_string name = TT_DB_MESSAGE_INFO_PROPERTY;
1674     results.results = db->getFileProperty(real_file,
1675                                           name,
1676                                           accessPtr,
1677                                           property);
1678   }
1679   
1680   _Tt_db_message_info_ptr message_info = new _Tt_db_message_info;
1681   _Tt_string_list_ptr     messages;
1682
1683   if (results.results == TT_DB_ERR_NO_SUCH_PROPERTY) {
1684     results.results = TT_DB_OK;
1685   }
1686   else if (results.results == TT_DB_OK) {
1687     _Tt_string_list_ptr dequeue_ptypes;
1688     _tt_get_rpc_strings(args->ptypes, dequeue_ptypes);
1689
1690     _Tt_string_list_cursor dequeue_ptypes_cursor(dequeue_ptypes);
1691
1692     // Loop through the message info property (effectively looping
1693     // through the message info entries)
1694     _Tt_string_list_cursor values_cursor(property->values);
1695     while (values_cursor.next()) {
1696       XDR xdrs;
1697
1698       // Un-XDR a message info structure
1699       xdrmem_create(&xdrs,
1700                     (char *)*values_cursor,
1701                     (*values_cursor).len(),
1702                     XDR_DECODE);
1703       (void)message_info->xdr(&xdrs);
1704
1705       // Eliminate all of the ptypes from the message info list
1706       // that match the callers ptype list.
1707       bool_t ptype_matched = FALSE;
1708       _Tt_string_list_cursor ptypes_cursor(message_info->ptypes);
1709       while (ptypes_cursor.next()) {
1710         while (dequeue_ptypes_cursor.next()) {
1711           if (*dequeue_ptypes_cursor == *ptypes_cursor) {
1712             ptypes_cursor.remove();
1713             ptype_matched = TRUE;
1714             break;
1715           }
1716         }
1717       }
1718
1719       // A ptype matched, this message is to be returned...
1720       if (ptype_matched) {
1721         if (messages.is_null()) {
1722           messages = new _Tt_string_list;
1723         }
1724
1725         // Reconstruct the message from the _TT_MSG_<ID#>_<PART#> properties
1726         _Tt_string message(message_info->messageSize);
1727         for (int i=0; (results.results == TT_DB_OK) &&
1728                       (i < message_info->numParts); i++) {
1729           // Construct the property name
1730           char name [64];
1731           sprintf(name, TT_DB_MESSAGE_PROPERTY, message_info->messageID, i);
1732
1733           // Get the property value
1734           _Tt_db_property_ptr property;
1735           results.results = db->getFileProperty(real_file,
1736                                                 name,
1737                                                 accessPtr,
1738                                                 property);
1739           if (results.results == TT_DB_OK) {
1740             _Tt_string message_bytes = (*property->values) [0];
1741
1742             // Copy each succesive part into a large buffer
1743             memcpy((char *)message+i*ISMAXRECLEN,
1744                    (char *)message_bytes,
1745                    message_bytes.len());
1746           }
1747         }
1748
1749         // Append the re-assembled message to the return list
1750         if (results.results == TT_DB_OK) {
1751           messages->append(message);
1752         }
1753       }
1754
1755       // No more ptypes left for this message, dequeue it...
1756       if (message_info->ptypes->is_empty()) {
1757         values_cursor.remove();
1758       }
1759       // Otherwise, update the property value with an updated version
1760       // of the message_info structure
1761       else {
1762         u_int  length;
1763         XDR    xdrs;
1764         _Tt_xdr_size_stream xdrsz;
1765
1766         // Get the XDR size of the updated message info structure
1767         (void)message_info->xdr((XDR *)xdrsz);
1768         length = (unsigned int) xdrsz.getsize();
1769
1770         // XDR the message info structure into "temp_string"
1771         _Tt_string temp_string((int)length);
1772         xdrmem_create(&xdrs, (char *)temp_string, length, XDR_ENCODE);
1773         if (!message_info->xdr(&xdrs)) {
1774           // Update the property value
1775           *values_cursor = temp_string;
1776         }
1777       }
1778     }
1779
1780     // Put the message info property back into the DB.  If all of
1781     // the message info structures have been deleted from the
1782     // property, then this should effectively delete the property.
1783     results.results = db->setFileProperty(real_file,
1784                                           property,
1785                                           accessPtr);
1786     property_written = TRUE;
1787
1788     if (!messages.is_null()) {
1789       if ((results.results == TT_DB_OK) && !messages->is_empty()) {
1790         // Allocate enough space to transport the messages back to the
1791         // caller
1792         results.messages.messages_val = (_tt_message *)
1793                                         malloc(sizeof(_tt_message)*
1794                                                messages->count());
1795         results.messages.messages_len = messages->count();
1796
1797         // Put the messages into the results structure
1798         int i = 0;
1799         _Tt_string_list_cursor messages_cursor(messages);
1800         while (messages_cursor.next()) {
1801           results.messages.messages_val [i].body.body_val =
1802             (char *)malloc((*messages_cursor).len());
1803           results.messages.messages_val [i].body.body_len =
1804             (*messages_cursor).len();
1805           memcpy(results.messages.messages_val [i].body.body_val,
1806                  (char *)*messages_cursor,
1807                  (*messages_cursor).len());
1808           i++;
1809         }
1810       }
1811     }
1812   }
1813
1814   if (property_written && (results.results == TT_DB_OK)) {
1815     int cache_level;
1816     results.results = _tt_increment_file_properties_cache_level(db,
1817                                                                 real_file,
1818                                                                 accessPtr,
1819                                                                 cache_level);
1820   }
1821
1822   return &results;
1823 }
1824
1825 // Since we're calling the wrapped API calls, bringing in tt_c.h
1826 // doesn't get us the declarations we need, so we have to bring
1827 // these two in manually like this.
1828 //
1829 extern char *           _tt_file_netfile(const char *);
1830 extern char *           _tt_netfile_file(const char *);
1831 extern Tt_status        _tt_pointer_error(void *p);
1832 extern char *           _tt_status_message(Tt_status s);
1833
1834
1835 // Call the API routine _tt_file_netfile() and return the
1836 // results.
1837 _tt_file_netfile_results *
1838 _tt_file_netfile_1 (_tt_file_netfile_args *args, SVCXPRT * /* transp */)
1839 {
1840
1841 #ifdef notdef
1842 printf("DEBUG: SERVER: _tt_file_netfile_1: calling _tt_file_netfile(%s)\n",
1843         (char *) args->file_or_netfile);
1844 #endif
1845
1846         static _tt_file_netfile_results results;
1847         static char * canonical_path;
1848
1849         // we have a netfilename, get the local file version...
1850         canonical_path = _tt_file_netfile(args->file_or_netfile);
1851
1852 #ifdef notdef
1853 printf("DEBUG: SERVER: _tt_file_netfile_1: _tt_file_netfile(%s) returned %s\n",
1854         args->file_or_netfile, canonical_path);
1855 #endif
1856
1857
1858         if (_tt_pointer_error(canonical_path) != TT_OK) {
1859                 results.results = TT_DB_ERR_ILLEGAL_FILE;
1860                 results.result_string = NULL;
1861         } else {
1862                 results.results = TT_DB_OK;
1863                 results.result_string = canonical_path;
1864         }
1865         results.tt_status = (int) _tt_pointer_error(canonical_path);
1866
1867 #ifdef notdef
1868 printf("\t results.tt_status == %s\n",
1869         _tt_status_message(_tt_pointer_error(canonical_path)));
1870 #endif
1871
1872         return &results;
1873 }
1874
1875
1876 // Call the API routine _tt_netfile_file() and return the
1877 // results.
1878 _tt_file_netfile_results *
1879 _tt_netfile_file_1 (_tt_file_netfile_args *args, SVCXPRT * /* transp */)
1880 {
1881
1882 #ifdef notdef
1883 printf("DEBUG: SERVER: _tt_netfile_file_1: calling _tt_netfile_file(%s)\n",
1884         (char *) args->file_or_netfile);
1885 #endif
1886
1887         static _tt_file_netfile_results results;
1888         static char * canonical_path;
1889
1890         // we have a netfilename, get the local file version...
1891         canonical_path = _tt_netfile_file(args->file_or_netfile);
1892
1893 #ifdef notdef
1894 printf("DEBUG: SERVER: _tt_netfile_file_1: _tt_netfile_file(%s) returned %s\n",
1895         args->file_or_netfile, canonical_path);
1896 #endif
1897
1898         if (_tt_pointer_error(canonical_path) != TT_OK) {
1899                 results.results = TT_DB_ERR_ILLEGAL_FILE;
1900                 results.result_string = NULL;
1901         } else {
1902                 results.results = TT_DB_OK;
1903                 results.result_string = canonical_path;
1904         }
1905         results.tt_status = (int) _tt_pointer_error(canonical_path);
1906
1907 #ifdef notdef
1908 printf("\t results.tt_status == %s\n",
1909         _tt_status_message(_tt_pointer_error(canonical_path)));
1910 #endif
1911
1912         return &results;
1913 }
1914
1915
1916 //
1917 // Delete the named session from the properties table.
1918 //
1919 _tt_delete_session_results      *
1920 _tt_delete_session_1(_tt_delete_session_args    *args,
1921                      SVCXPRT                    * /*NOTUSED*/)
1922 {
1923     static _tt_delete_session_results   results;                         
1924     Table_oid_prop                      record;
1925
1926     u_int                               fileOffset;
1927     int                                 propLen = strlen(propTable);
1928     int                                 isfd;
1929
1930     char                                *lastSlash;
1931     char                                *pathName;
1932
1933     results.tt_status = TT_DB_OK;
1934
1935     //
1936     // For each property_table that we manage,
1937     // Compare the sessionID with the session that
1938     // we just found to be dead, and delete it.
1939     //
1940     for (fileOffset = 0; fileOffset < _TT_MAX_ISFD; fileOffset++) {
1941
1942         pathName = _tt_db_table[fileOffset].db_path;
1943
1944         if (pathName && strlen(pathName) > 0) {
1945             if (_tt_db_table[fileOffset].client_has_open
1946                 || _tt_db_table[fileOffset].server_has_open) {
1947                                 
1948                 //
1949                 // Is the file name ".../property_table*" ?
1950                 //
1951                 lastSlash = strrchr(pathName, '/');
1952                 if (lastSlash) {
1953                     lastSlash++;
1954                     if (strncmp(propTable,lastSlash,propLen)==0) {
1955                         
1956                         // Get the FD and process the file.
1957                         isfd=cached_isopen(pathName, ISINOUT);
1958                         
1959                         //
1960                         // Get the 1st record.
1961                         //
1962                         LOCK_RPC();
1963                         isread(isfd, (char *)&record, ISFIRST);
1964                         ((char *)(&record))[isreclen] = '\0';
1965
1966                         // Delte the named session.
1967                         if (strcmp(sesProp, record.propname) == 0) {
1968                           if (strcmp(args->session.value, record.propval) == 0) {
1969                             isdelcurr(isfd);
1970                             isfsync(isfd);
1971                           }
1972                         }
1973
1974                         // Unconditionally delete ALL _MODIFICATION_DATE's
1975                         if (strcmp(modDate, record.propname) == 0) {
1976                           isdelcurr(isfd);
1977                           isfsync(isfd);
1978                         }
1979                         
1980                         UNLOCK_RPC();
1981                                                 
1982                         do {
1983                             LOCK_RPC();
1984                             if (isread(isfd, (char *)&record,ISNEXT) != 0) {
1985                                 UNLOCK_RPC();
1986                                 break;
1987                             }
1988                             ((char *)(&record))[isreclen] = '\0';
1989                             if (strcmp(sesProp, record.propname) == 0) {
1990                                 if(strcmp(args->session.value,
1991                                           record.propval) == 0) {
1992                                     isdelcurr(isfd);
1993                                     isfsync(isfd);
1994                                 }
1995                             }
1996
1997                             // Unconditionally delete ALL
1998                             //  _MODIFICATION_DATE's
1999                             if (strcmp(modDate, record.propname) == 0) {
2000                               isdelcurr(isfd);
2001                               isfsync(isfd);
2002                             }
2003                             UNLOCK_RPC();
2004                         } while(TRUE);
2005                         cached_isclose(isfd);
2006                     }
2007                 }
2008             }
2009         }
2010     }
2011     return(&results);
2012 }
2013
2014 //
2015 // *All* is an over statment.
2016 // It returns up to OPT_MAX_GET_SESSIONS sessions and the oidkey to use
2017 // to resume.
2018 //
2019 _tt_get_all_sessions_results *
2020 _tt_get_all_sessions_1(_tt_get_all_sessions_args * args,
2021                        SVCXPRT                   * /*NOTUSED*/)
2022 {
2023         static _tt_get_all_sessions_results     results;
2024
2025         static _Tt_string_list            *list;
2026         list = new _Tt_string_list;
2027
2028         int                       offset;
2029         int                       isfd;
2030         int                       recordCount = 0;
2031         int                       propLen = strlen(propTable);
2032
2033         char                    * lastSlash;
2034         char                    * pathName;
2035
2036         _Tt_string                propValue;
2037         Table_oid_prop            record;
2038
2039         //
2040         // Empty out any existing session or key results.
2041         //
2042         list->flush();
2043         if (results.oidkey.oidkey_val != NULL) {
2044                 free((char *)results.oidkey.oidkey_val);
2045         }
2046         for (offset = 0 ; offset < list->count() ; offset++) {
2047                 if (results.session_list.values_val[offset].value != NULL) {
2048                         free(results.session_list.values_val[offset].value);
2049                 }
2050         }
2051         if (results.session_list.values_val != NULL) {
2052                 free((char *)results.session_list.values_val);
2053                 results.session_list.values_val = NULL;
2054         }
2055         memset(&results.oidkey, '\0', sizeof(results.oidkey));
2056
2057         //
2058         // For each property_table that we manage,
2059         // pull out all of the session-ids and pass them back (up
2060         // to OPT_MAX_GET_SESSIONS passed back in each call)
2061         //
2062         for (offset = 0 ; offset < _TT_MAX_ISFD; offset++) {
2063
2064             pathName = _tt_db_table[offset].db_path;
2065
2066             if (pathName && strlen(pathName) > 0) {
2067                 if (_tt_db_table[offset].client_has_open
2068                     || _tt_db_table[offset].server_has_open) {
2069
2070                     //
2071                     // Is the file name ".../property_table*" ?
2072                     //
2073                     lastSlash = strrchr(pathName, '/');
2074                     if (lastSlash) {
2075                         lastSlash++;
2076                         if (strncmp(propTable, lastSlash, propLen) == 0) {
2077                                                 
2078                             // Get the FD and process the file.
2079                             isfd = cached_isopen(pathName, ISINOUT);
2080
2081                             //
2082                             // If the user passed in a starting key,
2083                             // then use it.
2084                             //
2085                             if (args->oidkey.oidkey_len > 0
2086                                 && args->oidkey.oidkey_val != NULL) {
2087                                 issetcurpos(isfd,
2088                                             (char *)args->oidkey.oidkey_val);
2089                             }
2090                             
2091                             //
2092                             // Get the 1st record.
2093                             //
2094                             isread(isfd, (char *)&record, ISFIRST);
2095                             ((char *)(&record))[isreclen] = '\0';
2096                             if (strcmp(sesProp, record.propname) == 0) {
2097                                 propValue = record.propval;
2098                                 
2099                                 // Append it to the list to send back.
2100                                 recordCount++;
2101                                 list->append(propValue);
2102                                 memset(&record, '\0', sizeof(record));
2103                             }
2104                             
2105                             while(isread(isfd, (char *)&record,ISNEXT) != -1) {
2106                               ((char *)(&record))[isreclen] = '\0';
2107                                 if (strcmp(sesProp, record.propname) == 0) {
2108                                     propValue = record.propval;
2109                                     list->append(propValue);
2110                                     if (++recordCount > OPT_MAX_GET_SESSIONS-1) {
2111                                         results.oidkey.oidkey_val = NULL;
2112                                         isgetcurpos(isfd,
2113                                                     (int *)&results.oidkey.oidkey_len,
2114                                                     (char **)&results.oidkey.oidkey_val);
2115                                         break;
2116                                         
2117                                     }
2118                                 }
2119                                 memset(&record, '\0', sizeof(record));
2120                             }
2121                             cached_isclose(isfd);
2122                             if (recordCount > OPT_MAX_GET_SESSIONS-1) {
2123                                 break;
2124                             }
2125                         }
2126                     }
2127                 }
2128             }
2129         }
2130         results.session_list.values_len = list->count();
2131         if (results.session_list.values_len > 0) {
2132           results.session_list.values_val = (_tt_string *)malloc(sizeof(_tt_string *) * list->count());
2133         } else {
2134           results.session_list.values_val = (_tt_string *)NULL;
2135         }
2136         for (offset = 0 ; offset < results.session_list.values_len ; offset++) {
2137                 propValue = list->top();
2138                 results.session_list.values_val[offset].value = strdup(propValue);
2139                 list->pop();
2140         }
2141         
2142         return(&results);
2143 }
2144
2145 _tt_garbage_collect_results *
2146 _tt_garbage_collect_1(void      * /*NOTUSED*/,
2147                       SVCXPRT   * /*NOTUSED*/)
2148 {
2149         static _tt_garbage_collect_results      results;
2150
2151
2152         memset(&results, '\0', sizeof(_tt_garbage_collect_results));
2153
2154 #if defined(OPT_GARBAGE_THREADS)
2155         int     id;
2156
2157         //
2158         // Collect the garbage and delete old sessions in
2159         // a separate thread. As soon as the thread is started
2160         // this function returns and the dbserver is again
2161         // processing user requests.
2162         id = _tt_run_garbage_collect(OPT_GARBAGE_IN_PARALLEL);
2163         results.tt_status = (id >= 0) ? TT_OK : TT_ERR_INTERNAL;
2164 #else
2165         //
2166         // Without threads, just compress (isgarbage) the 
2167         // db files. The user program will check for and
2168         // delete old sessions.
2169         //
2170         isgarbage_collect();
2171         results.tt_status = TT_OK;
2172 #endif
2173         return(&results);
2174 }
2175
2176
2177 //
2178 // ******* Static helper functions start here *******
2179 //
2180
2181 bool_t _tt_is_file_a_directory (const _Tt_string &file)
2182 {
2183   // This is sometimes called with a network path and a non-network path.
2184   // Make sure we always give stat a non-network path.
2185   char *slash = strchr((char *)file, '/');
2186   char *path = strchr((char *)file, ':');
2187   if (path != slash-1) {
2188     path = (char *)NULL;
2189   }
2190   DIR *dd = opendir(path ? path+1 : (char *)file);
2191
2192   if (dd) {
2193     (void)closedir(dd);
2194   }
2195
2196   return (dd ? TRUE : FALSE);
2197 }
2198
2199 // Replace the old partition with the new partition in the object ID
2200 static _Tt_string _tt_make_equivalent_object_id (const _Tt_string &objid,
2201                                                  const _Tt_string &partition)
2202 {
2203   _Tt_string temp_string = (char *)objid;
2204   _Tt_string new_objid;
2205
2206   temp_string = temp_string.rsplit (':', new_objid);
2207   new_objid = new_objid.cat(partition);
2208
2209   return new_objid;
2210 }
2211
2212 static _Tt_db_results _tt_get_partition_db (const _Tt_string     &partition,
2213                                             _Tt_db_server_db_ptr &db)
2214 {
2215   _Tt_db_partition_global_map_ref db_map;
2216   _Tt_db_results                  results = TT_DB_OK;
2217
2218   db = db_map.getDB(partition);
2219   if (db.is_null()) {
2220     results = TT_DB_ERR_DB_OPEN_FAILED;
2221   }
2222
2223   return results;
2224 }
2225
2226 static _Tt_db_access_ptr _tt_get_real_rpc_access (const _tt_access &rpc_access)
2227 {
2228   _Tt_db_access_ptr accessPtr;
2229   _tt_get_rpc_access(rpc_access, accessPtr);
2230
2231   accessPtr->user = _tt_uid;
2232   accessPtr->group = (gid_t)-1;
2233
2234   // Make sure the group ID is valid before using it
2235   for (int i=0; i < _tt_gidlen; i++) {
2236     if (_tt_gidlist [i] == _tt_gid) {
2237       accessPtr->group = _tt_gid;
2238     }
2239   }
2240
2241   return accessPtr;
2242 }
2243
2244 static _Tt_db_access_ptr _tt_get_file_access (const _Tt_string &file,
2245                                               const _tt_access &rpc_access)
2246 {
2247   _Tt_db_access_ptr accessPtr = _tt_get_unix_file_access(file);
2248
2249   if (accessPtr.is_null()) {
2250     accessPtr = _tt_get_real_rpc_access(rpc_access);
2251   }
2252   else {
2253     accessPtr->mode = (mode_t)-1;
2254   }
2255
2256   return accessPtr;
2257 }
2258
2259 static _Tt_db_access_ptr _tt_get_unix_file_access (const _Tt_string &file)
2260 {
2261   _Tt_db_access_ptr accessPtr;
2262
2263   struct stat stat_buf;
2264
2265   // Make sure we always give stat a non-network path.
2266   _Tt_string local_path = file;
2267
2268   if (_tt_is_network_path(file)) {
2269     _Tt_string temp_string;
2270     local_path = local_path.split(':', temp_string);
2271   }
2272
2273   if (!stat((char *)local_path, &stat_buf)) {
2274     accessPtr = new _Tt_db_access;
2275     accessPtr->user = stat_buf.st_uid;
2276     accessPtr->group = stat_buf.st_gid;
2277     accessPtr->mode = stat_buf.st_mode;
2278   }
2279
2280   return accessPtr;
2281 }
2282
2283 static _Tt_string _tt_get_file_partition (const _Tt_string &file)
2284 {
2285   _Tt_string temp_string;
2286   _Tt_string local_path = file;
2287   local_path = local_path.split(':', temp_string);
2288
2289   _Tt_file_system           fs;
2290   _Tt_file_system_entry_ptr entry = fs.bestMatchToPath(local_path);
2291
2292   return entry->getMountPoint();
2293 }
2294
2295 static _Tt_db_results
2296 _tt_increment_file_properties_cache_level
2297   (const _Tt_db_server_db_ptr &db,
2298    const _Tt_string           &file,
2299    const _Tt_db_access_ptr    &accessPtr,
2300    int                        &cache_level)
2301 {
2302   cache_level = -1;
2303
2304   _Tt_db_property_ptr property;
2305   _Tt_db_results results =
2306     db->getFileProperty(file,
2307                         TT_DB_PROPS_CACHE_LEVEL_PROPERTY,
2308                         accessPtr,
2309                         property);
2310
2311   if (results == TT_DB_OK) {
2312     _Tt_string cache_level_bytes = (*property->values) [0];
2313     memcpy ((char *)&cache_level, (char *)cache_level_bytes, sizeof(int));
2314
2315     cache_level++;
2316     memcpy ((char *)cache_level_bytes, (char *)&cache_level, sizeof(int));
2317     (*property->values) [0] = cache_level_bytes;
2318
2319     results = db->setFileProperty(file,
2320                                   property,
2321                                   accessPtr);
2322     if (results != TT_DB_OK) {
2323       cache_level = -1;
2324       results = TT_DB_ERR_PROPS_CACHE_ERROR;
2325     }
2326   }
2327   else if (results == TT_DB_ERR_NO_SUCH_PROPERTY) {
2328     cache_level = 0;
2329
2330     _Tt_string value(sizeof(int));
2331     memcpy((char *)value, (char *)&cache_level, sizeof(int));
2332
2333     _Tt_db_property_ptr property = new _Tt_db_property;
2334     property->name = TT_DB_PROPS_CACHE_LEVEL_PROPERTY;
2335     property->values->append(value);
2336
2337     results = db->setFileProperty(file,
2338                                   property,
2339                                   accessPtr);
2340     if (results != TT_DB_OK) {
2341       cache_level = -1;
2342       results = TT_DB_ERR_PROPS_CACHE_ERROR;
2343     }
2344   }
2345   else {
2346     results = TT_DB_ERR_PROPS_CACHE_ERROR;
2347   }
2348
2349   return results;
2350 }
2351
2352 static _Tt_db_results 
2353 _tt_get_file_properties_cache_level (const _Tt_db_server_db_ptr &db,
2354                                      const _Tt_string           &file,
2355                                      const _Tt_db_access_ptr    &accessPtr,
2356                                      int                        &cache_level)
2357 {
2358   cache_level = -1;
2359
2360   _Tt_db_property_ptr property;
2361   _Tt_db_results results =
2362     db->getFileProperty(file,
2363                         TT_DB_PROPS_CACHE_LEVEL_PROPERTY,
2364                         accessPtr,
2365                         property);
2366   if (results == TT_DB_OK) {
2367     _Tt_string cache_level_bytes = (*property->values) [0];
2368     memcpy ((char *)&cache_level, (char *)cache_level_bytes, sizeof(int));
2369   }
2370   // The file was probably created for an object.  The cache level
2371   // was never stored as a property...
2372   else if (results == TT_DB_ERR_NO_SUCH_PROPERTY) {
2373     results = _tt_increment_file_properties_cache_level(db,
2374                                                         file,
2375                                                         accessPtr,
2376                                                         cache_level);
2377   }
2378   else {
2379     results = TT_DB_ERR_PROPS_CACHE_ERROR;
2380   }
2381
2382   return results;
2383 }
2384
2385 static _Tt_string _tt_get_object_partition (const _Tt_string &objid)
2386 {
2387   _Tt_string partition = (char *)objid;
2388   _Tt_string temp_string;
2389
2390   // Get rid of file system type and hostname - the partition
2391   // is the only thing left
2392   partition = partition.split(':', temp_string);
2393   partition = partition.split(':', temp_string);
2394   partition = partition.split(':', temp_string);
2395
2396   return partition;
2397 }
2398
2399 static _Tt_db_results
2400 _tt_increment_object_properties_cache_level
2401   (const _Tt_db_server_db_ptr &db,
2402    const _Tt_string           &objid,
2403    const _Tt_db_access_ptr    &accessPtr,
2404    int                        &cache_level)
2405 {
2406   cache_level = -1;
2407
2408   _Tt_db_property_ptr property;
2409   _Tt_db_results results =
2410     db->getObjectProperty(objid,
2411                           TT_DB_PROPS_CACHE_LEVEL_PROPERTY,
2412                           accessPtr,
2413                           property);
2414
2415   if (results == TT_DB_OK) {
2416     _Tt_string cache_level_bytes = (*property->values) [0];
2417     memcpy ((char *)&cache_level, (char *)cache_level_bytes, sizeof(int));
2418
2419     cache_level++;
2420     memcpy ((char *)cache_level_bytes, (char *)&cache_level, sizeof(int));
2421     (*property->values) [0] = cache_level_bytes;
2422
2423     results = db->setObjectProperty(objid,
2424                                     property,
2425                                     accessPtr);
2426     if (results != TT_DB_OK) {
2427       cache_level = -1;
2428       results = TT_DB_ERR_PROPS_CACHE_ERROR;
2429     }
2430   }
2431   else if (results == TT_DB_ERR_NO_SUCH_PROPERTY) {
2432     cache_level = 0;
2433
2434     _Tt_string value(sizeof(int));
2435     memcpy((char *)value, (char *)&cache_level, sizeof(int));
2436
2437     _Tt_db_property_ptr property = new _Tt_db_property;
2438     property->name = TT_DB_PROPS_CACHE_LEVEL_PROPERTY;
2439     property->values->append(value);
2440
2441     results = db->setObjectProperty(objid,
2442                                     property,
2443                                     accessPtr);
2444     if (results != TT_DB_OK) {
2445       cache_level = -1;
2446       results = TT_DB_ERR_PROPS_CACHE_ERROR;
2447     }
2448   }
2449   else {
2450     results = TT_DB_ERR_PROPS_CACHE_ERROR;
2451   }
2452
2453   return results;
2454 }
2455
2456 static _Tt_db_results 
2457 _tt_get_object_properties_cache_level (const _Tt_db_server_db_ptr &db,
2458                                        const _Tt_string           &objid,
2459                                        const _Tt_db_access_ptr    &accessPtr,
2460                                        int                        &cache_level)
2461 {
2462   cache_level = -1;
2463
2464   _Tt_db_property_ptr property;
2465   _Tt_db_results results = 
2466     db->getObjectProperty(objid,
2467                           TT_DB_PROPS_CACHE_LEVEL_PROPERTY,
2468                           accessPtr,
2469                           property);
2470
2471   if (results == TT_DB_OK) {
2472     _Tt_string cache_level_bytes = (*property->values) [0];
2473     memcpy ((char *)&cache_level, (char *)cache_level_bytes, sizeof(int));
2474   }
2475   else {
2476     results = TT_DB_ERR_PROPS_CACHE_ERROR;
2477   }
2478
2479   return results;
2480 }
2481
2482 static void
2483 _tt_screen_object_properties (_Tt_db_property_list_ptr &properties)
2484 {
2485   _Tt_db_property_list_cursor properties_cursor (properties);
2486   while (properties_cursor.next ()) {
2487     if (properties_cursor->name ==  TT_DB_PROPS_CACHE_LEVEL_PROPERTY) {
2488       properties_cursor.remove ();
2489     }
2490     else if (properties_cursor->name == TT_DB_OBJECT_TYPE_PROPERTY) {
2491       properties_cursor.remove ();
2492     }
2493   }
2494
2495   if (properties->count () == 0) {
2496     properties = (_Tt_db_property_list *)NULL;
2497   }
2498 }
2499
2500 static _Tt_string _tt_get_local_path (const _Tt_string &network_path,
2501                                       _Tt_string       &hostname,
2502                                       _Tt_string       &partition)
2503 {
2504   _Tt_string temp_string = network_path;
2505   _Tt_string local_path = _tt_realpath (temp_string.split(':', hostname));
2506
2507   _Tt_file_system file_system;
2508   _Tt_file_system_entry_ptr entry = file_system.bestMatchToPath(local_path);
2509
2510   partition = entry->getMountPoint();
2511
2512   _Tt_string loop_back_mount_point = entry->getLoopBackMountPoint();
2513   if (loop_back_mount_point.len()) {
2514     // Get the path info after the loop back mount point path
2515     local_path = local_path.right(local_path.len()-loop_back_mount_point.len());
2516
2517     // Replace the loop back mount point path with the partition path
2518     local_path = partition.cat(local_path);
2519   }
2520
2521   return local_path;
2522 }
2523
2524 //
2525 // This is the thread that performs the garbage collection.
2526 // It is defined as a (void *) function for thr_create() compatibility.
2527 //
2528 static void     *
2529 _tt_garbage_collect(void * /*NOTUSED*/)
2530 {
2531         // thr_create() func returns (void *).
2532         void                    * results = NULL;
2533
2534         _tt_get_all_sessions_args        args;
2535
2536         _Tt_string                       sessionId;
2537         _Tt_string_list                 *sessions;
2538
2539         memset(&args, '\0', sizeof(args));
2540
2541 #if defined(OPT_GARBAGE_THREADS)
2542
2543         sigset_t        new_thr_sigset;
2544
2545         //
2546         // Tell ourself (this thread only) to ignore all SIGs, or quit.
2547         //
2548         if (sigfillset(&new_thr_sigset) != 0) {
2549                 return(results);
2550         }
2551
2552         if (thr_sigsetmask(SIG_BLOCK, &new_thr_sigset, NULL) < 0) {
2553                 return(results);
2554         }
2555
2556         LOCK_RPC();
2557         isgarbage_collect();            // 1st compress the DB files.
2558         UNLOCK_RPC();
2559 #else
2560         _Tt_db_client_ptr       dbClient;
2561
2562         if (!dbClient.is_null() 
2563             && dbClient->getConnectionResults() == TT_DB_OK) {
2564                 // Tell server to compress the files.
2565                 dbClient->garbage_collect_in_server();
2566 #endif
2567
2568                 // Get a list of all sessions.
2569                 do {
2570                         LOCK_RPC();
2571 #if defined(OPT_GARBAGE_THREADS)
2572                         _tt_get_all_sessions_results    *sessionList;
2573
2574                         sessionList = _tt_get_all_sessions_1(&args, NULL);
2575             
2576                         int                     offset;
2577                         _Tt_string              oneSession;
2578
2579                         sessions = new _Tt_string_list;
2580
2581                         for (offset = 0
2582                              ; offset < sessionList->session_list.values_len
2583                              ; offset++) {
2584                                 oneSession = sessionList->session_list.values_val[offset].value;
2585                                 sessions->append(oneSession);
2586                         }
2587 #else
2588                         sessions = dbClient->get_all_sessions();
2589 #endif
2590                         if (sessions== NULL     || sessions->count() == 0) {
2591                                 UNLOCK_RPC();
2592                                 break;
2593                         }
2594             
2595                 UNLOCK_RPC();
2596
2597                         // Delete the list of sessions that are dead.
2598                         do {
2599                                 Tt_status                       ttstatus;
2600 #if defined(OPT_GARBAGE_THREADS)
2601                                 _tt_delete_session_args         delsession;
2602 #endif
2603
2604                                 sessionId = sessions->top();
2605                                 if ((ttstatus=tt_default_session_set(sessionId)) != TT_OK) {
2606
2607 #if defined(OPT_GARBAGE_THREADS)
2608                                         delsession.session.value = sessionId;
2609                                         _tt_delete_session_1(&delsession,NULL);
2610 #else
2611                                         dbClient->delete_session(sessionId);
2612 #endif
2613                                 }
2614                                 sessions->pop();
2615                         } while(sessions->count() > 0);
2616
2617 #if defined(OPT_GARBAGE_THREADS)
2618                         //
2619                         // Copy over the re-start key.
2620                         // (for more than OPT_MAX_GET_SESSIONS).
2621                         memcpy(&args.oidkey,
2622                                &sessionList->oidkey,
2623                                sizeof(args.oidkey));
2624 #endif
2625                 } while (args.oidkey.oidkey_len != 0);
2626
2627 #if defined(OPT_GARBAGE_THREADS)
2628                 mutex_unlock(&garbage_run_in_process);
2629 #else
2630         }
2631 #endif
2632         return(results);
2633 }
2634
2635 //
2636 // Return the PID or TID of the running garbage collection function.
2637 //
2638 int
2639 _tt_run_garbage_collect(int in_parallel)
2640 {
2641         extern FILE     *errstr;
2642
2643         /* Make sure in_parallel is used to quiet warnings */
2644         if (in_parallel) {}
2645
2646 #if defined(OPT_GARBAGE_THREADS)
2647         static int      mutex_inited = 0;
2648
2649         // Error back from mutex_*() and thr_() funcs.
2650         int             err;
2651
2652         // Times to try thr_create() if it return with EAGAIN.
2653         int             create_tries = OPT_SOLARIS_THREADED_TRIES;
2654
2655         if (!mutex_inited) {
2656                 mutex_inited = 1;
2657                 // Init the RPC syncronazation mutex lock.
2658                 mutex_init(&rpc_client_busy, USYNC_THREAD, 0);
2659                 mutex_init(&garbage_run_in_process, USYNC_PROCESS, 0);
2660
2661                 // Raise the priority of ourselfs to be higher
2662                 // than our new thread.
2663                 thr_setprio(thr_self(), 10);
2664         }
2665
2666         //
2667         // See if anyone else is running, if so, then do not run
2668         // gabage collection again.
2669         //
2670         if (mutex_trylock(&garbage_run_in_process) != 0) {
2671                 return (_tt_garbage_id);
2672         }
2673
2674         //
2675
2676         //
2677         // Start the thread and keep trying OPT_SOLARIS_THREADED_TRIES,
2678         // or until it works.
2679         //
2680         while ((err = thr_create((void *)0,     // stack_base - use default.
2681                                  (size_t)0,     // stack_size - use default.
2682                                  _tt_garbage_collect,
2683                  (void *)_TT_GARBAGE_COLLECTION_FREQUENCY,// Arg to func.
2684                                  THR_SUSPENDED|THR_BOUND,
2685                                  (thread_t *)&_tt_garbage_id)) < 0) {
2686
2687                 if (errno == EAGAIN && (--create_tries > 0)) {
2688                         thr_yield();
2689                         continue;
2690                 }
2691
2692                 _tt_garbage_id = -2;
2693                 //
2694                 // Get here only on thr_create() error.
2695                 // Unable to create thread.
2696                 //
2697                 _tt_syslog(errstr, LOG_ERR, "%s",
2698                            catgets(_ttcatd, 5, 8,
2699                            "Unable to start garbage collection thread. thr_create()\n"));
2700         }
2701
2702
2703         //
2704         // If we are to garbage collect in parallel, then
2705         // let the garbage thread continue at a low priority.
2706         //
2707         // If we are not to garbage collect in parallel,
2708         // then let the thread run, then the main thread exits.
2709         //
2710         if (in_parallel == TRUE) {
2711                 if (_tt_garbage_id > 0) {
2712
2713                         // Lower the priority of garbage collection to lowest.
2714                         thr_setprio(_tt_garbage_id, 0);
2715
2716                         // And start it.
2717                         thr_continue((thread_t)_tt_garbage_id);
2718                 }
2719         } else {
2720                 if (_tt_garbage_id > 0) {
2721                         thr_continue((thread_t)_tt_garbage_id);
2722                         thr_yield();
2723                         thr_exit(0);
2724                 } else {
2725                         thr_exit(0);
2726                 }
2727         }
2728
2729 #else //defined(OPT_GARBAGE_THREADS)
2730
2731 #if defined(OPT_AUTO_GARBAG_COLLECT)
2732         //
2733         // Do not start another, if one is running.
2734         //
2735         if (in_parallel == TRUE) {
2736             if (_tt_garbage_id == -1) {
2737                 //
2738                 // FORK and EXEC ourself '-G'.
2739                 //
2740 #if defined(OPT_BUG_AIX) || defined(OPT_BUG_USL) || defined(OPT_BUG_UXP)
2741 #define vfork fork
2742 #endif
2743                 switch (_tt_garbage_id = (int)vfork()) {
2744                       case 0:           // child
2745                         {
2746                                 const char *newargv[3];
2747
2748                                 newargv[0] = global_argv[0];
2749                                 newargv[1] = "-G";
2750                                 newargv[2] = NULL;
2751                                 
2752                                 execve((const char *)newargv[0],
2753                                         (char *const *)newargv,
2754                                         (char *const *)global_envp);
2755
2756                                 _tt_syslog(errstr, LOG_ERR, "%s",
2757                                            catgets(_ttcatd, 5, 9,
2758                                 "Unable to fork() for garbage collection.\n"));
2759                                 _tt_garbage_id = -3;
2760                                 _exit(1);       // ERROR, so exit new child.
2761                         }
2762                         break;
2763
2764                       case -1:          // Error.
2765                         _tt_syslog(errstr, LOG_ERR, "%s",
2766                                    catgets(_ttcatd, 5, 9,
2767                             "Unable to fork() for garbage collection.\n"));
2768                         _tt_garbage_id = -4;
2769                         break;
2770
2771                       default:          // Parent.
2772                         break;
2773                     }
2774             }
2775         } else {
2776 #endif /* OPT_AUTO_GARBAGE_COLLECT*/
2777             exit((intptr_t)_tt_garbage_collect(NULL));
2778 #if defined(OPT_AUTO_GARBAG_COLLECT)
2779         }
2780 #endif /* OPT_AUTO_GARBAGE_COLLECT*/
2781
2782 #endif // ! OPT_GARBAGE_THREADS
2783         return (_tt_garbage_id);
2784 }
2785