libroken: Build on windows
[openafs.git] / src / libadmin / vos / afs_vosAdmin.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12
13 #include <roken.h>
14
15 #include <afs/stds.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <ctype.h>
19 #ifdef AFS_NT40_ENV
20 #include <winsock2.h>
21 #include <io.h>
22 #else
23 #include <sys/types.h>
24 #include <sys/socket.h>
25 #include <unistd.h>
26 #include <netinet/in.h>
27 #include <arpa/inet.h>
28 #include <netdb.h>
29 #endif
30 #include "afs_vosAdmin.h"
31 #include "../adminutil/afs_AdminInternal.h"
32 #include <afs/vlserver.h>
33 #include <afs/volser.h>
34 #include <afs/volint.h>
35
36 /* File descriptors are HANDLE's on NT. The following typedef helps catch
37  * type errors. Duplicated from vol/ihandle.h
38  */
39 #ifdef AFS_NT40_ENV
40 typedef HANDLE FD_t;
41 #else
42 typedef int FD_t;
43 #endif
44 #define INVALID_FD ((FD_t)-1)
45
46 #include <afs/partition.h>
47 #include <rx/rx.h>
48 #include <rx/rxstat.h>
49 #include <afs/afs_utilAdmin.h>
50 #include "vosutils.h"
51 #include "vsprocs.h"
52 #include "lockprocs.h"
53
54 typedef struct file_server {
55     int begin_magic;
56     int is_valid;
57     struct rx_connection *serv;
58     int end_magic;
59 } file_server_t, *file_server_p;
60
61 /*
62  * IsValidServerHandle - test a server handle for validity.
63  *
64  * PARAMETERS
65  *
66  * IN serverHandle - the serverHandle to be validated.
67  *
68  * LOCKS
69  * 
70  * No locks are obtained or released by this function
71  *
72  * RETURN CODES
73  *
74  * Returns != 0 upon successful completion.
75  */
76
77 static int
78 IsValidServerHandle(file_server_p serverHandle, afs_status_p st)
79 {
80     int rc = 0;
81     afs_status_t tst = 0;
82
83     if (serverHandle == NULL) {
84         tst = ADMVOSSERVERHANDLENULL;
85         goto fail_IsValidServerHandle;
86     }
87
88     if (serverHandle->is_valid != 1) {
89         tst = ADMVOSSERVERHANDLEINVALID;
90         goto fail_IsValidServerHandle;
91     }
92
93     if ((serverHandle->begin_magic != BEGIN_MAGIC)
94         || (serverHandle->end_magic != END_MAGIC)) {
95         tst = ADMVOSSERVERHANDLEBADMAGIC;
96         goto fail_IsValidServerHandle;
97     }
98     rc = 1;
99
100   fail_IsValidServerHandle:
101
102     if (st != NULL) {
103         *st = tst;
104     }
105
106     return rc;
107 }
108
109 /*
110  * IsValidCellHandle - verify that a cell handle can be used to make vos 
111  * requests.
112  *
113  * PARAMETERS
114  *
115  * IN cellHandle - the cellHandle to be validated.
116  *
117  * LOCKS
118  * 
119  * No locks are obtained or released by this function
120  *
121  * RETURN CODES
122  *
123  * Returns != 0 upon successful completion.
124  */
125
126 static int
127 IsValidCellHandle(afs_cell_handle_p cellHandle, afs_status_p st)
128 {
129     int rc = 0;
130     afs_status_t tst = 0;
131
132     if (!CellHandleIsValid((void *)cellHandle, &tst)) {
133         goto fail_IsValidCellHandle;
134     }
135
136     if (cellHandle->vos_valid == 0) {
137         tst = ADMVOSCELLHANDLEINVALIDVOS;
138         goto fail_IsValidCellHandle;
139     }
140     rc = 1;
141
142   fail_IsValidCellHandle:
143
144     if (st != NULL) {
145         *st = tst;
146     }
147     return rc;
148 }
149
150 /* set <server> and <part> to the correct values depending on
151  * <voltype> and <entry> */
152 static void
153 GetServerAndPart(struct nvldbentry *entry, int voltype, afs_int32 * server,
154                  afs_int32 * part, int *previdx)
155 {
156     int i, istart, vtype;
157
158     *server = -1;
159     *part = -1;
160
161     /* Doesn't check for non-existance of backup volume */
162     if ((voltype == RWVOL) || (voltype == BACKVOL)) {
163         vtype = ITSRWVOL;
164         istart = 0;             /* seach the entire entry */
165     } else {
166         vtype = ITSROVOL;
167         /* Seach from beginning of entry or pick up where we left off */
168         istart = ((*previdx < 0) ? 0 : *previdx + 1);
169     }
170
171     for (i = istart; i < entry->nServers; i++) {
172         if (entry->serverFlags[i] & vtype) {
173             *server = entry->serverNumber[i];
174             *part = entry->serverPartition[i];
175             *previdx = i;
176             return;
177         }
178     }
179
180     /* Didn't find any, return -1 */
181     *previdx = -1;
182     return;
183 }
184
185 /*
186  * vos_BackupVolumeCreate - create a backup volume for a volume.
187  *
188  * PARAMETERS
189  *
190  * IN cellHandle - a previously opened cellHandle that corresponds
191  * to the cell where volume exists.
192  *
193  * IN callBack - a call back function pointer that may be called to report
194  * status information.  Can be null.
195  *
196  * IN volumeId - the volume to create the back up for.
197  *
198  * LOCKS
199  * 
200  * No locks are obtained or released by this function
201  *
202  * RETURN CODES
203  *
204  * Returns != 0 upon successful completion.
205  */
206
207 int ADMINAPI
208 vos_BackupVolumeCreate(const void *cellHandle, vos_MessageCallBack_t callBack,
209                        unsigned int volumeId, afs_status_p st)
210 {
211     int rc = 0;
212     afs_status_t tst = 0;
213     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
214     struct nvldbentry rw_vol_entry;
215     afs_int32 rw_server;
216     afs_int32 rw_partition;
217     afs_int32 rw_vol_type;
218     struct nvldbentry bk_vol_entry;
219     afs_int32 bk_server;
220     afs_int32 bk_partition;
221     afs_int32 bk_vol_type;
222     int equal;
223
224     /*
225      * Validate arguments
226      */
227
228     if (!IsValidCellHandle(c_handle, &tst)) {
229         goto fail_vos_BackupVolumeCreate;
230     }
231
232     /*
233      * Get the volume information and verify that we've been passed
234      * a read write volume id
235      */
236
237     if (!GetVolumeInfo
238         (c_handle, volumeId, &rw_vol_entry, &rw_server, &rw_partition,
239          &rw_vol_type, &tst)) {
240         goto fail_vos_BackupVolumeCreate;
241     }
242
243     if (rw_vol_type != RWVOL) {
244         tst = ADMVOSMUSTBERWVOL;
245         goto fail_vos_BackupVolumeCreate;
246     }
247
248     /*
249      * Check to see that if a backup volume exists, it exists on the
250      * same server as volumeId
251      */
252
253     if (rw_vol_entry.flags & BACK_EXISTS) {
254         if (!GetVolumeInfo
255             (c_handle, rw_vol_entry.volumeId[BACKVOL], &bk_vol_entry,
256              &bk_server, &bk_partition, &bk_vol_type, &tst)) {
257             goto fail_vos_BackupVolumeCreate;
258         }
259         if (!VLDB_IsSameAddrs(c_handle, bk_server, rw_server, &equal, &tst)) {
260             goto fail_vos_BackupVolumeCreate;
261         }
262         if (!equal) {
263             tst = ADMVOSBACKUPVOLWRONGSERVER;
264             goto fail_vos_BackupVolumeCreate;
265         }
266     }
267
268     /*
269      * Create the new backup volume
270      */
271
272     rc = UV_BackupVolume(c_handle, rw_server, rw_partition, volumeId, &tst);
273
274   fail_vos_BackupVolumeCreate:
275
276     if (st != NULL) {
277         *st = tst;
278     }
279     return rc;
280 }
281
282 /*
283  * vos_BackupVolumeCreateMultiple - create backup volumes en masse.
284  *
285  * PARAMETERS
286  *
287  * IN cellHandle - a previously opened cellHandle that corresponds
288  * to the cell where the volumes exist.
289  *
290  * IN serverHandle - the server where the backups are to be created.  Can be
291  * null.
292  *
293  * IN callBack - a call back function pointer that may be called to report
294  * status information.  Can be null.
295  *
296  * IN partition - the partition where the backups are to be created.  Can be
297  * null.
298  *
299  * IN volumePrefix - all volumes with this prefix will have backup volumes
300  * created. Can be null.
301  *
302  * IN excludePrefix - exclude the volumes that match volumePrefix.
303  *
304  * LOCKS
305  * 
306  * No locks are obtained or released by this function
307  *
308  * RETURN CODES
309  *
310  * Returns != 0 upon successful completion.
311  */
312
313 int ADMINAPI
314 vos_BackupVolumeCreateMultiple(const void *cellHandle,
315                                const void *serverHandle,
316                                vos_MessageCallBack_t callBack,
317                                const unsigned int *partition,
318                                const char *volumePrefix,
319                                vos_exclude_t excludePrefix, afs_status_p st)
320 {
321     int rc = 0;
322     afs_status_t tst = 0;
323     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
324     file_server_p f_server = (file_server_p) serverHandle;
325     struct VldbListByAttributes attr;
326     int exclude = 0;
327     int prefix = 0;
328     size_t prefix_len = 0;
329     nbulkentries arrayEntries;
330     afs_int32 nentries = 0;
331     struct nvldbentry *entry;
332     int i;
333     afs_int32 rw_volid, rw_server, rw_partition;
334     int previdx;
335     int equal = 0;
336     char backbuf[1024];
337
338     memset((void *)&attr, 0, sizeof(attr));
339
340     /*
341      * Validate arguments
342      *
343      * The only required argument to this function is the cellHandle.
344      * If the excludePrefix is set to VOS_EXCLUDE, volumePrefix must
345      * be non-null.
346      */
347
348     if (!IsValidCellHandle(c_handle, &tst)) {
349         goto fail_vos_BackupVolumeCreateMultiple;
350     }
351
352     if ((excludePrefix == VOS_EXCLUDE)
353         && ((volumePrefix == NULL) || (*volumePrefix == 0))) {
354         tst = ADMVOSEXCLUDEREQUIRESPREFIX;
355         goto fail_vos_BackupVolumeCreateMultiple;
356     }
357
358     if (f_server != NULL) {
359         if (!IsValidServerHandle(f_server, &tst)) {
360             goto fail_vos_BackupVolumeCreateMultiple;
361         }
362         attr.server = ntohl(rx_HostOf(rx_PeerOf(f_server->serv)));
363         attr.Mask |= VLLIST_SERVER;
364     }
365
366     if (partition != NULL) {
367         if (*partition > VOLMAXPARTS) {
368             tst = ADMVOSPARTITIONTOOLARGE;
369             goto fail_vos_BackupVolumeCreateMultiple;
370         }
371         attr.partition = *partition;
372         attr.Mask |= VLLIST_PARTITION;
373     }
374
375     if (excludePrefix == VOS_EXCLUDE) {
376         exclude = 1;
377     }
378
379     if ((volumePrefix != NULL) && (*volumePrefix != 0)) {
380         prefix = 1;
381         prefix_len = strlen(volumePrefix);
382     }
383
384     memset((void *)&arrayEntries, 0, sizeof(arrayEntries));
385
386     /*
387      * Get a list of all the volumes in the cell
388      */
389
390     if (!VLDB_ListAttributes(c_handle, &attr, &nentries, &arrayEntries, &tst)) {
391         goto fail_vos_BackupVolumeCreateMultiple;
392     }
393
394     /*
395      * Cycle through the list of volumes and see if we should create a backup
396      * for each individual volume
397      */
398
399     for (i = 0; i < nentries; i++) {
400         entry = &arrayEntries.nbulkentries_val[i];
401
402         /*
403          * Skip entries that don't have a RW volume
404          */
405
406         if (!(entry->flags & RW_EXISTS)) {
407             if (callBack != NULL) {
408                 const char *messageText;
409                 if (util_AdminErrorCodeTranslate
410                     (ADMVOSVOLUMENOREADWRITE, 0, &messageText, &tst)) {
411                     sprintf(backbuf, "%s %s", messageText, entry->name);
412                     (**callBack) (VOS_VERBOSE_MESSAGE, backbuf);
413                 }
414             }
415             continue;
416         }
417
418         /*
419          * See if we should skip this entry because of the prefix/exclude
420          * combination we've been passed
421          */
422
423         if (prefix) {
424             if (exclude) {
425                 if (!strncmp(entry->name, volumePrefix, prefix_len)) {
426                     continue;
427                 }
428             } else {
429                 if (strncmp(entry->name, volumePrefix, prefix_len)) {
430                     continue;
431                 }
432             }
433         }
434
435         rw_volid = entry->volumeId[RWVOL];
436         GetServerAndPart(entry, RWVOL, &rw_server, &rw_partition, &previdx);
437
438         if ((rw_server == -1) || (rw_partition == -1)) {
439             if (callBack != NULL) {
440                 const char *messageText;
441                 if (util_AdminErrorCodeTranslate
442                     (ADMVOSVLDBBADENTRY, 0, &messageText, &tst)) {
443                     sprintf(backbuf, "%s %s", messageText, entry->name);
444                     (**callBack) (VOS_ERROR_MESSAGE, backbuf);
445                 }
446             }
447             continue;
448         }
449
450         /*
451          * Check that the RW volume is on the same server that we were
452          * passed
453          */
454
455         if (serverHandle != NULL) {
456             if (!VLDB_IsSameAddrs
457                 (c_handle, ntohl(rx_HostOf(rx_PeerOf(f_server->serv))),
458                  rw_server, &equal, &tst)) {
459                 if (callBack != NULL) {
460                     const char *messageText;
461                     if (util_AdminErrorCodeTranslate
462                         (ADMVOSVLDBBADSERVER, 0, &messageText, &tst)) {
463                         sprintf(backbuf, "%s %x %d", messageText,
464                                 ntohl(rx_HostOf(rx_PeerOf(f_server->serv))),
465                                 tst);
466                         (**callBack) (VOS_ERROR_MESSAGE, backbuf);
467                     }
468                 }
469                 continue;
470             }
471             if (!equal) {
472                 if (callBack != NULL) {
473                     const char *messageText;
474                     if (util_AdminErrorCodeTranslate
475                         (ADMVOSVLDBDIFFERENTADDR, 0, &messageText, &tst)) {
476                         sprintf(backbuf, "%s %s", messageText, entry->name);
477                         (**callBack) (VOS_ERROR_MESSAGE, backbuf);
478                     }
479                 }
480                 continue;
481             }
482         }
483
484         /*
485          * Check that the RW volume is on the same partition we were
486          * passed
487          */
488
489         if (partition != NULL) {
490             if (*partition != rw_partition) {
491                 continue;
492             }
493         }
494
495         /*
496          * Backup the volume
497          */
498
499         rc = UV_BackupVolume(c_handle, rw_server, rw_partition, rw_volid,
500                              &tst);
501     }
502
503   fail_vos_BackupVolumeCreateMultiple:
504
505     if (arrayEntries.nbulkentries_val) {
506         free(arrayEntries.nbulkentries_val);
507     }
508
509     if (st != NULL) {
510         *st = tst;
511     }
512     return rc;
513 }
514
515 /*
516  * vos_PartitionGet - get information about a single partition.
517  *
518  * PARAMETERS
519  *
520  * IN cellHandle - a previously opened cellHandle that corresponds
521  * to the cell where the server lives.
522  *
523  * IN serverHandle - a previously open vos server handle that holds
524  * the partition of interest.
525  *
526  * IN callBack - a call back function pointer that may be called to report
527  * status information.  Can be null.
528  *
529  * IN partition - the integer that represents the partition of interest.
530  *
531  * OUT partitionP - a pointer to a vos_partitionEntry_t that upon successful 
532  * completion contains information regarding the partition.
533  *
534  * LOCKS
535  * 
536  * No locks are obtained or released by this function
537  *
538  * RETURN CODES
539  *
540  * Returns != 0 upon successful completion.
541  */
542
543 int ADMINAPI
544 vos_PartitionGet(const void *cellHandle, const void *serverHandle,
545                  vos_MessageCallBack_t callBack, unsigned int partition,
546                  vos_partitionEntry_p partitionP, afs_status_p st)
547 {
548     int rc = 0;
549     afs_status_t tst = 0;
550     struct diskPartition part_info;
551     file_server_p f_server = (file_server_p) serverHandle;
552     char partitionName[10];     /* this rpc requires a character partition name */
553
554     /*
555      * Validate arguments
556      */
557
558     if (!IsValidServerHandle(f_server, &tst)) {
559         goto fail_vos_PartitionGet;
560     }
561
562     if (partitionP == NULL) {
563         tst = ADMVOSPARTITIONPNULL;
564         goto fail_vos_PartitionGet;
565     }
566
567     if (!vos_PartitionIdToName(partition, partitionName, &tst)) {
568         goto fail_vos_PartitionGet;
569     }
570
571     tst = AFSVolPartitionInfo(f_server->serv, partitionName, &part_info);
572     if (tst) {
573         goto fail_vos_PartitionGet;
574     }
575     strncpy(partitionP->name, part_info.name, VOS_MAX_PARTITION_NAME_LEN);
576     partitionP->name[VOS_MAX_PARTITION_NAME_LEN-1] = '\0';
577     strncpy(partitionP->deviceName, part_info.devName, VOS_MAX_PARTITION_NAME_LEN);
578     partitionP->deviceName[VOS_MAX_PARTITION_NAME_LEN-1] = '\0';
579     partitionP->lockFileDescriptor = part_info.lock_fd;
580     partitionP->totalSpace = part_info.minFree;
581     partitionP->totalFreeSpace = part_info.free;
582     rc = 1;
583
584   fail_vos_PartitionGet:
585
586     if (st != NULL) {
587         *st = tst;
588     }
589     return rc;
590 }
591
592 /*
593  * The iterator functions and data for the partition retrieval functions.
594  */
595
596 typedef struct partition_get {
597     afs_int32 total_received;   /* the total number of valid partiions retrieved */
598     int number_processed;       /* the number of valid paritions we've handed out */
599     int index;                  /* the current index into the part_list array */
600     struct partList part_list;  /* the list of partitions */
601     vos_partitionEntry_t partition[CACHED_ITEMS];       /* the cache of partitions */
602     const void *server;         /* the server where the parititions exist */
603 } partition_get_t, *partition_get_p;
604
605 static int
606 GetPartitionInfoRPC(void *rpc_specific, int slot, int *last_item,
607                     int *last_item_contains_data, afs_status_p st)
608 {
609     int rc = 0;
610     afs_status_t tst = 0;
611     partition_get_p part = (partition_get_p) rpc_specific;
612     vos_partitionEntry_p ptr = (vos_partitionEntry_p) & part->partition[slot];
613
614     /*
615      * Skip partition entries that are not valid
616      */
617
618     while (!(part->part_list.partFlags[part->index] & PARTVALID)) {
619         part->index++;
620     }
621
622     /*
623      * Get information for the next partition
624      */
625
626     if (!vos_PartitionGet
627         (0, part->server, 0,
628          (unsigned int)part->part_list.partId[part->index], ptr, &tst)) {
629         goto fail_GetPartitionInfoRPC;
630     }
631
632     part->index++;
633     part->number_processed++;
634
635     if (part->number_processed == part->total_received) {
636         *last_item = 1;
637         *last_item_contains_data = 1;
638     }
639     rc = 1;
640
641   fail_GetPartitionInfoRPC:
642
643     if (st != NULL) {
644         *st = tst;
645     }
646     return rc;
647 }
648
649 static int
650 GetPartitionInfoFromCache(void *rpc_specific, int slot, void *dest,
651                           afs_status_p st)
652 {
653     int rc = 0;
654     afs_status_t tst = 0;
655     partition_get_p part = (partition_get_p) rpc_specific;
656
657     memcpy(dest, (const void *)&part->partition[slot],
658            sizeof(vos_partitionEntry_t));
659     rc = 1;
660
661     if (st != NULL) {
662         *st = tst;
663     }
664     return rc;
665 }
666
667 /*
668  * vos_PartitionGetBegin - begin to iterate over the partitions at a 
669  * particular server.
670  *
671  * PARAMETERS
672  *
673  * IN cellHandle - a previously opened cellHandle that corresponds
674  * to the cell where the server exists.
675  *
676  * IN serverHandle - the server that houses the partitions of interest.
677  *
678  * IN callBack - a call back function pointer that may be called to report
679  * status information.  Can be null.
680  *
681  * OUT iterationIdP - upon successful completion, contains an iterator that can
682  * be passed to vos_PartitionGetNext.
683  *
684  * LOCKS
685  * 
686  * No locks are obtained or released by this function
687  *
688  * RETURN CODES
689  *
690  * Returns != 0 upon successful completion.
691  */
692
693 int ADMINAPI
694 vos_PartitionGetBegin(const void *cellHandle, const void *serverHandle,
695                       vos_MessageCallBack_t callBack, void **iterationIdP,
696                       afs_status_p st)
697 {
698     int rc = 0;
699     afs_status_t tst = 0;
700     file_server_p f_server = (file_server_p) serverHandle;
701     afs_admin_iterator_p iter =
702         (afs_admin_iterator_p) malloc(sizeof(afs_admin_iterator_t));
703     partition_get_p part =
704         (partition_get_p) calloc(1, sizeof(partition_get_t));
705
706     /*
707      * Validate arguments
708      */
709
710     if (!IsValidServerHandle(f_server, &tst)) {
711         goto fail_vos_PartitionGetBegin;
712     }
713
714     if (iterationIdP == NULL) {
715         goto fail_vos_PartitionGetBegin;
716     }
717
718     if ((iter == NULL) || (part == NULL)) {
719         tst = ADMNOMEM;
720         goto fail_vos_PartitionGetBegin;
721     }
722
723     /*
724      * Fill in the part structure
725      */
726
727     part->server = serverHandle;
728     if (!UV_ListPartitions
729         (f_server->serv, &part->part_list, &part->total_received, &tst)) {
730         goto fail_vos_PartitionGetBegin;
731     }
732
733     /*
734      * If we didn't receive any partitions, don't spawn a background thread.
735      * Mark the iterator complete.
736      */
737
738     if (part->total_received == 0) {
739         if (!IteratorInit(iter, (void *)part, NULL, NULL, NULL, NULL, &tst)) {
740             goto fail_vos_PartitionGetBegin;
741         }
742         iter->done_iterating = 1;
743         iter->st = ADMITERATORDONE;
744     } else {
745         if (!IteratorInit
746             (iter, (void *)part, GetPartitionInfoRPC,
747              GetPartitionInfoFromCache, NULL, NULL, &tst)) {
748             goto fail_vos_PartitionGetBegin;
749         }
750     }
751     *iterationIdP = (void *)iter;
752     rc = 1;
753
754   fail_vos_PartitionGetBegin:
755
756     if (rc == 0) {
757         if (iter != NULL) {
758             free(iter);
759         }
760         if (part != NULL) {
761             free(part);
762         }
763     }
764
765     if (st != NULL) {
766         *st = tst;
767     }
768     return rc;
769 }
770
771 /*
772  * vos_PartitionGetNext - get the next partition at a server.
773  *
774  * PARAMETERS
775  *
776  * IN iterationId - an iterator previously returned by vos_PartitionGetBegin
777  *
778  * OUT partitionP - a pointer to a vos_partitionEntry_t that upon successful
779  * completion contains the next partition.
780  *
781  * LOCKS
782  * 
783  * The iterator is locked while the next parition is retrieved.
784  *
785  * RETURN CODES
786  *
787  * Returns != 0 upon successful completion.
788  */
789
790 int ADMINAPI
791 vos_PartitionGetNext(const void *iterationId, vos_partitionEntry_p partitionP,
792                      afs_status_p st)
793 {
794     int rc = 0;
795     afs_status_t tst = 0;
796     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
797
798     if (iter == NULL) {
799         tst = ADMITERATORNULL;
800         goto fail_vos_PartitionGetNext;
801     }
802
803     if (partitionP == NULL) {
804         tst = ADMVOSPARTITIONPNULL;
805         goto fail_vos_PartitionGetNext;
806     }
807
808     rc = IteratorNext(iter, (void *)partitionP, &tst);
809
810   fail_vos_PartitionGetNext:
811
812     if (st != NULL) {
813         *st = tst;
814     }
815     return rc;
816 }
817
818 /*
819  * vos_PartitionGetDone - finish using a partition iterator.
820  *
821  * PARAMETERS
822  *
823  * IN iterationId - an iterator previously returned by vos_PartitionGetBegin
824  *
825  * LOCKS
826  * 
827  * The iterator is locked and then destroyed.
828  *
829  * RETURN CODES
830  *
831  * Returns != 0 upon successful completion.
832  */
833
834 int ADMINAPI
835 vos_PartitionGetDone(const void *iterationId, afs_status_p st)
836 {
837     int rc = 0;
838     afs_status_t tst = 0;
839     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
840
841     /*
842      * Validate arguments
843      */
844
845     if (iter == NULL) {
846         tst = ADMITERATORNULL;
847         goto fail_vos_PartitionGetDone;
848     }
849
850     rc = IteratorDone(iter, &tst);
851
852   fail_vos_PartitionGetDone:
853
854     if (st != NULL) {
855         *st = tst;
856     }
857     return rc;
858 }
859
860 /*
861  * vos_ServerOpen - open a handle to an individual server for future
862  * operations
863  *
864  * PARAMETERS
865  *
866  * IN cellHandle - a previously opened cellHandle that corresponds
867  * to the cell where the server lives.
868  *
869  * IN serverName - the machine name of the server
870  *
871  * OUT serverHandleP - a void pointer that upon successful completion 
872  * contains a handle that is used in future operations upon the server.
873  *
874  * LOCKS
875  * 
876  * No locks are obtained or released by this function
877  *
878  * RETURN CODES
879  *
880  * Returns != 0 upon successful completion.
881  */
882
883 int ADMINAPI
884 vos_ServerOpen(const void *cellHandle, const char *serverName,
885                void **serverHandleP, afs_status_p st)
886 {
887     int rc = 0;
888     afs_status_t tst = 0;
889     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
890     file_server_p f_server = (file_server_p) malloc(sizeof(file_server_t));
891     int server_address;
892     struct rx_securityClass *sc[3];
893     int scIndex;
894
895     if (f_server == NULL) {
896         tst = ADMNOMEM;
897         goto fail_vos_ServerOpen;
898     }
899
900     /*
901      * Validate arguments
902      */
903
904     if (!IsValidCellHandle(c_handle, &tst)) {
905         goto fail_vos_ServerOpen;
906     }
907
908     if (!c_handle->tokens->afs_token_set) {
909         tst = ADMVOSCELLHANDLENOAFSTOKENS;
910         goto fail_vos_ServerOpen;
911     }
912
913     if (!util_AdminServerAddressGetFromName
914         (serverName, &server_address, &tst)) {
915         goto fail_vos_ServerOpen;
916     }
917
918     scIndex = c_handle->tokens->sc_index;
919     sc[scIndex] = c_handle->tokens->afs_sc[scIndex];
920     f_server->serv =
921         rx_GetCachedConnection(htonl(server_address),
922                                htons(AFSCONF_VOLUMEPORT), VOLSERVICE_ID,
923                                sc[scIndex], scIndex);
924     if (f_server->serv != NULL) {
925         f_server->begin_magic = BEGIN_MAGIC;
926         f_server->end_magic = END_MAGIC;
927         f_server->is_valid = 1;
928         *serverHandleP = (void *)f_server;
929         rc = 1;
930     } else {
931         tst = ADMVOSSERVERNOCONNECTION;
932         goto fail_vos_ServerOpen;
933     }
934
935   fail_vos_ServerOpen:
936
937     if (st != NULL) {
938         *st = tst;
939     }
940     return rc;
941 }
942
943 /*
944  * vos_ServerClose - close a handle previously obtained from vos_ServerOpen
945  *
946  * PARAMETERS
947  *
948  * IN serverHandle - an existing server handle.
949  *
950  * LOCKS
951  * 
952  * No locks are obtained or released by this function
953  *
954  * RETURN CODES
955  *
956  * Returns != 0 upon successful completion.
957  */
958
959 int ADMINAPI
960 vos_ServerClose(const void *serverHandle, afs_status_p st)
961 {
962     int rc = 0;
963     afs_status_t tst = 0;
964     file_server_p f_server = (file_server_p) serverHandle;
965
966     if (!IsValidServerHandle(f_server, &tst)) {
967         goto fail_vos_ServerClose;
968     }
969
970     rx_ReleaseCachedConnection(f_server->serv);
971     f_server->is_valid = 0;
972     free(f_server);
973     rc = 1;
974
975   fail_vos_ServerClose:
976
977     if (st != NULL) {
978         *st = tst;
979     }
980     return rc;
981 }
982
983 /*
984  * vos_ServerSync - synchronize the vldb and the fileserver at a particular
985  * server.
986  *
987  * PARAMETERS
988  *
989  * IN cellHandle - a previously opened cellHandle that corresponds
990  * to the cell where the server lives.
991  *
992  * IN serverHandle - a handle to the server machine.
993  *
994  * IN callBack - a call back function pointer that may be called to report
995  * status information.  Can be null.
996  *
997  * IN partition - the partition to synchronize.  Can be NULL.
998  *
999  * IN force - force deletion of bad volumes.
1000  *
1001  * LOCKS
1002  * 
1003  * No locks are obtained or released by this function
1004  *
1005  * RETURN CODES
1006  *
1007  * Returns != 0 upon successful completion.
1008  */
1009
1010 int ADMINAPI
1011 vos_ServerSync(const void *cellHandle, const void *serverHandle,
1012                vos_MessageCallBack_t callBack, const unsigned int *partition,
1013                afs_status_p st)
1014 {
1015     int rc = 0;
1016     afs_status_t tst = 0;
1017     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
1018     file_server_p f_server = (file_server_p) serverHandle;
1019     afs_int32 part = 0;
1020     int flags = 0;
1021
1022     /*
1023      * Validate arguments
1024      */
1025
1026     if (!IsValidCellHandle(c_handle, &tst)) {
1027         goto fail_vos_ServerSync;
1028     }
1029
1030     if (!IsValidServerHandle(f_server, &tst)) {
1031         goto fail_vos_ServerSync;
1032     }
1033
1034     if (partition != NULL) {
1035         if (*partition > VOLMAXPARTS) {
1036             tst = ADMVOSPARTITIONTOOLARGE;
1037             goto fail_vos_ServerSync;
1038         }
1039         part = (afs_int32) * partition;
1040         flags = 1;
1041     }
1042
1043     /*
1044      * sync the server
1045      */
1046
1047     rc = UV_SyncServer(c_handle, f_server->serv, part, flags, &tst);
1048
1049   fail_vos_ServerSync:
1050
1051     if (st != NULL) {
1052         *st = tst;
1053     }
1054     return rc;
1055 }
1056
1057 /*
1058  * vos_FileServerAddressChange - change an existing file server address.
1059  *
1060  * PARAMETERS
1061  *
1062  * IN cellHandle - a previously opened cellHandle that corresponds
1063  * to the cell where the address should be changed.
1064  *
1065  * IN callBack - a call back function pointer that may be called to report
1066  * status information.  Can be null.
1067  *
1068  * IN oldAddress - the old server address in host byte order
1069  *
1070  * IN newAddress - the new server address in host byte order
1071  *
1072  * LOCKS
1073  * 
1074  * No locks are obtained or released by this function
1075  *
1076  * RETURN CODES
1077  *
1078  * Returns != 0 upon successful completion.
1079  */
1080
1081 int ADMINAPI
1082 vos_FileServerAddressChange(const void *cellHandle,
1083                             vos_MessageCallBack_t callBack,
1084                             unsigned int oldAddress,
1085                             unsigned int newAddress, afs_status_p st)
1086 {
1087     int rc = 0;
1088     afs_status_t tst = 0;
1089     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
1090
1091     /*
1092      * Validate arguments
1093      */
1094
1095     if (!IsValidCellHandle(c_handle, &tst)) {
1096         goto fail_vos_FileServerAddressChange;
1097     }
1098
1099     tst =
1100         ubik_VL_ChangeAddr(c_handle->vos, 0, oldAddress, newAddress);
1101     if (tst) {
1102         goto fail_vos_FileServerAddressChange;
1103     }
1104     rc = 1;
1105
1106   fail_vos_FileServerAddressChange:
1107
1108     if (st != NULL) {
1109         *st = tst;
1110     }
1111     return rc;
1112 }
1113
1114 /*
1115  * vos_FileServerAddressRemove - remove an existing file server address.
1116  *
1117  * PARAMETERS
1118  *
1119  * IN cellHandle - a previously opened cellHandle that corresponds
1120  * to the cell where the address should be removed.
1121  *
1122  * IN callBack - a call back function pointer that may be called to report
1123  * status information.  Can be null.
1124  *
1125  * IN serverAddress - the server address to remove in host byte order.
1126  *
1127  * LOCKS
1128  * 
1129  * No locks are obtained or released by this function
1130  *
1131  * RETURN CODES
1132  *
1133  * Returns != 0 upon successful completion.
1134  */
1135
1136 int ADMINAPI
1137 vos_FileServerAddressRemove(const void *cellHandle,
1138                             vos_MessageCallBack_t callBack,
1139                             unsigned int serverAddress,
1140                             afs_status_p st)
1141 {
1142     int rc = 0;
1143     afs_status_t tst = 0;
1144     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
1145     unsigned int dummyAddress = 0xffffffff;
1146
1147     /*
1148      * Validate arguments
1149      */
1150
1151     if (!IsValidCellHandle(c_handle, &tst)) {
1152         goto fail_vos_FileServerAddressRemove;
1153     }
1154
1155     tst =
1156         ubik_VL_ChangeAddr(c_handle->vos, 0, dummyAddress,
1157                       serverAddress);
1158     if (tst) {
1159         goto fail_vos_FileServerAddressRemove;
1160     }
1161     rc = 1;
1162
1163   fail_vos_FileServerAddressRemove:
1164
1165     if (st != NULL) {
1166         *st = tst;
1167     }
1168     return rc;
1169 }
1170
1171 /*
1172  * The iterator functions and data for the server retrieval functions.
1173  *
1174  * These functions are very similar to the FileServerAddressGet
1175  * functions.  The main difference being that instead of returning
1176  * a single address at a time for a server, we fill an array with
1177  * all the addresses of a server.
1178  */
1179
1180 typedef struct server_get {
1181     struct ubik_client *vldb;   /* connection for future rpc's if neccessary */
1182     afs_int32 total_addresses;  /* total number of addresses */
1183     bulkaddrs addresses;        /* the list of addresses */
1184     int address_index;          /* current index into address list */
1185     vos_fileServerEntry_t server[CACHED_ITEMS]; /* the cache of servers */
1186 } server_get_t, *server_get_p;
1187
1188 static int
1189 GetServerRPC(void *rpc_specific, int slot, int *last_item,
1190              int *last_item_contains_data, afs_status_p st)
1191 {
1192     int rc = 0;
1193     afs_status_t tst = 0;
1194     server_get_p serv = (server_get_p) rpc_specific;
1195     afs_uint32 *addrP = &serv->addresses.bulkaddrs_val[serv->address_index];
1196     afs_int32 base, index;
1197     afsUUID m_uuid;
1198     afs_int32 m_unique;
1199     ListAddrByAttributes m_attrs;
1200     afs_int32 total_multi;
1201     bulkaddrs addr_multi;
1202     int i;
1203
1204     /*
1205      * Check to see if this is a multihomed address server
1206      */
1207
1208     if (((*addrP & 0xff000000) == 0xff000000) && ((*addrP) & 0xffff)) {
1209         base = (*addrP >> 16) & 0xff;
1210         index = (*addrP) & 0xffff;
1211
1212         if ((base >= 0) && (base <= VL_MAX_ADDREXTBLKS) && (index >= 1)
1213             && (index <= VL_MHSRV_PERBLK)) {
1214
1215             /*
1216              * This is a multihomed server.  Make an rpc to retrieve
1217              * all its addresses.  Copy the addresses into the cache.
1218              */
1219
1220             m_attrs.Mask = VLADDR_INDEX;
1221             m_attrs.index = (base * VL_MHSRV_PERBLK) + index;
1222             total_multi = 0;
1223             addr_multi.bulkaddrs_val = 0;
1224             addr_multi.bulkaddrs_len = 0;
1225             tst =
1226                 ubik_VL_GetAddrsU(serv->vldb, 0, &m_attrs, &m_uuid,
1227                           &m_unique, &total_multi, &addr_multi);
1228             if (tst) {
1229                 goto fail_GetServerRPC;
1230             }
1231
1232             /*
1233              * Remove any bogus IP addresses which the user may have
1234              * been unable to remove.
1235              */
1236
1237             RemoveBadAddresses(&total_multi, &addr_multi);
1238
1239             /*
1240              * Copy all the addresses into the cache
1241              */
1242
1243             for (i = 0; i < total_multi; i++) {
1244                 serv->server[slot].serverAddress[i] =
1245                     addr_multi.bulkaddrs_val[i];
1246             }
1247
1248             serv->server[slot].count = total_multi;
1249             serv->address_index++;
1250             free(addr_multi.bulkaddrs_val);
1251         }
1252
1253         /*
1254          * The next address is just a plain old address
1255          */
1256
1257     } else {
1258         serv->server[slot].serverAddress[0] = *addrP;
1259         serv->server[slot].count = 1;
1260         serv->address_index++;
1261     }
1262
1263     /*
1264      * See if we've processed all the entries
1265      */
1266
1267
1268     if (serv->address_index == serv->total_addresses) {
1269         *last_item = 1;
1270         *last_item_contains_data = 1;
1271     }
1272     rc = 1;
1273
1274   fail_GetServerRPC:
1275
1276     if (st != NULL) {
1277         *st = tst;
1278     }
1279     return rc;
1280 }
1281
1282 static int
1283 GetServerFromCache(void *rpc_specific, int slot, void *dest, afs_status_p st)
1284 {
1285     int rc = 0;
1286     afs_status_t tst = 0;
1287     server_get_p serv = (server_get_p) rpc_specific;
1288
1289     memcpy(dest, (const void *)&serv->server[slot],
1290            sizeof(vos_fileServerEntry_t));
1291     rc = 1;
1292
1293     if (st != NULL) {
1294         *st = tst;
1295     }
1296     return rc;
1297 }
1298
1299
1300 static int
1301 DestroyServer(void *rpc_specific, afs_status_p st)
1302 {
1303     int rc = 0;
1304     afs_status_t tst = 0;
1305     server_get_p serv = (server_get_p) rpc_specific;
1306
1307     if (serv->addresses.bulkaddrs_val != NULL) {
1308         free(serv->addresses.bulkaddrs_val);
1309     }
1310     rc = 1;
1311
1312     if (st != NULL) {
1313         *st = tst;
1314     }
1315     return rc;
1316 }
1317
1318 /*
1319  * vos_FileServerGetBegin - begin to iterate over the file servers in a cell.
1320  *
1321  * PARAMETERS
1322  *
1323  * IN cellHandle - a previously opened cellHandle that corresponds
1324  * to the cell where the file servers exist.
1325  *
1326  * IN callBack - a call back function pointer that may be called to report
1327  * status information.  Can be null.
1328  *
1329  * OUT iterationIdP - upon successful completion, contains an iterator that
1330  * can be passed to vos_FileServerGetNext.
1331  *
1332  * LOCKS
1333  * 
1334  * No locks are obtained or released by this function
1335  *
1336  * RETURN CODES
1337  *
1338  * Returns != 0 upon successful completion.
1339  */
1340
1341 int ADMINAPI
1342 vos_FileServerGetBegin(const void *cellHandle, vos_MessageCallBack_t callBack,
1343                        void **iterationIdP, afs_status_p st)
1344 {
1345     int rc = 0;
1346     afs_status_t tst = 0;
1347     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
1348     afs_admin_iterator_p iter =
1349         (afs_admin_iterator_p) malloc(sizeof(afs_admin_iterator_t));
1350     server_get_p serv = (server_get_p) calloc(1, sizeof(server_get_t));
1351     struct VLCallBack unused;
1352
1353
1354     /*
1355      * Validate arguments
1356      */
1357
1358     if (!IsValidCellHandle(c_handle, &tst)) {
1359         goto fail_vos_FileServerGetBegin;
1360     }
1361
1362     if (iterationIdP == NULL) {
1363         goto fail_vos_FileServerGetBegin;
1364     }
1365
1366     if ((iter == NULL) || (serv == NULL)) {
1367         tst = ADMNOMEM;
1368         goto fail_vos_FileServerGetBegin;
1369     }
1370
1371     /*
1372      * Fill in the serv structure
1373      */
1374
1375     serv->vldb = c_handle->vos;
1376     tst =
1377         ubik_VL_GetAddrs(c_handle->vos, 0, 0, 0, &unused,
1378                       &serv->total_addresses, &serv->addresses);
1379
1380     if (tst) {
1381         goto fail_vos_FileServerGetBegin;
1382     }
1383
1384     /*
1385      * Remove any bogus IP addresses which the user may have
1386      * been unable to remove.
1387      */
1388
1389     RemoveBadAddresses(&serv->total_addresses, &serv->addresses);
1390
1391     if (serv->total_addresses == 0) {
1392         if (!IteratorInit(iter, (void *)serv, NULL, NULL, NULL, NULL, &tst)) {
1393             goto fail_vos_FileServerGetBegin;
1394         }
1395         iter->done_iterating = 1;
1396         iter->st = ADMITERATORDONE;
1397     } else {
1398         if (!IteratorInit
1399             (iter, (void *)serv, GetServerRPC, GetServerFromCache, NULL,
1400              DestroyServer, &tst)) {
1401             goto fail_vos_FileServerGetBegin;
1402         }
1403     }
1404     *iterationIdP = (void *)iter;
1405     rc = 1;
1406
1407   fail_vos_FileServerGetBegin:
1408
1409     if (rc == 0) {
1410         if (iter != NULL) {
1411             free(iter);
1412         }
1413         if (serv != NULL) {
1414             if (serv->addresses.bulkaddrs_val != NULL) {
1415                 free(serv->addresses.bulkaddrs_val);
1416             }
1417             free(serv);
1418         }
1419     }
1420
1421     if (st != NULL) {
1422         *st = tst;
1423     }
1424     return rc;
1425 }
1426
1427 /*
1428  * vos_FileServerGetNext - get information about the next fileserver in the cell.
1429  *
1430  * PARAMETERS
1431  *
1432  * IN iterationId - an iterator previously returned by
1433  * vos_FileServerGetBegin
1434  *
1435  * OUT serverEntryP - a pointer to a vos_fileServerEntry_t that upon successful
1436  * completion contains information about the next server in the cell.
1437  *
1438  * LOCKS
1439  * 
1440  * The iterator is locked while the next server is retrieved.
1441  *
1442  * RETURN CODES
1443  *
1444  * Returns != 0 upon successful completion.
1445  */
1446
1447 int ADMINAPI
1448 vos_FileServerGetNext(void *iterationId, vos_fileServerEntry_p serverEntryP,
1449                       afs_status_p st)
1450 {
1451     int rc = 0;
1452     afs_status_t tst = 0;
1453     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
1454
1455     if (iter == NULL) {
1456         tst = ADMITERATORNULL;
1457         goto fail_vos_FileServerGetNext;
1458     }
1459
1460     if (serverEntryP == NULL) {
1461         tst = ADMVOSSERVERENTRYPNULL;
1462         goto fail_vos_FileServerGetNext;
1463     }
1464
1465     rc = IteratorNext(iter, (void *)serverEntryP, &tst);
1466
1467   fail_vos_FileServerGetNext:
1468
1469     if (st != NULL) {
1470         *st = tst;
1471     }
1472     return rc;
1473 }
1474
1475 /*
1476  * vos_FileServerGetDone - finish using a partition iterator.
1477  *
1478  * PARAMETERS
1479  *
1480  * IN iterationId - an iterator previously returned by vos_FileServerGetBegin
1481  *
1482  * LOCKS
1483  * 
1484  * The iterator is locked and then destroyed.
1485  *
1486  * RETURN CODES
1487  *
1488  * Returns != 0 upon successful completion.
1489  */
1490
1491 int ADMINAPI
1492 vos_FileServerGetDone(void *iterationId, afs_status_p st)
1493 {
1494     int rc = 0;
1495     afs_status_t tst = 0;
1496     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
1497
1498     /*
1499      * Validate arguments
1500      */
1501
1502     if (iter == NULL) {
1503         tst = ADMITERATORNULL;
1504         goto fail_vos_FileServerGetDone;
1505     }
1506
1507     rc = IteratorDone(iter, &tst);
1508
1509   fail_vos_FileServerGetDone:
1510
1511     if (st != NULL) {
1512         *st = tst;
1513     }
1514     return rc;
1515 }
1516
1517 /*
1518  * The iterator functions and data for the transation retrieval functions.
1519  */
1520
1521 typedef struct transaction_get {
1522     afs_int32 total;            /* total number of transactions */
1523     afs_int32 index;            /* index to the current transaction */
1524     transDebugInfo *cur;        /* the current transaction */
1525     vos_serverTransactionStatus_t tran[CACHED_ITEMS];   /* the cache of trans */
1526 } transaction_get_t, *transaction_get_p;
1527
1528 static int
1529 GetTransactionRPC(void *rpc_specific, int slot, int *last_item,
1530                   int *last_item_contains_data, afs_status_p st)
1531 {
1532     int rc = 0;
1533     afs_status_t tst = 0;
1534     transaction_get_p t = (transaction_get_p) rpc_specific;
1535     int index = t->index;
1536
1537     /*
1538      * Copy the next transaction into the cache
1539      */
1540
1541     t->tran[slot].transactionId = t->cur[index].tid;
1542     t->tran[slot].lastActiveTime = t->cur[index].time;
1543     t->tran[slot].creationTime = t->cur[index].creationTime;
1544     t->tran[slot].errorCode = t->cur[index].returnCode;
1545     t->tran[slot].volumeId = t->cur[index].volid;
1546     t->tran[slot].partition = t->cur[index].partition;
1547     strcpy(t->tran[slot].lastProcedureName, t->cur[index].lastProcName);
1548     t->tran[slot].nextReceivePacketSequenceNumber = t->cur[index].readNext;
1549     t->tran[slot].nextSendPacketSequenceNumber = t->cur[index].transmitNext;
1550     t->tran[slot].lastReceiveTime = t->cur[index].lastReceiveTime;
1551     t->tran[slot].lastSendTime = t->cur[index].lastSendTime;
1552
1553     t->tran[slot].volumeAttachMode = VOS_VOLUME_ATTACH_MODE_OK;
1554
1555     switch (t->cur[index].iflags) {
1556     case ITOffline:
1557         t->tran[slot].volumeAttachMode = VOS_VOLUME_ATTACH_MODE_OFFLINE;
1558         break;
1559     case ITBusy:
1560         t->tran[slot].volumeAttachMode = VOS_VOLUME_ATTACH_MODE_BUSY;
1561         break;
1562     case ITReadOnly:
1563         t->tran[slot].volumeAttachMode = VOS_VOLUME_ATTACH_MODE_READONLY;
1564         break;
1565     case ITCreate:
1566         t->tran[slot].volumeAttachMode = VOS_VOLUME_ATTACH_MODE_CREATE;
1567         break;
1568     case ITCreateVolID:
1569         t->tran[slot].volumeAttachMode = VOS_VOLUME_ATTACH_MODE_CREATE_VOLID;
1570         break;
1571     }
1572
1573     t->tran[slot].volumeActiveStatus = VOS_VOLUME_ACTIVE_STATUS_OK;
1574
1575     switch (t->cur[index].vflags) {
1576     case VTDeleteOnSalvage:
1577         t->tran[slot].volumeActiveStatus =
1578             VOS_VOLUME_ACTIVE_STATUS_DELETE_ON_SALVAGE;
1579         break;
1580     case VTOutOfService:
1581         t->tran[slot].volumeActiveStatus =
1582             VOS_VOLUME_ACTIVE_STATUS_OUT_OF_SERVICE;
1583         break;
1584     case VTDeleted:
1585         t->tran[slot].volumeActiveStatus = VOS_VOLUME_ACTIVE_STATUS_DELETED;
1586         break;
1587     }
1588
1589     t->tran[slot].volumeTransactionStatus = VOS_VOLUME_TRANSACTION_STATUS_OK;
1590
1591     if (t->cur[index].tflags) {
1592         t->tran[slot].volumeTransactionStatus =
1593             VOS_VOLUME_TRANSACTION_STATUS_DELETED;
1594     }
1595     t->index++;
1596
1597
1598     /*
1599      * See if we've processed all the entries
1600      */
1601
1602
1603     if (t->index == t->total) {
1604         *last_item = 1;
1605         *last_item_contains_data = 1;
1606     }
1607     rc = 1;
1608
1609     if (st != NULL) {
1610         *st = tst;
1611     }
1612     return rc;
1613 }
1614
1615 static int
1616 GetTransactionFromCache(void *rpc_specific, int slot, void *dest,
1617                         afs_status_p st)
1618 {
1619     int rc = 0;
1620     afs_status_t tst = 0;
1621     transaction_get_p tran = (transaction_get_p) rpc_specific;
1622
1623     memcpy(dest, (const void *)&tran->tran[slot],
1624            sizeof(vos_serverTransactionStatus_p));
1625     rc = 1;
1626
1627     if (st != NULL) {
1628         *st = tst;
1629     }
1630     return rc;
1631 }
1632
1633
1634 static int
1635 DestroyTransaction(void *rpc_specific, afs_status_p st)
1636 {
1637     int rc = 0;
1638     afs_status_t tst = 0;
1639     transaction_get_p tran = (transaction_get_p) rpc_specific;
1640
1641     if (tran->cur != NULL) {
1642         free(tran->cur);
1643     }
1644     rc = 1;
1645
1646     if (st != NULL) {
1647         *st = tst;
1648     }
1649     return rc;
1650 }
1651
1652 /*
1653  * vos_ServerTransactionStatusGetBegin - begin to iterate over the transactions
1654  * at a volume server.
1655  *
1656  * PARAMETERS
1657  *
1658  * IN cellHandle - a previously opened cellHandle that corresponds
1659  * to the cell where the volume server exists.
1660  *
1661  * IN serverHandle - a handle to the server to query.
1662  *
1663  * IN callBack - a call back function pointer that may be called to report
1664  * status information.  Can be null.
1665  *
1666  * OUT iterationIdP - upon successful completion, contains an iterator that
1667  * can be passed to vos_ServerTransactionStatusGetNext.
1668  *
1669  * LOCKS
1670  * 
1671  * No locks are obtained or released by this function
1672  *
1673  * RETURN CODES
1674  *
1675  * Returns != 0 upon successful completion.
1676  */
1677
1678 int ADMINAPI
1679 vos_ServerTransactionStatusGetBegin(const void *cellHandle,
1680                                     const void *serverHandle,
1681                                     vos_MessageCallBack_t callBack,
1682                                     void **iterationIdP, afs_status_p st)
1683 {
1684     int rc = 0;
1685     afs_status_t tst = 0;
1686     file_server_p f_server = (file_server_p) serverHandle;
1687     afs_admin_iterator_p iter =
1688         (afs_admin_iterator_p) malloc(sizeof(afs_admin_iterator_t));
1689     transaction_get_p tran =
1690         (transaction_get_p) calloc(1, sizeof(transaction_get_t));
1691
1692
1693     /*
1694      * Validate arguments
1695      */
1696
1697     if (!IsValidServerHandle(f_server, &tst)) {
1698         goto fail_vos_ServerTransactionStatusGetBegin;
1699     }
1700
1701     if (iterationIdP == NULL) {
1702         goto fail_vos_ServerTransactionStatusGetBegin;
1703     }
1704
1705     if ((iter == NULL) || (tran == NULL)) {
1706         tst = ADMNOMEM;
1707         goto fail_vos_ServerTransactionStatusGetBegin;
1708     }
1709
1710     /*
1711      * Fill in the tran structure
1712      */
1713
1714     if (!UV_VolserStatus(f_server->serv, &tran->cur, &tran->total, &tst)) {
1715         goto fail_vos_ServerTransactionStatusGetBegin;
1716     }
1717
1718     if (tran->total == 0) {
1719         if (!IteratorInit(iter, (void *)tran, NULL, NULL, NULL, NULL, &tst)) {
1720             goto fail_vos_ServerTransactionStatusGetBegin;
1721         }
1722         iter->done_iterating = 1;
1723         iter->st = ADMITERATORDONE;
1724     } else {
1725         if (!IteratorInit
1726             (iter, (void *)tran, GetTransactionRPC, GetTransactionFromCache,
1727              NULL, DestroyTransaction, &tst)) {
1728             goto fail_vos_ServerTransactionStatusGetBegin;
1729         }
1730     }
1731     *iterationIdP = (void *)iter;
1732     rc = 1;
1733
1734   fail_vos_ServerTransactionStatusGetBegin:
1735
1736     if (rc == 0) {
1737         if (iter != NULL) {
1738             free(iter);
1739         }
1740         if (tran != NULL) {
1741             if (tran->cur != NULL) {
1742                 free(tran->cur);
1743             }
1744             free(tran);
1745         }
1746     }
1747
1748     if (st != NULL) {
1749         *st = tst;
1750     }
1751     return rc;
1752 }
1753
1754 /*
1755  * vos_ServerTransactionStatusGetNext - get information about the next 
1756  * active transaction.
1757  *
1758  * PARAMETERS
1759  *
1760  * IN iterationId - an iterator previously returned by
1761  * vos_ServerTransactionStatusGetBegin
1762  *
1763  * OUT serverTransactionStatusP - a pointer to a vos_serverTransactionStatus_p
1764  * that upon successful completion contains information about the
1765  * next transaction.
1766  *
1767  * LOCKS
1768  * 
1769  * The iterator is locked while the next item is retrieved.
1770  *
1771  * RETURN CODES
1772  *
1773  * Returns != 0 upon successful completion.
1774  */
1775
1776 int ADMINAPI
1777 vos_ServerTransactionStatusGetNext(const void *iterationId,
1778                                    vos_serverTransactionStatus_p
1779                                    serverTransactionStatusP, afs_status_p st)
1780 {
1781     int rc = 0;
1782     afs_status_t tst = 0;
1783     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
1784
1785     if (iter == NULL) {
1786         tst = ADMITERATORNULL;
1787         goto fail_vos_ServerTransactionStatusGetNext;
1788     }
1789
1790     if (serverTransactionStatusP == NULL) {
1791         tst = ADMVOSSERVERTRANSACTIONSTATUSPNULL;
1792         goto fail_vos_ServerTransactionStatusGetNext;
1793     }
1794
1795     rc = IteratorNext(iter, (void *)serverTransactionStatusP, &tst);
1796
1797   fail_vos_ServerTransactionStatusGetNext:
1798
1799     if (st != NULL) {
1800         *st = tst;
1801     }
1802     return rc;
1803 }
1804
1805 /*
1806  * vos_ServerTransactionStatusGetDone - finish using a transaction iterator.
1807  *
1808  * PARAMETERS
1809  *
1810  * IN iterationId - an iterator previously returned by
1811  * vos_ServerTransactionStatusGetBegin
1812  *
1813  * LOCKS
1814  * 
1815  * The iterator is locked and then destroyed.
1816  *
1817  * RETURN CODES
1818  *
1819  * Returns != 0 upon successful completion.
1820  */
1821
1822 int ADMINAPI
1823 vos_ServerTransactionStatusGetDone(const void *iterationId, afs_status_p st)
1824 {
1825     int rc = 0;
1826     afs_status_t tst = 0;
1827     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
1828
1829     /*
1830      * Validate arguments
1831      */
1832
1833     if (iter == NULL) {
1834         tst = ADMITERATORNULL;
1835         goto fail_vos_ServerTransactionStatusGetDone;
1836     }
1837
1838     rc = IteratorDone(iter, &tst);
1839
1840   fail_vos_ServerTransactionStatusGetDone:
1841
1842     if (st != NULL) {
1843         *st = tst;
1844     }
1845     return rc;
1846 }
1847
1848 static int
1849 copyVLDBEntry(struct nvldbentry *source, vos_vldbEntry_p dest,
1850               afs_status_p st)
1851 {
1852     int rc = 0;
1853     afs_status_t tst = 0;
1854     int i;
1855
1856     dest->numServers = source->nServers;
1857     for (i = 0; i < VOS_MAX_VOLUME_TYPES; i++) {
1858         dest->volumeId[i] = source->volumeId[i];
1859     }
1860     dest->cloneId = source->cloneId;
1861     dest->status = VOS_VLDB_ENTRY_OK;
1862     if (source->flags & VLOP_ALLOPERS) {
1863         dest->status |= VOS_VLDB_ENTRY_LOCKED;
1864     } else {
1865         if (source->flags & VLOP_MOVE) {
1866             dest->status |= VOS_VLDB_ENTRY_MOVE;
1867         }
1868         if (source->flags & VLOP_RELEASE) {
1869             dest->status |= VOS_VLDB_ENTRY_RELEASE;
1870         }
1871         if (source->flags & VLOP_BACKUP) {
1872             dest->status |= VOS_VLDB_ENTRY_BACKUP;
1873         }
1874         if (source->flags & VLOP_DELETE) {
1875             dest->status |= VOS_VLDB_ENTRY_DELETE;
1876         }
1877         if (source->flags & VLOP_DUMP) {
1878             dest->status |= VOS_VLDB_ENTRY_DUMP;
1879         }
1880     }
1881     if (source->flags & VLF_RWEXISTS) {
1882         dest->status |= VOS_VLDB_ENTRY_RWEXISTS;
1883     }
1884     if (source->flags & VLF_ROEXISTS) {
1885         dest->status |= VOS_VLDB_ENTRY_ROEXISTS;
1886     }
1887     if (source->flags & VLF_BACKEXISTS) {
1888         dest->status |= VOS_VLDB_ENTRY_BACKEXISTS;
1889     }
1890
1891     strncpy(dest->name, source->name, VOS_MAX_VOLUME_NAME_LEN);
1892     dest->name[VOS_MAX_VOLUME_NAME_LEN - 1] = '\0';
1893     for (i = 0; i < VOS_MAX_REPLICA_SITES; i++) {
1894         dest->volumeSites[i].serverAddress = source->serverNumber[i];
1895         dest->volumeSites[i].serverPartition = source->serverPartition[i];
1896         dest->volumeSites[i].serverFlags = 0;
1897
1898         if (source->serverFlags[i] & NEW_REPSITE) {
1899             dest->volumeSites[i].serverFlags |= VOS_VLDB_NEW_REPSITE;
1900         }
1901         if (source->serverFlags[i] & ITSROVOL) {
1902             dest->volumeSites[i].serverFlags |= VOS_VLDB_READ_ONLY;
1903         }
1904         if (source->serverFlags[i] & ITSRWVOL) {
1905             dest->volumeSites[i].serverFlags |= VOS_VLDB_READ_WRITE;
1906         }
1907         if (source->serverFlags[i] & ITSBACKVOL) {
1908             dest->volumeSites[i].serverFlags |= VOS_VLDB_BACKUP;
1909         }
1910         if (source->serverFlags[i] & RO_DONTUSE) {
1911             dest->volumeSites[i].serverFlags |= VOS_VLDB_DONT_USE;
1912         }
1913
1914     }
1915
1916     rc = 1;
1917     if (st != NULL) {
1918         *st = tst;
1919     }
1920     return rc;
1921 }
1922
1923 /*
1924  * vos_VLDBGet- get a volume's vldb entry.
1925  *
1926  * PARAMETERS
1927  *
1928  * IN cellHandle - a previously opened cellHandle that corresponds
1929  * to the cell where the volume entries exist.
1930  *
1931  * IN callBack - a call back function pointer that may be called to report
1932  * status information.  Can be null.
1933  *
1934  * IN volumeId - the id of the volume to retrieve.
1935  *
1936  * IN volumeName - the name of the volume to retrieve.
1937  *
1938  * OUT vldbEntry - upon successful completion, contains the information regarding
1939  * the volume.
1940  *
1941  * LOCKS
1942  * 
1943  * No locks are obtained or released by this function
1944  *
1945  * RETURN CODES
1946  *
1947  * Returns != 0 upon successful completion.
1948  */
1949
1950 int ADMINAPI
1951 vos_VLDBGet(const void *cellHandle, vos_MessageCallBack_t callBack,
1952             const unsigned int *volumeId, char *volumeName,
1953             vos_vldbEntry_p vldbEntry, afs_status_p st)
1954 {
1955     int rc = 0;
1956     afs_status_t tst = 0;
1957     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
1958     struct nvldbentry entry;
1959
1960
1961     /*
1962      * Validate arguments
1963      */
1964
1965     if (!IsValidCellHandle(c_handle, &tst)) {
1966         goto fail_vos_VLDBGet;
1967     }
1968
1969     if (vldbEntry == NULL) {
1970         tst = ADMVOSVLDBENTRYNULL;
1971         goto fail_vos_VLDBGet;
1972     }
1973
1974     if (((volumeName == NULL) || (*volumeName == 0)) && (volumeId == NULL)) {
1975         tst = ADMVOSVOLUMENAMEANDVOLUMEIDNULL;
1976         goto fail_vos_VLDBGet;
1977     }
1978
1979     /*
1980      * Retrieve the entry
1981      */
1982
1983     if (!((volumeName == NULL) || (*volumeName == 0))) {
1984         if (!ValidateVolumeName(volumeName, &tst)) {
1985             goto fail_vos_VLDBGet;
1986         }
1987         if (!aVLDB_GetEntryByName(c_handle, volumeName, &entry, &tst)) {
1988             goto fail_vos_VLDBGet;
1989         }
1990     } else {
1991         if (!aVLDB_GetEntryByID(c_handle, *volumeId, -1, &entry, &tst)) {
1992             goto fail_vos_VLDBGet;
1993         }
1994     }
1995
1996     /*
1997      * Copy the entry into our structure
1998      */
1999
2000     if (!copyVLDBEntry(&entry, vldbEntry, &tst)) {
2001         goto fail_vos_VLDBGet;
2002     }
2003     rc = 1;
2004
2005   fail_vos_VLDBGet:
2006
2007     if (st != NULL) {
2008         *st = tst;
2009     }
2010     return rc;
2011 }
2012
2013 /*
2014  * The iterator functions and data for the vldb entry retrieval functions.
2015  */
2016
2017 typedef struct vldb_entry_get {
2018     afs_int32 total;            /* total number of vldb entries */
2019     afs_int32 index;            /* index to the current vldb entry */
2020     nbulkentries entries;       /* the list of entries retrieved */
2021     vos_vldbEntry_t entry[CACHED_ITEMS];        /* the cache of entries */
2022 } vldb_entry_get_t, *vldb_entry_get_p;
2023
2024 static int
2025 GetVLDBEntryRPC(void *rpc_specific, int slot, int *last_item,
2026                 int *last_item_contains_data, afs_status_p st)
2027 {
2028     int rc = 0;
2029     afs_status_t tst = 0;
2030     vldb_entry_get_p entry = (vldb_entry_get_p) rpc_specific;
2031
2032     /*
2033      * Copy the next entry into the cache
2034      */
2035
2036     if (!copyVLDBEntry
2037         (&entry->entries.nbulkentries_val[entry->index], &entry->entry[slot],
2038          &tst)) {
2039         goto fail_GetVLDBEntryRPC;
2040     }
2041     entry->index++;
2042
2043     /*
2044      * See if we've processed all the entries
2045      */
2046
2047
2048     if (entry->index == entry->total) {
2049         *last_item = 1;
2050         *last_item_contains_data = 1;
2051     }
2052     rc = 1;
2053
2054   fail_GetVLDBEntryRPC:
2055
2056     if (st != NULL) {
2057         *st = tst;
2058     }
2059     return rc;
2060 }
2061
2062 static int
2063 GetVLDBEntryFromCache(void *rpc_specific, int slot, void *dest,
2064                       afs_status_p st)
2065 {
2066     int rc = 0;
2067     afs_status_t tst = 0;
2068     vldb_entry_get_p entry = (vldb_entry_get_p) rpc_specific;
2069
2070     memcpy(dest, (const void *)&entry->entry[slot], sizeof(vos_vldbEntry_t));
2071     rc = 1;
2072
2073     if (st != NULL) {
2074         *st = tst;
2075     }
2076     return rc;
2077 }
2078
2079
2080 static int
2081 DestroyVLDBEntry(void *rpc_specific, afs_status_p st)
2082 {
2083     int rc = 0;
2084     afs_status_t tst = 0;
2085     vldb_entry_get_p entry = (vldb_entry_get_p) rpc_specific;
2086
2087     if (entry->entries.nbulkentries_val != NULL) {
2088         free(entry->entries.nbulkentries_val);
2089     }
2090     rc = 1;
2091
2092     if (st != NULL) {
2093         *st = tst;
2094     }
2095     return rc;
2096 }
2097
2098
2099 /*
2100  * vos_VLDBGetBegin - begin to iterate over the VLDB.
2101  *
2102  * PARAMETERS
2103  *
2104  * IN cellHandle - a previously opened cellHandle that corresponds
2105  * to the cell where the volume entries exist.
2106  *
2107  * IN serverHandle - a handle to the server whose entries should be listed.
2108  * Can be null.
2109  *
2110  * IN callBack - a call back function pointer that may be called to report
2111  * status information.  Can be null.
2112  *
2113  * IN partition - the partition whose entries should be listed.
2114  * Can be null.
2115  *
2116  * OUT iterationIdP - upon successful completion, contains an iterator that
2117  * can be passed to vos_VLDBGetNext.
2118  *
2119  * LOCKS
2120  * 
2121  * No locks are obtained or released by this function
2122  *
2123  * RETURN CODES
2124  *
2125  * Returns != 0 upon successful completion.
2126  */
2127
2128 int ADMINAPI
2129 vos_VLDBGetBegin(const void *cellHandle, const void *serverHandle,
2130                  vos_MessageCallBack_t callBack, unsigned int *partition,
2131                  void **iterationIdP, afs_status_p st)
2132 {
2133     int rc = 0;
2134     afs_status_t tst = 0;
2135     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2136     file_server_p f_server = (file_server_p) serverHandle;
2137     afs_admin_iterator_p iter =
2138         (afs_admin_iterator_p) malloc(sizeof(afs_admin_iterator_t));
2139     vldb_entry_get_p entry =
2140         (vldb_entry_get_p) calloc(1, sizeof(vldb_entry_get_t));
2141     struct VldbListByAttributes attr;
2142
2143     attr.Mask = 0;
2144     memset(&attr, 0, sizeof(attr));
2145
2146     /*
2147      * Validate arguments
2148      */
2149
2150     if (!IsValidCellHandle(c_handle, &tst)) {
2151         goto fail_vos_VLDBGetBegin;
2152     }
2153
2154     if ((iter == NULL) || (entry == NULL)) {
2155         tst = ADMNOMEM;
2156         goto fail_vos_VLDBGetBegin;
2157     }
2158
2159     if (f_server != NULL) {
2160         if (!IsValidServerHandle(f_server, &tst)) {
2161             goto fail_vos_VLDBGetBegin;
2162         }
2163         attr.server = ntohl(rx_HostOf(rx_PeerOf(f_server->serv)));
2164         attr.Mask |= VLLIST_SERVER;
2165     }
2166
2167     if (partition != NULL) {
2168         if (*partition > VOLMAXPARTS) {
2169             tst = ADMVOSPARTITIONTOOLARGE;
2170             goto fail_vos_VLDBGetBegin;
2171         }
2172         attr.partition = *partition;
2173         attr.Mask |= VLLIST_PARTITION;
2174     }
2175
2176     if (!VLDB_ListAttributes
2177         (c_handle, &attr, &entry->total, &entry->entries, &tst)) {
2178         goto fail_vos_VLDBGetBegin;
2179     }
2180
2181     if (entry->total <= 0) {
2182         if (!IteratorInit(iter, (void *)entry, NULL, NULL, NULL, NULL, &tst)) {
2183             goto fail_vos_VLDBGetBegin;
2184         }
2185         iter->done_iterating = 1;
2186         iter->st = ADMITERATORDONE;
2187     } else {
2188         if (!IteratorInit
2189             (iter, (void *)entry, GetVLDBEntryRPC, GetVLDBEntryFromCache,
2190              NULL, DestroyVLDBEntry, &tst)) {
2191             goto fail_vos_VLDBGetBegin;
2192         }
2193     }
2194     *iterationIdP = (void *)iter;
2195     rc = 1;
2196
2197   fail_vos_VLDBGetBegin:
2198
2199     if (rc == 0) {
2200         if (iter != NULL) {
2201             free(iter);
2202         }
2203         if (entry->entries.nbulkentries_val != NULL) {
2204             free(entry->entries.nbulkentries_val);
2205         }
2206         if (entry != NULL) {
2207             free(entry);
2208         }
2209     }
2210
2211     if (st != NULL) {
2212         *st = tst;
2213     }
2214     return rc;
2215 }
2216
2217 /*
2218  * vos_VLDBGetNext - get information about the next volume.
2219  *
2220  * PARAMETERS
2221  *
2222  * IN iterationId - an iterator previously returned by
2223  * vos_VLDBGetBegin
2224  *
2225  * OUT vldbEntry - a pointer to a vos_vldbEntry_t
2226  * that upon successful completion contains information about the
2227  * next volume.
2228  *
2229  * LOCKS
2230  * 
2231  * The iterator is locked while the next item is retrieved.
2232  *
2233  * RETURN CODES
2234  *
2235  * Returns != 0 upon successful completion.
2236  */
2237
2238 int ADMINAPI
2239 vos_VLDBGetNext(const void *iterationId, vos_vldbEntry_p vldbEntry,
2240                 afs_status_p st)
2241 {
2242     int rc = 0;
2243     afs_status_t tst = 0;
2244     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
2245
2246     if (iter == NULL) {
2247         tst = ADMITERATORNULL;
2248         goto fail_vos_VLDBGetNext;
2249     }
2250
2251     if (vldbEntry == NULL) {
2252         tst = ADMVOSVLDBENTRYNULL;
2253         goto fail_vos_VLDBGetNext;
2254     }
2255
2256     rc = IteratorNext(iter, (void *)vldbEntry, &tst);
2257
2258   fail_vos_VLDBGetNext:
2259
2260     if (st != NULL) {
2261         *st = tst;
2262     }
2263     return rc;
2264 }
2265
2266 /*
2267  * vos_VLDBGetDone - finish using a volume iterator.
2268  *
2269  * PARAMETERS
2270  *
2271  * IN iterationId - an iterator previously returned by vos_VLDBGetBegin
2272  *
2273  * LOCKS
2274  * 
2275  * The iterator is locked and then destroyed.
2276  *
2277  * RETURN CODES
2278  *
2279  * Returns != 0 upon successful completion.
2280  */
2281
2282 int ADMINAPI
2283 vos_VLDBGetDone(const void *iterationId, afs_status_p st)
2284 {
2285     int rc = 0;
2286     afs_status_t tst = 0;
2287     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
2288
2289     /*
2290      * Validate arguments
2291      */
2292
2293     if (iter == NULL) {
2294         tst = ADMITERATORNULL;
2295         goto fail_vos_VLDBGetDone;
2296     }
2297
2298     rc = IteratorDone(iter, &tst);
2299
2300   fail_vos_VLDBGetDone:
2301
2302     if (st != NULL) {
2303         *st = tst;
2304     }
2305     return rc;
2306 }
2307
2308 /*
2309  * vos_VLDBEntryRemove - remove a vldb entry.
2310  *
2311  * PARAMETERS
2312  *
2313  * IN cellHandle - a previously opened cellHandle that corresponds
2314  * to the cell where the vldb entry exists.
2315  *
2316  * IN serverHandle - a previously opened serverHandle that corresponds
2317  * to the server where the vldb entry exists.  Can be null.
2318  *
2319  * IN callBack - a call back function pointer that may be called to report
2320  * status information.  Can be null.
2321  *
2322  * IN partition - the partition where the vldb entry exists.  Can be null.
2323  *
2324  * IN volumeId - the volume id of the vldb entry to be deleted. Can be null.
2325  *
2326  * LOCKS
2327  * 
2328  * No locks are obtained or released by this function
2329  *
2330  * RETURN CODES
2331  *
2332  * Returns != 0 upon successful completion.
2333  */
2334
2335 int ADMINAPI
2336 vos_VLDBEntryRemove(const void *cellHandle, const void *serverHandle,
2337                     vos_MessageCallBack_t callBack,
2338                     const unsigned int *partition, unsigned int *volumeId,
2339                     afs_status_p st)
2340 {
2341     int rc = 0;
2342     afs_status_t tst = 0;
2343     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2344     file_server_p f_server = (file_server_p) serverHandle;
2345     struct VldbListByAttributes attr;
2346     nbulkentries entries;
2347     afs_int32 nentries;
2348     int i;
2349
2350     memset(&attr, 0, sizeof(attr));
2351     memset(&entries, 0, sizeof(entries));
2352
2353     /*
2354      * Validate arguments
2355      */
2356
2357     if (!IsValidCellHandle(c_handle, &tst)) {
2358         goto fail_vos_VLDBEntryRemove;
2359     }
2360
2361     /*
2362      * If the volume is specified, just delete it
2363      */
2364
2365     if (volumeId != NULL) {
2366         tst = ubik_VL_DeleteEntry(c_handle->vos, 0, *volumeId, -1);
2367         if (tst != 0) {
2368             goto fail_vos_VLDBEntryRemove;
2369         }
2370     }
2371
2372     if (f_server != NULL) {
2373         if (!IsValidServerHandle(f_server, &tst)) {
2374             goto fail_vos_VLDBEntryRemove;
2375         }
2376         attr.server = ntohl(rx_HostOf(rx_PeerOf(f_server->serv)));
2377         attr.Mask |= VLLIST_SERVER;
2378     }
2379
2380     if (partition != NULL) {
2381         if (*partition > VOLMAXPARTS) {
2382             tst = ADMVOSPARTITIONTOOLARGE;
2383             goto fail_vos_VLDBEntryRemove;
2384         }
2385         attr.partition = *partition;
2386         attr.Mask |= VLLIST_PARTITION;
2387     }
2388
2389     if ((f_server == NULL) && (partition == NULL)) {
2390         tst = ADMVOSVLDBDELETEALLNULL;
2391         goto fail_vos_VLDBEntryRemove;
2392     }
2393
2394     if (!VLDB_ListAttributes(c_handle, &attr, &nentries, &entries, &tst)) {
2395         goto fail_vos_VLDBEntryRemove;
2396     }
2397
2398     if (nentries <= 0) {
2399         tst = ADMVOSVLDBNOENTRIES;
2400         goto fail_vos_VLDBEntryRemove;
2401     }
2402
2403     for (i = 0; i < nentries; i++) {
2404         ubik_VL_DeleteEntry(c_handle->vos, 0,
2405                   entries.nbulkentries_val[i].volumeId[RWVOL], -1);
2406     }
2407     rc = 1;
2408
2409   fail_vos_VLDBEntryRemove:
2410
2411     if (entries.nbulkentries_val) {
2412         free(entries.nbulkentries_val);
2413     }
2414
2415     if (st != NULL) {
2416         *st = tst;
2417     }
2418     return rc;
2419 }
2420
2421 /*
2422  * vos_VLDBUnlock - unlock vldb entries en masse.
2423  *
2424  * PARAMETERS
2425  *
2426  * IN cellHandle - a previously opened cellHandle that corresponds
2427  * to the cell where the vldb entries exist.
2428  *
2429  * IN serverHandle - a previously opened serverHandle that corresponds
2430  * to the server where the vldb entries exist.  Can be null.
2431  *
2432  * IN callBack - a call back function pointer that may be called to report
2433  * status information.  Can be null.
2434  *
2435  * IN partition - the partition where the vldb entries exist.  Can be null.
2436  *
2437  * LOCKS
2438  * 
2439  * No locks are obtained or released by this function
2440  *
2441  * RETURN CODES
2442  *
2443  * Returns != 0 upon successful completion.
2444  */
2445
2446 int ADMINAPI
2447 vos_VLDBUnlock(const void *cellHandle, const void *serverHandle,
2448                vos_MessageCallBack_t callBack, const unsigned int *partition,
2449                afs_status_p st)
2450 {
2451     int rc = 0;
2452     afs_status_t tst = 0;
2453     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2454     file_server_p f_server = (file_server_p) serverHandle;
2455     struct VldbListByAttributes attr;
2456     nbulkentries entries;
2457     afs_int32 nentries;
2458     int i;
2459
2460     memset(&attr, 0, sizeof(attr));
2461     memset(&entries, 0, sizeof(entries));
2462
2463     /*
2464      * Validate arguments
2465      */
2466
2467     if (!IsValidCellHandle(c_handle, &tst)) {
2468         goto fail_vos_VLDBUnlock;
2469     }
2470
2471     if (f_server != NULL) {
2472         if (!IsValidServerHandle(f_server, &tst)) {
2473             goto fail_vos_VLDBUnlock;
2474         }
2475         attr.server = ntohl(rx_HostOf(rx_PeerOf(f_server->serv)));
2476         attr.Mask |= VLLIST_SERVER;
2477     }
2478
2479     if (partition != NULL) {
2480         if (*partition > VOLMAXPARTS) {
2481             tst = ADMVOSPARTITIONTOOLARGE;
2482             goto fail_vos_VLDBUnlock;
2483         }
2484         attr.partition = *partition;
2485         attr.Mask |= VLLIST_PARTITION;
2486     }
2487     attr.flag = VLOP_ALLOPERS;
2488     attr.Mask |= VLLIST_FLAG;
2489
2490
2491     if (!VLDB_ListAttributes(c_handle, &attr, &nentries, &entries, &tst)) {
2492         goto fail_vos_VLDBUnlock;
2493     }
2494
2495     if (nentries <= 0) {
2496         tst = ADMVOSVLDBNOENTRIES;
2497         goto fail_vos_VLDBUnlock;
2498     }
2499
2500     for (i = 0; i < nentries; i++) {
2501         vos_VLDBEntryUnlock(cellHandle, 0,
2502                             entries.nbulkentries_val[i].volumeId[RWVOL],
2503                             &tst);
2504     }
2505     rc = 1;
2506
2507   fail_vos_VLDBUnlock:
2508
2509     if (entries.nbulkentries_val) {
2510         free(entries.nbulkentries_val);
2511     }
2512
2513     if (st != NULL) {
2514         *st = tst;
2515     }
2516     return rc;
2517 }
2518
2519
2520 /*
2521  * vos_VLDBEntryLock - lock a vldb entry.
2522  *
2523  * PARAMETERS
2524  *
2525  * IN cellHandle - a previously opened cellHandle that corresponds
2526  * to the cell where the vldb entry exists.
2527  *
2528  * IN callBack - a call back function pointer that may be called to report
2529  * status information.  Can be null.
2530  *
2531  * IN volumeId - the volume id of the vldb entry to be deleted.
2532  *
2533  * LOCKS
2534  * 
2535  * No locks are obtained or released by this function
2536  *
2537  * RETURN CODES
2538  *
2539  * Returns != 0 upon successful completion.
2540  */
2541
2542 int ADMINAPI
2543 vos_VLDBEntryLock(const void *cellHandle, vos_MessageCallBack_t callBack,
2544                   unsigned int volumeId, afs_status_p st)
2545 {
2546     int rc = 0;
2547     afs_status_t tst = 0;
2548     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2549
2550     /*
2551      * Validate arguments
2552      */
2553
2554     if (!IsValidCellHandle(c_handle, &tst)) {
2555         goto fail_vos_VLDBEntryLock;
2556     }
2557
2558     tst = ubik_VL_SetLock(c_handle->vos, 0, volumeId, -1, VLOP_DELETE);
2559     if (tst != 0) {
2560         goto fail_vos_VLDBEntryLock;
2561     }
2562     rc = 1;
2563
2564   fail_vos_VLDBEntryLock:
2565
2566     if (st != NULL) {
2567         *st = tst;
2568     }
2569     return rc;
2570 }
2571
2572 /*
2573  * vos_VLDBEntryUnlock - unlock a vldb entry.
2574  *
2575  * PARAMETERS
2576  *
2577  * IN cellHandle - a previously opened cellHandle that corresponds
2578  * to the cell where the vldb entry exists.
2579  *
2580  * IN callBack - a call back function pointer that may be called to report
2581  * status information.  Can be null.
2582  *
2583  * IN volumeId - the volume id of the vldb entry to be unlocked.
2584  *
2585  * LOCKS
2586  * 
2587  * No locks are obtained or released by this function
2588  *
2589  * RETURN CODES
2590  *
2591  * Returns != 0 upon successful completion.
2592  */
2593
2594 int ADMINAPI
2595 vos_VLDBEntryUnlock(const void *cellHandle, vos_MessageCallBack_t callBack,
2596                     unsigned int volumeId, afs_status_p st)
2597 {
2598     int rc = 0;
2599     afs_status_t tst = 0;
2600     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2601
2602     /*
2603      * Validate arguments
2604      */
2605
2606     if (!IsValidCellHandle(c_handle, &tst)) {
2607         goto fail_vos_VLDBEntryUnlock;
2608     }
2609
2610
2611     tst =
2612         ubik_VL_ReleaseLock(c_handle->vos, 0, volumeId, -1,
2613                   LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP);
2614     if (tst != 0) {
2615         goto fail_vos_VLDBEntryUnlock;
2616     }
2617     rc = 1;
2618
2619   fail_vos_VLDBEntryUnlock:
2620
2621     if (st != NULL) {
2622         *st = tst;
2623     }
2624     return rc;
2625 }
2626
2627 /*
2628  * vos_VLDBReadOnlySiteCreate - create a readonly site for a volume.
2629  *
2630  * PARAMETERS
2631  *
2632  * IN cellHandle - a previously opened cellHandle that corresponds
2633  * to the cell where the volume exists.
2634  *
2635  * IN serverHandle - a previously opened serverHandle that corresponds
2636  * to the server where the new volume should be created.
2637  *
2638  * IN callBack - a call back function pointer that may be called to report
2639  * status information.  Can be null.
2640  *
2641  * IN partition - the partition where then new volume should be created.
2642  *
2643  * IN volumeId - the volume id of the volume to be replicated.
2644  *
2645  * LOCKS
2646  * 
2647  * No locks are obtained or released by this function
2648  *
2649  * RETURN CODES
2650  *
2651  * Returns != 0 upon successful completion.
2652  */
2653
2654 int ADMINAPI
2655 vos_VLDBReadOnlySiteCreate(const void *cellHandle, const void *serverHandle,
2656                            vos_MessageCallBack_t callBack,
2657                            unsigned int partition, unsigned int volumeId,
2658                            afs_status_p st)
2659 {
2660     int rc = 0;
2661     afs_status_t tst = 0;
2662     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2663     file_server_p f_server = (file_server_p) serverHandle;
2664
2665     /*
2666      * Validate arguments
2667      */
2668
2669     if (!IsValidCellHandle(c_handle, &tst)) {
2670         goto fail_vos_VLDBReadOnlySiteCreate;
2671     }
2672
2673     if (!IsValidServerHandle(f_server, &tst)) {
2674         goto fail_vos_VLDBReadOnlySiteCreate;
2675     }
2676
2677     if (partition > VOLMAXPARTS) {
2678         tst = ADMVOSPARTITIONTOOLARGE;
2679         goto fail_vos_VLDBReadOnlySiteCreate;
2680     }
2681
2682     if (!UV_AddSite
2683         (c_handle, ntohl(rx_HostOf(rx_PeerOf(f_server->serv))), partition,
2684          volumeId, &tst)) {
2685         goto fail_vos_VLDBReadOnlySiteCreate;
2686     }
2687     rc = 1;
2688
2689   fail_vos_VLDBReadOnlySiteCreate:
2690
2691     if (st != NULL) {
2692         *st = tst;
2693     }
2694     return rc;
2695 }
2696
2697 /*
2698  * vos_VLDBReadOnlySiteDelete - delete a replication site for a volume.
2699  *
2700  * PARAMETERS
2701  *
2702  *
2703  * IN cellHandle - a previously opened cellHandle that corresponds
2704  * to the cell where the volume exists.
2705  *
2706  * IN serverHandle - a previously opened serverHandle that corresponds
2707  * to the server where the volume should be deleted.
2708  *
2709  * IN callBack - a call back function pointer that may be called to report
2710  * status information.  Can be null.
2711  *
2712  * IN partition - the partition where then volume should be deleted.
2713  *
2714  * IN volumeId - the volume id of the volume to be deleted.
2715  *
2716  * LOCKS
2717  * 
2718  * No locks are obtained or released by this function
2719  *
2720  * RETURN CODES
2721  *
2722  * Returns != 0 upon successful completion.
2723  */
2724
2725 int ADMINAPI
2726 vos_VLDBReadOnlySiteDelete(const void *cellHandle, const void *serverHandle,
2727                            vos_MessageCallBack_t callBack,
2728                            unsigned int partition, unsigned int volumeId,
2729                            afs_status_p st)
2730 {
2731     int rc = 0;
2732     afs_status_t tst = 0;
2733     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2734     file_server_p f_server = (file_server_p) serverHandle;
2735
2736     /*
2737      * Validate arguments
2738      */
2739
2740     if (!IsValidCellHandle(c_handle, &tst)) {
2741         goto fail_vos_VLDBReadOnlySiteDelete;
2742     }
2743
2744     if (!IsValidServerHandle(f_server, &tst)) {
2745         goto fail_vos_VLDBReadOnlySiteDelete;
2746     }
2747
2748     if (partition > VOLMAXPARTS) {
2749         tst = ADMVOSPARTITIONTOOLARGE;
2750         goto fail_vos_VLDBReadOnlySiteDelete;
2751     }
2752
2753     if (!UV_RemoveSite
2754         (c_handle, ntohl(rx_HostOf(rx_PeerOf(f_server->serv))), partition,
2755          volumeId, &tst)) {
2756         goto fail_vos_VLDBReadOnlySiteDelete;
2757     }
2758     rc = 1;
2759
2760   fail_vos_VLDBReadOnlySiteDelete:
2761
2762     if (st != NULL) {
2763         *st = tst;
2764     }
2765     return rc;
2766 }
2767
2768 /*
2769  * vos_VLDBSync - synchronize the vldb with the fileserver.
2770  *
2771  * PARAMETERS
2772  *
2773  * IN cellHandle - a previously opened cellHandle that corresponds
2774  * to the cell where the sync should occur.
2775  *
2776  * IN serverHandle - a previously opened serverHandle that corresponds
2777  * to the server where the sync should occur.
2778  *
2779  * IN callBack - a call back function pointer that may be called to report
2780  * status information.  Can be null.
2781  *
2782  * IN partition - the partition where the sync should occur.  Can be null.
2783  *
2784  * IN force - force deletion of bad volumes.
2785  *
2786  * LOCKS
2787  * 
2788  * No locks are obtained or released by this function
2789  *
2790  * RETURN CODES
2791  *
2792  * Returns != 0 upon successful completion.
2793  */
2794
2795 int ADMINAPI
2796 vos_VLDBSync(const void *cellHandle, const void *serverHandle,
2797              vos_MessageCallBack_t callBack, const unsigned int *partition,
2798              vos_force_t force, afs_status_p st)
2799 {
2800     int rc = 0;
2801     afs_status_t tst = 0;
2802     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2803     file_server_p f_server = (file_server_p) serverHandle;
2804     afs_int32 part = 0;
2805     int flags = 0;
2806     int force_flag = 0;
2807
2808     /*
2809      * Validate arguments
2810      */
2811
2812     if (!IsValidCellHandle(c_handle, &tst)) {
2813         goto fail_vos_VLDBSync;
2814     }
2815
2816     if (!IsValidServerHandle(f_server, &tst)) {
2817         goto fail_vos_VLDBSync;
2818     }
2819
2820     if (partition != NULL) {
2821         if (*partition > VOLMAXPARTS) {
2822             tst = ADMVOSPARTITIONTOOLARGE;
2823             goto fail_vos_VLDBSync;
2824         }
2825         part = (afs_int32) * partition;
2826         flags = 1;
2827     }
2828
2829     if (force == VOS_FORCE) {
2830         force_flag = 1;
2831     }
2832
2833     /*
2834      * sync the vldb
2835      */
2836
2837     rc = UV_SyncVldb(c_handle, f_server->serv, part, flags, force_flag, &tst);
2838
2839   fail_vos_VLDBSync:
2840
2841     if (st != NULL) {
2842         *st = tst;
2843     }
2844     return rc;
2845 }
2846
2847 /*
2848  * vos_VolumeCreate - create a new partition.
2849  *
2850  * PARAMETERS
2851  *
2852  * IN cellHandle - a previously opened cellHandle that corresponds
2853  * to the cell where the server lives.
2854  *
2855  * IN serverHandle - a previously open vos server handle that holds
2856  * the partition where the volume should be create.
2857  *
2858  * IN callBack - a call back function pointer that may be called to report
2859  * status information.  Can be null.
2860  *
2861  * IN partition - the integer that represents the partition that will 
2862  * house the new volume.
2863  *
2864  * IN volumeName - the name of the new volume.
2865  *
2866  * IN quota - the quota of the new volume.
2867  *
2868  * OUT volumeId - the volume id of the newly created volume.
2869  *
2870  * LOCKS
2871  * 
2872  * No locks are obtained or released by this function
2873  *
2874  * RETURN CODES
2875  *
2876  * Returns != 0 upon successful completion.
2877  */
2878
2879 int ADMINAPI
2880 vos_VolumeCreate(const void *cellHandle, const void *serverHandle,
2881                  vos_MessageCallBack_t callBack, unsigned int partition,
2882                  char *volumeName, unsigned int quota,
2883                  unsigned int *volumeId, afs_status_p st)
2884 {
2885     int rc = 0;
2886     afs_status_t tst = 0;
2887     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2888     file_server_p f_server = (file_server_p) serverHandle;
2889     vos_partitionEntry_t pinfo;
2890     struct nvldbentry vinfo;
2891
2892     /*
2893      * Validate arguments
2894      */
2895
2896     if (!IsValidCellHandle(c_handle, &tst)) {
2897         goto fail_vos_VolumeCreate;
2898     }
2899
2900     if (!IsValidServerHandle(f_server, &tst)) {
2901         goto fail_vos_VolumeCreate;
2902     }
2903
2904     if (partition > VOLMAXPARTS) {
2905         tst = ADMVOSPARTITIONTOOLARGE;
2906         goto fail_vos_VolumeCreate;
2907     }
2908
2909     if (!ValidateVolumeName(volumeName, &tst)) {
2910         goto fail_vos_VolumeCreate;
2911     }
2912
2913     if (volumeId == NULL) {
2914         tst = ADMVOSVOLUMEID;
2915         goto fail_vos_VolumeCreate;
2916     }
2917
2918     /*
2919      * Check that partition is valid at the server
2920      */
2921
2922     if (!vos_PartitionGet
2923         (cellHandle, serverHandle, 0, partition, &pinfo, &tst)) {
2924         goto fail_vos_VolumeCreate;
2925     }
2926
2927     /*
2928      * Check that the volume doesn't already exist
2929      */
2930
2931     if (aVLDB_GetEntryByName(c_handle, volumeName, &vinfo, &tst)) {
2932         tst = ADMVOSVOLUMENAMEDUP;
2933         goto fail_vos_VolumeCreate;
2934     }
2935
2936     /*
2937      * Create the new volume
2938      */
2939
2940     rc = UV_CreateVolume(c_handle, f_server->serv, partition, volumeName,
2941                          quota, volumeId, &tst);
2942
2943   fail_vos_VolumeCreate:
2944
2945     if (st != NULL) {
2946         *st = tst;
2947     }
2948     return rc;
2949 }
2950
2951 /*
2952  * vos_VolumeDelete - remove a volume.
2953  *
2954  * PARAMETERS
2955  *
2956  * IN cellHandle - a previously opened cellHandle that corresponds
2957  * to the cell where the volume exists.
2958  *
2959  * IN serverHandle - a previously opened serverHandle that corresponds
2960  * to the server where the volume exists.
2961  *
2962  * IN callBack - a call back function pointer that may be called to report
2963  * status information.  Can be null.
2964  *
2965  * IN partition - the partition where the volume exists.
2966  *
2967  * IN volumeId - the volume id of the volume to be deleted.
2968  *
2969  * LOCKS
2970  * 
2971  * No locks are obtained or released by this function
2972  *
2973  * RETURN CODES
2974  *
2975  * Returns != 0 upon successful completion.
2976  */
2977
2978 int ADMINAPI
2979 vos_VolumeDelete(const void *cellHandle, const void *serverHandle,
2980                  vos_MessageCallBack_t callBack, unsigned int partition,
2981                  unsigned int volumeId, afs_status_p st)
2982 {
2983     int rc = 0;
2984     afs_status_t tst = 0;
2985     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2986     file_server_p f_server = (file_server_p) serverHandle;
2987     vos_partitionEntry_t pinfo;
2988
2989     /*
2990      * Validate arguments
2991      */
2992
2993     if (!IsValidCellHandle(c_handle, &tst)) {
2994         goto fail_vos_VolumeDelete;
2995     }
2996
2997     if (!IsValidServerHandle(f_server, &tst)) {
2998         goto fail_vos_VolumeDelete;
2999     }
3000
3001     if (partition > VOLMAXPARTS) {
3002         tst = ADMVOSPARTITIONTOOLARGE;
3003         goto fail_vos_VolumeDelete;
3004     }
3005
3006     /*
3007      * Check that partition is valid at the server
3008      */
3009
3010     if (!vos_PartitionGet
3011         (cellHandle, serverHandle, 0, partition, &pinfo, &tst)) {
3012         goto fail_vos_VolumeDelete;
3013     }
3014
3015     rc = UV_DeleteVolume(c_handle, f_server->serv, partition, volumeId, &tst);
3016
3017   fail_vos_VolumeDelete:
3018
3019     if (st != NULL) {
3020         *st = tst;
3021     }
3022     return rc;
3023 }
3024
3025 /*
3026  * vos_VolumeRename - rename a volume.
3027  *
3028  * PARAMETERS
3029  *
3030  * IN cellHandle - a previously opened cellHandle that corresponds
3031  * to the cell where the volume exists.
3032  *
3033  * IN serverHandle - a previously opened serverHandle that corresponds
3034  * to the server where the vldb entry exists.  Can be null.
3035  *
3036  * IN callBack - a call back function pointer that may be called to report
3037  * status information.  Can be null.
3038  *
3039  * IN readWriteVolumeId - the volume id of the volume to be renamed.
3040  *
3041  * IN newVolumeName - the new name.
3042  *
3043  * LOCKS
3044  * 
3045  * No locks are obtained or released by this function
3046  *
3047  * RETURN CODES
3048  *
3049  * Returns != 0 upon successful completion.
3050  */
3051
3052 int ADMINAPI
3053 vos_VolumeRename(const void *cellHandle, vos_MessageCallBack_t callBack,
3054                  unsigned int readWriteVolumeId, char *newVolumeName,
3055                  afs_status_p st)
3056 {
3057     int rc = 0;
3058     afs_status_t tst = 0;
3059     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
3060     struct nvldbentry entry;
3061
3062     /*
3063      * Validate arguments
3064      */
3065
3066     if (!IsValidCellHandle(c_handle, &tst)) {
3067         goto fail_vos_VolumeRename;
3068     }
3069
3070     if ((newVolumeName == NULL) || (*newVolumeName == 0)) {
3071         tst = ADMVOSNEWVOLUMENAMENULL;
3072         goto fail_vos_VolumeRename;
3073     }
3074
3075     /*
3076      * Retrieve the entry
3077      */
3078
3079     if (!aVLDB_GetEntryByID(c_handle, readWriteVolumeId, -1, &entry, &tst)) {
3080         goto fail_vos_VolumeRename;
3081     }
3082
3083     rc = UV_RenameVolume(c_handle, &entry, newVolumeName, &tst);
3084
3085   fail_vos_VolumeRename:
3086
3087     if (st != NULL) {
3088         *st = tst;
3089     }
3090     return rc;
3091 }
3092
3093 /*
3094  * vos_VolumeDump - dump a volume
3095  *
3096  * PARAMETERS
3097  *
3098  * IN cellHandle - a previously opened cellHandle that corresponds
3099  * to the cell where the volume exists.
3100  *
3101  * IN serverHandle - a previously opened serverHandle that corresponds
3102  * to the server where the volume exists.  Can be null.
3103  *
3104  * IN callBack - a call back function pointer that may be called to report
3105  * status information.  Can be null.
3106  *
3107  * IN volumeId - the volume id of the volume to be dumped.
3108  *
3109  * IN startTime - files with modification times >= this time will be dumped.
3110  *
3111  * IN dumpFile - the file to dump the volume to.
3112  *
3113  * LOCKS
3114  * 
3115  * No locks are obtained or released by this function
3116  *
3117  * RETURN CODES
3118  *
3119  * Returns != 0 upon successful completion.
3120  */
3121
3122 int ADMINAPI
3123 vos_VolumeDump(const void *cellHandle, const void *serverHandle,
3124                vos_MessageCallBack_t callBack, unsigned int *partition,
3125                unsigned int volumeId, unsigned int startTime,
3126                const char *dumpFile, afs_status_p st)
3127 {
3128     int rc = 0;
3129     afs_status_t tst = 0;
3130     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
3131     file_server_p f_server = (file_server_p) serverHandle;
3132     afs_int32 server, part, voltype;
3133     struct nvldbentry entry;
3134
3135     /*
3136      * Validate arguments
3137      */
3138
3139     if (!IsValidCellHandle(c_handle, &tst)) {
3140         goto fail_vos_VolumeDump;
3141     }
3142
3143     if (serverHandle != NULL) {
3144         if (!IsValidServerHandle(f_server, &tst)) {
3145             goto fail_vos_VolumeDump;
3146         }
3147     }
3148
3149     /*
3150      * You must specify both the serverHandle and the partition
3151      */
3152
3153     if (serverHandle || partition) {
3154         if (!serverHandle || !partition) {
3155             tst = ADMVOSSERVERANDPARTITION;
3156             goto fail_vos_VolumeDump;
3157         } else {
3158             if (*partition > VOLMAXPARTS) {
3159                 tst = ADMVOSPARTITIONTOOLARGE;
3160                 goto fail_vos_VolumeDump;
3161             }
3162             server = ntohl(rx_HostOf(rx_PeerOf(f_server->serv)));
3163             part = *partition;
3164         }
3165     } else {
3166         if (!GetVolumeInfo
3167             (c_handle, volumeId, &entry, &server, &part, &voltype, &tst)) {
3168             goto fail_vos_VolumeDump;
3169         }
3170     }
3171
3172     if ((dumpFile == NULL) || (*dumpFile == 0)) {
3173         tst = ADMVOSDUMPFILENULL;
3174         goto fail_vos_VolumeDump;
3175     }
3176
3177     rc = UV_DumpVolume(c_handle, volumeId, server, part, startTime, dumpFile,
3178                        &tst);
3179
3180   fail_vos_VolumeDump:
3181
3182     if (st != NULL) {
3183         *st = tst;
3184     }
3185     return rc;
3186 }
3187
3188 /*
3189  * vos_VolumeRestore - restore a volume from a dump
3190  *
3191  * PARAMETERS
3192  *
3193  * IN cellHandle - a previously opened cellHandle that corresponds
3194  * to the cell where the volume exists.
3195  *
3196  * IN serverHandle - a previously opened serverHandle that corresponds
3197  * to the server where the volume exists.
3198  *
3199  * IN callBack - a call back function pointer that may be called to report
3200  * status information.  Can be null.
3201  *
3202  * IN partition - the partition where the volume exists.
3203  *
3204  * IN volumeId - the volume id of the volume to be restored.
3205  *
3206  * IN volumeName - the volume name of the volume to be restored.
3207  *
3208  * IN dumpFile - the file from which to restore the volume.
3209  *
3210  * IN dumpType - the type of dump to perform.
3211  *
3212  * LOCKS
3213  * 
3214  * No locks are obtained or released by this function
3215  *
3216  * RETURN CODES
3217  *
3218  * Returns != 0 upon successful completion.
3219  */
3220
3221 int ADMINAPI
3222 vos_VolumeRestore(const void *cellHandle, const void *serverHandle,
3223                   vos_MessageCallBack_t callBack, unsigned int partition,
3224                   unsigned int *volumeId, char *volumeName,
3225                   const char *dumpFile, vos_volumeRestoreType_t dumpType,
3226                   afs_status_p st)
3227 {
3228     int rc = 0;
3229     afs_status_t tst = 0;
3230     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
3231     file_server_p f_server = (file_server_p) serverHandle;
3232     struct nvldbentry entry;
3233     afs_int32 volid, server;
3234     int fd;
3235     struct stat status;
3236     int restoreflags = 0;
3237     afs_int32 Oserver, Opart, Otype;
3238     struct nvldbentry Oentry;
3239     int equal;
3240
3241     /*
3242      * Validate arguments
3243      */
3244
3245     if (!IsValidCellHandle(c_handle, &tst)) {
3246         goto fail_vos_VolumeRestore;
3247     }
3248
3249     if (serverHandle != NULL) {
3250         if (!IsValidServerHandle(f_server, &tst)) {
3251             goto fail_vos_VolumeRestore;
3252         }
3253     }
3254
3255     /*
3256      * Must pass volumeName
3257      */
3258
3259     if ((volumeName == NULL) || (*volumeName == 0)) {
3260         tst = ADMVOSVOLUMENAMENULL;
3261         goto fail_vos_VolumeRestore;
3262     }
3263
3264     if (!ValidateVolumeName(volumeName, &tst)) {
3265         goto fail_vos_VolumeRestore;
3266     }
3267
3268     /*
3269      * If volumeId is passed, it must be a valid volume id
3270      */
3271
3272     if (volumeId != NULL) {
3273         if (!aVLDB_GetEntryByID(c_handle, *volumeId, -1, &entry, &tst)) {
3274             goto fail_vos_VolumeRestore;
3275         }
3276         volid = *volumeId;
3277     } else {
3278         volid = 0;
3279     }
3280
3281     server = ntohl(rx_HostOf(rx_PeerOf(f_server->serv)));
3282
3283     if (partition > VOLMAXPARTS) {
3284         tst = ADMVOSPARTITIONTOOLARGE;
3285         goto fail_vos_VolumeRestore;
3286     }
3287
3288     /*
3289      * Check that dumpFile exists and can be accessed
3290      */
3291
3292     fd = open(dumpFile, 0);
3293     if ((fd < 0) || (fstat(fd, &status) < 0)) {
3294         close(fd);
3295         tst = ADMVOSDUMPFILEOPENFAIL;
3296         goto fail_vos_VolumeRestore;
3297     } else {
3298         close(fd);
3299     }
3300
3301     if (!aVLDB_GetEntryByName(c_handle, volumeName, &entry, &tst)) {
3302         restoreflags = RV_FULLRST;
3303     } else if (Lp_GetRwIndex(c_handle, &entry, 0) == -1) {
3304         restoreflags = RV_FULLRST;
3305         if (volid == 0) {
3306             volid = entry.volumeId[RWVOL];
3307         } else if ((entry.volumeId[RWVOL] != 0)
3308                    && (entry.volumeId[RWVOL] != volid)) {
3309             volid = entry.volumeId[RWVOL];
3310         }
3311     } else {
3312
3313         if (volid == 0) {
3314             volid = entry.volumeId[RWVOL];
3315         } else if ((entry.volumeId[RWVOL] != 0)
3316                    && (entry.volumeId[RWVOL] != volid)) {
3317             volid = entry.volumeId[RWVOL];
3318         }
3319
3320         /*
3321          * If the vldb says the same volume exists somewhere else
3322          * the caller must specify a full restore, not an incremental
3323          */
3324
3325         if (dumpType == VOS_RESTORE_FULL) {
3326             restoreflags = RV_FULLRST;
3327         } else {
3328
3329             /*
3330              * Check to see if the volume exists where the caller said
3331              */
3332             if (!GetVolumeInfo
3333                 (c_handle, volid, &Oentry, &Oserver, &Opart, &Otype, &tst)) {
3334                 goto fail_vos_VolumeRestore;
3335             }
3336             if (!VLDB_IsSameAddrs(c_handle, Oserver, server, &equal, &tst)) {
3337                 goto fail_vos_VolumeRestore;
3338             }
3339
3340             if (!equal) {
3341                 tst = ADMVOSRESTOREVOLEXIST;
3342                 goto fail_vos_VolumeRestore;
3343             }
3344         }
3345     }
3346
3347     rc = UV_RestoreVolume(c_handle, server, partition, volid, volumeName,
3348                           restoreflags, dumpFile, &tst);
3349
3350   fail_vos_VolumeRestore:
3351
3352     if (st != NULL) {
3353         *st = tst;
3354     }
3355     return rc;
3356 }
3357
3358 /*
3359  * vos_VolumeOnline - bring a volume online.
3360  *
3361  * PARAMETERS
3362  *
3363  * IN serverHandle - a previously opened serverHandle that corresponds
3364  * to the server where the volume exists.
3365  *
3366  * IN callBack - a call back function pointer that may be called to report
3367  * status information.  Can be null.
3368  *
3369  * IN partition - the partition where the volume exists.
3370  *
3371  * IN volumeId - the volume id of the volume to be brought online.
3372  *
3373  * LOCKS
3374  * 
3375  * No locks are obtained or released by this function
3376  *
3377  * RETURN CODES
3378  *
3379  * Returns != 0 upon successful completion.
3380  */
3381
3382 int ADMINAPI
3383 vos_VolumeOnline(const void *serverHandle, vos_MessageCallBack_t callBack,
3384                  unsigned int partition, unsigned int volumeId,
3385                  unsigned int sleepTime, vos_volumeOnlineType_t volumeStatus,
3386                  afs_status_p st)
3387 {
3388     int rc = 0;
3389     afs_status_t tst = 0;
3390     file_server_p f_server = (file_server_p) serverHandle;
3391     int up = ITOffline;
3392
3393     /*
3394      * Validate arguments
3395      */
3396
3397     if (!IsValidServerHandle(f_server, &tst)) {
3398         goto fail_vos_VolumeOnline;
3399     }
3400
3401     if (partition > VOLMAXPARTS) {
3402         tst = ADMVOSPARTITIONIDTOOLARGE;
3403         goto fail_vos_VolumeOnline;
3404     }
3405
3406     if (volumeStatus == VOS_ONLINE_BUSY) {
3407         up = ITBusy;
3408     }
3409
3410     rc = UV_SetVolume(f_server->serv, partition, volumeId, up, 0, sleepTime,
3411                       &tst);
3412
3413   fail_vos_VolumeOnline:
3414
3415     if (st != NULL) {
3416         *st = tst;
3417     }
3418     return rc;
3419 }
3420
3421 /*
3422  * vos_VolumeOffline - take a volume offline.
3423  *
3424  * PARAMETERS
3425  *
3426  * IN serverHandle - a previously opened serverHandle that corresponds
3427  * to the server where the volume exists.
3428  *
3429  * IN callBack - a call back function pointer that may be called to report
3430  * status information.  Can be null.
3431  *
3432  * IN partition - the partition where the volume exists.
3433  *
3434  * IN volumeId - the volume id of the volume to be taken offline.
3435  *
3436  * LOCKS
3437  * 
3438  * No locks are obtained or released by this function
3439  *
3440  * RETURN CODES
3441  *
3442  * Returns != 0 upon successful completion.
3443  */
3444
3445 int ADMINAPI
3446 vos_VolumeOffline(const void *serverHandle, vos_MessageCallBack_t callBack,
3447                   unsigned int partition, unsigned int volumeId,
3448                   afs_status_p st)
3449 {
3450     int rc = 0;
3451     afs_status_t tst = 0;
3452     file_server_p f_server = (file_server_p) serverHandle;
3453
3454     /*
3455      * Validate arguments
3456      */
3457
3458     if (!IsValidServerHandle(f_server, &tst)) {
3459         goto fail_vos_VolumeOffline;
3460     }
3461
3462     if (partition > VOLMAXPARTS) {
3463         tst = ADMVOSPARTITIONIDTOOLARGE;
3464         goto fail_vos_VolumeOffline;
3465     }
3466
3467     rc = UV_SetVolume(f_server->serv, partition, volumeId, ITOffline,
3468                       VTOutOfService, 0, &tst);
3469
3470   fail_vos_VolumeOffline:
3471
3472     if (st != NULL) {
3473         *st = tst;
3474     }
3475     return rc;
3476 }
3477
3478 /*
3479  * copyvolintXInfo - copy a struct volintXInfo to a vos_volumeEntry_p.
3480  *
3481  * PARAMETERS
3482  *
3483  * IN source - the volintXInfo structure to copy.
3484  *
3485  * OUT dest - the vos_volumeEntry_t to fill
3486  *
3487  * LOCKS
3488  * 
3489  * No locks are obtained or released by this function
3490  *
3491  * RETURN CODES
3492  *
3493  * Returns != 0 upon successful completion.
3494  */
3495
3496 static int
3497 copyvolintXInfo(struct volintXInfo *source, vos_volumeEntry_p dest,
3498                 afs_status_p st)
3499 {
3500     int rc = 0;
3501     afs_status_t tst = 0;
3502     int i;
3503
3504     /*
3505      * If the volume is not marked OK, all the other fields are invalid
3506      * We take the extra step of blanking out dest here to prevent the
3507      * user from seeing stale data from a previous call
3508      */
3509
3510     memset(dest, 0, sizeof(dest));
3511
3512     switch (source->status) {
3513     case VOK:
3514         dest->status = VOS_OK;
3515         break;
3516     case VSALVAGE:
3517         dest->status = VOS_SALVAGE;
3518         break;
3519     case VNOVNODE:
3520         dest->status = VOS_NO_VNODE;
3521         break;
3522     case VNOVOL:
3523         dest->status = VOS_NO_VOL;
3524         break;
3525     case VVOLEXISTS:
3526         dest->status = VOS_VOL_EXISTS;
3527         break;
3528     case VNOSERVICE:
3529         dest->status = VOS_NO_SERVICE;
3530         break;
3531     case VOFFLINE:
3532         dest->status = VOS_OFFLINE;
3533         break;
3534     case VONLINE:
3535         dest->status = VOS_ONLINE;
3536         break;
3537     case VDISKFULL:
3538         dest->status = VOS_DISK_FULL;
3539         break;
3540     case VOVERQUOTA:
3541         dest->status = VOS_OVER_QUOTA;
3542         break;
3543     case VBUSY:
3544         dest->status = VOS_BUSY;
3545         break;
3546     case VMOVED:
3547         dest->status = VOS_MOVED;
3548         break;
3549     }
3550
3551     /*
3552      * Check to see if the entry is marked ok before copying all the
3553      * fields
3554      */
3555
3556     if (dest->status == VOS_OK) {
3557         strncpy(dest->name, source->name, VOS_MAX_VOLUME_NAME_LEN);
3558         dest->name[VOS_MAX_VOLUME_NAME_LEN - 1] = '\0';
3559         dest->id = source->volid;
3560         if (source->type == 0) {
3561             dest->type = VOS_READ_WRITE_VOLUME;
3562         } else if (source->type == 1) {
3563             dest->type = VOS_READ_ONLY_VOLUME;
3564         } else if (source->type == 2) {
3565             dest->type = VOS_BACKUP_VOLUME;
3566         }
3567         dest->backupId = source->backupID;
3568         dest->readWriteId = source->parentID;
3569         dest->readOnlyId = source->cloneID;
3570         dest->copyCreationDate = source->copyDate;
3571         dest->creationDate = source->creationDate;
3572         dest->lastAccessDate = source->accessDate;
3573         dest->lastUpdateDate = source->updateDate;
3574         dest->lastBackupDate = source->backupDate;
3575         dest->accessesSinceMidnight = source->dayUse;
3576         dest->fileCount = source->filecount;
3577         dest->maxQuota = source->maxquota;
3578         dest->currentSize = source->size;
3579         if (source->inUse == 1) {
3580             dest->volumeDisposition = VOS_ONLINE;
3581         } else {
3582             dest->volumeDisposition = VOS_OFFLINE;
3583         }
3584
3585         for (i = 0; i < VOS_VOLUME_READ_WRITE_STATS_NUMBER; i++) {
3586             dest->readStats[i] = source->stat_reads[i];
3587             dest->writeStats[i] = source->stat_writes[i];
3588         }
3589
3590         for (i = 0; i < VOS_VOLUME_TIME_STATS_NUMBER; i++) {
3591             dest->fileAuthorWriteSameNetwork[i] =
3592                 source->stat_fileSameAuthor[i];
3593             dest->fileAuthorWriteDifferentNetwork[i] =
3594                 source->stat_fileDiffAuthor[i];
3595             dest->dirAuthorWriteSameNetwork[i] =
3596                 source->stat_dirSameAuthor[i];
3597             dest->dirAuthorWriteDifferentNetwork[i] =
3598                 source->stat_dirDiffAuthor[i];
3599         }
3600     }
3601
3602     rc = 1;
3603
3604     if (st != NULL) {
3605         *st = tst;
3606     }
3607     return rc;
3608 }
3609
3610 /*
3611  * vos_VolumeGet - get information about a particular volume.
3612  *
3613  * PARAMETERS
3614  *
3615  * IN cellHandle - a previously opened cellHandle that corresponds
3616  * to the cell where the volume exists.
3617  *
3618  * IN serverHandle - a previously opened serverHandle that corresponds
3619  * to the server where the volume exists.
3620  *
3621  * IN callBack - a call back function pointer that may be called to report
3622  * status information.  Can be null.
3623  *
3624  * IN partition - the partition where the volume exists.
3625  *
3626  * IN volumeId - the volume id of the volume to be retrieved.
3627  *
3628  * OUT volumeP - upon successful completion, contains the information about the 
3629  * specified volume.
3630  *
3631  * LOCKS
3632  * 
3633  * No locks are obtained or released by this function
3634  *
3635  * RETURN CODES
3636  *
3637  * Returns != 0 upon successful completion.
3638  */
3639
3640 int ADMINAPI
3641 vos_VolumeGet(const void *cellHandle, const void *serverHandle,
3642               vos_MessageCallBack_t callBack, unsigned int partition,
3643               unsigned int volumeId, vos_volumeEntry_p volumeP,
3644               afs_status_p st)
3645 {
3646     int rc = 0;
3647     afs_status_t tst = 0;
3648     file_server_p f_server = (file_server_p) serverHandle;
3649     struct volintXInfo *info = NULL;
3650
3651     /*
3652      * Validate arguments
3653      */
3654
3655     if (!IsValidServerHandle(f_server, &tst)) {
3656         goto fail_vos_VolumeGet;
3657     }
3658
3659     if (partition > VOLMAXPARTS) {
3660         tst = ADMVOSPARTITIONIDTOOLARGE;
3661         goto fail_vos_VolumeGet;
3662     }
3663
3664     if (volumeP == NULL) {
3665         tst = ADMVOSVOLUMEPNULL;
3666         goto fail_vos_VolumeGet;
3667     }
3668
3669     /*
3670      * Retrieve the information for the volume
3671      */
3672
3673     if (!UV_XListOneVolume(f_server->serv, partition, volumeId, &info, &tst)) {
3674         goto fail_vos_VolumeGet;
3675     }
3676
3677     /*
3678      * Copy the volume info to our structure
3679      */
3680
3681     if (!copyvolintXInfo(info, volumeP, &tst)) {
3682         goto fail_vos_VolumeGet;
3683     }
3684     rc = 1;
3685
3686   fail_vos_VolumeGet:
3687
3688     if (info != NULL) {
3689         free(info);
3690     }
3691
3692     if (st != NULL) {
3693         *st = tst;
3694     }
3695     return rc;
3696 }
3697
3698 /*
3699  * The iterator functions and data for the volume retrieval functions.
3700  */
3701
3702 typedef struct volume_get {
3703     struct volintXInfo *vollist;
3704     afs_int32 total;            /* total number of volumes at this partition */
3705     afs_int32 index;            /* index to the current volume */
3706     vos_volumeEntry_t entry[CACHED_ITEMS];      /* the cache of entries */
3707 } volume_get_t, *volume_get_p;
3708
3709 static int
3710 GetVolumeRPC(void *rpc_specific, int slot, int *last_item,
3711              int *last_item_contains_data, afs_status_p st)
3712 {
3713     int rc = 0;
3714     afs_status_t tst = 0;
3715     volume_get_p entry = (volume_get_p) rpc_specific;
3716
3717     /*
3718      * Copy the next entry into the cache
3719      */
3720
3721     if (!copyvolintXInfo
3722         (&entry->vollist[entry->index], &entry->entry[slot], &tst)) {
3723         goto fail_GetVolumeRPC;
3724     }
3725     entry->index++;
3726
3727     /*
3728      * See if we've processed all the entries
3729      */
3730
3731
3732     if (entry->index == entry->total) {
3733         *last_item = 1;
3734         *last_item_contains_data = 1;
3735     }
3736     rc = 1;
3737
3738   fail_GetVolumeRPC:
3739
3740     if (st != NULL) {
3741         *st = tst;
3742     }
3743     return rc;
3744 }
3745
3746 static int
3747 GetVolumeFromCache(void *rpc_specific, int slot, void *dest, afs_status_p st)
3748 {
3749     int rc = 0;
3750     afs_status_t tst = 0;
3751     volume_get_p entry = (volume_get_p) rpc_specific;
3752
3753     memcpy(dest, (const void *)&entry->entry[slot],
3754            sizeof(vos_volumeEntry_t));
3755     rc = 1;
3756
3757     if (st != NULL) {
3758         *st = tst;
3759     }
3760     return rc;
3761 }
3762
3763
3764 static int
3765 DestroyVolume(void *rpc_specific, afs_status_p st)
3766 {
3767     int rc = 0;
3768     afs_status_t tst = 0;
3769     volume_get_p entry = (volume_get_p) rpc_specific;
3770
3771     if (entry->vollist != NULL) {
3772         free(entry->vollist);
3773     }
3774     rc = 1;
3775
3776     if (st != NULL) {
3777         *st = tst;
3778     }
3779     return rc;
3780 }
3781
3782
3783 /*
3784  * vos_VolumeGetBegin - begin to iterator over the list of volumes at a server.
3785  *
3786  * PARAMETERS
3787  *
3788  * IN cellHandle - a previously opened cellHandle that corresponds
3789  * to the cell where the volumes exist.
3790  *
3791  * IN serverHandle - a handle to the server where the volumes exist.
3792  *
3793  * IN callBack - a call back function pointer that may be called to report
3794  * status information.  Can be null.
3795  *
3796  * IN partition - the partition whose volumes should be listed.  Can be null.
3797  *
3798  * OUT iterationIdP - upon successful completion, contains an iterator that
3799  * can be passed to vos_VolumeGetBegin.
3800  *
3801  * LOCKS
3802  * 
3803  * No locks are obtained or released by this function
3804  *
3805  * RETURN CODES
3806  *
3807  * Returns != 0 upon successful completion.
3808  */
3809
3810 int ADMINAPI
3811 vos_VolumeGetBegin(const void *cellHandle, const void *serverHandle,
3812                    vos_MessageCallBack_t callBack, unsigned int partition,
3813                    void **iterationIdP, afs_status_p st)
3814 {
3815     int rc = 0;
3816     afs_status_t tst = 0;
3817     file_server_p f_server = (file_server_p) serverHandle;
3818     afs_admin_iterator_p iter =
3819         (afs_admin_iterator_p) malloc(sizeof(afs_admin_iterator_t));
3820     volume_get_p entry = (volume_get_p) calloc(1, sizeof(volume_get_t));
3821
3822     /*
3823      * Validate arguments
3824      */
3825
3826     if (!IsValidServerHandle(f_server, &tst)) {
3827         goto fail_vos_VolumeGetBegin;
3828     }
3829
3830     if (partition > VOLMAXPARTS) {
3831         tst = ADMVOSPARTITIONIDTOOLARGE;
3832         goto fail_vos_VolumeGetBegin;
3833     }
3834
3835     if ((iter == NULL) || (entry == NULL)) {
3836         tst = ADMNOMEM;
3837         goto fail_vos_VolumeGetBegin;
3838     }
3839
3840     /*
3841      * Get a list of all the volumes contained in the partition at the
3842      * server
3843      */
3844
3845     if (!UV_XListVolumes
3846         (f_server->serv, partition, 1, &entry->vollist, &entry->total,
3847          &tst)) {
3848         goto fail_vos_VolumeGetBegin;
3849     }
3850
3851     if (entry->total == 0) {
3852         if (!IteratorInit(iter, (void *)entry, NULL, NULL, NULL, NULL, &tst)) {
3853             goto fail_vos_VolumeGetBegin;
3854         }
3855         iter->done_iterating = 1;
3856         iter->st = ADMITERATORDONE;
3857     } else {
3858         if (!IteratorInit
3859             (iter, (void *)entry, GetVolumeRPC, GetVolumeFromCache, NULL,
3860              DestroyVolume, &tst)) {
3861             goto fail_vos_VolumeGetBegin;
3862         }
3863     }
3864     *iterationIdP = (void *)iter;
3865     rc = 1;
3866
3867   fail_vos_VolumeGetBegin:
3868
3869     if (rc == 0) {
3870         if (iter != NULL) {
3871             free(iter);
3872         }
3873         if (entry != NULL) {
3874             free(entry);
3875         }
3876     }
3877
3878     if (st != NULL) {
3879         *st = tst;
3880     }
3881     return rc;
3882 }
3883
3884 /*
3885  * vos_VolumeGetNext - get information about the next volume.
3886  *
3887  * PARAMETERS
3888  *
3889  * IN iterationId - an iterator previously returned by
3890  * vos_VolumeGetBegin
3891  *
3892  * OUT volumeP - a pointer to a vos_volumeEntry_t
3893  * that upon successful completion contains information about the
3894  * next volume.
3895  *
3896  * LOCKS
3897  * 
3898  * The iterator is locked while the next item is retrieved.
3899  *
3900  * RETURN CODES
3901  *
3902  * Returns != 0 upon successful completion.
3903  */
3904
3905 int ADMINAPI
3906 vos_VolumeGetNext(const void *iterationId, vos_volumeEntry_p volumeP,
3907                   afs_status_p st)
3908 {
3909     int rc = 0;
3910     afs_status_t tst = 0;
3911     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
3912
3913     if (iter == NULL) {
3914         tst = ADMITERATORNULL;
3915         goto fail_vos_VolumeGetNext;
3916     }
3917
3918     if (volumeP == NULL) {
3919         tst = ADMVOSVOLUMEPNULL;
3920         goto fail_vos_VolumeGetNext;
3921     }
3922
3923     rc = IteratorNext(iter, (void *)volumeP, &tst);
3924
3925   fail_vos_VolumeGetNext:
3926
3927     if (st != NULL) {
3928         *st = tst;
3929     }
3930     return rc;
3931 }
3932
3933 /*
3934  * vos_VolumeGetDone - finish using a volume iterator.
3935  *
3936  * PARAMETERS
3937  *
3938  * IN iterationId - an iterator previously returned by vos_VolumeGetBegin
3939  *
3940  * LOCKS
3941  * 
3942  * The iterator is locked and then destroyed.
3943  *
3944  * RETURN CODES
3945  *
3946  * Returns != 0 upon successful completion.
3947  */
3948
3949 int ADMINAPI
3950 vos_VolumeGetDone(const void *iterationId, afs_status_p st)
3951 {
3952     int rc = 0;
3953     afs_status_t tst = 0;
3954     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
3955
3956     /*
3957      * Validate arguments
3958      */
3959
3960     if (iter == NULL) {
3961         tst = ADMITERATORNULL;
3962         goto fail_vos_VolumeGetDone;
3963     }
3964
3965     rc = IteratorDone(iter, &tst);
3966
3967   fail_vos_VolumeGetDone:
3968
3969     if (st != NULL) {
3970         *st = tst;
3971     }
3972     return rc;
3973 }
3974
3975 /*
3976  * vos_VolumeMove - move a volume from one server to another.
3977  *
3978  * PARAMETERS
3979  *
3980  * IN cellHandle - a previously opened cellHandle that corresponds
3981  * to the cell where the volume exists.
3982  *
3983  * IN callBack - a call back function pointer that may be called to report
3984  * status information.  Can be null.
3985  *
3986  * IN volumeId - the volume id of the volume to be moved.
3987  *
3988  * IN fromServer - a previously opened serverHandle that corresponds
3989  * to the server where the volume currently resides.
3990  *
3991  * IN fromPartition - the partition where the volume currently resides.
3992  *
3993  * IN toServer - a previously opened serverHandle that corresponds
3994  * to the server where the volume will be moved.
3995  *
3996  * IN toPartition - the partition where the volume will be moved.
3997  *
3998  * LOCKS
3999  * 
4000  * No locks are obtained or released by this function
4001  *
4002  * RETURN CODES
4003  *
4004  * Returns != 0 upon successful completion.
4005  */
4006
4007 int ADMINAPI
4008 vos_VolumeMove(const void *cellHandle, vos_MessageCallBack_t callBack,
4009                unsigned int volumeId, const void *fromServer,
4010                unsigned int fromPartition, const void *toServer,
4011                unsigned int toPartition, afs_status_p st)
4012 {
4013     int rc = 0;
4014     afs_status_t tst = 0;
4015     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
4016     file_server_p from_server = (file_server_p) fromServer;
4017     file_server_p to_server = (file_server_p) toServer;
4018     afs_int32 from_server_addr =
4019         ntohl(rx_HostOf(rx_PeerOf(from_server->serv)));
4020     afs_int32 to_server_addr = ntohl(rx_HostOf(rx_PeerOf(to_server->serv)));
4021     afs_int32 from_partition = fromPartition;
4022     afs_int32 to_partition = toPartition;
4023
4024     /*
4025      * Validate arguments
4026      */
4027
4028     if (!IsValidCellHandle(c_handle, &tst)) {
4029         goto fail_vos_VolumeMove;
4030     }
4031
4032     if (!IsValidServerHandle(from_server, &tst)) {
4033         goto fail_vos_VolumeMove;
4034     }
4035
4036     if (!IsValidServerHandle(to_server, &tst)) {
4037         goto fail_vos_VolumeMove;
4038     }
4039
4040     if (fromPartition > VOLMAXPARTS) {
4041         tst = ADMVOSPARTITIONIDTOOLARGE;
4042         goto fail_vos_VolumeMove;
4043     }
4044
4045     if (toPartition > VOLMAXPARTS) {
4046         tst = ADMVOSPARTITIONIDTOOLARGE;
4047         goto fail_vos_VolumeMove;
4048     }
4049
4050     /*
4051      * Move the volume
4052      */
4053
4054     rc = UV_MoveVolume(c_handle, volumeId, from_server_addr, from_partition,
4055                        to_server_addr, to_partition, &tst);
4056
4057   fail_vos_VolumeMove:
4058
4059     if (st != NULL) {
4060         *st = tst;
4061     }
4062     return rc;
4063 }
4064
4065 /*
4066  * vos_VolumeRelease - release a volume.
4067  *
4068  * PARAMETERS
4069  *
4070  * IN cellHandle - a previously opened cellHandle that corresponds
4071  * to the cell where the volume exists.
4072  *
4073  * IN callBack - a call back function pointer that may be called to report
4074  * status information.  Can be null.
4075  *
4076  * IN volumeId - the volume to be released.
4077  *
4078  * IN force - force a complete release.
4079  *
4080  * LOCKS
4081  * 
4082  * No locks are obtained or released by this function
4083  *
4084  * RETURN CODES
4085  *
4086  * Returns != 0 upon successful completion.
4087  */
4088
4089 int ADMINAPI
4090 vos_VolumeRelease(const void *cellHandle, vos_MessageCallBack_t callBack,
4091                   unsigned int volumeId, vos_force_t force, afs_status_p st)
4092 {
4093     int rc = 0;
4094     afs_status_t tst = 0;
4095     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
4096     afs_int32 server, part, forc = 0, voltype, volume;
4097     struct nvldbentry entry;
4098
4099     /*
4100      * Validate arguments
4101      */
4102
4103     if (!IsValidCellHandle(c_handle, &tst)) {
4104         goto fail_vos_VolumeRelease;
4105     }
4106
4107     if (!GetVolumeInfo
4108         (c_handle, volumeId, &entry, &server, &part, &voltype, &tst)) {
4109         goto fail_vos_VolumeRelease;
4110     }
4111
4112     if (force == VOS_FORCE) {
4113         forc = 1;
4114     }
4115
4116     volume = volumeId;
4117     rc = UV_ReleaseVolume(c_handle, volume, server, part, forc, &tst);
4118
4119   fail_vos_VolumeRelease:
4120
4121     if (st != NULL) {
4122         *st = tst;
4123     }
4124     return rc;
4125 }
4126
4127 /*
4128  * vos_VolumeZap - forcibly delete a volume.
4129  *
4130  * PARAMETERS
4131  *
4132  * IN cellHandle - a previously opened cellHandle that corresponds
4133  * to the cell where the volume exists.
4134  *
4135  * IN serverHandle - a previously opened serverHandle that corresponds
4136  * to the server where the volume exists.
4137  *
4138  * IN callBack - a call back function pointer that may be called to report
4139  * status information.  Can be null.
4140  *
4141  * IN partition - the partition where the volume exists.
4142  *
4143  * IN volumeId - the volume id of the vldb entry to be deleted.
4144  *
4145  * IN force - force the deletion of bad volumes.
4146  *
4147  * LOCKS
4148  * 
4149  * No locks are obtained or released by this function
4150  *
4151  * RETURN CODES
4152  *
4153  * Returns != 0 upon successful completion.
4154  */
4155
4156 int ADMINAPI
4157 vos_VolumeZap(const void *cellHandle, const void *serverHandle,
4158               vos_MessageCallBack_t callBack, unsigned int partition,
4159               unsigned int volumeId, vos_force_t force, afs_status_p st)
4160 {
4161     int rc = 0;
4162     afs_status_t tst = 0;
4163     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
4164     file_server_p f_server = (file_server_p) serverHandle;
4165
4166     /*
4167      * Verify that the cellHandle is capable of making vos rpc's
4168      */
4169
4170     if (!IsValidCellHandle(c_handle, &tst)) {
4171         goto fail_vos_VolumeZap;
4172     }
4173
4174     if (!IsValidServerHandle(f_server, &tst)) {
4175         goto fail_vos_VolumeZap;
4176     }
4177
4178     if (force == VOS_FORCE) {
4179         rc = UV_NukeVolume(c_handle, f_server->serv, partition, volumeId,
4180                            &tst);
4181     } else {
4182         rc = UV_VolumeZap(c_handle, f_server->serv, partition, volumeId,
4183                           &tst);
4184     }
4185
4186   fail_vos_VolumeZap:
4187
4188     if (st != NULL) {
4189         *st = tst;
4190     }
4191     return rc;
4192 }
4193
4194 /*
4195  * vos_PartitionNameToId - translate a string representing a partition
4196  * to a number.
4197  *
4198  * PARAMETERS
4199  *
4200  * IN partitionName - a string representing a partition.  Must be of
4201  * the form /vicep..
4202  *
4203  * OUT partitionId - a number containing the partition id upon successful 
4204  * completion.
4205  *
4206  * LOCKS
4207  * 
4208  * No locks are obtained or released by this function
4209  *
4210  * RETURN CODES
4211  *
4212  * Returns != 0 upon successful completion.
4213  */
4214
4215 int ADMINAPI
4216 vos_PartitionNameToId(const char *partitionName, unsigned int *partitionId,
4217                       afs_status_p st)
4218 {
4219     int rc = 0;
4220     afs_status_t tst = 0;
4221     size_t partition_name_len;
4222     int i;
4223
4224     /* 
4225      * Validate arguments
4226      */
4227
4228     if (partitionName == NULL) {
4229         tst = ADMVOSPARTITIONNAMENULL;
4230         goto fail_vos_PartitionNameToId;
4231     }
4232
4233     if (partitionId == NULL) {
4234         tst = ADMVOSPARTITIONIDNULL;
4235         goto fail_vos_PartitionNameToId;
4236     }
4237
4238     /*
4239      * Check that string begins with /vicep
4240      */
4241
4242     if (strncmp(partitionName, VICE_PARTITION_PREFIX, VICE_PREFIX_SIZE)) {
4243         tst = ADMVOSPARTITIONNAMEINVALID;
4244         goto fail_vos_PartitionNameToId;
4245     }
4246
4247     /*
4248      * Check that the string is either one or two characters
4249      * longer than VICE_PREFIX_SIZE
4250      */
4251
4252     partition_name_len = strlen(partitionName);
4253
4254     if (partition_name_len == VICE_PREFIX_SIZE) {
4255         tst = ADMVOSPARTITIONNAMETOOSHORT;
4256         goto fail_vos_PartitionNameToId;
4257     }
4258
4259     if (partition_name_len > (VICE_PREFIX_SIZE + 2)) {
4260         tst = ADMVOSPARTITIONNAMETOOLONG;
4261         goto fail_vos_PartitionNameToId;
4262     }
4263
4264     /*
4265      * Check that all characters past the prefix are lower case
4266      */
4267
4268     for (i = VICE_PREFIX_SIZE; i < partition_name_len; i++) {
4269         if (!islower(partitionName[i])) {
4270             tst = ADMVOSPARTITIONNAMENOTLOWER;
4271             goto fail_vos_PartitionNameToId;
4272         }
4273     }
4274
4275     /*
4276      * Convert the name to a number
4277      */
4278
4279     if (partitionName[VICE_PREFIX_SIZE + 1] == 0) {
4280         *partitionId = partitionName[VICE_PREFIX_SIZE] - 'a';
4281     } else {
4282         *partitionId =
4283             (partitionName[VICE_PREFIX_SIZE] - 'a') * 26 +
4284             (partitionName[VICE_PREFIX_SIZE + 1] - 'a') + 26;
4285     }
4286
4287     if (*partitionId > VOLMAXPARTS) {
4288         tst = ADMVOSPARTITIONIDTOOLARGE;
4289         goto fail_vos_PartitionNameToId;
4290     }
4291     rc = 1;
4292
4293   fail_vos_PartitionNameToId:
4294
4295     if (st != NULL) {
4296         *st = tst;
4297     }
4298     return rc;
4299 }
4300
4301 /*
4302  * vos_PartitionIdToName - translate a number representing a partition
4303  * to a character string.
4304  *
4305  * PARAMETERS
4306  *
4307  * IN partitionId - an integer representing the partition.
4308  *
4309  * OUT partitionName - a string containing the converted partition ID
4310  * upon successful completion.
4311  *
4312  * LOCKS
4313  * 
4314  * No locks are obtained or released by this function
4315  *
4316  * RETURN CODES
4317  *
4318  * Returns != 0 upon successful completion.
4319  */
4320
4321 int ADMINAPI
4322 vos_PartitionIdToName(unsigned int partitionId, char *partitionName,
4323                       afs_status_p st)
4324 {
4325     int rc = 0;
4326     afs_status_t tst = 0;
4327
4328     if (partitionId > VOLMAXPARTS) {
4329         tst = ADMVOSPARTITIONIDTOOLARGE;
4330         goto fail_vos_PartitionIdToName;
4331     }
4332
4333     if (partitionName == NULL) {
4334         tst = ADMVOSPARTITIONNAMENULL;
4335         goto fail_vos_PartitionIdToName;
4336     }
4337
4338     if (partitionId < 26) {
4339         strcpy(partitionName, VICE_PARTITION_PREFIX);
4340         partitionName[6] = partitionId + 'a';
4341         partitionName[7] = '\0';
4342     } else {
4343         strcpy(partitionName, VICE_PARTITION_PREFIX);
4344         partitionId -= 26;
4345         partitionName[6] = 'a' + (partitionId / 26);
4346         partitionName[7] = 'a' + (partitionId % 26);
4347         partitionName[8] = '\0';
4348     }
4349     rc = 1;
4350
4351   fail_vos_PartitionIdToName:
4352
4353     if (st != NULL) {
4354         *st = tst;
4355     }
4356     return rc;
4357 }
4358
4359 /*
4360  * vos_VolumeQuotaChange - change the quota of a volume.
4361  *
4362  * PARAMETERS
4363  *
4364  * IN cellHandle - a previously opened cellHandle that corresponds
4365  * to the cell where the volume exists.
4366  *
4367  * IN serverHandle - a previously opened serverHandle that corresponds
4368  * to the server where the volume exists.
4369  *
4370  * IN callBack - a call back function pointer that may be called to report
4371  * status information.  Can be null.
4372  *
4373  * IN partition - the partition where the volume exists.
4374  *
4375  * IN volumeId - the volume id of the volume to be modified.
4376  *
4377  * IN volumeQuota - the new volume quota.
4378  *
4379  * LOCKS
4380  * 
4381  * No locks are obtained or released by this function
4382  *
4383  * RETURN CODES
4384  *
4385  * Returns != 0 upon successful completion.
4386  */
4387
4388 int ADMINAPI
4389 vos_VolumeQuotaChange(const void *cellHandle, const void *serverHandle,
4390                       vos_MessageCallBack_t callBack, unsigned int partition,
4391                       unsigned int volumeId, unsigned int volumeQuota,
4392                       afs_status_p st)
4393 {
4394     int rc = 0;
4395     afs_status_t tst = 0;
4396     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
4397     file_server_p f_server = (file_server_p) serverHandle;
4398     int ttid = 0;
4399     int rcode = 0;
4400     struct volintInfo tstatus;
4401     int active_trans = 0;
4402
4403     /*
4404      * Verify that the cellHandle is capable of making vos rpc's
4405      */
4406
4407     if (!IsValidCellHandle(c_handle, &tst)) {
4408         goto fail_vos_VolumeQuotaChange;
4409     }
4410
4411     if (!IsValidServerHandle(f_server, &tst)) {
4412         goto fail_vos_VolumeQuotaChange;
4413     }
4414
4415     memset((void *)&tstatus, 0, sizeof(tstatus));
4416     tstatus.dayUse = -1;
4417     tstatus.spare2 = -1;
4418     tstatus.maxquota = volumeQuota;
4419
4420
4421     tst =
4422         AFSVolTransCreate(f_server->serv, volumeId, partition, ITBusy, &ttid);
4423     if (tst) {
4424         goto fail_vos_VolumeQuotaChange;
4425     }
4426     active_trans = 1;
4427
4428     tst = AFSVolSetInfo(f_server->serv, ttid, &tstatus);
4429     if (tst) {
4430         goto fail_vos_VolumeQuotaChange;
4431     }
4432     rc = 1;
4433
4434   fail_vos_VolumeQuotaChange:
4435
4436     if (active_trans) {
4437         afs_status_t tst2 = 0;
4438         tst2 = AFSVolEndTrans(f_server->serv, ttid, &rcode);
4439         if (tst2) {
4440             if (tst == 0) {
4441                 tst = tst2;
4442                 rc = 0;
4443             }
4444         }
4445         if (rcode) {
4446             if (tst == 0) {
4447                 tst = rcode;
4448                 rc = 0;
4449             }
4450         }
4451     }
4452
4453     if (st != NULL) {
4454         *st = tst;
4455     }
4456     return rc;
4457 }
4458 /*
4459  * vos_VolumeGet2 - get information about a particular volume.
4460  *
4461  * PARAMETERS
4462  *
4463  * IN cellHandle - a previously opened cellHandle that corresponds
4464  * to the cell where the volume exists.
4465  *
4466  * IN serverHandle - a previously opened serverHandle that corresponds
4467  * to the server where the volume exists.
4468  *
4469  * IN callBack - a call back function pointer that may be called to report
4470  * status information.  Can be null.
4471  *
4472  * IN partition - the partition where the volume exists.
4473  *
4474  * IN volumeId - the volume id of the volume to be retrieved.
4475  *
4476  * OUT pinfo - upon successful completion, contains the information about the 
4477  * specified volume.
4478  *
4479  * LOCKS
4480  * 
4481  * No locks are obtained or released by this function
4482  *
4483  * RETURN CODES
4484  *
4485  * Returns != 0 upon successful completion.
4486  */
4487
4488 int ADMINAPI
4489 vos_VolumeGet2(const void *cellHandle, const void *serverHandle,
4490               vos_MessageCallBack_t callBack, unsigned int partition,
4491               unsigned int volumeId, volintInfo* pinfo,
4492               afs_status_p st)
4493 {
4494     int rc = 0;
4495     afs_status_t tst = 0;
4496     file_server_p f_server = (file_server_p) serverHandle;
4497     volintInfo *pinfo_=0;
4498
4499     /*
4500      * Validate arguments
4501      */
4502
4503     if (!IsValidServerHandle(f_server, &tst)) {
4504         goto fail_vos_VolumeGet2;
4505     }
4506
4507     if (partition > VOLMAXPARTS) {
4508         tst = ADMVOSPARTITIONIDTOOLARGE;
4509         goto fail_vos_VolumeGet2;
4510     }
4511
4512     if (pinfo == NULL) {
4513         tst = ADMVOSVOLUMEPNULL;
4514         goto fail_vos_VolumeGet2;
4515     }
4516
4517     /*
4518      * Retrieve the information for the volume
4519      */
4520
4521     if (!UV_ListOneVolume(f_server->serv, partition, volumeId, &pinfo_,&tst)) {
4522         goto fail_vos_VolumeGet2;
4523     }
4524
4525
4526     rc = 1;
4527
4528   fail_vos_VolumeGet2:
4529
4530     if (pinfo_ != NULL) {
4531      memcpy(pinfo,pinfo_,sizeof(volintInfo));
4532         free(pinfo_);
4533     }
4534
4535     if (st != NULL) {
4536         *st = tst;
4537     }
4538     return rc;
4539 }
4540
4541 /*
4542  * vos_ClearVolUpdateCounter - reset volUpdateCounter of a volume to zero
4543  *
4544  * PARAMETERS
4545  *
4546  * IN cellHandle - a previously opened cellHandle that corresponds
4547  * to the cell where the volume exists.
4548  *
4549  * IN serverHandle - a previously opened serverHandle that corresponds
4550  * to the server where the volume exists.
4551  *
4552  * IN partition - the partition where the volume exists.
4553  *
4554  * IN volumeId - the volume id of the volume to be retrieved.
4555  *
4556  * LOCKS
4557  * 
4558  * No locks are obtained or released by this function
4559  *
4560  * RETURN CODES
4561  *
4562  * Returns != 0 upon successful completion.
4563  */
4564
4565 int ADMINAPI
4566 vos_ClearVolUpdateCounter(const void *cellHandle,
4567                                   const void *serverHandle,
4568                                   unsigned int partition,
4569                                   unsigned int volumeId,
4570                                   afs_status_p st)
4571 {
4572     int rc = 0;
4573     afs_status_t tst = 0;
4574     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
4575     file_server_p f_server = (file_server_p) serverHandle;
4576     int ttid = 0;
4577     int rcode = 0;
4578     struct volintInfo tstatus;
4579     int active_trans = 0;
4580
4581     /*
4582      * Verify that the cellHandle is capable of making vos rpc's
4583      */
4584
4585     if (!IsValidCellHandle(c_handle, &tst)) {
4586         goto fail_vos_ClearVolUpdateCounter;
4587     }
4588
4589     if (!IsValidServerHandle(f_server, &tst)) {
4590         goto fail_vos_ClearVolUpdateCounter;
4591     }
4592
4593     memset((void *)&tstatus, 0, sizeof(tstatus));
4594     tstatus.maxquota = -1;
4595     tstatus.dayUse = -1;
4596     tstatus.creationDate = -1;
4597     tstatus.updateDate = -1;
4598     tstatus.flags = -1;
4599     tstatus.spare0 = -1;
4600     tstatus.spare1 = -1;
4601     tstatus.spare2 = 0;
4602     tstatus.spare3 = -1;
4603     
4604     tst =
4605         AFSVolTransCreate(f_server->serv, volumeId, partition, ITBusy, &ttid);
4606     if (tst) {
4607         goto fail_vos_ClearVolUpdateCounter;
4608     }
4609     active_trans = 1;
4610
4611     tst = AFSVolSetInfo(f_server->serv, ttid, &tstatus);
4612     if (tst) {
4613         goto fail_vos_ClearVolUpdateCounter;
4614     }
4615     rc = 1;
4616
4617   fail_vos_ClearVolUpdateCounter:
4618
4619     if (active_trans) {
4620         afs_status_t tst2 = 0;
4621         tst2 = AFSVolEndTrans(f_server->serv, ttid, &rcode);
4622         if (tst2) {
4623             if (tst == 0) {
4624                 tst = tst2;
4625                 rc = 0;
4626             }
4627         }
4628         if (rcode) {
4629             if (tst == 0) {
4630                 tst = rcode;
4631                 rc = 0;
4632             }
4633         }
4634     }
4635
4636     if (st != NULL) {
4637         *st = tst;
4638     }
4639     return rc;
4640 }
4641