volid-unsigned-int32-20090323
[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 RCSID
14     ("$Header$");
15
16 #include <afs/stds.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include <ctype.h>
20 #ifdef AFS_NT40_ENV
21 #include <winsock2.h>
22 #include <io.h>
23 #else
24 #include <sys/types.h>
25 #include <sys/socket.h>
26 #include <unistd.h>
27 #include <netinet/in.h>
28 #include <arpa/inet.h>
29 #include <netdb.h>
30 #endif
31 #include "afs_vosAdmin.h"
32 #include "../adminutil/afs_AdminInternal.h"
33 #include <afs/vlserver.h>
34 #include <afs/volser.h>
35 #include <afs/volint.h>
36 #include <afs/partition.h>
37 #include <rx/rx.h>
38 #include <rx/rxstat.h>
39 #include <afs/afs_utilAdmin.h>
40 #include "vosutils.h"
41 #include "vsprocs.h"
42 #include "lockprocs.h"
43
44 /* File descriptors are HANDLE's on NT. The following typedef helps catch
45  * type errors. Duplicated from vol/ihandle.h
46  */
47 #ifdef AFS_NT40_ENV
48 typedef HANDLE FD_t;
49 #else
50 typedef int FD_t;
51 #endif
52 #define INVALID_FD ((FD_t)-1)
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     register 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, int oldAddress,
1084                             int newAddress, afs_status_p st)
1085 {
1086     int rc = 0;
1087     afs_status_t tst = 0;
1088     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
1089
1090     /*
1091      * Validate arguments
1092      */
1093
1094     if (!IsValidCellHandle(c_handle, &tst)) {
1095         goto fail_vos_FileServerAddressChange;
1096     }
1097
1098     tst =
1099         ubik_Call_New(VL_ChangeAddr, c_handle->vos, 0, oldAddress,
1100                       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, int serverAddress,
1139                             afs_status_p st)
1140 {
1141     int rc = 0;
1142     afs_status_t tst = 0;
1143     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
1144     int dummyAddress = 0xffffffff;
1145
1146     /*
1147      * Validate arguments
1148      */
1149
1150     if (!IsValidCellHandle(c_handle, &tst)) {
1151         goto fail_vos_FileServerAddressRemove;
1152     }
1153
1154     tst =
1155         ubik_Call_New(VL_ChangeAddr, c_handle->vos, 0, dummyAddress,
1156                       serverAddress);
1157     if (tst) {
1158         goto fail_vos_FileServerAddressRemove;
1159     }
1160     rc = 1;
1161
1162   fail_vos_FileServerAddressRemove:
1163
1164     if (st != NULL) {
1165         *st = tst;
1166     }
1167     return rc;
1168 }
1169
1170 /*
1171  * The iterator functions and data for the server retrieval functions.
1172  *
1173  * These functions are very similar to the FileServerAddressGet
1174  * functions.  The main difference being that instead of returning
1175  * a single address at a time for a server, we fill an array with
1176  * all the addresses of a server.
1177  */
1178
1179 typedef struct server_get {
1180     struct ubik_client *vldb;   /* connection for future rpc's if neccessary */
1181     afs_int32 total_addresses;  /* total number of addresses */
1182     bulkaddrs addresses;        /* the list of addresses */
1183     int address_index;          /* current index into address list */
1184     vos_fileServerEntry_t server[CACHED_ITEMS]; /* the cache of servers */
1185 } server_get_t, *server_get_p;
1186
1187 static int
1188 GetServerRPC(void *rpc_specific, int slot, int *last_item,
1189              int *last_item_contains_data, afs_status_p st)
1190 {
1191     int rc = 0;
1192     afs_status_t tst = 0;
1193     server_get_p serv = (server_get_p) rpc_specific;
1194     afs_uint32 *addrP = &serv->addresses.bulkaddrs_val[serv->address_index];
1195     afs_int32 base, index;
1196     afsUUID m_uuid;
1197     afs_int32 m_unique;
1198     ListAddrByAttributes m_attrs;
1199     afs_int32 total_multi;
1200     bulkaddrs addr_multi;
1201     int i;
1202
1203     /*
1204      * Check to see if this is a multihomed address server
1205      */
1206
1207     if (((*addrP & 0xff000000) == 0xff000000) && ((*addrP) & 0xffff)) {
1208         base = (*addrP >> 16) & 0xff;
1209         index = (*addrP) & 0xffff;
1210
1211         if ((base >= 0) && (base <= VL_MAX_ADDREXTBLKS) && (index >= 1)
1212             && (index <= VL_MHSRV_PERBLK)) {
1213
1214             /*
1215              * This is a multihomed server.  Make an rpc to retrieve
1216              * all its addresses.  Copy the addresses into the cache.
1217              */
1218
1219             m_attrs.Mask = VLADDR_INDEX;
1220             m_attrs.index = (base * VL_MHSRV_PERBLK) + index;
1221             total_multi = 0;
1222             addr_multi.bulkaddrs_val = 0;
1223             addr_multi.bulkaddrs_len = 0;
1224             tst =
1225                 ubik_VL_GetAddrsU(serv->vldb, 0, &m_attrs, &m_uuid,
1226                           &m_unique, &total_multi, &addr_multi);
1227             if (tst) {
1228                 goto fail_GetServerRPC;
1229             }
1230
1231             /*
1232              * Remove any bogus IP addresses which the user may have
1233              * been unable to remove.
1234              */
1235
1236             RemoveBadAddresses(&total_multi, &addr_multi);
1237
1238             /*
1239              * Copy all the addresses into the cache
1240              */
1241
1242             for (i = 0; i < total_multi; i++) {
1243                 serv->server[slot].serverAddress[i] =
1244                     addr_multi.bulkaddrs_val[i];
1245             }
1246
1247             serv->server[slot].count = total_multi;
1248             serv->address_index++;
1249             free(addr_multi.bulkaddrs_val);
1250         }
1251
1252         /*
1253          * The next address is just a plain old address
1254          */
1255
1256     } else {
1257         serv->server[slot].serverAddress[0] = *addrP;
1258         serv->server[slot].count = 1;
1259         serv->address_index++;
1260     }
1261
1262     /*
1263      * See if we've processed all the entries
1264      */
1265
1266
1267     if (serv->address_index == serv->total_addresses) {
1268         *last_item = 1;
1269         *last_item_contains_data = 1;
1270     }
1271     rc = 1;
1272
1273   fail_GetServerRPC:
1274
1275     if (st != NULL) {
1276         *st = tst;
1277     }
1278     return rc;
1279 }
1280
1281 static int
1282 GetServerFromCache(void *rpc_specific, int slot, void *dest, afs_status_p st)
1283 {
1284     int rc = 0;
1285     afs_status_t tst = 0;
1286     server_get_p serv = (server_get_p) rpc_specific;
1287
1288     memcpy(dest, (const void *)&serv->server[slot],
1289            sizeof(vos_fileServerEntry_t));
1290     rc = 1;
1291
1292     if (st != NULL) {
1293         *st = tst;
1294     }
1295     return rc;
1296 }
1297
1298
1299 static int
1300 DestroyServer(void *rpc_specific, afs_status_p st)
1301 {
1302     int rc = 0;
1303     afs_status_t tst = 0;
1304     server_get_p serv = (server_get_p) rpc_specific;
1305
1306     if (serv->addresses.bulkaddrs_val != NULL) {
1307         free(serv->addresses.bulkaddrs_val);
1308     }
1309     rc = 1;
1310
1311     if (st != NULL) {
1312         *st = tst;
1313     }
1314     return rc;
1315 }
1316
1317 /*
1318  * vos_FileServerGetBegin - begin to iterate over the file servers in a cell.
1319  *
1320  * PARAMETERS
1321  *
1322  * IN cellHandle - a previously opened cellHandle that corresponds
1323  * to the cell where the file servers exist.
1324  *
1325  * IN callBack - a call back function pointer that may be called to report
1326  * status information.  Can be null.
1327  *
1328  * OUT iterationIdP - upon successful completion, contains an iterator that
1329  * can be passed to vos_FileServerGetNext.
1330  *
1331  * LOCKS
1332  * 
1333  * No locks are obtained or released by this function
1334  *
1335  * RETURN CODES
1336  *
1337  * Returns != 0 upon successful completion.
1338  */
1339
1340 int ADMINAPI
1341 vos_FileServerGetBegin(const void *cellHandle, vos_MessageCallBack_t callBack,
1342                        void **iterationIdP, afs_status_p st)
1343 {
1344     int rc = 0;
1345     afs_status_t tst = 0;
1346     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
1347     afs_admin_iterator_p iter =
1348         (afs_admin_iterator_p) malloc(sizeof(afs_admin_iterator_t));
1349     server_get_p serv = (server_get_p) calloc(1, sizeof(server_get_t));
1350     struct VLCallBack unused;
1351
1352
1353     /*
1354      * Validate arguments
1355      */
1356
1357     if (!IsValidCellHandle(c_handle, &tst)) {
1358         goto fail_vos_FileServerGetBegin;
1359     }
1360
1361     if (iterationIdP == NULL) {
1362         goto fail_vos_FileServerGetBegin;
1363     }
1364
1365     if ((iter == NULL) || (serv == NULL)) {
1366         tst = ADMNOMEM;
1367         goto fail_vos_FileServerGetBegin;
1368     }
1369
1370     /*
1371      * Fill in the serv structure
1372      */
1373
1374     serv->vldb = c_handle->vos;
1375     tst =
1376         ubik_Call_New(VL_GetAddrs, c_handle->vos, 0, 0, 0, &unused,
1377                       &serv->total_addresses, &serv->addresses);
1378
1379     if (tst) {
1380         goto fail_vos_FileServerGetBegin;
1381     }
1382
1383     /*
1384      * Remove any bogus IP addresses which the user may have
1385      * been unable to remove.
1386      */
1387
1388     RemoveBadAddresses(&serv->total_addresses, &serv->addresses);
1389
1390     if (serv->total_addresses == 0) {
1391         if (!IteratorInit(iter, (void *)serv, NULL, NULL, NULL, NULL, &tst)) {
1392             goto fail_vos_FileServerGetBegin;
1393         }
1394         iter->done_iterating = 1;
1395         iter->st = ADMITERATORDONE;
1396     } else {
1397         if (!IteratorInit
1398             (iter, (void *)serv, GetServerRPC, GetServerFromCache, NULL,
1399              DestroyServer, &tst)) {
1400             goto fail_vos_FileServerGetBegin;
1401         }
1402     }
1403     *iterationIdP = (void *)iter;
1404     rc = 1;
1405
1406   fail_vos_FileServerGetBegin:
1407
1408     if (rc == 0) {
1409         if (iter != NULL) {
1410             free(iter);
1411         }
1412         if (serv != NULL) {
1413             if (serv->addresses.bulkaddrs_val != NULL) {
1414                 free(serv->addresses.bulkaddrs_val);
1415             }
1416             free(serv);
1417         }
1418     }
1419
1420     if (st != NULL) {
1421         *st = tst;
1422     }
1423     return rc;
1424 }
1425
1426 /*
1427  * vos_FileServerGetNext - get information about the next fileserver in the cell.
1428  *
1429  * PARAMETERS
1430  *
1431  * IN iterationId - an iterator previously returned by
1432  * vos_FileServerGetBegin
1433  *
1434  * OUT serverEntryP - a pointer to a vos_fileServerEntry_t that upon successful
1435  * completion contains information about the next server in the cell.
1436  *
1437  * LOCKS
1438  * 
1439  * The iterator is locked while the next server is retrieved.
1440  *
1441  * RETURN CODES
1442  *
1443  * Returns != 0 upon successful completion.
1444  */
1445
1446 int ADMINAPI
1447 vos_FileServerGetNext(void *iterationId, vos_fileServerEntry_p serverEntryP,
1448                       afs_status_p st)
1449 {
1450     int rc = 0;
1451     afs_status_t tst = 0;
1452     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
1453
1454     if (iter == NULL) {
1455         tst = ADMITERATORNULL;
1456         goto fail_vos_FileServerGetNext;
1457     }
1458
1459     if (serverEntryP == NULL) {
1460         tst = ADMVOSSERVERENTRYPNULL;
1461         goto fail_vos_FileServerGetNext;
1462     }
1463
1464     rc = IteratorNext(iter, (void *)serverEntryP, &tst);
1465
1466   fail_vos_FileServerGetNext:
1467
1468     if (st != NULL) {
1469         *st = tst;
1470     }
1471     return rc;
1472 }
1473
1474 /*
1475  * vos_FileServerGetDone - finish using a partition iterator.
1476  *
1477  * PARAMETERS
1478  *
1479  * IN iterationId - an iterator previously returned by vos_FileServerGetBegin
1480  *
1481  * LOCKS
1482  * 
1483  * The iterator is locked and then destroyed.
1484  *
1485  * RETURN CODES
1486  *
1487  * Returns != 0 upon successful completion.
1488  */
1489
1490 int ADMINAPI
1491 vos_FileServerGetDone(void *iterationId, afs_status_p st)
1492 {
1493     int rc = 0;
1494     afs_status_t tst = 0;
1495     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
1496
1497     /*
1498      * Validate arguments
1499      */
1500
1501     if (iter == NULL) {
1502         tst = ADMITERATORNULL;
1503         goto fail_vos_FileServerGetDone;
1504     }
1505
1506     rc = IteratorDone(iter, &tst);
1507
1508   fail_vos_FileServerGetDone:
1509
1510     if (st != NULL) {
1511         *st = tst;
1512     }
1513     return rc;
1514 }
1515
1516 /*
1517  * The iterator functions and data for the transation retrieval functions.
1518  */
1519
1520 typedef struct transaction_get {
1521     afs_int32 total;            /* total number of transactions */
1522     afs_int32 index;            /* index to the current transaction */
1523     transDebugInfo *cur;        /* the current transaction */
1524     vos_serverTransactionStatus_t tran[CACHED_ITEMS];   /* the cache of trans */
1525 } transaction_get_t, *transaction_get_p;
1526
1527 static int
1528 GetTransactionRPC(void *rpc_specific, int slot, int *last_item,
1529                   int *last_item_contains_data, afs_status_p st)
1530 {
1531     int rc = 0;
1532     afs_status_t tst = 0;
1533     transaction_get_p t = (transaction_get_p) rpc_specific;
1534     int index = t->index;
1535
1536     /*
1537      * Copy the next transaction into the cache
1538      */
1539
1540     t->tran[slot].transactionId = t->cur[index].tid;
1541     t->tran[slot].lastActiveTime = t->cur[index].time;
1542     t->tran[slot].creationTime = t->cur[index].creationTime;
1543     t->tran[slot].errorCode = t->cur[index].returnCode;
1544     t->tran[slot].volumeId = t->cur[index].volid;
1545     t->tran[slot].partition = t->cur[index].partition;
1546     strcpy(t->tran[slot].lastProcedureName, t->cur[index].lastProcName);
1547     t->tran[slot].nextReceivePacketSequenceNumber = t->cur[index].readNext;
1548     t->tran[slot].nextSendPacketSequenceNumber = t->cur[index].transmitNext;
1549     t->tran[slot].lastReceiveTime = t->cur[index].lastReceiveTime;
1550     t->tran[slot].lastSendTime = t->cur[index].lastSendTime;
1551
1552     t->tran[slot].volumeAttachMode = VOS_VOLUME_ATTACH_MODE_OK;
1553
1554     switch (t->cur[index].iflags) {
1555     case ITOffline:
1556         t->tran[slot].volumeAttachMode = VOS_VOLUME_ATTACH_MODE_OFFLINE;
1557         break;
1558     case ITBusy:
1559         t->tran[slot].volumeAttachMode = VOS_VOLUME_ATTACH_MODE_BUSY;
1560         break;
1561     case ITReadOnly:
1562         t->tran[slot].volumeAttachMode = VOS_VOLUME_ATTACH_MODE_READONLY;
1563         break;
1564     case ITCreate:
1565         t->tran[slot].volumeAttachMode = VOS_VOLUME_ATTACH_MODE_CREATE;
1566         break;
1567     case ITCreateVolID:
1568         t->tran[slot].volumeAttachMode = VOS_VOLUME_ATTACH_MODE_CREATE_VOLID;
1569         break;
1570     }
1571
1572     t->tran[slot].volumeActiveStatus = VOS_VOLUME_ACTIVE_STATUS_OK;
1573
1574     switch (t->cur[index].vflags) {
1575     case VTDeleteOnSalvage:
1576         t->tran[slot].volumeActiveStatus =
1577             VOS_VOLUME_ACTIVE_STATUS_DELETE_ON_SALVAGE;
1578         break;
1579     case VTOutOfService:
1580         t->tran[slot].volumeActiveStatus =
1581             VOS_VOLUME_ACTIVE_STATUS_OUT_OF_SERVICE;
1582         break;
1583     case VTDeleted:
1584         t->tran[slot].volumeActiveStatus = VOS_VOLUME_ACTIVE_STATUS_DELETED;
1585         break;
1586     }
1587
1588     t->tran[slot].volumeTransactionStatus = VOS_VOLUME_TRANSACTION_STATUS_OK;
1589
1590     if (t->cur[index].tflags) {
1591         t->tran[slot].volumeTransactionStatus =
1592             VOS_VOLUME_TRANSACTION_STATUS_DELETED;
1593     }
1594     t->index++;
1595
1596
1597     /*
1598      * See if we've processed all the entries
1599      */
1600
1601
1602     if (t->index == t->total) {
1603         *last_item = 1;
1604         *last_item_contains_data = 1;
1605     }
1606     rc = 1;
1607
1608     if (st != NULL) {
1609         *st = tst;
1610     }
1611     return rc;
1612 }
1613
1614 static int
1615 GetTransactionFromCache(void *rpc_specific, int slot, void *dest,
1616                         afs_status_p st)
1617 {
1618     int rc = 0;
1619     afs_status_t tst = 0;
1620     transaction_get_p tran = (transaction_get_p) rpc_specific;
1621
1622     memcpy(dest, (const void *)&tran->tran[slot],
1623            sizeof(vos_serverTransactionStatus_p));
1624     rc = 1;
1625
1626     if (st != NULL) {
1627         *st = tst;
1628     }
1629     return rc;
1630 }
1631
1632
1633 static int
1634 DestroyTransaction(void *rpc_specific, afs_status_p st)
1635 {
1636     int rc = 0;
1637     afs_status_t tst = 0;
1638     transaction_get_p tran = (transaction_get_p) rpc_specific;
1639
1640     if (tran->cur != NULL) {
1641         free(tran->cur);
1642     }
1643     rc = 1;
1644
1645     if (st != NULL) {
1646         *st = tst;
1647     }
1648     return rc;
1649 }
1650
1651 /*
1652  * vos_ServerTransactionStatusGetBegin - begin to iterate over the transactions
1653  * at a volume server.
1654  *
1655  * PARAMETERS
1656  *
1657  * IN cellHandle - a previously opened cellHandle that corresponds
1658  * to the cell where the volume server exists.
1659  *
1660  * IN serverHandle - a handle to the server to query.
1661  *
1662  * IN callBack - a call back function pointer that may be called to report
1663  * status information.  Can be null.
1664  *
1665  * OUT iterationIdP - upon successful completion, contains an iterator that
1666  * can be passed to vos_ServerTransactionStatusGetNext.
1667  *
1668  * LOCKS
1669  * 
1670  * No locks are obtained or released by this function
1671  *
1672  * RETURN CODES
1673  *
1674  * Returns != 0 upon successful completion.
1675  */
1676
1677 int ADMINAPI
1678 vos_ServerTransactionStatusGetBegin(const void *cellHandle,
1679                                     const void *serverHandle,
1680                                     vos_MessageCallBack_t callBack,
1681                                     void **iterationIdP, afs_status_p st)
1682 {
1683     int rc = 0;
1684     afs_status_t tst = 0;
1685     file_server_p f_server = (file_server_p) serverHandle;
1686     afs_admin_iterator_p iter =
1687         (afs_admin_iterator_p) malloc(sizeof(afs_admin_iterator_t));
1688     transaction_get_p tran =
1689         (transaction_get_p) calloc(1, sizeof(transaction_get_t));
1690
1691
1692     /*
1693      * Validate arguments
1694      */
1695
1696     if (!IsValidServerHandle(f_server, &tst)) {
1697         goto fail_vos_ServerTransactionStatusGetBegin;
1698     }
1699
1700     if (iterationIdP == NULL) {
1701         goto fail_vos_ServerTransactionStatusGetBegin;
1702     }
1703
1704     if ((iter == NULL) || (tran == NULL)) {
1705         tst = ADMNOMEM;
1706         goto fail_vos_ServerTransactionStatusGetBegin;
1707     }
1708
1709     /*
1710      * Fill in the tran structure
1711      */
1712
1713     if (!UV_VolserStatus(f_server->serv, &tran->cur, &tran->total, &tst)) {
1714         goto fail_vos_ServerTransactionStatusGetBegin;
1715     }
1716
1717     if (tran->total == 0) {
1718         if (!IteratorInit(iter, (void *)tran, NULL, NULL, NULL, NULL, &tst)) {
1719             goto fail_vos_ServerTransactionStatusGetBegin;
1720         }
1721         iter->done_iterating = 1;
1722         iter->st = ADMITERATORDONE;
1723     } else {
1724         if (!IteratorInit
1725             (iter, (void *)tran, GetTransactionRPC, GetTransactionFromCache,
1726              NULL, DestroyTransaction, &tst)) {
1727             goto fail_vos_ServerTransactionStatusGetBegin;
1728         }
1729     }
1730     *iterationIdP = (void *)iter;
1731     rc = 1;
1732
1733   fail_vos_ServerTransactionStatusGetBegin:
1734
1735     if (rc == 0) {
1736         if (iter != NULL) {
1737             free(iter);
1738         }
1739         if (tran != NULL) {
1740             if (tran->cur != NULL) {
1741                 free(tran->cur);
1742             }
1743             free(tran);
1744         }
1745     }
1746
1747     if (st != NULL) {
1748         *st = tst;
1749     }
1750     return rc;
1751 }
1752
1753 /*
1754  * vos_ServerTransactionStatusGetNext - get information about the next 
1755  * active transaction.
1756  *
1757  * PARAMETERS
1758  *
1759  * IN iterationId - an iterator previously returned by
1760  * vos_ServerTransactionStatusGetBegin
1761  *
1762  * OUT serverTransactionStatusP - a pointer to a vos_serverTransactionStatus_p
1763  * that upon successful completion contains information about the
1764  * next transaction.
1765  *
1766  * LOCKS
1767  * 
1768  * The iterator is locked while the next item is retrieved.
1769  *
1770  * RETURN CODES
1771  *
1772  * Returns != 0 upon successful completion.
1773  */
1774
1775 int ADMINAPI
1776 vos_ServerTransactionStatusGetNext(const void *iterationId,
1777                                    vos_serverTransactionStatus_p
1778                                    serverTransactionStatusP, afs_status_p st)
1779 {
1780     int rc = 0;
1781     afs_status_t tst = 0;
1782     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
1783
1784     if (iter == NULL) {
1785         tst = ADMITERATORNULL;
1786         goto fail_vos_ServerTransactionStatusGetNext;
1787     }
1788
1789     if (serverTransactionStatusP == NULL) {
1790         tst = ADMVOSSERVERTRANSACTIONSTATUSPNULL;
1791         goto fail_vos_ServerTransactionStatusGetNext;
1792     }
1793
1794     rc = IteratorNext(iter, (void *)serverTransactionStatusP, &tst);
1795
1796   fail_vos_ServerTransactionStatusGetNext:
1797
1798     if (st != NULL) {
1799         *st = tst;
1800     }
1801     return rc;
1802 }
1803
1804 /*
1805  * vos_ServerTransactionStatusGetDone - finish using a transaction iterator.
1806  *
1807  * PARAMETERS
1808  *
1809  * IN iterationId - an iterator previously returned by
1810  * vos_ServerTransactionStatusGetBegin
1811  *
1812  * LOCKS
1813  * 
1814  * The iterator is locked and then destroyed.
1815  *
1816  * RETURN CODES
1817  *
1818  * Returns != 0 upon successful completion.
1819  */
1820
1821 int ADMINAPI
1822 vos_ServerTransactionStatusGetDone(const void *iterationId, afs_status_p st)
1823 {
1824     int rc = 0;
1825     afs_status_t tst = 0;
1826     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
1827
1828     /*
1829      * Validate arguments
1830      */
1831
1832     if (iter == NULL) {
1833         tst = ADMITERATORNULL;
1834         goto fail_vos_ServerTransactionStatusGetDone;
1835     }
1836
1837     rc = IteratorDone(iter, &tst);
1838
1839   fail_vos_ServerTransactionStatusGetDone:
1840
1841     if (st != NULL) {
1842         *st = tst;
1843     }
1844     return rc;
1845 }
1846
1847 static int
1848 copyVLDBEntry(struct nvldbentry *source, vos_vldbEntry_p dest,
1849               afs_status_p st)
1850 {
1851     int rc = 0;
1852     afs_status_t tst = 0;
1853     int i;
1854
1855     dest->numServers = source->nServers;
1856     for (i = 0; i < VOS_MAX_VOLUME_TYPES; i++) {
1857         dest->volumeId[i] = source->volumeId[i];
1858     }
1859     dest->cloneId = source->cloneId;
1860     dest->status = VOS_VLDB_ENTRY_OK;
1861     if (source->flags & VLOP_ALLOPERS) {
1862         dest->status |= VOS_VLDB_ENTRY_LOCKED;
1863     } else {
1864         if (source->flags & VLOP_MOVE) {
1865             dest->status |= VOS_VLDB_ENTRY_MOVE;
1866         }
1867         if (source->flags & VLOP_RELEASE) {
1868             dest->status |= VOS_VLDB_ENTRY_RELEASE;
1869         }
1870         if (source->flags & VLOP_BACKUP) {
1871             dest->status |= VOS_VLDB_ENTRY_BACKUP;
1872         }
1873         if (source->flags & VLOP_DELETE) {
1874             dest->status |= VOS_VLDB_ENTRY_DELETE;
1875         }
1876         if (source->flags & VLOP_DUMP) {
1877             dest->status |= VOS_VLDB_ENTRY_DUMP;
1878         }
1879     }
1880     if (source->flags & VLF_RWEXISTS) {
1881         dest->status |= VOS_VLDB_ENTRY_RWEXISTS;
1882     }
1883     if (source->flags & VLF_ROEXISTS) {
1884         dest->status |= VOS_VLDB_ENTRY_ROEXISTS;
1885     }
1886     if (source->flags & VLF_BACKEXISTS) {
1887         dest->status |= VOS_VLDB_ENTRY_BACKEXISTS;
1888     }
1889
1890     strncpy(dest->name, source->name, VOS_MAX_VOLUME_NAME_LEN);
1891     dest->name[VOS_MAX_VOLUME_NAME_LEN - 1] = '\0';
1892     for (i = 0; i < VOS_MAX_REPLICA_SITES; i++) {
1893         dest->volumeSites[i].serverAddress = source->serverNumber[i];
1894         dest->volumeSites[i].serverPartition = source->serverPartition[i];
1895         dest->volumeSites[i].serverFlags = 0;
1896
1897         if (source->serverFlags[i] & NEW_REPSITE) {
1898             dest->volumeSites[i].serverFlags |= VOS_VLDB_NEW_REPSITE;
1899         }
1900         if (source->serverFlags[i] & ITSROVOL) {
1901             dest->volumeSites[i].serverFlags |= VOS_VLDB_READ_ONLY;
1902         }
1903         if (source->serverFlags[i] & ITSRWVOL) {
1904             dest->volumeSites[i].serverFlags |= VOS_VLDB_READ_WRITE;
1905         }
1906         if (source->serverFlags[i] & ITSBACKVOL) {
1907             dest->volumeSites[i].serverFlags |= VOS_VLDB_BACKUP;
1908         }
1909         if (source->serverFlags[i] & RO_DONTUSE) {
1910             dest->volumeSites[i].serverFlags |= VOS_VLDB_DONT_USE;
1911         }
1912
1913     }
1914
1915     rc = 1;
1916     if (st != NULL) {
1917         *st = tst;
1918     }
1919     return rc;
1920 }
1921
1922 /*
1923  * vos_VLDBGet- get a volume's vldb entry.
1924  *
1925  * PARAMETERS
1926  *
1927  * IN cellHandle - a previously opened cellHandle that corresponds
1928  * to the cell where the volume entries exist.
1929  *
1930  * IN callBack - a call back function pointer that may be called to report
1931  * status information.  Can be null.
1932  *
1933  * IN volumeId - the id of the volume to retrieve.
1934  *
1935  * IN volumeName - the name of the volume to retrieve.
1936  *
1937  * OUT vldbEntry - upon successful completion, contains the information regarding
1938  * the volume.
1939  *
1940  * LOCKS
1941  * 
1942  * No locks are obtained or released by this function
1943  *
1944  * RETURN CODES
1945  *
1946  * Returns != 0 upon successful completion.
1947  */
1948
1949 int ADMINAPI
1950 vos_VLDBGet(const void *cellHandle, vos_MessageCallBack_t callBack,
1951             const unsigned int *volumeId, const char *volumeName,
1952             vos_vldbEntry_p vldbEntry, afs_status_p st)
1953 {
1954     int rc = 0;
1955     afs_status_t tst = 0;
1956     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
1957     struct nvldbentry entry;
1958
1959
1960     /*
1961      * Validate arguments
1962      */
1963
1964     if (!IsValidCellHandle(c_handle, &tst)) {
1965         goto fail_vos_VLDBGet;
1966     }
1967
1968     if (vldbEntry == NULL) {
1969         tst = ADMVOSVLDBENTRYNULL;
1970         goto fail_vos_VLDBGet;
1971     }
1972
1973     if (((volumeName == NULL) || (*volumeName == 0)) && (volumeId == NULL)) {
1974         tst = ADMVOSVOLUMENAMEANDVOLUMEIDNULL;
1975         goto fail_vos_VLDBGet;
1976     }
1977
1978     /*
1979      * Retrieve the entry
1980      */
1981
1982     if (!((volumeName == NULL) || (*volumeName == 0))) {
1983         if (!ValidateVolumeName(volumeName, &tst)) {
1984             goto fail_vos_VLDBGet;
1985         }
1986         if (!aVLDB_GetEntryByName(c_handle, volumeName, &entry, &tst)) {
1987             goto fail_vos_VLDBGet;
1988         }
1989     } else {
1990         if (!aVLDB_GetEntryByID(c_handle, *volumeId, -1, &entry, &tst)) {
1991             goto fail_vos_VLDBGet;
1992         }
1993     }
1994
1995     /*
1996      * Copy the entry into our structure
1997      */
1998
1999     if (!copyVLDBEntry(&entry, vldbEntry, &tst)) {
2000         goto fail_vos_VLDBGet;
2001     }
2002     rc = 1;
2003
2004   fail_vos_VLDBGet:
2005
2006     if (st != NULL) {
2007         *st = tst;
2008     }
2009     return rc;
2010 }
2011
2012 /*
2013  * The iterator functions and data for the vldb entry retrieval functions.
2014  */
2015
2016 typedef struct vldb_entry_get {
2017     afs_int32 total;            /* total number of vldb entries */
2018     afs_int32 index;            /* index to the current vldb entry */
2019     nbulkentries entries;       /* the list of entries retrieved */
2020     vos_vldbEntry_t entry[CACHED_ITEMS];        /* the cache of entries */
2021 } vldb_entry_get_t, *vldb_entry_get_p;
2022
2023 static int
2024 GetVLDBEntryRPC(void *rpc_specific, int slot, int *last_item,
2025                 int *last_item_contains_data, afs_status_p st)
2026 {
2027     int rc = 0;
2028     afs_status_t tst = 0;
2029     vldb_entry_get_p entry = (vldb_entry_get_p) rpc_specific;
2030
2031     /*
2032      * Copy the next entry into the cache
2033      */
2034
2035     if (!copyVLDBEntry
2036         (&entry->entries.nbulkentries_val[entry->index], &entry->entry[slot],
2037          &tst)) {
2038         goto fail_GetVLDBEntryRPC;
2039     }
2040     entry->index++;
2041
2042     /*
2043      * See if we've processed all the entries
2044      */
2045
2046
2047     if (entry->index == entry->total) {
2048         *last_item = 1;
2049         *last_item_contains_data = 1;
2050     }
2051     rc = 1;
2052
2053   fail_GetVLDBEntryRPC:
2054
2055     if (st != NULL) {
2056         *st = tst;
2057     }
2058     return rc;
2059 }
2060
2061 static int
2062 GetVLDBEntryFromCache(void *rpc_specific, int slot, void *dest,
2063                       afs_status_p st)
2064 {
2065     int rc = 0;
2066     afs_status_t tst = 0;
2067     vldb_entry_get_p entry = (vldb_entry_get_p) rpc_specific;
2068
2069     memcpy(dest, (const void *)&entry->entry[slot], sizeof(vos_vldbEntry_t));
2070     rc = 1;
2071
2072     if (st != NULL) {
2073         *st = tst;
2074     }
2075     return rc;
2076 }
2077
2078
2079 static int
2080 DestroyVLDBEntry(void *rpc_specific, afs_status_p st)
2081 {
2082     int rc = 0;
2083     afs_status_t tst = 0;
2084     vldb_entry_get_p entry = (vldb_entry_get_p) rpc_specific;
2085
2086     if (entry->entries.nbulkentries_val != NULL) {
2087         free(entry->entries.nbulkentries_val);
2088     }
2089     rc = 1;
2090
2091     if (st != NULL) {
2092         *st = tst;
2093     }
2094     return rc;
2095 }
2096
2097
2098 /*
2099  * vos_VLDBGetBegin - begin to iterate over the VLDB.
2100  *
2101  * PARAMETERS
2102  *
2103  * IN cellHandle - a previously opened cellHandle that corresponds
2104  * to the cell where the volume entries exist.
2105  *
2106  * IN serverHandle - a handle to the server whose entries should be listed.
2107  * Can be null.
2108  *
2109  * IN callBack - a call back function pointer that may be called to report
2110  * status information.  Can be null.
2111  *
2112  * IN partition - the partition whose entries should be listed.
2113  * Can be null.
2114  *
2115  * OUT iterationIdP - upon successful completion, contains an iterator that
2116  * can be passed to vos_VLDBGetNext.
2117  *
2118  * LOCKS
2119  * 
2120  * No locks are obtained or released by this function
2121  *
2122  * RETURN CODES
2123  *
2124  * Returns != 0 upon successful completion.
2125  */
2126
2127 int ADMINAPI
2128 vos_VLDBGetBegin(const void *cellHandle, const void *serverHandle,
2129                  vos_MessageCallBack_t callBack, unsigned int *partition,
2130                  void **iterationIdP, afs_status_p st)
2131 {
2132     int rc = 0;
2133     afs_status_t tst = 0;
2134     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2135     file_server_p f_server = (file_server_p) serverHandle;
2136     afs_admin_iterator_p iter =
2137         (afs_admin_iterator_p) malloc(sizeof(afs_admin_iterator_t));
2138     vldb_entry_get_p entry =
2139         (vldb_entry_get_p) calloc(1, sizeof(vldb_entry_get_t));
2140     struct VldbListByAttributes attr;
2141
2142     attr.Mask = 0;
2143     memset(&attr, 0, sizeof(attr));
2144
2145     /*
2146      * Validate arguments
2147      */
2148
2149     if (!IsValidCellHandle(c_handle, &tst)) {
2150         goto fail_vos_VLDBGetBegin;
2151     }
2152
2153     if ((iter == NULL) || (entry == NULL)) {
2154         tst = ADMNOMEM;
2155         goto fail_vos_VLDBGetBegin;
2156     }
2157
2158     if (f_server != NULL) {
2159         if (!IsValidServerHandle(f_server, &tst)) {
2160             goto fail_vos_VLDBGetBegin;
2161         }
2162         attr.server = ntohl(rx_HostOf(rx_PeerOf(f_server->serv)));
2163         attr.Mask |= VLLIST_SERVER;
2164     }
2165
2166     if (partition != NULL) {
2167         if (*partition > VOLMAXPARTS) {
2168             tst = ADMVOSPARTITIONTOOLARGE;
2169             goto fail_vos_VLDBGetBegin;
2170         }
2171         attr.partition = *partition;
2172         attr.Mask |= VLLIST_PARTITION;
2173     }
2174
2175     if (!VLDB_ListAttributes
2176         (c_handle, &attr, &entry->total, &entry->entries, &tst)) {
2177         goto fail_vos_VLDBGetBegin;
2178     }
2179
2180     if (entry->total <= 0) {
2181         if (!IteratorInit(iter, (void *)entry, NULL, NULL, NULL, NULL, &tst)) {
2182             goto fail_vos_VLDBGetBegin;
2183         }
2184         iter->done_iterating = 1;
2185         iter->st = ADMITERATORDONE;
2186     } else {
2187         if (!IteratorInit
2188             (iter, (void *)entry, GetVLDBEntryRPC, GetVLDBEntryFromCache,
2189              NULL, DestroyVLDBEntry, &tst)) {
2190             goto fail_vos_VLDBGetBegin;
2191         }
2192     }
2193     *iterationIdP = (void *)iter;
2194     rc = 1;
2195
2196   fail_vos_VLDBGetBegin:
2197
2198     if (rc == 0) {
2199         if (iter != NULL) {
2200             free(iter);
2201         }
2202         if (entry->entries.nbulkentries_val != NULL) {
2203             free(entry->entries.nbulkentries_val);
2204         }
2205         if (entry != NULL) {
2206             free(entry);
2207         }
2208     }
2209
2210     if (st != NULL) {
2211         *st = tst;
2212     }
2213     return rc;
2214 }
2215
2216 /*
2217  * vos_VLDBGetNext - get information about the next volume.
2218  *
2219  * PARAMETERS
2220  *
2221  * IN iterationId - an iterator previously returned by
2222  * vos_VLDBGetBegin
2223  *
2224  * OUT vldbEntry - a pointer to a vos_vldbEntry_t
2225  * that upon successful completion contains information about the
2226  * next volume.
2227  *
2228  * LOCKS
2229  * 
2230  * The iterator is locked while the next item is retrieved.
2231  *
2232  * RETURN CODES
2233  *
2234  * Returns != 0 upon successful completion.
2235  */
2236
2237 int ADMINAPI
2238 vos_VLDBGetNext(const void *iterationId, vos_vldbEntry_p vldbEntry,
2239                 afs_status_p st)
2240 {
2241     int rc = 0;
2242     afs_status_t tst = 0;
2243     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
2244
2245     if (iter == NULL) {
2246         tst = ADMITERATORNULL;
2247         goto fail_vos_VLDBGetNext;
2248     }
2249
2250     if (vldbEntry == NULL) {
2251         tst = ADMVOSVLDBENTRYNULL;
2252         goto fail_vos_VLDBGetNext;
2253     }
2254
2255     rc = IteratorNext(iter, (void *)vldbEntry, &tst);
2256
2257   fail_vos_VLDBGetNext:
2258
2259     if (st != NULL) {
2260         *st = tst;
2261     }
2262     return rc;
2263 }
2264
2265 /*
2266  * vos_VLDBGetDone - finish using a volume iterator.
2267  *
2268  * PARAMETERS
2269  *
2270  * IN iterationId - an iterator previously returned by vos_VLDBGetBegin
2271  *
2272  * LOCKS
2273  * 
2274  * The iterator is locked and then destroyed.
2275  *
2276  * RETURN CODES
2277  *
2278  * Returns != 0 upon successful completion.
2279  */
2280
2281 int ADMINAPI
2282 vos_VLDBGetDone(const void *iterationId, afs_status_p st)
2283 {
2284     int rc = 0;
2285     afs_status_t tst = 0;
2286     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
2287
2288     /*
2289      * Validate arguments
2290      */
2291
2292     if (iter == NULL) {
2293         tst = ADMITERATORNULL;
2294         goto fail_vos_VLDBGetDone;
2295     }
2296
2297     rc = IteratorDone(iter, &tst);
2298
2299   fail_vos_VLDBGetDone:
2300
2301     if (st != NULL) {
2302         *st = tst;
2303     }
2304     return rc;
2305 }
2306
2307 /*
2308  * vos_VLDBEntryRemove - remove a vldb entry.
2309  *
2310  * PARAMETERS
2311  *
2312  * IN cellHandle - a previously opened cellHandle that corresponds
2313  * to the cell where the vldb entry exists.
2314  *
2315  * IN serverHandle - a previously opened serverHandle that corresponds
2316  * to the server where the vldb entry exists.  Can be null.
2317  *
2318  * IN callBack - a call back function pointer that may be called to report
2319  * status information.  Can be null.
2320  *
2321  * IN partition - the partition where the vldb entry exists.  Can be null.
2322  *
2323  * IN volumeId - the volume id of the vldb entry to be deleted. Can be null.
2324  *
2325  * LOCKS
2326  * 
2327  * No locks are obtained or released by this function
2328  *
2329  * RETURN CODES
2330  *
2331  * Returns != 0 upon successful completion.
2332  */
2333
2334 int ADMINAPI
2335 vos_VLDBEntryRemove(const void *cellHandle, const void *serverHandle,
2336                     vos_MessageCallBack_t callBack,
2337                     const unsigned int *partition, unsigned int *volumeId,
2338                     afs_status_p st)
2339 {
2340     int rc = 0;
2341     afs_status_t tst = 0;
2342     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2343     file_server_p f_server = (file_server_p) serverHandle;
2344     struct VldbListByAttributes attr;
2345     nbulkentries entries;
2346     afs_int32 nentries;
2347     int i;
2348
2349     memset(&attr, 0, sizeof(attr));
2350     memset(&entries, 0, sizeof(entries));
2351
2352     /*
2353      * Validate arguments
2354      */
2355
2356     if (!IsValidCellHandle(c_handle, &tst)) {
2357         goto fail_vos_VLDBEntryRemove;
2358     }
2359
2360     /*
2361      * If the volume is specified, just delete it
2362      */
2363
2364     if (volumeId != NULL) {
2365         tst = ubik_VL_DeleteEntry(c_handle->vos, 0, *volumeId, -1);
2366         if (tst != 0) {
2367             goto fail_vos_VLDBEntryRemove;
2368         }
2369     }
2370
2371     if (f_server != NULL) {
2372         if (!IsValidServerHandle(f_server, &tst)) {
2373             goto fail_vos_VLDBEntryRemove;
2374         }
2375         attr.server = ntohl(rx_HostOf(rx_PeerOf(f_server->serv)));
2376         attr.Mask |= VLLIST_SERVER;
2377     }
2378
2379     if (partition != NULL) {
2380         if (*partition > VOLMAXPARTS) {
2381             tst = ADMVOSPARTITIONTOOLARGE;
2382             goto fail_vos_VLDBEntryRemove;
2383         }
2384         attr.partition = *partition;
2385         attr.Mask |= VLLIST_PARTITION;
2386     }
2387
2388     if ((f_server == NULL) && (partition == NULL)) {
2389         tst = ADMVOSVLDBDELETEALLNULL;
2390         goto fail_vos_VLDBEntryRemove;
2391     }
2392
2393     if (!VLDB_ListAttributes(c_handle, &attr, &nentries, &entries, &tst)) {
2394         goto fail_vos_VLDBEntryRemove;
2395     }
2396
2397     if (nentries <= 0) {
2398         tst = ADMVOSVLDBNOENTRIES;
2399         goto fail_vos_VLDBEntryRemove;
2400     }
2401
2402     for (i = 0; i < nentries; i++) {
2403         ubik_VL_DeleteEntry(c_handle->vos, 0,
2404                   entries.nbulkentries_val[i].volumeId[RWVOL], -1);
2405     }
2406     rc = 1;
2407
2408   fail_vos_VLDBEntryRemove:
2409
2410     if (entries.nbulkentries_val) {
2411         free(entries.nbulkentries_val);
2412     }
2413
2414     if (st != NULL) {
2415         *st = tst;
2416     }
2417     return rc;
2418 }
2419
2420 /*
2421  * vos_VLDBUnlock - unlock vldb entries en masse.
2422  *
2423  * PARAMETERS
2424  *
2425  * IN cellHandle - a previously opened cellHandle that corresponds
2426  * to the cell where the vldb entries exist.
2427  *
2428  * IN serverHandle - a previously opened serverHandle that corresponds
2429  * to the server where the vldb entries exist.  Can be null.
2430  *
2431  * IN callBack - a call back function pointer that may be called to report
2432  * status information.  Can be null.
2433  *
2434  * IN partition - the partition where the vldb entries exist.  Can be null.
2435  *
2436  * LOCKS
2437  * 
2438  * No locks are obtained or released by this function
2439  *
2440  * RETURN CODES
2441  *
2442  * Returns != 0 upon successful completion.
2443  */
2444
2445 int ADMINAPI
2446 vos_VLDBUnlock(const void *cellHandle, const void *serverHandle,
2447                vos_MessageCallBack_t callBack, const unsigned int *partition,
2448                afs_status_p st)
2449 {
2450     int rc = 0;
2451     afs_status_t tst = 0;
2452     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2453     file_server_p f_server = (file_server_p) serverHandle;
2454     struct VldbListByAttributes attr;
2455     nbulkentries entries;
2456     afs_int32 nentries;
2457     int i;
2458
2459     memset(&attr, 0, sizeof(attr));
2460     memset(&entries, 0, sizeof(entries));
2461
2462     /*
2463      * Validate arguments
2464      */
2465
2466     if (!IsValidCellHandle(c_handle, &tst)) {
2467         goto fail_vos_VLDBUnlock;
2468     }
2469
2470     if (f_server != NULL) {
2471         if (!IsValidServerHandle(f_server, &tst)) {
2472             goto fail_vos_VLDBUnlock;
2473         }
2474         attr.server = ntohl(rx_HostOf(rx_PeerOf(f_server->serv)));
2475         attr.Mask |= VLLIST_SERVER;
2476     }
2477
2478     if (partition != NULL) {
2479         if (*partition > VOLMAXPARTS) {
2480             tst = ADMVOSPARTITIONTOOLARGE;
2481             goto fail_vos_VLDBUnlock;
2482         }
2483         attr.partition = *partition;
2484         attr.Mask |= VLLIST_PARTITION;
2485     }
2486     attr.flag = VLOP_ALLOPERS;
2487     attr.Mask |= VLLIST_FLAG;
2488
2489
2490     if (!VLDB_ListAttributes(c_handle, &attr, &nentries, &entries, &tst)) {
2491         goto fail_vos_VLDBUnlock;
2492     }
2493
2494     if (nentries <= 0) {
2495         tst = ADMVOSVLDBNOENTRIES;
2496         goto fail_vos_VLDBUnlock;
2497     }
2498
2499     for (i = 0; i < nentries; i++) {
2500         vos_VLDBEntryUnlock(cellHandle, 0,
2501                             entries.nbulkentries_val[i].volumeId[RWVOL],
2502                             &tst);
2503     }
2504     rc = 1;
2505
2506   fail_vos_VLDBUnlock:
2507
2508     if (entries.nbulkentries_val) {
2509         free(entries.nbulkentries_val);
2510     }
2511
2512     if (st != NULL) {
2513         *st = tst;
2514     }
2515     return rc;
2516 }
2517
2518
2519 /*
2520  * vos_VLDBEntryLock - lock a vldb entry.
2521  *
2522  * PARAMETERS
2523  *
2524  * IN cellHandle - a previously opened cellHandle that corresponds
2525  * to the cell where the vldb entry exists.
2526  *
2527  * IN callBack - a call back function pointer that may be called to report
2528  * status information.  Can be null.
2529  *
2530  * IN volumeId - the volume id of the vldb entry to be deleted.
2531  *
2532  * LOCKS
2533  * 
2534  * No locks are obtained or released by this function
2535  *
2536  * RETURN CODES
2537  *
2538  * Returns != 0 upon successful completion.
2539  */
2540
2541 int ADMINAPI
2542 vos_VLDBEntryLock(const void *cellHandle, vos_MessageCallBack_t callBack,
2543                   unsigned int volumeId, afs_status_p st)
2544 {
2545     int rc = 0;
2546     afs_status_t tst = 0;
2547     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2548
2549     /*
2550      * Validate arguments
2551      */
2552
2553     if (!IsValidCellHandle(c_handle, &tst)) {
2554         goto fail_vos_VLDBEntryLock;
2555     }
2556
2557     tst = ubik_VL_SetLock(c_handle->vos, 0, volumeId, -1, VLOP_DELETE);
2558     if (tst != 0) {
2559         goto fail_vos_VLDBEntryLock;
2560     }
2561     rc = 1;
2562
2563   fail_vos_VLDBEntryLock:
2564
2565     if (st != NULL) {
2566         *st = tst;
2567     }
2568     return rc;
2569 }
2570
2571 /*
2572  * vos_VLDBEntryUnlock - unlock a vldb entry.
2573  *
2574  * PARAMETERS
2575  *
2576  * IN cellHandle - a previously opened cellHandle that corresponds
2577  * to the cell where the vldb entry exists.
2578  *
2579  * IN callBack - a call back function pointer that may be called to report
2580  * status information.  Can be null.
2581  *
2582  * IN volumeId - the volume id of the vldb entry to be unlocked.
2583  *
2584  * LOCKS
2585  * 
2586  * No locks are obtained or released by this function
2587  *
2588  * RETURN CODES
2589  *
2590  * Returns != 0 upon successful completion.
2591  */
2592
2593 int ADMINAPI
2594 vos_VLDBEntryUnlock(const void *cellHandle, vos_MessageCallBack_t callBack,
2595                     unsigned int volumeId, afs_status_p st)
2596 {
2597     int rc = 0;
2598     afs_status_t tst = 0;
2599     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2600
2601     /*
2602      * Validate arguments
2603      */
2604
2605     if (!IsValidCellHandle(c_handle, &tst)) {
2606         goto fail_vos_VLDBEntryUnlock;
2607     }
2608
2609
2610     tst =
2611         ubik_VL_ReleaseLock(c_handle->vos, 0, volumeId, -1,
2612                   LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP);
2613     if (tst != 0) {
2614         goto fail_vos_VLDBEntryUnlock;
2615     }
2616     rc = 1;
2617
2618   fail_vos_VLDBEntryUnlock:
2619
2620     if (st != NULL) {
2621         *st = tst;
2622     }
2623     return rc;
2624 }
2625
2626 /*
2627  * vos_VLDBReadOnlySiteCreate - create a readonly site for a volume.
2628  *
2629  * PARAMETERS
2630  *
2631  * IN cellHandle - a previously opened cellHandle that corresponds
2632  * to the cell where the volume exists.
2633  *
2634  * IN serverHandle - a previously opened serverHandle that corresponds
2635  * to the server where the new volume should be created.
2636  *
2637  * IN callBack - a call back function pointer that may be called to report
2638  * status information.  Can be null.
2639  *
2640  * IN partition - the partition where then new volume should be created.
2641  *
2642  * IN volumeId - the volume id of the volume to be replicated.
2643  *
2644  * LOCKS
2645  * 
2646  * No locks are obtained or released by this function
2647  *
2648  * RETURN CODES
2649  *
2650  * Returns != 0 upon successful completion.
2651  */
2652
2653 int ADMINAPI
2654 vos_VLDBReadOnlySiteCreate(const void *cellHandle, const void *serverHandle,
2655                            vos_MessageCallBack_t callBack,
2656                            unsigned int partition, unsigned int volumeId,
2657                            afs_status_p st)
2658 {
2659     int rc = 0;
2660     afs_status_t tst = 0;
2661     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2662     file_server_p f_server = (file_server_p) serverHandle;
2663
2664     /*
2665      * Validate arguments
2666      */
2667
2668     if (!IsValidCellHandle(c_handle, &tst)) {
2669         goto fail_vos_VLDBReadOnlySiteCreate;
2670     }
2671
2672     if (!IsValidServerHandle(f_server, &tst)) {
2673         goto fail_vos_VLDBReadOnlySiteCreate;
2674     }
2675
2676     if (partition > VOLMAXPARTS) {
2677         tst = ADMVOSPARTITIONTOOLARGE;
2678         goto fail_vos_VLDBReadOnlySiteCreate;
2679     }
2680
2681     if (!UV_AddSite
2682         (c_handle, ntohl(rx_HostOf(rx_PeerOf(f_server->serv))), partition,
2683          volumeId, &tst)) {
2684         goto fail_vos_VLDBReadOnlySiteCreate;
2685     }
2686     rc = 1;
2687
2688   fail_vos_VLDBReadOnlySiteCreate:
2689
2690     if (st != NULL) {
2691         *st = tst;
2692     }
2693     return rc;
2694 }
2695
2696 /*
2697  * vos_VLDBReadOnlySiteDelete - delete a replication site for a volume.
2698  *
2699  * PARAMETERS
2700  *
2701  *
2702  * IN cellHandle - a previously opened cellHandle that corresponds
2703  * to the cell where the volume exists.
2704  *
2705  * IN serverHandle - a previously opened serverHandle that corresponds
2706  * to the server where the volume should be deleted.
2707  *
2708  * IN callBack - a call back function pointer that may be called to report
2709  * status information.  Can be null.
2710  *
2711  * IN partition - the partition where then volume should be deleted.
2712  *
2713  * IN volumeId - the volume id of the volume to be deleted.
2714  *
2715  * LOCKS
2716  * 
2717  * No locks are obtained or released by this function
2718  *
2719  * RETURN CODES
2720  *
2721  * Returns != 0 upon successful completion.
2722  */
2723
2724 int ADMINAPI
2725 vos_VLDBReadOnlySiteDelete(const void *cellHandle, const void *serverHandle,
2726                            vos_MessageCallBack_t callBack,
2727                            unsigned int partition, unsigned int volumeId,
2728                            afs_status_p st)
2729 {
2730     int rc = 0;
2731     afs_status_t tst = 0;
2732     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2733     file_server_p f_server = (file_server_p) serverHandle;
2734
2735     /*
2736      * Validate arguments
2737      */
2738
2739     if (!IsValidCellHandle(c_handle, &tst)) {
2740         goto fail_vos_VLDBReadOnlySiteDelete;
2741     }
2742
2743     if (!IsValidServerHandle(f_server, &tst)) {
2744         goto fail_vos_VLDBReadOnlySiteDelete;
2745     }
2746
2747     if (partition > VOLMAXPARTS) {
2748         tst = ADMVOSPARTITIONTOOLARGE;
2749         goto fail_vos_VLDBReadOnlySiteDelete;
2750     }
2751
2752     if (!UV_RemoveSite
2753         (c_handle, ntohl(rx_HostOf(rx_PeerOf(f_server->serv))), partition,
2754          volumeId, &tst)) {
2755         goto fail_vos_VLDBReadOnlySiteDelete;
2756     }
2757     rc = 1;
2758
2759   fail_vos_VLDBReadOnlySiteDelete:
2760
2761     if (st != NULL) {
2762         *st = tst;
2763     }
2764     return rc;
2765 }
2766
2767 /*
2768  * vos_VLDBSync - synchronize the vldb with the fileserver.
2769  *
2770  * PARAMETERS
2771  *
2772  * IN cellHandle - a previously opened cellHandle that corresponds
2773  * to the cell where the sync should occur.
2774  *
2775  * IN serverHandle - a previously opened serverHandle that corresponds
2776  * to the server where the sync should occur.
2777  *
2778  * IN callBack - a call back function pointer that may be called to report
2779  * status information.  Can be null.
2780  *
2781  * IN partition - the partition where the sync should occur.  Can be null.
2782  *
2783  * IN force - force deletion of bad volumes.
2784  *
2785  * LOCKS
2786  * 
2787  * No locks are obtained or released by this function
2788  *
2789  * RETURN CODES
2790  *
2791  * Returns != 0 upon successful completion.
2792  */
2793
2794 int ADMINAPI
2795 vos_VLDBSync(const void *cellHandle, const void *serverHandle,
2796              vos_MessageCallBack_t callBack, const unsigned int *partition,
2797              vos_force_t force, afs_status_p st)
2798 {
2799     int rc = 0;
2800     afs_status_t tst = 0;
2801     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2802     file_server_p f_server = (file_server_p) serverHandle;
2803     afs_int32 part = 0;
2804     int flags = 0;
2805     int force_flag = 0;
2806
2807     /*
2808      * Validate arguments
2809      */
2810
2811     if (!IsValidCellHandle(c_handle, &tst)) {
2812         goto fail_vos_VLDBSync;
2813     }
2814
2815     if (!IsValidServerHandle(f_server, &tst)) {
2816         goto fail_vos_VLDBSync;
2817     }
2818
2819     if (partition != NULL) {
2820         if (*partition > VOLMAXPARTS) {
2821             tst = ADMVOSPARTITIONTOOLARGE;
2822             goto fail_vos_VLDBSync;
2823         }
2824         part = (afs_int32) * partition;
2825         flags = 1;
2826     }
2827
2828     if (force == VOS_FORCE) {
2829         force_flag = 1;
2830     }
2831
2832     /*
2833      * sync the vldb
2834      */
2835
2836     rc = UV_SyncVldb(c_handle, f_server->serv, part, flags, force_flag, &tst);
2837
2838   fail_vos_VLDBSync:
2839
2840     if (st != NULL) {
2841         *st = tst;
2842     }
2843     return rc;
2844 }
2845
2846 /*
2847  * vos_VolumeCreate - create a new partition.
2848  *
2849  * PARAMETERS
2850  *
2851  * IN cellHandle - a previously opened cellHandle that corresponds
2852  * to the cell where the server lives.
2853  *
2854  * IN serverHandle - a previously open vos server handle that holds
2855  * the partition where the volume should be create.
2856  *
2857  * IN callBack - a call back function pointer that may be called to report
2858  * status information.  Can be null.
2859  *
2860  * IN partition - the integer that represents the partition that will 
2861  * house the new volume.
2862  *
2863  * IN volumeName - the name of the new volume.
2864  *
2865  * IN quota - the quota of the new volume.
2866  *
2867  * OUT volumeId - the volume id of the newly created volume.
2868  *
2869  * LOCKS
2870  * 
2871  * No locks are obtained or released by this function
2872  *
2873  * RETURN CODES
2874  *
2875  * Returns != 0 upon successful completion.
2876  */
2877
2878 int ADMINAPI
2879 vos_VolumeCreate(const void *cellHandle, const void *serverHandle,
2880                  vos_MessageCallBack_t callBack, unsigned int partition,
2881                  const char *volumeName, unsigned int quota,
2882                  unsigned int *volumeId, afs_status_p st)
2883 {
2884     int rc = 0;
2885     afs_status_t tst = 0;
2886     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2887     file_server_p f_server = (file_server_p) serverHandle;
2888     vos_partitionEntry_t pinfo;
2889     struct nvldbentry vinfo;
2890
2891     /*
2892      * Validate arguments
2893      */
2894
2895     if (!IsValidCellHandle(c_handle, &tst)) {
2896         goto fail_vos_VolumeCreate;
2897     }
2898
2899     if (!IsValidServerHandle(f_server, &tst)) {
2900         goto fail_vos_VolumeCreate;
2901     }
2902
2903     if (partition > VOLMAXPARTS) {
2904         tst = ADMVOSPARTITIONTOOLARGE;
2905         goto fail_vos_VolumeCreate;
2906     }
2907
2908     if (!ValidateVolumeName(volumeName, &tst)) {
2909         goto fail_vos_VolumeCreate;
2910     }
2911
2912     if (volumeId == NULL) {
2913         tst = ADMVOSVOLUMEID;
2914         goto fail_vos_VolumeCreate;
2915     }
2916
2917     /*
2918      * Check that partition is valid at the server
2919      */
2920
2921     if (!vos_PartitionGet
2922         (cellHandle, serverHandle, 0, partition, &pinfo, &tst)) {
2923         goto fail_vos_VolumeCreate;
2924     }
2925
2926     /*
2927      * Check that the volume doesn't already exist
2928      */
2929
2930     if (aVLDB_GetEntryByName(c_handle, volumeName, &vinfo, &tst)) {
2931         tst = ADMVOSVOLUMENAMEDUP;
2932         goto fail_vos_VolumeCreate;
2933     }
2934
2935     /*
2936      * Create the new volume
2937      */
2938
2939     rc = UV_CreateVolume(c_handle, f_server->serv, partition, volumeName,
2940                          quota, volumeId, &tst);
2941
2942   fail_vos_VolumeCreate:
2943
2944     if (st != NULL) {
2945         *st = tst;
2946     }
2947     return rc;
2948 }
2949
2950 /*
2951  * vos_VolumeDelete - remove a volume.
2952  *
2953  * PARAMETERS
2954  *
2955  * IN cellHandle - a previously opened cellHandle that corresponds
2956  * to the cell where the volume exists.
2957  *
2958  * IN serverHandle - a previously opened serverHandle that corresponds
2959  * to the server where the volume exists.
2960  *
2961  * IN callBack - a call back function pointer that may be called to report
2962  * status information.  Can be null.
2963  *
2964  * IN partition - the partition where the volume exists.
2965  *
2966  * IN volumeId - the volume id of the volume to be deleted.
2967  *
2968  * LOCKS
2969  * 
2970  * No locks are obtained or released by this function
2971  *
2972  * RETURN CODES
2973  *
2974  * Returns != 0 upon successful completion.
2975  */
2976
2977 int ADMINAPI
2978 vos_VolumeDelete(const void *cellHandle, const void *serverHandle,
2979                  vos_MessageCallBack_t callBack, unsigned int partition,
2980                  unsigned int volumeId, afs_status_p st)
2981 {
2982     int rc = 0;
2983     afs_status_t tst = 0;
2984     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2985     file_server_p f_server = (file_server_p) serverHandle;
2986     vos_partitionEntry_t pinfo;
2987
2988     /*
2989      * Validate arguments
2990      */
2991
2992     if (!IsValidCellHandle(c_handle, &tst)) {
2993         goto fail_vos_VolumeDelete;
2994     }
2995
2996     if (!IsValidServerHandle(f_server, &tst)) {
2997         goto fail_vos_VolumeDelete;
2998     }
2999
3000     if (partition > VOLMAXPARTS) {
3001         tst = ADMVOSPARTITIONTOOLARGE;
3002         goto fail_vos_VolumeDelete;
3003     }
3004
3005     /*
3006      * Check that partition is valid at the server
3007      */
3008
3009     if (!vos_PartitionGet
3010         (cellHandle, serverHandle, 0, partition, &pinfo, &tst)) {
3011         goto fail_vos_VolumeDelete;
3012     }
3013
3014     rc = UV_DeleteVolume(c_handle, f_server->serv, partition, volumeId, &tst);
3015
3016   fail_vos_VolumeDelete:
3017
3018     if (st != NULL) {
3019         *st = tst;
3020     }
3021     return rc;
3022 }
3023
3024 /*
3025  * vos_VolumeRename - rename a volume.
3026  *
3027  * PARAMETERS
3028  *
3029  * IN cellHandle - a previously opened cellHandle that corresponds
3030  * to the cell where the volume exists.
3031  *
3032  * IN serverHandle - a previously opened serverHandle that corresponds
3033  * to the server where the vldb entry exists.  Can be null.
3034  *
3035  * IN callBack - a call back function pointer that may be called to report
3036  * status information.  Can be null.
3037  *
3038  * IN readWriteVolumeId - the volume id of the volume to be renamed.
3039  *
3040  * IN newVolumeName - the new name.
3041  *
3042  * LOCKS
3043  * 
3044  * No locks are obtained or released by this function
3045  *
3046  * RETURN CODES
3047  *
3048  * Returns != 0 upon successful completion.
3049  */
3050
3051 int ADMINAPI
3052 vos_VolumeRename(const void *cellHandle, vos_MessageCallBack_t callBack,
3053                  unsigned int readWriteVolumeId, const char *newVolumeName,
3054                  afs_status_p st)
3055 {
3056     int rc = 0;
3057     afs_status_t tst = 0;
3058     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
3059     struct nvldbentry entry;
3060
3061     /*
3062      * Validate arguments
3063      */
3064
3065     if (!IsValidCellHandle(c_handle, &tst)) {
3066         goto fail_vos_VolumeRename;
3067     }
3068
3069     if ((newVolumeName == NULL) || (*newVolumeName == 0)) {
3070         tst = ADMVOSNEWVOLUMENAMENULL;
3071         goto fail_vos_VolumeRename;
3072     }
3073
3074     /*
3075      * Retrieve the entry
3076      */
3077
3078     if (!aVLDB_GetEntryByID(c_handle, readWriteVolumeId, -1, &entry, &tst)) {
3079         goto fail_vos_VolumeRename;
3080     }
3081
3082     rc = UV_RenameVolume(c_handle, &entry, newVolumeName, &tst);
3083
3084   fail_vos_VolumeRename:
3085
3086     if (st != NULL) {
3087         *st = tst;
3088     }
3089     return rc;
3090 }
3091
3092 /*
3093  * vos_VolumeDump - dump a volume
3094  *
3095  * PARAMETERS
3096  *
3097  * IN cellHandle - a previously opened cellHandle that corresponds
3098  * to the cell where the volume exists.
3099  *
3100  * IN serverHandle - a previously opened serverHandle that corresponds
3101  * to the server where the volume exists.  Can be null.
3102  *
3103  * IN callBack - a call back function pointer that may be called to report
3104  * status information.  Can be null.
3105  *
3106  * IN volumeId - the volume id of the volume to be dumped.
3107  *
3108  * IN startTime - files with modification times >= this time will be dumped.
3109  *
3110  * IN dumpFile - the file to dump the volume to.
3111  *
3112  * LOCKS
3113  * 
3114  * No locks are obtained or released by this function
3115  *
3116  * RETURN CODES
3117  *
3118  * Returns != 0 upon successful completion.
3119  */
3120
3121 int ADMINAPI
3122 vos_VolumeDump(const void *cellHandle, const void *serverHandle,
3123                vos_MessageCallBack_t callBack, unsigned int *partition,
3124                unsigned int volumeId, unsigned int startTime,
3125                const char *dumpFile, afs_status_p st)
3126 {
3127     int rc = 0;
3128     afs_status_t tst = 0;
3129     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
3130     file_server_p f_server = (file_server_p) serverHandle;
3131     afs_int32 server, part, voltype;
3132     struct nvldbentry entry;
3133
3134     /*
3135      * Validate arguments
3136      */
3137
3138     if (!IsValidCellHandle(c_handle, &tst)) {
3139         goto fail_vos_VolumeDump;
3140     }
3141
3142     if (serverHandle != NULL) {
3143         if (!IsValidServerHandle(f_server, &tst)) {
3144             goto fail_vos_VolumeDump;
3145         }
3146     }
3147
3148     /*
3149      * You must specify both the serverHandle and the partition
3150      */
3151
3152     if (serverHandle || partition) {
3153         if (!serverHandle || !partition) {
3154             tst = ADMVOSSERVERANDPARTITION;
3155             goto fail_vos_VolumeDump;
3156         } else {
3157             if (*partition > VOLMAXPARTS) {
3158                 tst = ADMVOSPARTITIONTOOLARGE;
3159                 goto fail_vos_VolumeDump;
3160             }
3161             server = ntohl(rx_HostOf(rx_PeerOf(f_server->serv)));
3162             part = *partition;
3163         }
3164     } else {
3165         if (!GetVolumeInfo
3166             (c_handle, volumeId, &entry, &server, &part, &voltype, &tst)) {
3167             goto fail_vos_VolumeDump;
3168         }
3169     }
3170
3171     if ((dumpFile == NULL) || (*dumpFile == 0)) {
3172         tst = ADMVOSDUMPFILENULL;
3173         goto fail_vos_VolumeDump;
3174     }
3175
3176     rc = UV_DumpVolume(c_handle, volumeId, server, part, startTime, dumpFile,
3177                        &tst);
3178
3179   fail_vos_VolumeDump:
3180
3181     if (st != NULL) {
3182         *st = tst;
3183     }
3184     return rc;
3185 }
3186
3187 /*
3188  * vos_VolumeRestore - restore a volume from a dump
3189  *
3190  * PARAMETERS
3191  *
3192  * IN cellHandle - a previously opened cellHandle that corresponds
3193  * to the cell where the volume exists.
3194  *
3195  * IN serverHandle - a previously opened serverHandle that corresponds
3196  * to the server where the volume exists.
3197  *
3198  * IN callBack - a call back function pointer that may be called to report
3199  * status information.  Can be null.
3200  *
3201  * IN partition - the partition where the volume exists.
3202  *
3203  * IN volumeId - the volume id of the volume to be restored.
3204  *
3205  * IN volumeName - the volume name of the volume to be restored.
3206  *
3207  * IN dumpFile - the file from which to restore the volume.
3208  *
3209  * IN dumpType - the type of dump to perform.
3210  *
3211  * LOCKS
3212  * 
3213  * No locks are obtained or released by this function
3214  *
3215  * RETURN CODES
3216  *
3217  * Returns != 0 upon successful completion.
3218  */
3219
3220 int ADMINAPI
3221 vos_VolumeRestore(const void *cellHandle, const void *serverHandle,
3222                   vos_MessageCallBack_t callBack, unsigned int partition,
3223                   unsigned int *volumeId, const char *volumeName,
3224                   const char *dumpFile, vos_volumeRestoreType_t dumpType,
3225                   afs_status_p st)
3226 {
3227     int rc = 0;
3228     afs_status_t tst = 0;
3229     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
3230     file_server_p f_server = (file_server_p) serverHandle;
3231     struct nvldbentry entry;
3232     afs_int32 volid, server;
3233     int fd;
3234     struct stat status;
3235     int restoreflags = 0;
3236     afs_int32 Oserver, Opart, Otype;
3237     struct nvldbentry Oentry;
3238     int equal;
3239
3240     /*
3241      * Validate arguments
3242      */
3243
3244     if (!IsValidCellHandle(c_handle, &tst)) {
3245         goto fail_vos_VolumeRestore;
3246     }
3247
3248     if (serverHandle != NULL) {
3249         if (!IsValidServerHandle(f_server, &tst)) {
3250             goto fail_vos_VolumeRestore;
3251         }
3252     }
3253
3254     /*
3255      * Must pass volumeName
3256      */
3257
3258     if ((volumeName == NULL) || (*volumeName == 0)) {
3259         tst = ADMVOSVOLUMENAMENULL;
3260         goto fail_vos_VolumeRestore;
3261     }
3262
3263     if (!ValidateVolumeName(volumeName, &tst)) {
3264         goto fail_vos_VolumeRestore;
3265     }
3266
3267     /*
3268      * If volumeId is passed, it must be a valid volume id
3269      */
3270
3271     if (volumeId != NULL) {
3272         if (!aVLDB_GetEntryByID(c_handle, *volumeId, -1, &entry, &tst)) {
3273             goto fail_vos_VolumeRestore;
3274         }
3275         volid = *volumeId;
3276     } else {
3277         volid = 0;
3278     }
3279
3280     server = ntohl(rx_HostOf(rx_PeerOf(f_server->serv)));
3281
3282     if (partition > VOLMAXPARTS) {
3283         tst = ADMVOSPARTITIONTOOLARGE;
3284         goto fail_vos_VolumeRestore;
3285     }
3286
3287     /*
3288      * Check that dumpFile exists and can be accessed
3289      */
3290
3291     fd = open(dumpFile, 0);
3292     if ((fd < 0) || (fstat(fd, &status) < 0)) {
3293         close(fd);
3294         tst = ADMVOSDUMPFILEOPENFAIL;
3295         goto fail_vos_VolumeRestore;
3296     } else {
3297         close(fd);
3298     }
3299
3300     if (!aVLDB_GetEntryByName(c_handle, volumeName, &entry, &tst)) {
3301         restoreflags = RV_FULLRST;
3302     } else if (Lp_GetRwIndex(c_handle, &entry, 0) == -1) {
3303         restoreflags = RV_FULLRST;
3304         if (volid == 0) {
3305             volid = entry.volumeId[RWVOL];
3306         } else if ((entry.volumeId[RWVOL] != 0)
3307                    && (entry.volumeId[RWVOL] != volid)) {
3308             volid = entry.volumeId[RWVOL];
3309         }
3310     } else {
3311
3312         if (volid == 0) {
3313             volid = entry.volumeId[RWVOL];
3314         } else if ((entry.volumeId[RWVOL] != 0)
3315                    && (entry.volumeId[RWVOL] != volid)) {
3316             volid = entry.volumeId[RWVOL];
3317         }
3318
3319         /*
3320          * If the vldb says the same volume exists somewhere else
3321          * the caller must specify a full restore, not an incremental
3322          */
3323
3324         if (dumpType == VOS_RESTORE_FULL) {
3325             restoreflags = RV_FULLRST;
3326         } else {
3327
3328             /*
3329              * Check to see if the volume exists where the caller said
3330              */
3331             if (!GetVolumeInfo
3332                 (c_handle, volid, &Oentry, &Oserver, &Opart, &Otype, &tst)) {
3333                 goto fail_vos_VolumeRestore;
3334             }
3335             if (!VLDB_IsSameAddrs(c_handle, Oserver, server, &equal, &tst)) {
3336                 goto fail_vos_VolumeRestore;
3337             }
3338
3339             if (!equal) {
3340                 tst = ADMVOSRESTOREVOLEXIST;
3341                 goto fail_vos_VolumeRestore;
3342             }
3343         }
3344     }
3345
3346     rc = UV_RestoreVolume(c_handle, server, partition, volid, volumeName,
3347                           restoreflags, dumpFile, &tst);
3348
3349   fail_vos_VolumeRestore:
3350
3351     if (st != NULL) {
3352         *st = tst;
3353     }
3354     return rc;
3355 }
3356
3357 /*
3358  * vos_VolumeOnline - bring a volume online.
3359  *
3360  * PARAMETERS
3361  *
3362  * IN serverHandle - a previously opened serverHandle that corresponds
3363  * to the server where the volume exists.
3364  *
3365  * IN callBack - a call back function pointer that may be called to report
3366  * status information.  Can be null.
3367  *
3368  * IN partition - the partition where the volume exists.
3369  *
3370  * IN volumeId - the volume id of the volume to be brought online.
3371  *
3372  * LOCKS
3373  * 
3374  * No locks are obtained or released by this function
3375  *
3376  * RETURN CODES
3377  *
3378  * Returns != 0 upon successful completion.
3379  */
3380
3381 int ADMINAPI
3382 vos_VolumeOnline(const void *serverHandle, vos_MessageCallBack_t callBack,
3383                  unsigned int partition, unsigned int volumeId,
3384                  unsigned int sleepTime, vos_volumeOnlineType_t volumeStatus,
3385                  afs_status_p st)
3386 {
3387     int rc = 0;
3388     afs_status_t tst = 0;
3389     file_server_p f_server = (file_server_p) serverHandle;
3390     int up = ITOffline;
3391
3392     /*
3393      * Validate arguments
3394      */
3395
3396     if (!IsValidServerHandle(f_server, &tst)) {
3397         goto fail_vos_VolumeOnline;
3398     }
3399
3400     if (partition > VOLMAXPARTS) {
3401         tst = ADMVOSPARTITIONIDTOOLARGE;
3402         goto fail_vos_VolumeOnline;
3403     }
3404
3405     if (volumeStatus == VOS_ONLINE_BUSY) {
3406         up = ITBusy;
3407     }
3408
3409     rc = UV_SetVolume(f_server->serv, partition, volumeId, up, 0, sleepTime,
3410                       &tst);
3411
3412   fail_vos_VolumeOnline:
3413
3414     if (st != NULL) {
3415         *st = tst;
3416     }
3417     return rc;
3418 }
3419
3420 /*
3421  * vos_VolumeOffline - take a volume offline.
3422  *
3423  * PARAMETERS
3424  *
3425  * IN serverHandle - a previously opened serverHandle that corresponds
3426  * to the server where the volume exists.
3427  *
3428  * IN callBack - a call back function pointer that may be called to report
3429  * status information.  Can be null.
3430  *
3431  * IN partition - the partition where the volume exists.
3432  *
3433  * IN volumeId - the volume id of the volume to be taken offline.
3434  *
3435  * LOCKS
3436  * 
3437  * No locks are obtained or released by this function
3438  *
3439  * RETURN CODES
3440  *
3441  * Returns != 0 upon successful completion.
3442  */
3443
3444 int ADMINAPI
3445 vos_VolumeOffline(const void *serverHandle, vos_MessageCallBack_t callBack,
3446                   unsigned int partition, unsigned int volumeId,
3447                   afs_status_p st)
3448 {
3449     int rc = 0;
3450     afs_status_t tst = 0;
3451     file_server_p f_server = (file_server_p) serverHandle;
3452
3453     /*
3454      * Validate arguments
3455      */
3456
3457     if (!IsValidServerHandle(f_server, &tst)) {
3458         goto fail_vos_VolumeOffline;
3459     }
3460
3461     if (partition > VOLMAXPARTS) {
3462         tst = ADMVOSPARTITIONIDTOOLARGE;
3463         goto fail_vos_VolumeOffline;
3464     }
3465
3466     rc = UV_SetVolume(f_server->serv, partition, volumeId, ITOffline,
3467                       VTOutOfService, 0, &tst);
3468
3469   fail_vos_VolumeOffline:
3470
3471     if (st != NULL) {
3472         *st = tst;
3473     }
3474     return rc;
3475 }
3476
3477 /*
3478  * copyvolintXInfo - copy a struct volintXInfo to a vos_volumeEntry_p.
3479  *
3480  * PARAMETERS
3481  *
3482  * IN source - the volintXInfo structure to copy.
3483  *
3484  * OUT dest - the vos_volumeEntry_t to fill
3485  *
3486  * LOCKS
3487  * 
3488  * No locks are obtained or released by this function
3489  *
3490  * RETURN CODES
3491  *
3492  * Returns != 0 upon successful completion.
3493  */
3494
3495 static int
3496 copyvolintXInfo(struct volintXInfo *source, vos_volumeEntry_p dest,
3497                 afs_status_p st)
3498 {
3499     int rc = 0;
3500     afs_status_t tst = 0;
3501     int i;
3502
3503     /*
3504      * If the volume is not marked OK, all the other fields are invalid
3505      * We take the extra step of blanking out dest here to prevent the
3506      * user from seeing stale data from a previous call
3507      */
3508
3509     memset(dest, 0, sizeof(dest));
3510
3511     switch (source->status) {
3512     case VOK:
3513         dest->status = VOS_OK;
3514         break;
3515     case VSALVAGE:
3516         dest->status = VOS_SALVAGE;
3517         break;
3518     case VNOVNODE:
3519         dest->status = VOS_NO_VNODE;
3520         break;
3521     case VNOVOL:
3522         dest->status = VOS_NO_VOL;
3523         break;
3524     case VVOLEXISTS:
3525         dest->status = VOS_VOL_EXISTS;
3526         break;
3527     case VNOSERVICE:
3528         dest->status = VOS_NO_SERVICE;
3529         break;
3530     case VOFFLINE:
3531         dest->status = VOS_OFFLINE;
3532         break;
3533     case VONLINE:
3534         dest->status = VOS_ONLINE;
3535         break;
3536     case VDISKFULL:
3537         dest->status = VOS_DISK_FULL;
3538         break;
3539     case VOVERQUOTA:
3540         dest->status = VOS_OVER_QUOTA;
3541         break;
3542     case VBUSY:
3543         dest->status = VOS_BUSY;
3544         break;
3545     case VMOVED:
3546         dest->status = VOS_MOVED;
3547         break;
3548     }
3549
3550     /*
3551      * Check to see if the entry is marked ok before copying all the
3552      * fields
3553      */
3554
3555     if (dest->status == VOS_OK) {
3556         strncpy(dest->name, source->name, VOS_MAX_VOLUME_NAME_LEN);
3557         dest->name[VOS_MAX_VOLUME_NAME_LEN - 1] = '\0';
3558         dest->id = source->volid;
3559         if (source->type == 0) {
3560             dest->type = VOS_READ_WRITE_VOLUME;
3561         } else if (source->type == 1) {
3562             dest->type = VOS_READ_ONLY_VOLUME;
3563         } else if (source->type == 2) {
3564             dest->type = VOS_BACKUP_VOLUME;
3565         }
3566         dest->backupId = source->backupID;
3567         dest->readWriteId = source->parentID;
3568         dest->readOnlyId = source->cloneID;
3569         dest->copyCreationDate = source->copyDate;
3570         dest->creationDate = source->creationDate;
3571         dest->lastAccessDate = source->accessDate;
3572         dest->lastUpdateDate = source->updateDate;
3573         dest->lastBackupDate = source->backupDate;
3574         dest->accessesSinceMidnight = source->dayUse;
3575         dest->fileCount = source->filecount;
3576         dest->maxQuota = source->maxquota;
3577         dest->currentSize = source->size;
3578         if (source->inUse == 1) {
3579             dest->volumeDisposition = VOS_ONLINE;
3580         } else {
3581             dest->volumeDisposition = VOS_OFFLINE;
3582         }
3583
3584         for (i = 0; i < VOS_VOLUME_READ_WRITE_STATS_NUMBER; i++) {
3585             dest->readStats[i] = source->stat_reads[i];
3586             dest->writeStats[i] = source->stat_writes[i];
3587         }
3588
3589         for (i = 0; i < VOS_VOLUME_TIME_STATS_NUMBER; i++) {
3590             dest->fileAuthorWriteSameNetwork[i] =
3591                 source->stat_fileSameAuthor[i];
3592             dest->fileAuthorWriteDifferentNetwork[i] =
3593                 source->stat_fileDiffAuthor[i];
3594             dest->dirAuthorWriteSameNetwork[i] =
3595                 source->stat_dirSameAuthor[i];
3596             dest->dirAuthorWriteDifferentNetwork[i] =
3597                 source->stat_dirDiffAuthor[i];
3598         }
3599     }
3600
3601     rc = 1;
3602
3603     if (st != NULL) {
3604         *st = tst;
3605     }
3606     return rc;
3607 }
3608
3609 /*
3610  * vos_VolumeGet - get information about a particular volume.
3611  *
3612  * PARAMETERS
3613  *
3614  * IN cellHandle - a previously opened cellHandle that corresponds
3615  * to the cell where the volume exists.
3616  *
3617  * IN serverHandle - a previously opened serverHandle that corresponds
3618  * to the server where the volume exists.
3619  *
3620  * IN callBack - a call back function pointer that may be called to report
3621  * status information.  Can be null.
3622  *
3623  * IN partition - the partition where the volume exists.
3624  *
3625  * IN volumeId - the volume id of the volume to be retrieved.
3626  *
3627  * OUT volumeP - upon successful completion, contains the information about the 
3628  * specified volume.
3629  *
3630  * LOCKS
3631  * 
3632  * No locks are obtained or released by this function
3633  *
3634  * RETURN CODES
3635  *
3636  * Returns != 0 upon successful completion.
3637  */
3638
3639 int ADMINAPI
3640 vos_VolumeGet(const void *cellHandle, const void *serverHandle,
3641               vos_MessageCallBack_t callBack, unsigned int partition,
3642               unsigned int volumeId, vos_volumeEntry_p volumeP,
3643               afs_status_p st)
3644 {
3645     int rc = 0;
3646     afs_status_t tst = 0;
3647     file_server_p f_server = (file_server_p) serverHandle;
3648     struct volintXInfo *info = NULL;
3649
3650     /*
3651      * Validate arguments
3652      */
3653
3654     if (!IsValidServerHandle(f_server, &tst)) {
3655         goto fail_vos_VolumeGet;
3656     }
3657
3658     if (partition > VOLMAXPARTS) {
3659         tst = ADMVOSPARTITIONIDTOOLARGE;
3660         goto fail_vos_VolumeGet;
3661     }
3662
3663     if (volumeP == NULL) {
3664         tst = ADMVOSVOLUMEPNULL;
3665         goto fail_vos_VolumeGet;
3666     }
3667
3668     /*
3669      * Retrieve the information for the volume
3670      */
3671
3672     if (!UV_XListOneVolume(f_server->serv, partition, volumeId, &info, &tst)) {
3673         goto fail_vos_VolumeGet;
3674     }
3675
3676     /*
3677      * Copy the volume info to our structure
3678      */
3679
3680     if (!copyvolintXInfo(info, volumeP, &tst)) {
3681         goto fail_vos_VolumeGet;
3682     }
3683     rc = 1;
3684
3685   fail_vos_VolumeGet:
3686
3687     if (info != NULL) {
3688         free(info);
3689     }
3690
3691     if (st != NULL) {
3692         *st = tst;
3693     }
3694     return rc;
3695 }
3696
3697 /*
3698  * The iterator functions and data for the volume retrieval functions.
3699  */
3700
3701 typedef struct volume_get {
3702     struct volintXInfo *vollist;
3703     afs_int32 total;            /* total number of volumes at this partition */
3704     afs_int32 index;            /* index to the current volume */
3705     vos_volumeEntry_t entry[CACHED_ITEMS];      /* the cache of entries */
3706 } volume_get_t, *volume_get_p;
3707
3708 static int
3709 GetVolumeRPC(void *rpc_specific, int slot, int *last_item,
3710              int *last_item_contains_data, afs_status_p st)
3711 {
3712     int rc = 0;
3713     afs_status_t tst = 0;
3714     volume_get_p entry = (volume_get_p) rpc_specific;
3715
3716     /*
3717      * Copy the next entry into the cache
3718      */
3719
3720     if (!copyvolintXInfo
3721         (&entry->vollist[entry->index], &entry->entry[slot], &tst)) {
3722         goto fail_GetVolumeRPC;
3723     }
3724     entry->index++;
3725
3726     /*
3727      * See if we've processed all the entries
3728      */
3729
3730
3731     if (entry->index == entry->total) {
3732         *last_item = 1;
3733         *last_item_contains_data = 1;
3734     }
3735     rc = 1;
3736
3737   fail_GetVolumeRPC:
3738
3739     if (st != NULL) {
3740         *st = tst;
3741     }
3742     return rc;
3743 }
3744
3745 static int
3746 GetVolumeFromCache(void *rpc_specific, int slot, void *dest, afs_status_p st)
3747 {
3748     int rc = 0;
3749     afs_status_t tst = 0;
3750     volume_get_p entry = (volume_get_p) rpc_specific;
3751
3752     memcpy(dest, (const void *)&entry->entry[slot],
3753            sizeof(vos_volumeEntry_t));
3754     rc = 1;
3755
3756     if (st != NULL) {
3757         *st = tst;
3758     }
3759     return rc;
3760 }
3761
3762
3763 static int
3764 DestroyVolume(void *rpc_specific, afs_status_p st)
3765 {
3766     int rc = 0;
3767     afs_status_t tst = 0;
3768     volume_get_p entry = (volume_get_p) rpc_specific;
3769
3770     if (entry->vollist != NULL) {
3771         free(entry->vollist);
3772     }
3773     rc = 1;
3774
3775     if (st != NULL) {
3776         *st = tst;
3777     }
3778     return rc;
3779 }
3780
3781
3782 /*
3783  * vos_VolumeGetBegin - begin to iterator over the list of volumes at a server.
3784  *
3785  * PARAMETERS
3786  *
3787  * IN cellHandle - a previously opened cellHandle that corresponds
3788  * to the cell where the volumes exist.
3789  *
3790  * IN serverHandle - a handle to the server where the volumes exist.
3791  *
3792  * IN callBack - a call back function pointer that may be called to report
3793  * status information.  Can be null.
3794  *
3795  * IN partition - the partition whose volumes should be listed.  Can be null.
3796  *
3797  * OUT iterationIdP - upon successful completion, contains an iterator that
3798  * can be passed to vos_VolumeGetBegin.
3799  *
3800  * LOCKS
3801  * 
3802  * No locks are obtained or released by this function
3803  *
3804  * RETURN CODES
3805  *
3806  * Returns != 0 upon successful completion.
3807  */
3808
3809 int ADMINAPI
3810 vos_VolumeGetBegin(const void *cellHandle, const void *serverHandle,
3811                    vos_MessageCallBack_t callBack, unsigned int partition,
3812                    void **iterationIdP, afs_status_p st)
3813 {
3814     int rc = 0;
3815     afs_status_t tst = 0;
3816     file_server_p f_server = (file_server_p) serverHandle;
3817     afs_admin_iterator_p iter =
3818         (afs_admin_iterator_p) malloc(sizeof(afs_admin_iterator_t));
3819     volume_get_p entry = (volume_get_p) calloc(1, sizeof(volume_get_t));
3820
3821     /*
3822      * Validate arguments
3823      */
3824
3825     if (!IsValidServerHandle(f_server, &tst)) {
3826         goto fail_vos_VolumeGetBegin;
3827     }
3828
3829     if (partition > VOLMAXPARTS) {
3830         tst = ADMVOSPARTITIONIDTOOLARGE;
3831         goto fail_vos_VolumeGetBegin;
3832     }
3833
3834     if ((iter == NULL) || (entry == NULL)) {
3835         tst = ADMNOMEM;
3836         goto fail_vos_VolumeGetBegin;
3837     }
3838
3839     /*
3840      * Get a list of all the volumes contained in the partition at the
3841      * server
3842      */
3843
3844     if (!UV_XListVolumes
3845         (f_server->serv, partition, 1, &entry->vollist, &entry->total,
3846          &tst)) {
3847         goto fail_vos_VolumeGetBegin;
3848     }
3849
3850     if (entry->total == 0) {
3851         if (!IteratorInit(iter, (void *)entry, NULL, NULL, NULL, NULL, &tst)) {
3852             goto fail_vos_VolumeGetBegin;
3853         }
3854         iter->done_iterating = 1;
3855         iter->st = ADMITERATORDONE;
3856     } else {
3857         if (!IteratorInit
3858             (iter, (void *)entry, GetVolumeRPC, GetVolumeFromCache, NULL,
3859              DestroyVolume, &tst)) {
3860             goto fail_vos_VolumeGetBegin;
3861         }
3862     }
3863     *iterationIdP = (void *)iter;
3864     rc = 1;
3865
3866   fail_vos_VolumeGetBegin:
3867
3868     if (rc == 0) {
3869         if (iter != NULL) {
3870             free(iter);
3871         }
3872         if (entry != NULL) {
3873             free(entry);
3874         }
3875     }
3876
3877     if (st != NULL) {
3878         *st = tst;
3879     }
3880     return rc;
3881 }
3882
3883 /*
3884  * vos_VolumeGetNext - get information about the next volume.
3885  *
3886  * PARAMETERS
3887  *
3888  * IN iterationId - an iterator previously returned by
3889  * vos_VolumeGetBegin
3890  *
3891  * OUT volumeP - a pointer to a vos_volumeEntry_t
3892  * that upon successful completion contains information about the
3893  * next volume.
3894  *
3895  * LOCKS
3896  * 
3897  * The iterator is locked while the next item is retrieved.
3898  *
3899  * RETURN CODES
3900  *
3901  * Returns != 0 upon successful completion.
3902  */
3903
3904 int ADMINAPI
3905 vos_VolumeGetNext(const void *iterationId, vos_volumeEntry_p volumeP,
3906                   afs_status_p st)
3907 {
3908     int rc = 0;
3909     afs_status_t tst = 0;
3910     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
3911
3912     if (iter == NULL) {
3913         tst = ADMITERATORNULL;
3914         goto fail_vos_VolumeGetNext;
3915     }
3916
3917     if (volumeP == NULL) {
3918         tst = ADMVOSVOLUMEPNULL;
3919         goto fail_vos_VolumeGetNext;
3920     }
3921
3922     rc = IteratorNext(iter, (void *)volumeP, &tst);
3923
3924   fail_vos_VolumeGetNext:
3925
3926     if (st != NULL) {
3927         *st = tst;
3928     }
3929     return rc;
3930 }
3931
3932 /*
3933  * vos_VolumeGetDone - finish using a volume iterator.
3934  *
3935  * PARAMETERS
3936  *
3937  * IN iterationId - an iterator previously returned by vos_VolumeGetBegin
3938  *
3939  * LOCKS
3940  * 
3941  * The iterator is locked and then destroyed.
3942  *
3943  * RETURN CODES
3944  *
3945  * Returns != 0 upon successful completion.
3946  */
3947
3948 int ADMINAPI
3949 vos_VolumeGetDone(const void *iterationId, afs_status_p st)
3950 {
3951     int rc = 0;
3952     afs_status_t tst = 0;
3953     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
3954
3955     /*
3956      * Validate arguments
3957      */
3958
3959     if (iter == NULL) {
3960         tst = ADMITERATORNULL;
3961         goto fail_vos_VolumeGetDone;
3962     }
3963
3964     rc = IteratorDone(iter, &tst);
3965
3966   fail_vos_VolumeGetDone:
3967
3968     if (st != NULL) {
3969         *st = tst;
3970     }
3971     return rc;
3972 }
3973
3974 /*
3975  * vos_VolumeMove - move a volume from one server to another.
3976  *
3977  * PARAMETERS
3978  *
3979  * IN cellHandle - a previously opened cellHandle that corresponds
3980  * to the cell where the volume exists.
3981  *
3982  * IN callBack - a call back function pointer that may be called to report
3983  * status information.  Can be null.
3984  *
3985  * IN volumeId - the volume id of the volume to be moved.
3986  *
3987  * IN fromServer - a previously opened serverHandle that corresponds
3988  * to the server where the volume currently resides.
3989  *
3990  * IN fromPartition - the partition where the volume currently resides.
3991  *
3992  * IN toServer - a previously opened serverHandle that corresponds
3993  * to the server where the volume will be moved.
3994  *
3995  * IN toPartition - the partition where the volume will be moved.
3996  *
3997  * LOCKS
3998  * 
3999  * No locks are obtained or released by this function
4000  *
4001  * RETURN CODES
4002  *
4003  * Returns != 0 upon successful completion.
4004  */
4005
4006 int ADMINAPI
4007 vos_VolumeMove(const void *cellHandle, vos_MessageCallBack_t callBack,
4008                unsigned int volumeId, const void *fromServer,
4009                unsigned int fromPartition, const void *toServer,
4010                unsigned int toPartition, afs_status_p st)
4011 {
4012     int rc = 0;
4013     afs_status_t tst = 0;
4014     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
4015     file_server_p from_server = (file_server_p) fromServer;
4016     file_server_p to_server = (file_server_p) toServer;
4017     afs_int32 from_server_addr =
4018         ntohl(rx_HostOf(rx_PeerOf(from_server->serv)));
4019     afs_int32 to_server_addr = ntohl(rx_HostOf(rx_PeerOf(to_server->serv)));
4020     afs_int32 from_partition = fromPartition;
4021     afs_int32 to_partition = toPartition;
4022
4023     /*
4024      * Validate arguments
4025      */
4026
4027     if (!IsValidCellHandle(c_handle, &tst)) {
4028         goto fail_vos_VolumeMove;
4029     }
4030
4031     if (!IsValidServerHandle(from_server, &tst)) {
4032         goto fail_vos_VolumeMove;
4033     }
4034
4035     if (!IsValidServerHandle(to_server, &tst)) {
4036         goto fail_vos_VolumeMove;
4037     }
4038
4039     if (fromPartition > VOLMAXPARTS) {
4040         tst = ADMVOSPARTITIONIDTOOLARGE;
4041         goto fail_vos_VolumeMove;
4042     }
4043
4044     if (toPartition > VOLMAXPARTS) {
4045         tst = ADMVOSPARTITIONIDTOOLARGE;
4046         goto fail_vos_VolumeMove;
4047     }
4048
4049     /*
4050      * Move the volume
4051      */
4052
4053     rc = UV_MoveVolume(c_handle, volumeId, from_server_addr, from_partition,
4054                        to_server_addr, to_partition, &tst);
4055
4056   fail_vos_VolumeMove:
4057
4058     if (st != NULL) {
4059         *st = tst;
4060     }
4061     return rc;
4062 }
4063
4064 /*
4065  * vos_VolumeRelease - release a volume.
4066  *
4067  * PARAMETERS
4068  *
4069  * IN cellHandle - a previously opened cellHandle that corresponds
4070  * to the cell where the volume exists.
4071  *
4072  * IN callBack - a call back function pointer that may be called to report
4073  * status information.  Can be null.
4074  *
4075  * IN volumeId - the volume to be released.
4076  *
4077  * IN force - force a complete release.
4078  *
4079  * LOCKS
4080  * 
4081  * No locks are obtained or released by this function
4082  *
4083  * RETURN CODES
4084  *
4085  * Returns != 0 upon successful completion.
4086  */
4087
4088 int ADMINAPI
4089 vos_VolumeRelease(const void *cellHandle, vos_MessageCallBack_t callBack,
4090                   unsigned int volumeId, vos_force_t force, afs_status_p st)
4091 {
4092     int rc = 0;
4093     afs_status_t tst = 0;
4094     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
4095     afs_int32 server, part, forc = 0, voltype, volume;
4096     struct nvldbentry entry;
4097
4098     /*
4099      * Validate arguments
4100      */
4101
4102     if (!IsValidCellHandle(c_handle, &tst)) {
4103         goto fail_vos_VolumeRelease;
4104     }
4105
4106     if (!GetVolumeInfo
4107         (c_handle, volumeId, &entry, &server, &part, &voltype, &tst)) {
4108         goto fail_vos_VolumeRelease;
4109     }
4110
4111     if (force == VOS_FORCE) {
4112         forc = 1;
4113     }
4114
4115     volume = volumeId;
4116     rc = UV_ReleaseVolume(c_handle, volume, server, part, forc, &tst);
4117
4118   fail_vos_VolumeRelease:
4119
4120     if (st != NULL) {
4121         *st = tst;
4122     }
4123     return rc;
4124 }
4125
4126 /*
4127  * vos_VolumeZap - forcibly delete a volume.
4128  *
4129  * PARAMETERS
4130  *
4131  * IN cellHandle - a previously opened cellHandle that corresponds
4132  * to the cell where the volume exists.
4133  *
4134  * IN serverHandle - a previously opened serverHandle that corresponds
4135  * to the server where the volume exists.
4136  *
4137  * IN callBack - a call back function pointer that may be called to report
4138  * status information.  Can be null.
4139  *
4140  * IN partition - the partition where the volume exists.
4141  *
4142  * IN volumeId - the volume id of the vldb entry to be deleted.
4143  *
4144  * IN force - force the deletion of bad volumes.
4145  *
4146  * LOCKS
4147  * 
4148  * No locks are obtained or released by this function
4149  *
4150  * RETURN CODES
4151  *
4152  * Returns != 0 upon successful completion.
4153  */
4154
4155 int ADMINAPI
4156 vos_VolumeZap(const void *cellHandle, const void *serverHandle,
4157               vos_MessageCallBack_t callBack, unsigned int partition,
4158               unsigned int volumeId, vos_force_t force, afs_status_p st)
4159 {
4160     int rc = 0;
4161     afs_status_t tst = 0;
4162     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
4163     file_server_p f_server = (file_server_p) serverHandle;
4164
4165     /*
4166      * Verify that the cellHandle is capable of making vos rpc's
4167      */
4168
4169     if (!IsValidCellHandle(c_handle, &tst)) {
4170         goto fail_vos_VolumeZap;
4171     }
4172
4173     if (!IsValidServerHandle(f_server, &tst)) {
4174         goto fail_vos_VolumeZap;
4175     }
4176
4177     if (force == VOS_FORCE) {
4178         rc = UV_NukeVolume(c_handle, f_server->serv, partition, volumeId,
4179                            &tst);
4180     } else {
4181         rc = UV_VolumeZap(c_handle, f_server->serv, partition, volumeId,
4182                           &tst);
4183     }
4184
4185   fail_vos_VolumeZap:
4186
4187     if (st != NULL) {
4188         *st = tst;
4189     }
4190     return rc;
4191 }
4192
4193 /*
4194  * vos_PartitionNameToId - translate a string representing a partition
4195  * to a number.
4196  *
4197  * PARAMETERS
4198  *
4199  * IN partitionName - a string representing a partition.  Must be of
4200  * the form /vicep..
4201  *
4202  * OUT partitionId - a number containing the partition id upon successful 
4203  * completion.
4204  *
4205  * LOCKS
4206  * 
4207  * No locks are obtained or released by this function
4208  *
4209  * RETURN CODES
4210  *
4211  * Returns != 0 upon successful completion.
4212  */
4213
4214 int ADMINAPI
4215 vos_PartitionNameToId(const char *partitionName, unsigned int *partitionId,
4216                       afs_status_p st)
4217 {
4218     int rc = 0;
4219     afs_status_t tst = 0;
4220     size_t partition_name_len;
4221     int i;
4222
4223     /* 
4224      * Validate arguments
4225      */
4226
4227     if (partitionName == NULL) {
4228         tst = ADMVOSPARTITIONNAMENULL;
4229         goto fail_vos_PartitionNameToId;
4230     }
4231
4232     if (partitionId == NULL) {
4233         tst = ADMVOSPARTITIONIDNULL;
4234         goto fail_vos_PartitionNameToId;
4235     }
4236
4237     /*
4238      * Check that string begins with /vicep
4239      */
4240
4241     if (strncmp(partitionName, VICE_PARTITION_PREFIX, VICE_PREFIX_SIZE)) {
4242         tst = ADMVOSPARTITIONNAMEINVALID;
4243         goto fail_vos_PartitionNameToId;
4244     }
4245
4246     /*
4247      * Check that the string is either one or two characters
4248      * longer than VICE_PREFIX_SIZE
4249      */
4250
4251     partition_name_len = strlen(partitionName);
4252
4253     if (partition_name_len == VICE_PREFIX_SIZE) {
4254         tst = ADMVOSPARTITIONNAMETOOSHORT;
4255         goto fail_vos_PartitionNameToId;
4256     }
4257
4258     if (partition_name_len > (VICE_PREFIX_SIZE + 2)) {
4259         tst = ADMVOSPARTITIONNAMETOOLONG;
4260         goto fail_vos_PartitionNameToId;
4261     }
4262
4263     /*
4264      * Check that all characters past the prefix are lower case
4265      */
4266
4267     for (i = VICE_PREFIX_SIZE; i < partition_name_len; i++) {
4268         if (!islower(partitionName[i])) {
4269             tst = ADMVOSPARTITIONNAMENOTLOWER;
4270             goto fail_vos_PartitionNameToId;
4271         }
4272     }
4273
4274     /*
4275      * Convert the name to a number
4276      */
4277
4278     if (partitionName[VICE_PREFIX_SIZE + 1] == 0) {
4279         *partitionId = partitionName[VICE_PREFIX_SIZE] - 'a';
4280     } else {
4281         *partitionId =
4282             (partitionName[VICE_PREFIX_SIZE] - 'a') * 26 +
4283             (partitionName[VICE_PREFIX_SIZE + 1] - 'a') + 26;
4284     }
4285
4286     if (*partitionId > VOLMAXPARTS) {
4287         tst = ADMVOSPARTITIONIDTOOLARGE;
4288         goto fail_vos_PartitionNameToId;
4289     }
4290     rc = 1;
4291
4292   fail_vos_PartitionNameToId:
4293
4294     if (st != NULL) {
4295         *st = tst;
4296     }
4297     return rc;
4298 }
4299
4300 /*
4301  * vos_PartitionIdToName - translate a number representing a partition
4302  * to a character string.
4303  *
4304  * PARAMETERS
4305  *
4306  * IN partitionId - an integer representing the partition.
4307  *
4308  * OUT partitionName - a string containing the converted partition ID
4309  * upon successful completion.
4310  *
4311  * LOCKS
4312  * 
4313  * No locks are obtained or released by this function
4314  *
4315  * RETURN CODES
4316  *
4317  * Returns != 0 upon successful completion.
4318  */
4319
4320 int ADMINAPI
4321 vos_PartitionIdToName(unsigned int partitionId, char *partitionName,
4322                       afs_status_p st)
4323 {
4324     int rc = 0;
4325     afs_status_t tst = 0;
4326
4327     if (partitionId > VOLMAXPARTS) {
4328         tst = ADMVOSPARTITIONIDTOOLARGE;
4329         goto fail_vos_PartitionIdToName;
4330     }
4331
4332     if (partitionName == NULL) {
4333         tst = ADMVOSPARTITIONNAMENULL;
4334         goto fail_vos_PartitionIdToName;
4335     }
4336
4337     if (partitionId < 26) {
4338         strcpy(partitionName, VICE_PARTITION_PREFIX);
4339         partitionName[6] = partitionId + 'a';
4340         partitionName[7] = '\0';
4341     } else {
4342         strcpy(partitionName, VICE_PARTITION_PREFIX);
4343         partitionId -= 26;
4344         partitionName[6] = 'a' + (partitionId / 26);
4345         partitionName[7] = 'a' + (partitionId % 26);
4346         partitionName[8] = '\0';
4347     }
4348     rc = 1;
4349
4350   fail_vos_PartitionIdToName:
4351
4352     if (st != NULL) {
4353         *st = tst;
4354     }
4355     return rc;
4356 }
4357
4358 /*
4359  * vos_VolumeQuotaChange - change the quota of a volume.
4360  *
4361  * PARAMETERS
4362  *
4363  * IN cellHandle - a previously opened cellHandle that corresponds
4364  * to the cell where the volume exists.
4365  *
4366  * IN serverHandle - a previously opened serverHandle that corresponds
4367  * to the server where the volume exists.
4368  *
4369  * IN callBack - a call back function pointer that may be called to report
4370  * status information.  Can be null.
4371  *
4372  * IN partition - the partition where the volume exists.
4373  *
4374  * IN volumeId - the volume id of the volume to be modified.
4375  *
4376  * IN volumeQuota - the new volume quota.
4377  *
4378  * LOCKS
4379  * 
4380  * No locks are obtained or released by this function
4381  *
4382  * RETURN CODES
4383  *
4384  * Returns != 0 upon successful completion.
4385  */
4386
4387 int ADMINAPI
4388 vos_VolumeQuotaChange(const void *cellHandle, const void *serverHandle,
4389                       vos_MessageCallBack_t callBack, unsigned int partition,
4390                       unsigned int volumeId, unsigned int volumeQuota,
4391                       afs_status_p st)
4392 {
4393     int rc = 0;
4394     afs_status_t tst = 0;
4395     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
4396     file_server_p f_server = (file_server_p) serverHandle;
4397     int ttid = 0;
4398     int rcode = 0;
4399     struct volintInfo tstatus;
4400     int active_trans = 0;
4401
4402     /*
4403      * Verify that the cellHandle is capable of making vos rpc's
4404      */
4405
4406     if (!IsValidCellHandle(c_handle, &tst)) {
4407         goto fail_vos_VolumeQuotaChange;
4408     }
4409
4410     if (!IsValidServerHandle(f_server, &tst)) {
4411         goto fail_vos_VolumeQuotaChange;
4412     }
4413
4414     memset((void *)&tstatus, 0, sizeof(tstatus));
4415     tstatus.dayUse = -1;
4416     tstatus.spare2 = -1;
4417     tstatus.maxquota = volumeQuota;
4418
4419
4420     tst =
4421         AFSVolTransCreate(f_server->serv, volumeId, partition, ITBusy, &ttid);
4422     if (tst) {
4423         goto fail_vos_VolumeQuotaChange;
4424     }
4425     active_trans = 1;
4426
4427     tst = AFSVolSetInfo(f_server->serv, ttid, &tstatus);
4428     if (tst) {
4429         goto fail_vos_VolumeQuotaChange;
4430     }
4431     rc = 1;
4432
4433   fail_vos_VolumeQuotaChange:
4434
4435     if (active_trans) {
4436         afs_status_t tst2 = 0;
4437         tst2 = AFSVolEndTrans(f_server->serv, ttid, &rcode);
4438         if (tst2) {
4439             if (tst == 0) {
4440                 tst = tst2;
4441                 rc = 0;
4442             }
4443         }
4444         if (rcode) {
4445             if (tst == 0) {
4446                 tst = rcode;
4447                 rc = 0;
4448             }
4449         }
4450     }
4451
4452     if (st != NULL) {
4453         *st = tst;
4454     }
4455     return rc;
4456 }
4457 /*
4458  * vos_VolumeGet2 - get information about a particular volume.
4459  *
4460  * PARAMETERS
4461  *
4462  * IN cellHandle - a previously opened cellHandle that corresponds
4463  * to the cell where the volume exists.
4464  *
4465  * IN serverHandle - a previously opened serverHandle that corresponds
4466  * to the server where the volume exists.
4467  *
4468  * IN callBack - a call back function pointer that may be called to report
4469  * status information.  Can be null.
4470  *
4471  * IN partition - the partition where the volume exists.
4472  *
4473  * IN volumeId - the volume id of the volume to be retrieved.
4474  *
4475  * OUT pinfo - upon successful completion, contains the information about the 
4476  * specified volume.
4477  *
4478  * LOCKS
4479  * 
4480  * No locks are obtained or released by this function
4481  *
4482  * RETURN CODES
4483  *
4484  * Returns != 0 upon successful completion.
4485  */
4486
4487 int ADMINAPI
4488 vos_VolumeGet2(const void *cellHandle, const void *serverHandle,
4489               vos_MessageCallBack_t callBack, unsigned int partition,
4490               unsigned int volumeId, volintInfo* pinfo,
4491               afs_status_p st)
4492 {
4493     int rc = 0;
4494     afs_status_t tst = 0;
4495     file_server_p f_server = (file_server_p) serverHandle;
4496     volintInfo *pinfo_=0;
4497
4498     /*
4499      * Validate arguments
4500      */
4501
4502     if (!IsValidServerHandle(f_server, &tst)) {
4503         goto fail_vos_VolumeGet2;
4504     }
4505
4506     if (partition > VOLMAXPARTS) {
4507         tst = ADMVOSPARTITIONIDTOOLARGE;
4508         goto fail_vos_VolumeGet2;
4509     }
4510
4511     if (pinfo == NULL) {
4512         tst = ADMVOSVOLUMEPNULL;
4513         goto fail_vos_VolumeGet2;
4514     }
4515
4516     /*
4517      * Retrieve the information for the volume
4518      */
4519
4520     if (!UV_ListOneVolume(f_server->serv, partition, volumeId, &pinfo_,&tst)) {
4521         goto fail_vos_VolumeGet2;
4522     }
4523
4524
4525     rc = 1;
4526
4527   fail_vos_VolumeGet2:
4528
4529     if (pinfo_ != NULL) {
4530      memcpy(pinfo,pinfo_,sizeof(volintInfo));
4531         free(pinfo_);
4532     }
4533
4534     if (st != NULL) {
4535         *st = tst;
4536     }
4537     return rc;
4538 }
4539
4540 /*
4541  * vos_ClearVolUpdateCounter - reset volUpdateCounter of a volume to zero
4542  *
4543  * PARAMETERS
4544  *
4545  * IN cellHandle - a previously opened cellHandle that corresponds
4546  * to the cell where the volume exists.
4547  *
4548  * IN serverHandle - a previously opened serverHandle that corresponds
4549  * to the server where the volume exists.
4550  *
4551  * IN partition - the partition where the volume exists.
4552  *
4553  * IN volumeId - the volume id of the volume to be retrieved.
4554  *
4555  * LOCKS
4556  * 
4557  * No locks are obtained or released by this function
4558  *
4559  * RETURN CODES
4560  *
4561  * Returns != 0 upon successful completion.
4562  */
4563
4564 int ADMINAPI
4565 vos_ClearVolUpdateCounter(const void *cellHandle,
4566                                   const void *serverHandle,
4567                                   unsigned int partition,
4568                                   unsigned int volumeId,
4569                                   afs_status_p st)
4570 {
4571     int rc = 0;
4572     afs_status_t tst = 0;
4573     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
4574     file_server_p f_server = (file_server_p) serverHandle;
4575     int ttid = 0;
4576     int rcode = 0;
4577     struct volintInfo tstatus;
4578     int active_trans = 0;
4579
4580     /*
4581      * Verify that the cellHandle is capable of making vos rpc's
4582      */
4583
4584     if (!IsValidCellHandle(c_handle, &tst)) {
4585         goto fail_vos_ClearVolUpdateCounter;
4586     }
4587
4588     if (!IsValidServerHandle(f_server, &tst)) {
4589         goto fail_vos_ClearVolUpdateCounter;
4590     }
4591
4592     memset((void *)&tstatus, 0, sizeof(tstatus));
4593     tstatus.maxquota = -1;
4594     tstatus.dayUse = -1;
4595     tstatus.creationDate = -1;
4596     tstatus.updateDate = -1;
4597     tstatus.flags = -1;
4598     tstatus.spare0 = -1;
4599     tstatus.spare1 = -1;
4600     tstatus.spare2 = 0;
4601     tstatus.spare3 = -1;
4602     
4603     tst =
4604         AFSVolTransCreate(f_server->serv, volumeId, partition, ITBusy, &ttid);
4605     if (tst) {
4606         goto fail_vos_ClearVolUpdateCounter;
4607     }
4608     active_trans = 1;
4609
4610     tst = AFSVolSetInfo(f_server->serv, ttid, &tstatus);
4611     if (tst) {
4612         goto fail_vos_ClearVolUpdateCounter;
4613     }
4614     rc = 1;
4615
4616   fail_vos_ClearVolUpdateCounter:
4617
4618     if (active_trans) {
4619         afs_status_t tst2 = 0;
4620         tst2 = AFSVolEndTrans(f_server->serv, ttid, &rcode);
4621         if (tst2) {
4622             if (tst == 0) {
4623                 tst = tst2;
4624                 rc = 0;
4625             }
4626         }
4627         if (rcode) {
4628             if (tst == 0) {
4629                 tst = rcode;
4630                 rc = 0;
4631             }
4632         }
4633     }
4634
4635     if (st != NULL) {
4636         *st = tst;
4637     }
4638     return rc;
4639 }
4640