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