volserver-split-volume-functionality-20090324
[openafs.git] / src / volser / volprocs.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  * Portions Copyright (c) 2007-2008 Sine Nomine Associates
10  */
11
12 #include <afsconfig.h>
13 #include <afs/param.h>
14
15 RCSID
16     ("$Header$");
17
18 #include <stdio.h>
19 #include <sys/types.h>
20 #include <string.h>
21 #include <errno.h>
22 #ifdef AFS_NT40_ENV
23 #include <stdlib.h>
24 #include <fcntl.h>
25 #include <winsock2.h>
26 #else
27 #include <sys/file.h>
28 #include <netinet/in.h>
29 #include <unistd.h>
30 #endif
31
32 #include <dirent.h>
33 #include <sys/stat.h>
34 #include <rx/xdr.h>
35 #include <rx/rx.h>
36 #include <rx/rxkad.h>
37 #include <afs/afsint.h>
38 #include <signal.h>
39 #ifdef AFS_PTHREAD_ENV
40 #include <assert.h>
41 #else /* AFS_PTHREAD_ENV */
42 #include <afs/assert.h>
43 #endif /* AFS_PTHREAD_ENV */
44 #include <afs/prs_fs.h>
45 #include <afs/nfs.h>
46 #include <lwp.h>
47 #include <lock.h>
48 #include <afs/cellconfig.h>
49 #include <afs/keys.h>
50 #include <ubik.h>
51 #include <afs/ihandle.h>
52 #ifdef AFS_NT40_ENV
53 #include <afs/ntops.h>
54 #endif
55 #include <afs/vnode.h>
56 #include <afs/volume.h>
57 #include <afs/volume_inline.h>
58 #include <afs/partition.h>
59 #include "vol.h"
60 #include <afs/daemon_com.h>
61 #include <afs/fssync.h>
62 #include <afs/acl.h>
63 #include "afs/audit.h"
64 #include <afs/dir.h>
65
66 #include "volser.h"
67 #include "volint.h"
68
69 #include "volser_prototypes.h"
70
71 extern int DoLogging;
72 extern struct volser_trans *FindTrans(), *NewTrans(), *TransList();
73 extern struct afsconf_dir *tdir;
74
75 /* Needed by Irix. Leave, or include a header */
76 extern char *volutil_PartitionName();
77
78 extern void LogError(afs_int32 errcode);
79
80 /* Forward declarations */
81 static int GetPartName(afs_int32 partid, char *pname);
82
83 #define OneDay (24*60*60)
84
85 #ifdef AFS_NT40_ENV
86 #define ENOTCONN 134
87 #endif
88
89 afs_int32 localTid = 1;
90 afs_int32 VolPartitionInfo(), VolNukeVolume(), VolCreateVolume(),
91 VolDeleteVolume(), VolClone();
92 afs_int32 VolReClone(), VolTransCreate(), VolGetNthVolume(), VolGetFlags(),
93 VolForward(), VolDump();
94 afs_int32 VolRestore(), VolEndTrans(), VolSetForwarding(), VolGetStatus(),
95 VolSetInfo(), VolGetName();
96 afs_int32 VolListPartitions(), VolListOneVolume(),
97 VolXListOneVolume(), VolXListVolumes();
98 afs_int32 VolListVolumes(), XVolListPartitions(), VolMonitor(),
99 VolSetIdsTypes(), VolSetDate(), VolSetFlags();
100
101 /* this call unlocks all of the partition locks we've set */
102 int 
103 VPFullUnlock()
104 {
105     register struct DiskPartition64 *tp;
106     for (tp = DiskPartitionList; tp; tp = tp->next) {
107         if (tp->lock_fd != INVALID_FD) {
108             close(tp->lock_fd); /* releases flock held on this partition */
109             tp->lock_fd = INVALID_FD;
110         }
111     }
112     return 0;
113 }
114
115 /* get partition id from a name */
116 afs_int32
117 PartitionID(char *aname)
118 {
119     register char tc;
120     register int code = 0;
121     char ascii[3];
122
123     tc = *aname;
124     if (tc == 0)
125         return -1;              /* unknown */
126
127     /* otherwise check for vicepa or /vicepa, or just plain "a" */
128     ascii[2] = 0;
129     if (!strncmp(aname, "/vicep", 6)) {
130         strncpy(ascii, aname + 6, 2);
131     } else
132         return -1;              /* bad partition name */
133     /* now partitions are named /vicepa ... /vicepz, /vicepaa, /vicepab, .../vicepzz, and are numbered
134      * from 0.  Do the appropriate conversion */
135     if (ascii[1] == 0) {
136         /* one char name, 0..25 */
137         if (ascii[0] < 'a' || ascii[0] > 'z')
138             return -1;          /* wrongo */
139         return ascii[0] - 'a';
140     } else {
141         /* two char name, 26 .. <whatever> */
142         if (ascii[0] < 'a' || ascii[0] > 'z')
143             return -1;          /* wrongo */
144         if (ascii[1] < 'a' || ascii[1] > 'z')
145             return -1;          /* just as bad */
146         code = (ascii[0] - 'a') * 26 + (ascii[1] - 'a') + 26;
147         if (code > VOLMAXPARTS)
148             return -1;
149         return code;
150     }
151 }
152
153 static int
154 ConvertVolume(afs_uint32 avol, char *aname, afs_int32 asize)
155 {
156     if (asize < 18)
157         return -1;
158     /* It's better using the Generic VFORMAT since otherwise we have to make changes to too many places... The 14 char limitation in names hits us again in AIX; print in field of 9 digits (still 10 for the rest), right justified with 0 padding */
159     (void)afs_snprintf(aname, asize, VFORMAT, (unsigned long)avol);
160     return 0;
161 }
162
163 static int
164 ConvertPartition(int apartno, char *aname, int asize)
165 {
166     if (asize < 10)
167         return E2BIG;
168     if (apartno < 0)
169         return EINVAL;
170     strcpy(aname, "/vicep");
171     if (apartno < 26) {
172         aname[6] = 'a' + apartno;
173         aname[7] = 0;
174     } else {
175         apartno -= 26;
176         aname[6] = 'a' + (apartno / 26);
177         aname[7] = 'a' + (apartno % 26);
178         aname[8] = 0;
179     }
180     return 0;
181 }
182
183 /* the only attach function that takes a partition is "...ByName", so we use it */
184 struct Volume *
185 XAttachVolume(afs_int32 *error, afs_uint32 avolid, afs_int32 apartid, int amode)
186 {
187     char pbuf[30], vbuf[20];
188     register struct Volume *tv;
189
190     if (ConvertPartition(apartid, pbuf, sizeof(pbuf))) {
191         *error = EINVAL;
192         return NULL;
193     }
194     if (ConvertVolume(avolid, vbuf, sizeof(vbuf))) {
195         *error = EINVAL;
196         return NULL;
197     }
198     tv = VAttachVolumeByName((Error *)error, pbuf, vbuf, amode);
199     return tv;
200 }
201
202 /* Adapted from the file server; create a root directory for this volume */
203 static int
204 ViceCreateRoot(Volume *vp)
205 {
206     DirHandle dir;
207     struct acl_accessList *ACL;
208     ViceFid did;
209     Inode inodeNumber, nearInode;
210     struct VnodeDiskObject *vnode;
211     struct VnodeClassInfo *vcp = &VnodeClassInfo[vLarge];
212     IHandle_t *h;
213     FdHandle_t *fdP;
214     int code;
215     afs_fsize_t length;
216
217     vnode = (struct VnodeDiskObject *)malloc(SIZEOF_LARGEDISKVNODE);
218     if (!vnode)
219         return ENOMEM;
220     memset(vnode, 0, SIZEOF_LARGEDISKVNODE);
221
222     V_pref(vp, nearInode);
223     inodeNumber =
224         IH_CREATE(V_linkHandle(vp), V_device(vp),
225                   VPartitionPath(V_partition(vp)), nearInode, V_parentId(vp),
226                   1, 1, 0);
227     assert(VALID_INO(inodeNumber));
228
229     SetSalvageDirHandle(&dir, V_parentId(vp), vp->device, inodeNumber);
230     did.Volume = V_id(vp);
231     did.Vnode = (VnodeId) 1;
232     did.Unique = 1;
233
234     assert(!(MakeDir(&dir, (afs_int32 *)&did, (afs_int32 *)&did)));
235     DFlush();                   /* flush all modified dir buffers out */
236     DZap((afs_int32 *)&dir);                    /* Remove all buffers for this dir */
237     length = Length(&dir);      /* Remember size of this directory */
238
239     FidZap(&dir);               /* Done with the dir handle obtained via SetSalvageDirHandle() */
240
241     /* build a single entry ACL that gives all rights to system:administrators */
242     /* this section of code assumes that access list format is not going to
243      * change
244      */
245     ACL = VVnodeDiskACL(vnode);
246     ACL->size = sizeof(struct acl_accessList);
247     ACL->version = ACL_ACLVERSION;
248     ACL->total = 1;
249     ACL->positive = 1;
250     ACL->negative = 0;
251     ACL->entries[0].id = -204;  /* this assumes System:administrators is group -204 */
252     ACL->entries[0].rights =
253         PRSFS_READ | PRSFS_WRITE | PRSFS_INSERT | PRSFS_LOOKUP | PRSFS_DELETE
254         | PRSFS_LOCK | PRSFS_ADMINISTER;
255
256     vnode->type = vDirectory;
257     vnode->cloned = 0;
258     vnode->modeBits = 0777;
259     vnode->linkCount = 2;
260     VNDISK_SET_LEN(vnode, length);
261     vnode->uniquifier = 1;
262     V_uniquifier(vp) = vnode->uniquifier + 1;
263     vnode->dataVersion = 1;
264     VNDISK_SET_INO(vnode, inodeNumber);
265     vnode->unixModifyTime = vnode->serverModifyTime = V_creationDate(vp);
266     vnode->author = 0;
267     vnode->owner = 0;
268     vnode->parent = 0;
269     vnode->vnodeMagic = vcp->magic;
270
271     IH_INIT(h, vp->device, V_parentId(vp),
272             vp->vnodeIndex[vLarge].handle->ih_ino);
273     fdP = IH_OPEN(h);
274     assert(fdP != NULL);
275     code = FDH_SEEK(fdP, vnodeIndexOffset(vcp, 1), SEEK_SET);
276     assert(code >= 0);
277     code = FDH_WRITE(fdP, vnode, SIZEOF_LARGEDISKVNODE);
278     assert(code == SIZEOF_LARGEDISKVNODE);
279     FDH_REALLYCLOSE(fdP);
280     IH_RELEASE(h);
281     VNDISK_GET_LEN(length, vnode);
282     V_diskused(vp) = nBlocks(length);
283
284     free(vnode);
285     return 1;
286 }
287
288 afs_int32
289 SAFSVolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition 
290                      *partition)
291 {
292     afs_int32 code;
293     struct diskPartition64 *dp = (struct diskPartition64 *)
294         malloc(sizeof(struct diskPartition64));
295
296     code = VolPartitionInfo(acid, pname, dp);
297     if (!code) {
298         strncpy(partition->name, dp->name, 32);
299         strncpy(partition->devName, dp->devName, 32);
300         partition->lock_fd = dp->lock_fd;
301         partition->free=RoundInt64ToInt32(dp->free);
302         partition->minFree=RoundInt64ToInt32(dp->minFree);
303     }
304     free(dp);
305     osi_auditU(acid, VS_ParInfEvent, code, AUD_STR, pname, AUD_END);
306     return code;
307 }
308
309 afs_int32
310 SAFSVolPartitionInfo64(struct rx_call *acid, char *pname, struct diskPartition64 
311                      *partition)
312 {
313     afs_int32 code;
314
315     code = VolPartitionInfo(acid, pname, partition);
316     osi_auditU(acid, VS_ParInfEvent, code, AUD_STR, pname, AUD_END);
317     return code;
318 }
319
320 afs_int32
321 VolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition64 
322                  *partition)
323 {
324     register struct DiskPartition64 *dp;
325
326 /*
327     if (!afsconf_SuperUser(tdir, acid, caller)) return VOLSERBAD_ACCESS;
328 */
329     VResetDiskUsage();
330     dp = VGetPartition(pname, 0);
331     if (dp) {
332         strncpy(partition->name, dp->name, 32);
333         strncpy(partition->devName, dp->devName, 32);
334         partition->lock_fd = (int)dp->lock_fd;
335         partition->free = dp->free;
336         partition->minFree = dp->totalUsable;
337         return 0;
338     } else
339         return VOLSERILLEGAL_PARTITION;
340 }
341
342 /* obliterate a volume completely, and slowly. */
343 afs_int32
344 SAFSVolNukeVolume(struct rx_call *acid, afs_int32 apartID, afs_uint32 avolID)
345 {
346     afs_int32 code;
347
348     code = VolNukeVolume(acid, apartID, avolID);
349     osi_auditU(acid, VS_NukVolEvent, code, AUD_LONG, avolID, AUD_END);
350     return code;
351 }
352
353 afs_int32
354 VolNukeVolume(struct rx_call *acid, afs_int32 apartID, afs_uint32 avolID)
355 {
356     char partName[50];
357     afs_int32 error;
358     register afs_int32 code;
359     struct Volume *tvp;
360     char caller[MAXKTCNAMELEN];
361
362     /* check for access */
363     if (!afsconf_SuperUser(tdir, acid, caller))
364         return VOLSERBAD_ACCESS;
365     if (DoLogging)
366         Log("%s is executing VolNukeVolume %u\n", caller, avolID);
367
368     if (volutil_PartitionName2_r(apartID, partName, sizeof(partName)) != 0)
369         return VOLSERNOVOL;
370     /* we first try to attach the volume in update mode, so that the file
371      * server doesn't try to use it (and abort) while (or after) we delete it.
372      * If we don't get the volume, that's fine, too.  We just won't put it back.
373      */
374     tvp = XAttachVolume(&error, avolID, apartID, V_VOLUPD);
375     code = nuke(partName, avolID);
376     if (tvp)
377         VDetachVolume(&error, tvp);
378     return code;
379 }
380
381 /* create a new volume, with name aname, on the specified partition (1..n)
382  * and of type atype (readwriteVolume, readonlyVolume, backupVolume).
383  * As input, if *avolid is 0, we allocate a new volume id, otherwise we use *avolid
384  * for the volume id (useful for things like volume restore).
385  * Return the new volume id in *avolid.
386  */
387 afs_int32
388 SAFSVolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname, 
389                     afs_int32 atype, afs_uint32 aparent, afs_uint32 *avolid, 
390                     afs_int32 *atrans)
391 {
392     afs_int32 code;
393
394     code =
395         VolCreateVolume(acid, apart, aname, atype, aparent, avolid, atrans);
396     osi_auditU(acid, VS_CrVolEvent, code, AUD_LONG, *atrans, AUD_LONG,
397                *avolid, AUD_STR, aname, AUD_LONG, atype, AUD_LONG, aparent,
398                AUD_END);
399     return code;
400 }
401
402 afs_int32
403 VolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname, 
404                     afs_int32 atype, afs_uint32 aparent, afs_uint32 *avolid, 
405                     afs_int32 *atrans)
406 {
407     afs_int32 error;
408     register Volume *vp;
409     afs_int32 junk;             /* discardable error code */
410     afs_uint32 volumeID;
411     afs_int32 doCreateRoot = 1;
412     register struct volser_trans *tt;
413     char ppath[30];
414     char caller[MAXKTCNAMELEN];
415
416     if (strlen(aname) > 31)
417         return VOLSERBADNAME;
418     if (!afsconf_SuperUser(tdir, acid, caller))
419         return VOLSERBAD_ACCESS;
420     if (DoLogging)
421         Log("%s is executing CreateVolume '%s'\n", caller, aname);
422     if ((error = ConvertPartition(apart, ppath, sizeof(ppath))))
423         return error;           /*a standard unix error */
424     if (atype != readwriteVolume && atype != readonlyVolume
425         && atype != backupVolume)
426         return EINVAL;
427     if ((volumeID = *avolid) == 0) {
428
429         Log("1 Volser: CreateVolume: missing volume number; %s volume not created\n", aname);
430         return E2BIG;
431
432     }
433     if ((aparent == volumeID) && (atype == readwriteVolume)) {
434         doCreateRoot = 0;
435     }
436     if (aparent == 0)
437         aparent = volumeID;
438     tt = NewTrans(volumeID, apart);
439     if (!tt) {
440         Log("1 createvolume: failed to create trans\n");
441         return VOLSERVOLBUSY;   /* volume already busy! */
442     }
443     vp = VCreateVolume(&error, ppath, volumeID, aparent);
444     if (error) {
445         Log("1 Volser: CreateVolume: Unable to create the volume; aborted, error code %u\n", error);
446         LogError(error);
447         DeleteTrans(tt, 1);
448         return EIO;
449     }
450     V_uniquifier(vp) = 1;
451     V_updateDate(vp) = V_creationDate(vp) = V_copyDate(vp);
452     V_inService(vp) = V_blessed(vp) = 1;
453     V_type(vp) = atype;
454     AssignVolumeName(&V_disk(vp), aname, 0);
455     if (doCreateRoot)
456         ViceCreateRoot(vp);
457     V_destroyMe(vp) = DESTROY_ME;
458     V_inService(vp) = 0;
459     V_maxquota(vp) = 5000;      /* set a quota of 5000 at init time */
460     VUpdateVolume(&error, vp);
461     if (error) {
462         Log("1 Volser: create UpdateVolume failed, code %d\n", error);
463         LogError(error);
464         DeleteTrans(tt, 1);
465         VDetachVolume(&junk, vp);       /* rather return the real error code */
466         return error;
467     }
468     tt->volume = vp;
469     *atrans = tt->tid;
470     strcpy(tt->lastProcName, "CreateVolume");
471     tt->rxCallPtr = acid;
472     Log("1 Volser: CreateVolume: volume %u (%s) created\n", volumeID, aname);
473     tt->rxCallPtr = (struct rx_call *)0;
474     if (TRELE(tt))
475         return VOLSERTRELE_ERROR;
476     return 0;
477 }
478
479 /* delete the volume associated with this transaction */
480 afs_int32
481 SAFSVolDeleteVolume(struct rx_call *acid, afs_int32 atrans)
482 {
483     afs_int32 code;
484
485     code = VolDeleteVolume(acid, atrans);
486     osi_auditU(acid, VS_DelVolEvent, code, AUD_LONG, atrans, AUD_END);
487     return code;
488 }
489
490 afs_int32
491 VolDeleteVolume(struct rx_call *acid, afs_int32 atrans)
492 {
493     register struct volser_trans *tt;
494     afs_int32 error;
495     char caller[MAXKTCNAMELEN];
496
497     if (!afsconf_SuperUser(tdir, acid, caller))
498         return VOLSERBAD_ACCESS;
499     tt = FindTrans(atrans);
500     if (!tt)
501         return ENOENT;
502     if (tt->vflags & VTDeleted) {
503         Log("1 Volser: Delete: volume %u already deleted \n", tt->volid);
504         TRELE(tt);
505         return ENOENT;
506     }
507     if (DoLogging)
508         Log("%s is executing Delete Volume %u\n", caller, tt->volid);
509     strcpy(tt->lastProcName, "DeleteVolume");
510     tt->rxCallPtr = acid;
511     VPurgeVolume(&error, tt->volume);   /* don't check error code, it is not set! */
512     V_destroyMe(tt->volume) = DESTROY_ME; /* so endtrans does the right fssync opcode */
513     tt->vflags |= VTDeleted;    /* so we know not to do anything else to it */
514     tt->rxCallPtr = (struct rx_call *)0;
515     if (TRELE(tt))
516         return VOLSERTRELE_ERROR;
517
518     Log("1 Volser: Delete: volume %u deleted \n", tt->volid);
519     return 0;                   /* vpurgevolume doesn't set an error code */
520 }
521
522 /* make a clone of the volume associated with atrans, possibly giving it a new
523  * number (allocate a new number if *newNumber==0, otherwise use *newNumber
524  * for the clone's id).  The new clone is given the name newName.  Finally, due to
525  * efficiency considerations, if purgeId is non-zero, we purge that volume when doing
526  * the clone operation.  This may be useful when making new backup volumes, for instance
527  * since the net result of a clone and a purge generally leaves many inode ref counts
528  * the same, while doing them separately would result in far more iincs and idecs being
529  * peformed (and they are slow operations).
530  */
531 /* for efficiency reasons, sometimes faster to piggyback a purge here */
532 afs_int32
533 SAFSVolClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 purgeId, 
534              afs_int32 newType, char *newName, afs_uint32 *newNumber)
535 {
536     afs_int32 code;
537
538     code = VolClone(acid, atrans, purgeId, newType, newName, newNumber);
539     osi_auditU(acid, VS_CloneEvent, code, AUD_LONG, atrans, AUD_LONG, purgeId,
540                AUD_STR, newName, AUD_LONG, newType, AUD_LONG, *newNumber,
541                AUD_END);
542     return code;
543 }
544
545 afs_int32
546 VolClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 purgeId, 
547              afs_int32 newType, char *newName, afs_uint32 *newNumber)
548 {
549     afs_uint32 newId;
550     register struct Volume *originalvp, *purgevp, *newvp;
551     Error error, code;
552     register struct volser_trans *tt, *ttc;
553     char caller[MAXKTCNAMELEN];
554
555     if (strlen(newName) > 31)
556         return VOLSERBADNAME;
557     if (!afsconf_SuperUser(tdir, acid, caller))
558         return VOLSERBAD_ACCESS;        /*not a super user */
559     if (DoLogging)
560         Log("%s is executing Clone Volume new name=%s\n", caller, newName);
561     error = 0;
562     originalvp = (Volume *) 0;
563     purgevp = (Volume *) 0;
564     newvp = (Volume *) 0;
565     tt = ttc = (struct volser_trans *)0;
566
567     if (!newNumber || !*newNumber) {
568         Log("1 Volser: Clone: missing volume number for the clone; aborted\n");
569         goto fail;
570     }
571     newId = *newNumber;
572
573     if (newType != readonlyVolume && newType != backupVolume)
574         return EINVAL;
575     tt = FindTrans(atrans);
576     if (!tt)
577         return ENOENT;
578     if (tt->vflags & VTDeleted) {
579         Log("1 Volser: Clone: volume %u has been deleted \n", tt->volid);
580         TRELE(tt);
581         return ENOENT;
582     }
583     ttc = NewTrans(newId, tt->partition);
584     if (!ttc) {                 /* someone is messing with the clone already */
585         TRELE(tt);
586         return VBUSY;
587     }
588     strcpy(tt->lastProcName, "Clone");
589     tt->rxCallPtr = acid;
590
591
592     if (purgeId) {
593         purgevp = VAttachVolume(&error, purgeId, V_VOLUPD);
594         if (error) {
595             Log("1 Volser: Clone: Could not attach 'purge' volume %u; clone aborted\n", purgeId);
596             goto fail;
597         }
598     } else {
599         purgevp = NULL;
600     }
601     originalvp = tt->volume;
602     if ((V_type(originalvp) == backupVolume)
603         || (V_type(originalvp) == readonlyVolume)) {
604         Log("1 Volser: Clone: The volume to be cloned must be a read/write; aborted\n");
605         error = EROFS;
606         goto fail;
607     }
608     if ((V_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) {
609         Log("1 Volser: Clone: Volume %d is offline and cannot be cloned\n",
610             V_id(originalvp));
611         error = VOFFLINE;
612         goto fail;
613     }
614     if (purgevp) {
615         if (originalvp->device != purgevp->device) {
616             Log("1 Volser: Clone: Volumes %u and %u are on different devices\n", tt->volid, purgeId);
617             error = EXDEV;
618             goto fail;
619         }
620         if (V_type(purgevp) != readonlyVolume) {
621             Log("1 Volser: Clone: The \"purge\" volume must be a read only volume; aborted\n");
622             error = EINVAL;
623             goto fail;
624         }
625         if (V_type(originalvp) == readonlyVolume
626             && V_parentId(originalvp) != V_parentId(purgevp)) {
627             Log("1 Volser: Clone: Volume %u and volume %u were not cloned from the same parent volume; aborted\n", tt->volid, purgeId);
628             error = EXDEV;
629             goto fail;
630         }
631         if (V_type(originalvp) == readwriteVolume
632             && tt->volid != V_parentId(purgevp)) {
633             Log("1 Volser: Clone: Volume %u was not originally cloned from volume %u; aborted\n", purgeId, tt->volid);
634             error = EXDEV;
635             goto fail;
636         }
637     }
638
639     error = 0;
640
641     newvp =
642         VCreateVolume(&error, originalvp->partition->name, newId,
643                       V_parentId(originalvp));
644     if (error) {
645         Log("1 Volser: Clone: Couldn't create new volume; clone aborted\n");
646         newvp = (Volume *) 0;
647         goto fail;
648     }
649     if (newType == readonlyVolume)
650         V_cloneId(originalvp) = newId;
651     Log("1 Volser: Clone: Cloning volume %u to new volume %u\n", tt->volid,
652         newId);
653     if (purgevp)
654         Log("1 Volser: Clone: Purging old read only volume %u\n", purgeId);
655     CloneVolume(&error, originalvp, newvp, purgevp);
656     purgevp = NULL;             /* clone releases it, maybe even if error */
657     if (error) {
658         Log("1 Volser: Clone: clone operation failed with code %u\n", error);
659         LogError(error);
660         goto fail;
661     }
662     if (newType == readonlyVolume) {
663         AssignVolumeName(&V_disk(newvp), V_name(originalvp), ".readonly");
664         V_type(newvp) = readonlyVolume;
665     } else if (newType == backupVolume) {
666         AssignVolumeName(&V_disk(newvp), V_name(originalvp), ".backup");
667         V_type(newvp) = backupVolume;
668         V_backupId(originalvp) = newId;
669     }
670     strcpy(newvp->header->diskstuff.name, newName);
671     V_creationDate(newvp) = V_copyDate(newvp);
672     ClearVolumeStats(&V_disk(newvp));
673     V_destroyMe(newvp) = DESTROY_ME;
674     V_inService(newvp) = 0;
675     if (newType == backupVolume) {
676         V_backupDate(originalvp) = V_copyDate(newvp);
677         V_backupDate(newvp) = V_copyDate(newvp);
678     }
679     V_inUse(newvp) = 0;
680     VUpdateVolume(&error, newvp);
681     if (error) {
682         Log("1 Volser: Clone: VUpdate failed code %u\n", error);
683         LogError(error);
684         goto fail;
685     }
686     VDetachVolume(&error, newvp);       /* allow file server to get it's hands on it */
687     newvp = NULL;
688     VUpdateVolume(&error, originalvp);
689     if (error) {
690         Log("1 Volser: Clone: original update %u\n", error);
691         LogError(error);
692         goto fail;
693     }
694     tt->rxCallPtr = (struct rx_call *)0;
695     if (TRELE(tt)) {
696         tt = (struct volser_trans *)0;
697         error = VOLSERTRELE_ERROR;
698         goto fail;
699     }
700     DeleteTrans(ttc, 1);
701     return 0;
702
703   fail:
704     if (purgevp)
705         VDetachVolume(&code, purgevp);
706     if (newvp)
707         VDetachVolume(&code, newvp);
708     if (tt) {
709         tt->rxCallPtr = (struct rx_call *)0;
710         TRELE(tt);
711     }
712     if (ttc)
713         DeleteTrans(ttc, 1);
714     return error;
715 }
716
717 /* reclone this volume into the specified id */
718 afs_int32
719 SAFSVolReClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 cloneId)
720 {
721     afs_int32 code;
722
723     code = VolReClone(acid, atrans, cloneId);
724     osi_auditU(acid, VS_ReCloneEvent, code, AUD_LONG, atrans, AUD_LONG,
725                cloneId, AUD_END);
726     return code;
727 }
728
729 afs_int32
730 VolReClone(struct rx_call *acid, afs_int32 atrans, afs_int32 cloneId)
731 {
732     register struct Volume *originalvp, *clonevp;
733     Error error, code;
734     afs_int32 newType;
735     register struct volser_trans *tt, *ttc;
736     char caller[MAXKTCNAMELEN];
737
738     /*not a super user */
739     if (!afsconf_SuperUser(tdir, acid, caller))
740         return VOLSERBAD_ACCESS;
741     if (DoLogging)
742         Log("%s is executing Reclone Volume %u\n", caller, cloneId);
743     error = 0;
744     clonevp = originalvp = (Volume *) 0;
745     tt = (struct volser_trans *)0;
746
747     tt = FindTrans(atrans);
748     if (!tt)
749         return ENOENT;
750     if (tt->vflags & VTDeleted) {
751         Log("1 Volser: VolReClone: volume %u has been deleted \n", tt->volid);
752         TRELE(tt);
753         return ENOENT;
754     }
755     ttc = NewTrans(cloneId, tt->partition);
756     if (!ttc) {                 /* someone is messing with the clone already */
757         TRELE(tt);
758         return VBUSY;
759     }
760     strcpy(tt->lastProcName, "ReClone");
761     tt->rxCallPtr = acid;
762
763     originalvp = tt->volume;
764     if ((V_type(originalvp) == backupVolume)
765         || (V_type(originalvp) == readonlyVolume)) {
766         Log("1 Volser: Clone: The volume to be cloned must be a read/write; aborted\n");
767         error = EROFS;
768         goto fail;
769     }
770     if ((V_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) {
771         Log("1 Volser: Clone: Volume %d is offline and cannot be cloned\n",
772             V_id(originalvp));
773         error = VOFFLINE;
774         goto fail;
775     }
776
777     clonevp = VAttachVolume(&error, cloneId, V_VOLUPD);
778     if (error) {
779         Log("1 Volser: can't attach clone %d\n", cloneId);
780         goto fail;
781     }
782
783     newType = V_type(clonevp);  /* type of the new volume */
784
785     if (originalvp->device != clonevp->device) {
786         Log("1 Volser: Clone: Volumes %u and %u are on different devices\n",
787             tt->volid, cloneId);
788         error = EXDEV;
789         goto fail;
790     }
791     if (V_type(clonevp) != readonlyVolume && V_type(clonevp) != backupVolume) {
792         Log("1 Volser: Clone: The \"recloned\" volume must be a read only volume; aborted\n");
793         error = EINVAL;
794         goto fail;
795     }
796     if (V_type(originalvp) == readonlyVolume
797         && V_parentId(originalvp) != V_parentId(clonevp)) {
798         Log("1 Volser: Clone: Volume %u and volume %u were not cloned from the same parent volume; aborted\n", tt->volid, cloneId);
799         error = EXDEV;
800         goto fail;
801     }
802     if (V_type(originalvp) == readwriteVolume
803         && tt->volid != V_parentId(clonevp)) {
804         Log("1 Volser: Clone: Volume %u was not originally cloned from volume %u; aborted\n", cloneId, tt->volid);
805         error = EXDEV;
806         goto fail;
807     }
808
809     error = 0;
810     Log("1 Volser: Clone: Recloning volume %u to volume %u\n", tt->volid,
811         cloneId);
812     CloneVolume(&error, originalvp, clonevp, clonevp);
813     if (error) {
814         Log("1 Volser: Clone: reclone operation failed with code %d\n",
815             error);
816         LogError(error);
817         goto fail;
818     }
819
820     /* fix up volume name and type, CloneVolume just propagated RW's */
821     if (newType == readonlyVolume) {
822         AssignVolumeName(&V_disk(clonevp), V_name(originalvp), ".readonly");
823         V_type(clonevp) = readonlyVolume;
824     } else if (newType == backupVolume) {
825         AssignVolumeName(&V_disk(clonevp), V_name(originalvp), ".backup");
826         V_type(clonevp) = backupVolume;
827         V_backupId(originalvp) = cloneId;
828     }
829     /* don't do strcpy onto diskstuff.name, it's still OK from 1st clone */
830
831     /* pretend recloned volume is a totally new instance */
832     V_copyDate(clonevp) = time(0);
833     V_creationDate(clonevp) = V_copyDate(clonevp);
834     ClearVolumeStats(&V_disk(clonevp));
835     V_destroyMe(clonevp) = 0;
836     V_inService(clonevp) = 0;
837     if (newType == backupVolume) {
838         V_backupDate(originalvp) = V_copyDate(clonevp);
839         V_backupDate(clonevp) = V_copyDate(clonevp);
840     }
841     V_inUse(clonevp) = 0;
842     VUpdateVolume(&error, clonevp);
843     if (error) {
844         Log("1 Volser: Clone: VUpdate failed code %u\n", error);
845         LogError(error);
846         goto fail;
847     }
848     /* VUpdateVolume succeeded. Mark it in service so there's no window 
849      * between FSYNC_VOL_ON and VolSetFlags where it's offline with no  
850      * specialStatus; this is a reclone and this volume started online  
851      */
852     V_inService(clonevp) = 1;
853     VDetachVolume(&error, clonevp);     /* allow file server to get it's hands on it */
854     clonevp = NULL;
855     VUpdateVolume(&error, originalvp);
856     if (error) {
857         Log("1 Volser: Clone: original update %u\n", error);
858         LogError(error);
859         goto fail;
860     }
861     tt->rxCallPtr = (struct rx_call *)0;
862     if (TRELE(tt)) {
863         tt = (struct volser_trans *)0;
864         error = VOLSERTRELE_ERROR;
865         goto fail;
866     }
867
868     DeleteTrans(ttc, 1);
869
870     {
871         struct DiskPartition64 *tpartp = originalvp->partition;
872         FSYNC_VolOp(cloneId, tpartp->name, FSYNC_VOL_BREAKCBKS, 0, NULL);
873     }
874     return 0;
875
876   fail:
877     if (clonevp)
878         VDetachVolume(&code, clonevp);
879     if (tt) {
880         tt->rxCallPtr = (struct rx_call *)0;
881         TRELE(tt);
882     }
883     if (ttc)
884         DeleteTrans(ttc, 1);
885     return error;
886 }
887
888 /* create a new transaction, associated with volume and partition.  Type of
889  * volume transaction is spec'd by iflags.  New trans id is returned in ttid.
890  * See volser.h for definition of iflags (the constants are named IT*).
891  */
892 afs_int32
893 SAFSVolTransCreate(struct rx_call *acid, afs_uint32 volume, afs_int32 partition,
894                    afs_int32 iflags, afs_int32 *ttid)
895 {
896     afs_int32 code;
897
898     code = VolTransCreate(acid, volume, partition, iflags, ttid);
899     osi_auditU(acid, VS_TransCrEvent, code, AUD_LONG, *ttid, AUD_LONG, volume,
900                AUD_END);
901     return code;
902 }
903
904 afs_int32
905 VolTransCreate(struct rx_call *acid, afs_uint32 volume, afs_int32 partition,
906                    afs_int32 iflags, afs_int32 *ttid)
907 {
908     register struct volser_trans *tt;
909     register Volume *tv;
910     afs_int32 error, code;
911     afs_int32 mode;
912     char caller[MAXKTCNAMELEN];
913
914     if (!afsconf_SuperUser(tdir, acid, caller))
915         return VOLSERBAD_ACCESS;        /*not a super user */
916     if (iflags & ITCreate)
917         mode = V_SECRETLY;
918     else if (iflags & ITBusy)
919         mode = V_CLONE;
920     else if (iflags & ITReadOnly)
921         mode = V_READONLY;
922     else if (iflags & ITOffline)
923         mode = V_VOLUPD;
924     else {
925         Log("1 Volser: TransCreate: Could not create trans, error %u\n",
926             EINVAL);
927         LogError(EINVAL);
928         return EINVAL;
929     }
930     tt = NewTrans(volume, partition);
931     if (!tt) {
932         /* can't create a transaction? put the volume back */
933         Log("1 transcreate: can't create transaction\n");
934         return VOLSERVOLBUSY;
935     }
936     tv = XAttachVolume(&error, volume, partition, mode);
937     if (error) {
938         /* give up */
939         if (tv)
940             VDetachVolume(&code, tv);
941         DeleteTrans(tt, 1);
942         return error;
943     }
944     tt->volume = tv;
945     *ttid = tt->tid;
946     tt->iflags = iflags;
947     tt->vflags = 0;
948     strcpy(tt->lastProcName, "TransCreate");
949     if (TRELE(tt))
950         return VOLSERTRELE_ERROR;
951
952     return 0;
953 }
954
955 /* using aindex as a 0-based index, return the aindex'th volume on this server
956  * Both the volume number and partition number (one-based) are returned.
957  */
958 afs_int32
959 SAFSVolGetNthVolume(struct rx_call *acid, afs_int32 aindex, afs_uint32 *avolume,
960                     afs_int32 *apart)
961 {
962     afs_int32 code;
963
964     code = VolGetNthVolume(acid, aindex, avolume, apart);
965     osi_auditU(acid, VS_GetNVolEvent, code, AUD_LONG, *avolume, AUD_END);
966     return code;
967 }
968
969 afs_int32
970 VolGetNthVolume(struct rx_call *acid, afs_int32 aindex, afs_int32 *avolume,
971                     afs_int32 *apart)
972 {
973     Log("1 Volser: GetNthVolume: Not yet implemented\n");
974     return VOLSERNO_OP;
975 }
976
977 /* return the volume flags (VT* constants in volser.h) associated with this
978  * transaction.
979  */
980 afs_int32
981 SAFSVolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
982 {
983     afs_int32 code;
984
985     code = VolGetFlags(acid, atid, aflags);
986     osi_auditU(acid, VS_GetFlgsEvent, code, AUD_LONG, atid, AUD_END);
987     return code;
988 }
989
990 afs_int32
991 VolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
992 {
993     register struct volser_trans *tt;
994
995     tt = FindTrans(atid);
996     if (!tt)
997         return ENOENT;
998     if (tt->vflags & VTDeleted) {
999         Log("1 Volser: VolGetFlags: volume %u has been deleted \n",
1000             tt->volid);
1001         TRELE(tt);
1002         return ENOENT;
1003     }
1004     strcpy(tt->lastProcName, "GetFlags");
1005     tt->rxCallPtr = acid;
1006     *aflags = tt->vflags;
1007     tt->rxCallPtr = (struct rx_call *)0;
1008     if (TRELE(tt))
1009         return VOLSERTRELE_ERROR;
1010
1011     return 0;
1012 }
1013
1014 /* Change the volume flags (VT* constants in volser.h) associated with this
1015  * transaction.  Effects take place immediately on volume, although volume
1016  * remains attached as usual by the transaction.
1017  */
1018 afs_int32
1019 SAFSVolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1020 {
1021     afs_int32 code;
1022
1023     code = VolSetFlags(acid, atid, aflags);
1024     osi_auditU(acid, VS_SetFlgsEvent, code, AUD_LONG, atid, AUD_LONG, aflags,
1025                AUD_END);
1026     return code;
1027 }
1028
1029 afs_int32
1030 VolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1031 {
1032     register struct volser_trans *tt;
1033     register struct Volume *vp;
1034     afs_int32 error;
1035     char caller[MAXKTCNAMELEN];
1036
1037     if (!afsconf_SuperUser(tdir, acid, caller))
1038         return VOLSERBAD_ACCESS;        /*not a super user */
1039     /* find the trans */
1040     tt = FindTrans(atid);
1041     if (!tt)
1042         return ENOENT;
1043     if (tt->vflags & VTDeleted) {
1044         Log("1 Volser: VolSetFlags: volume %u has been deleted \n",
1045             tt->volid);
1046         TRELE(tt);
1047         return ENOENT;
1048     }
1049     strcpy(tt->lastProcName, "SetFlags");
1050     tt->rxCallPtr = acid;
1051     vp = tt->volume;            /* pull volume out of transaction */
1052
1053     /* check if we're allowed to make any updates */
1054     if (tt->iflags & ITReadOnly) {
1055         TRELE(tt);
1056         return EROFS;
1057     }
1058
1059     /* handle delete-on-salvage flag */
1060     if (aflags & VTDeleteOnSalvage) {
1061         V_destroyMe(tt->volume) = DESTROY_ME;
1062     } else {
1063         V_destroyMe(tt->volume) = 0;
1064     }
1065
1066     if (aflags & VTOutOfService) {
1067         V_inService(vp) = 0;
1068     } else {
1069         V_inService(vp) = 1;
1070     }
1071     VUpdateVolume(&error, vp);
1072     tt->vflags = aflags;
1073     tt->rxCallPtr = (struct rx_call *)0;
1074     if (TRELE(tt) && !error)
1075         return VOLSERTRELE_ERROR;
1076
1077     return error;
1078 }
1079
1080 /* dumpS the volume associated with a particular transaction from a particular
1081  * date.  Send the dump to a different transaction (destTrans) on the server
1082  * specified by the destServer structure.
1083  */
1084 afs_int32
1085 SAFSVolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1086                struct destServer *destination, afs_int32 destTrans, 
1087                struct restoreCookie *cookie)
1088 {
1089     afs_int32 code;
1090
1091     code =
1092         VolForward(acid, fromTrans, fromDate, destination, destTrans, cookie);
1093     osi_auditU(acid, VS_ForwardEvent, code, AUD_LONG, fromTrans, AUD_HOST,
1094                destination->destHost, AUD_LONG, destTrans, AUD_END);
1095     return code;
1096 }
1097
1098 afs_int32
1099 VolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1100                struct destServer *destination, afs_int32 destTrans, 
1101                struct restoreCookie *cookie)
1102 {
1103     register struct volser_trans *tt;
1104     register afs_int32 code;
1105     register struct rx_connection *tcon;
1106     struct rx_call *tcall;
1107     register struct Volume *vp;
1108     struct rx_securityClass *securityObject;
1109     afs_int32 securityIndex;
1110     char caller[MAXKTCNAMELEN];
1111
1112     if (!afsconf_SuperUser(tdir, acid, caller))
1113         return VOLSERBAD_ACCESS;        /*not a super user */
1114     /* initialize things */
1115     tcon = (struct rx_connection *)0;
1116     tt = (struct volser_trans *)0;
1117
1118     /* find the local transaction */
1119     tt = FindTrans(fromTrans);
1120     if (!tt)
1121         return ENOENT;
1122     if (tt->vflags & VTDeleted) {
1123         Log("1 Volser: VolForward: volume %u has been deleted \n", tt->volid);
1124         TRELE(tt);
1125         return ENOENT;
1126     }
1127     vp = tt->volume;
1128     strcpy(tt->lastProcName, "Forward");
1129
1130     /* get auth info for the this connection (uses afs from ticket file) */
1131     code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
1132     if (code) {
1133         TRELE(tt);
1134         return code;
1135     }
1136
1137     /* make an rpc connection to the other server */
1138     tcon =
1139         rx_NewConnection(htonl(destination->destHost),
1140                          htons(destination->destPort), VOLSERVICE_ID,
1141                          securityObject, securityIndex);
1142     if (!tcon) {
1143         tt->rxCallPtr = (struct rx_call *)0;
1144         TRELE(tt);
1145         return ENOTCONN;
1146     }
1147     tcall = rx_NewCall(tcon);
1148     tt->rxCallPtr = tcall;
1149     /* start restore going.  fromdate == 0 --> doing an incremental dump/restore */
1150     code = StartAFSVolRestore(tcall, destTrans, (fromDate ? 1 : 0), cookie);
1151     if (code) {
1152         goto fail;
1153     }
1154
1155     /* these next calls implictly call rx_Write when writing out data */
1156     code = DumpVolume(tcall, vp, fromDate, 0);  /* last field = don't dump all dirs */
1157     if (code)
1158         goto fail;
1159     EndAFSVolRestore(tcall);    /* probably doesn't do much */
1160     tt->rxCallPtr = (struct rx_call *)0;
1161     code = rx_EndCall(tcall, 0);
1162     rx_DestroyConnection(tcon); /* done with the connection */
1163     tcon = NULL;
1164     if (code)
1165         goto fail;
1166     if (TRELE(tt))
1167         return VOLSERTRELE_ERROR;
1168
1169     return 0;
1170
1171   fail:
1172     if (tcon) {
1173         (void)rx_EndCall(tcall, 0);
1174         rx_DestroyConnection(tcon);
1175     }
1176     if (tt) {
1177         tt->rxCallPtr = (struct rx_call *)0;
1178         TRELE(tt);
1179     }
1180     return code;
1181 }
1182
1183 /* Start a dump and send it to multiple places simultaneously.
1184  * If this returns an error (eg, return ENOENT), it means that
1185  * none of the releases worked.  If this returns 0, that means 
1186  * that one or more of the releases worked, and the caller has
1187  * to examine the results array to see which one(s).
1188  * This will only do EITHER incremental or full, not both, so it's
1189  * the caller's responsibility to be sure that all the destinations
1190  * need just an incremental (and from the same time), if that's 
1191  * what we're doing. 
1192  */
1193 afs_int32
1194 SAFSVolForwardMultiple(struct rx_call *acid, afs_int32 fromTrans, afs_int32 
1195                        fromDate, manyDests *destinations, afs_int32 spare,
1196                        struct restoreCookie *cookie, manyResults *results)
1197 {
1198     afs_int32 securityIndex;
1199     struct rx_securityClass *securityObject;
1200     char caller[MAXKTCNAMELEN];
1201     struct volser_trans *tt;
1202     afs_int32 ec, code, *codes;
1203     struct rx_connection **tcons;
1204     struct rx_call **tcalls;
1205     struct Volume *vp;
1206     int i, is_incremental;
1207
1208     if (results) {
1209         memset(results, 0, sizeof(manyResults));
1210         i = results->manyResults_len = destinations->manyDests_len;
1211         results->manyResults_val = codes =
1212           (afs_int32 *) malloc(i * sizeof(afs_int32));
1213     }   
1214     if (!results || !results->manyResults_val)
1215         return ENOMEM;
1216
1217     if (!afsconf_SuperUser(tdir, acid, caller))
1218         return VOLSERBAD_ACCESS;        /*not a super user */
1219     tt = FindTrans(fromTrans);
1220     if (!tt)
1221         return ENOENT;
1222     if (tt->vflags & VTDeleted) {
1223         Log("1 Volser: VolForward: volume %u has been deleted \n", tt->volid);
1224         TRELE(tt);
1225         return ENOENT;
1226     }
1227     vp = tt->volume;
1228     strcpy(tt->lastProcName, "ForwardMulti");
1229
1230     /* (fromDate == 0) ==> full dump */
1231     is_incremental = (fromDate ? 1 : 0);
1232
1233     tcons =
1234         (struct rx_connection **)malloc(i * sizeof(struct rx_connection *));
1235     if (!tcons) {
1236         return ENOMEM;
1237     }
1238     tcalls = (struct rx_call **)malloc(i * sizeof(struct rx_call *));
1239     if (!tcalls) {
1240         free(tcons);
1241         return ENOMEM;
1242     }
1243
1244     /* get auth info for this connection (uses afs from ticket file) */
1245     code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
1246     if (code) {
1247         goto fail;              /* in order to audit each failure */
1248     }
1249
1250     /* make connections to all the other servers */
1251     for (i = 0; i < destinations->manyDests_len; i++) {
1252         struct replica *dest = &(destinations->manyDests_val[i]);
1253         tcons[i] =
1254             rx_NewConnection(htonl(dest->server.destHost),
1255                              htons(dest->server.destPort), VOLSERVICE_ID,
1256                              securityObject, securityIndex);
1257         if (!tcons[i]) {
1258             codes[i] = ENOTCONN;
1259         } else {
1260             if (!(tcalls[i] = rx_NewCall(tcons[i])))
1261                 codes[i] = ENOTCONN;
1262             else {
1263                 codes[i] =
1264                     StartAFSVolRestore(tcalls[i], dest->trans, is_incremental,
1265                                        cookie);
1266                 if (codes[i]) {
1267                     (void)rx_EndCall(tcalls[i], 0);
1268                     tcalls[i] = 0;
1269                     rx_DestroyConnection(tcons[i]);
1270                     tcons[i] = 0;
1271                 }
1272             }
1273         }
1274     }
1275
1276     /* these next calls implictly call rx_Write when writing out data */
1277     code = DumpVolMulti(tcalls, i, vp, fromDate, 0, codes);
1278
1279
1280   fail:
1281     for (i--; i >= 0; i--) {
1282         struct replica *dest = &(destinations->manyDests_val[i]);
1283
1284         if (!code && tcalls[i] && !codes[i]) {
1285             EndAFSVolRestore(tcalls[i]);
1286         }
1287         if (tcalls[i]) {
1288             ec = rx_EndCall(tcalls[i], 0);
1289             if (!codes[i])
1290                 codes[i] = ec;
1291         }
1292         if (tcons[i]) {
1293             rx_DestroyConnection(tcons[i]);     /* done with the connection */
1294         }
1295
1296         osi_auditU(acid, VS_ForwardEvent, (code ? code : codes[i]), AUD_LONG,
1297                    fromTrans, AUD_HOST, dest->server.destHost, AUD_LONG,
1298                    dest->trans, AUD_END);
1299     }
1300     free(tcons);
1301     free(tcalls);
1302
1303     if (tt) {
1304         tt->rxCallPtr = (struct rx_call *)0;
1305         if (TRELE(tt) && !code) /* return the first code if it's set */
1306             return VOLSERTRELE_ERROR;
1307     }
1308
1309     return code;
1310 }
1311
1312 afs_int32
1313 SAFSVolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate)
1314 {
1315     afs_int32 code;
1316
1317     code = VolDump(acid, fromTrans, fromDate, 0);
1318     osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1319     return code;
1320 }
1321
1322 afs_int32
1323 SAFSVolDumpV2(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate, afs_int32 flags)
1324 {
1325     afs_int32 code;
1326
1327     code = VolDump(acid, fromTrans, fromDate, flags);
1328     osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1329     return code;
1330 }
1331
1332 afs_int32
1333 VolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate, afs_int32 flags)
1334 {
1335     int code = 0;
1336     register struct volser_trans *tt;
1337     char caller[MAXKTCNAMELEN];
1338
1339     if (!afsconf_SuperUser(tdir, acid, caller))
1340         return VOLSERBAD_ACCESS;        /*not a super user */
1341     tt = FindTrans(fromTrans);
1342     if (!tt)
1343         return ENOENT;
1344     if (tt->vflags & VTDeleted) {
1345         Log("1 Volser: VolDump: volume %u has been deleted \n", tt->volid);
1346         TRELE(tt);
1347         return ENOENT;
1348     }
1349     strcpy(tt->lastProcName, "Dump");
1350     tt->rxCallPtr = acid;
1351     code = DumpVolume(acid, tt->volume, fromDate, (flags & VOLDUMPV2_OMITDIRS)
1352                       ? 0 : 1); /* squirt out the volume's data, too */
1353     if (code) {
1354         tt->rxCallPtr = (struct rx_call *)0;
1355         TRELE(tt);
1356         return code;
1357     }
1358     tt->rxCallPtr = (struct rx_call *)0;
1359
1360     if (TRELE(tt))
1361         return VOLSERTRELE_ERROR;
1362
1363     return 0;
1364 }
1365
1366 /* 
1367  * Ha!  No more helper process!
1368  */
1369 afs_int32
1370 SAFSVolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags, 
1371                struct restoreCookie *cookie)
1372 {
1373     afs_int32 code;
1374
1375     code = VolRestore(acid, atrans, aflags, cookie);
1376     osi_auditU(acid, VS_RestoreEvent, code, AUD_LONG, atrans, AUD_END);
1377     return code;
1378 }
1379
1380 afs_int32
1381 VolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags, 
1382                struct restoreCookie *cookie)
1383 {
1384     register struct volser_trans *tt;
1385     register afs_int32 code, tcode;
1386     char caller[MAXKTCNAMELEN];
1387
1388     if (!afsconf_SuperUser(tdir, acid, caller))
1389         return VOLSERBAD_ACCESS;        /*not a super user */
1390     tt = FindTrans(atrans);
1391     if (!tt)
1392         return ENOENT;
1393     if (tt->vflags & VTDeleted) {
1394         Log("1 Volser: VolRestore: volume %u has been deleted \n", tt->volid);
1395         TRELE(tt);
1396         return ENOENT;
1397     }
1398     strcpy(tt->lastProcName, "Restore");
1399     tt->rxCallPtr = acid;
1400
1401     DFlushVolume(V_parentId(tt->volume)); /* Ensure dir buffers get dropped */
1402
1403     code = RestoreVolume(acid, tt->volume, (aflags & 1), cookie);       /* last is incrementalp */
1404     FSYNC_VolOp(tt->volid, NULL, FSYNC_VOL_BREAKCBKS, 0l, NULL);
1405     tt->rxCallPtr = (struct rx_call *)0;
1406     tcode = TRELE(tt);
1407
1408     return (code ? code : tcode);
1409 }
1410
1411 /* end a transaction, returning the transaction's final error code in rcode */
1412 afs_int32
1413 SAFSVolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1414 {
1415     afs_int32 code;
1416
1417     code = VolEndTrans(acid, destTrans, rcode);
1418     osi_auditU(acid, VS_EndTrnEvent, code, AUD_LONG, destTrans, AUD_END);
1419     return code;
1420 }
1421
1422 afs_int32
1423 VolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1424 {
1425     register struct volser_trans *tt;
1426     char caller[MAXKTCNAMELEN];
1427
1428     if (!afsconf_SuperUser(tdir, acid, caller))
1429         return VOLSERBAD_ACCESS;        /*not a super user */
1430     tt = FindTrans(destTrans);
1431     if (!tt) {
1432         return ENOENT;
1433     }
1434     *rcode = tt->returnCode;
1435     DeleteTrans(tt, 1);         /* this does an implicit TRELE */
1436
1437     return 0;
1438 }
1439
1440 afs_int32
1441 SAFSVolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1442 {
1443     afs_int32 code;
1444
1445     code = VolSetForwarding(acid, atid, anewsite);
1446     osi_auditU(acid, VS_SetForwEvent, code, AUD_LONG, atid, AUD_HOST,
1447                anewsite, AUD_END);
1448     return code;
1449 }
1450
1451 afs_int32
1452 VolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1453 {
1454     register struct volser_trans *tt;
1455     char caller[MAXKTCNAMELEN];
1456     char partName[16];
1457
1458     if (!afsconf_SuperUser(tdir, acid, caller))
1459         return VOLSERBAD_ACCESS;        /*not a super user */
1460     tt = FindTrans(atid);
1461     if (!tt)
1462         return ENOENT;
1463     if (tt->vflags & VTDeleted) {
1464         Log("1 Volser: VolSetForwarding: volume %u has been deleted \n",
1465             tt->volid);
1466         TRELE(tt);
1467         return ENOENT;
1468     }
1469     strcpy(tt->lastProcName, "SetForwarding");
1470     tt->rxCallPtr = acid;
1471     if (volutil_PartitionName2_r(tt->partition, partName, sizeof(partName)) != 0) {
1472         partName[0] = '\0';
1473     }
1474     FSYNC_VolOp(tt->volid, partName, FSYNC_VOL_MOVE, anewsite, NULL);
1475     tt->rxCallPtr = (struct rx_call *)0;
1476     if (TRELE(tt))
1477         return VOLSERTRELE_ERROR;
1478
1479     return 0;
1480 }
1481
1482 afs_int32
1483 SAFSVolGetStatus(struct rx_call *acid, afs_int32 atrans, 
1484                  register struct volser_status *astatus)
1485 {
1486     afs_int32 code;
1487
1488     code = VolGetStatus(acid, atrans, astatus);
1489     osi_auditU(acid, VS_GetStatEvent, code, AUD_LONG, atrans, AUD_END);
1490     return code;
1491 }
1492
1493 afs_int32
1494 VolGetStatus(struct rx_call *acid, afs_int32 atrans, 
1495                  register struct volser_status *astatus)
1496 {
1497     register struct Volume *tv;
1498     register struct VolumeDiskData *td;
1499     struct volser_trans *tt;
1500
1501
1502     tt = FindTrans(atrans);
1503     if (!tt)
1504         return ENOENT;
1505     if (tt->vflags & VTDeleted) {
1506         Log("1 Volser: VolGetStatus: volume %u has been deleted \n",
1507             tt->volid);
1508         TRELE(tt);
1509         return ENOENT;
1510     }
1511     strcpy(tt->lastProcName, "GetStatus");
1512     tt->rxCallPtr = acid;
1513     tv = tt->volume;
1514     if (!tv) {
1515         tt->rxCallPtr = (struct rx_call *)0;
1516         TRELE(tt);
1517         return ENOENT;
1518     }
1519
1520     td = &tv->header->diskstuff;
1521     astatus->volID = td->id;
1522     astatus->nextUnique = td->uniquifier;
1523     astatus->type = td->type;
1524     astatus->parentID = td->parentId;
1525     astatus->cloneID = td->cloneId;
1526     astatus->backupID = td->backupId;
1527     astatus->restoredFromID = td->restoredFromId;
1528     astatus->maxQuota = td->maxquota;
1529     astatus->minQuota = td->minquota;
1530     astatus->owner = td->owner;
1531     astatus->creationDate = td->creationDate;
1532     astatus->accessDate = td->accessDate;
1533     astatus->updateDate = td->updateDate;
1534     astatus->expirationDate = td->expirationDate;
1535     astatus->backupDate = td->backupDate;
1536     astatus->copyDate = td->copyDate;
1537     tt->rxCallPtr = (struct rx_call *)0;
1538     if (TRELE(tt))
1539         return VOLSERTRELE_ERROR;
1540
1541     return 0;
1542 }
1543
1544 afs_int32
1545 SAFSVolSetInfo(struct rx_call *acid, afs_int32 atrans, 
1546                register struct volintInfo *astatus)
1547 {
1548     afs_int32 code;
1549
1550     code = VolSetInfo(acid, atrans, astatus);
1551     osi_auditU(acid, VS_SetInfoEvent, code, AUD_LONG, atrans, AUD_END);
1552     return code;
1553 }
1554
1555 afs_int32
1556 VolSetInfo(struct rx_call *acid, afs_int32 atrans, 
1557                register struct volintInfo *astatus)
1558 {
1559     register struct Volume *tv;
1560     register struct VolumeDiskData *td;
1561     struct volser_trans *tt;
1562     char caller[MAXKTCNAMELEN];
1563     afs_int32 error;
1564
1565     if (!afsconf_SuperUser(tdir, acid, caller))
1566         return VOLSERBAD_ACCESS;        /*not a super user */
1567     tt = FindTrans(atrans);
1568     if (!tt)
1569         return ENOENT;
1570     if (tt->vflags & VTDeleted) {
1571         Log("1 Volser: VolSetInfo: volume %u has been deleted \n", tt->volid);
1572         TRELE(tt);
1573         return ENOENT;
1574     }
1575     strcpy(tt->lastProcName, "SetStatus");
1576     tt->rxCallPtr = acid;
1577     tv = tt->volume;
1578     if (!tv) {
1579         tt->rxCallPtr = (struct rx_call *)0;
1580         TRELE(tt);
1581         return ENOENT;
1582     }
1583
1584     td = &tv->header->diskstuff;
1585     /*
1586      * Add more fields as necessary
1587      */
1588     if (astatus->maxquota != -1)
1589         td->maxquota = astatus->maxquota;
1590     if (astatus->dayUse != -1)
1591         td->dayUse = astatus->dayUse;
1592     if (astatus->creationDate != -1)
1593         td->creationDate = astatus->creationDate;
1594     if (astatus->updateDate != -1)
1595         td->updateDate = astatus->updateDate;
1596     if (astatus->spare2 != -1)
1597         td->volUpdateCounter = (unsigned int)astatus->spare2;
1598     VUpdateVolume(&error, tv);
1599     tt->rxCallPtr = (struct rx_call *)0;
1600     if (TRELE(tt))
1601         return VOLSERTRELE_ERROR;
1602     return 0;
1603 }
1604
1605
1606 afs_int32
1607 SAFSVolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1608 {
1609     afs_int32 code;
1610
1611     code = VolGetName(acid, atrans, aname);
1612     osi_auditU(acid, VS_GetNameEvent, code, AUD_LONG, atrans, AUD_END);
1613     return code;
1614 }
1615
1616 afs_int32
1617 VolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1618 {
1619     register struct Volume *tv;
1620     register struct VolumeDiskData *td;
1621     struct volser_trans *tt;
1622     register int len;
1623
1624     /* We need to at least fill it in */
1625     *aname = (char *)malloc(1);
1626     if (!*aname)
1627         return ENOMEM;
1628     tt = FindTrans(atrans);
1629     if (!tt)
1630         return ENOENT;
1631     if (tt->vflags & VTDeleted) {
1632         Log("1 Volser: VolGetName: volume %u has been deleted \n", tt->volid);
1633         TRELE(tt);
1634         return ENOENT;
1635     }
1636     strcpy(tt->lastProcName, "GetName");
1637     tt->rxCallPtr = acid;
1638     tv = tt->volume;
1639     if (!tv) {
1640         tt->rxCallPtr = (struct rx_call *)0;
1641         TRELE(tt);
1642         return ENOENT;
1643     }
1644
1645     td = &tv->header->diskstuff;
1646     len = strlen(td->name) + 1; /* don't forget the null */
1647     if (len >= SIZE) {
1648         tt->rxCallPtr = (struct rx_call *)0;
1649         TRELE(tt);
1650         return E2BIG;
1651     }
1652     *aname = (char *)realloc(*aname, len);
1653     strcpy(*aname, td->name);
1654     tt->rxCallPtr = (struct rx_call *)0;
1655     if (TRELE(tt))
1656         return VOLSERTRELE_ERROR;
1657
1658     return 0;
1659 }
1660
1661 /*this is a handshake to indicate that the next call will be SAFSVolRestore
1662  * - a noop now !*/
1663 afs_int32
1664 SAFSVolSignalRestore(struct rx_call *acid, char volname[], int volType, 
1665                      afs_uint32 parentId, afs_uint32 cloneId)
1666 {
1667     return 0;
1668 }
1669
1670
1671 /*return a list of all partitions on the server. The non mounted
1672  *partitions are returned as -1 in the corresponding slot in partIds*/
1673 afs_int32
1674 SAFSVolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1675 {
1676     afs_int32 code;
1677
1678     code = VolListPartitions(acid, partIds);
1679     osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1680     return code;
1681 }
1682
1683 afs_int32
1684 VolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1685 {
1686     char namehead[9];
1687     char i;
1688
1689     strcpy(namehead, "/vicep"); /*7 including null terminator */
1690
1691     /* Just return attached partitions. */
1692     namehead[7] = '\0';
1693     for (i = 0; i < 26; i++) {
1694         namehead[6] = i + 'a';
1695         partIds->partIds[i] = VGetPartition(namehead, 0) ? i : -1;
1696     }
1697
1698     return 0;
1699 }
1700
1701 /*return a list of all partitions on the server. The non mounted
1702  *partitions are returned as -1 in the corresponding slot in partIds*/
1703 afs_int32
1704 SAFSVolXListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1705 {
1706     afs_int32 code;
1707
1708     code = XVolListPartitions(acid, pEntries);
1709     osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1710     return code;
1711 }
1712
1713 afs_int32
1714 XVolListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1715 {
1716     char namehead[9];
1717     struct partList partList;
1718     struct DiskPartition64 *dp;
1719     int i, j = 0, k;
1720
1721     strcpy(namehead, "/vicep"); /*7 including null terminator */
1722
1723     /* Only report attached partitions */
1724     for (i = 0; i < VOLMAXPARTS; i++) {
1725 #ifdef AFS_DEMAND_ATTACH_FS
1726         dp = VGetPartitionById(i, 0);
1727 #else
1728         if (i < 26) {
1729             namehead[6] = i + 'a';
1730             namehead[7] = '\0';
1731         } else {
1732             k = i - 26;
1733             namehead[6] = 'a' + (k / 26);
1734             namehead[7] = 'a' + (k % 26);
1735             namehead[8] = '\0';
1736         }
1737         dp = VGetPartition(namehead, 0);
1738 #endif
1739         if (dp)
1740             partList.partId[j++] = i;
1741     }
1742     pEntries->partEntries_val = (afs_int32 *) malloc(j * sizeof(int));
1743     if (!pEntries->partEntries_val)
1744         return ENOMEM;
1745     memcpy((char *)pEntries->partEntries_val, (char *)&partList,
1746            j * sizeof(int));
1747     pEntries->partEntries_len = j;
1748     return 0;
1749
1750 }
1751
1752 /*extract the volume id from string vname. Its of the form " V0*<id>.vol  "*/
1753 afs_int32
1754 ExtractVolId(char vname[])
1755 {
1756     int i;
1757     char name[VOLSER_MAXVOLNAME + 1];
1758
1759     strcpy(name, vname);
1760     i = 0;
1761     while (name[i] == 'V' || name[i] == '0')
1762         i++;
1763
1764     name[11] = '\0';            /* smash the "." */
1765     return (atol(&name[i]));
1766 }
1767
1768 /*return the name of the next volume header in the directory associated with dirp and dp.
1769 *the volume id is  returned in volid, and volume header name is returned in volname*/
1770 int
1771 GetNextVol(DIR * dirp, char *volname, afs_uint32 * volid)
1772 {
1773     struct dirent *dp;
1774
1775     dp = readdir(dirp);         /*read next entry in the directory */
1776     if (dp) {
1777         if ((dp->d_name[0] == 'V') && !strcmp(&(dp->d_name[11]), VHDREXT)) {
1778             *volid = ExtractVolId(dp->d_name);
1779             strcpy(volname, dp->d_name);
1780             return 0;           /*return the name of the file representing a volume */
1781         } else {
1782             strcpy(volname, "");
1783             return 0;           /*volname doesnot represent a volume */
1784         }
1785     } else {
1786         strcpy(volname, "EOD");
1787         return 0;               /*end of directory */
1788     }
1789
1790 }
1791
1792 /**
1793  * volint vol info structure type.
1794  */
1795 typedef enum {
1796     VOLINT_INFO_TYPE_BASE,  /**< volintInfo type */
1797     VOLINT_INFO_TYPE_EXT    /**< volintXInfo type */
1798 } volint_info_type_t;
1799
1800 /**
1801  * handle to various on-wire vol info types.
1802  */
1803 typedef struct {
1804     volint_info_type_t volinfo_type;
1805     union {
1806         void * opaque;
1807         volintInfo * base;
1808         volintXInfo * ext;
1809     } volinfo_ptr;
1810 } volint_info_handle_t;
1811
1812 /**
1813  * store value to a field at the appropriate location in on-wire structure.
1814  */
1815 #define VOLINT_INFO_STORE(handle, name, val) \
1816     do { \
1817         if ((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) { \
1818             (handle)->volinfo_ptr.base->name = (val); \
1819         } else { \
1820             (handle)->volinfo_ptr.ext->name = (val); \
1821         } \
1822     } while(0)
1823
1824 /**
1825  * get pointer to appropriate offset of field in on-wire structure.
1826  */
1827 #define VOLINT_INFO_PTR(handle, name) \
1828     (((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) ? \
1829      &((handle)->volinfo_ptr.base->name) : \
1830      &((handle)->volinfo_ptr.ext->name))
1831
1832 /**
1833  * fill in appropriate type of on-wire volume metadata structure.
1834  *
1835  * @param vp      pointer to volume object
1836  * @param handle  pointer to wire format handle object
1837  *
1838  * @pre vp object must contain header & pending_vol_op structurs (populate if from RPC)
1839  * @pre handle object must have a valid pointer and enumeration value
1840  *
1841  * @note passing a NULL value for vp means that the fileserver doesn't
1842  *       know about this particular volume, thus implying it is offline.
1843  *
1844  * @return operation status
1845  *   @retval 0 success
1846  *   @retval 1 failure
1847  */
1848 static int
1849 FillVolInfo(Volume * vp, volint_info_handle_t * handle)
1850 {
1851     unsigned int numStatBytes, now;
1852     register struct VolumeDiskData *hdr = &vp->header->diskstuff;
1853
1854     /*read in the relevant info */
1855     strcpy((char *)VOLINT_INFO_PTR(handle, name), hdr->name);
1856     VOLINT_INFO_STORE(handle, status, VOK);     /*its ok */
1857     VOLINT_INFO_STORE(handle, volid, hdr->id);
1858     VOLINT_INFO_STORE(handle, type, hdr->type); /*if ro volume */
1859     VOLINT_INFO_STORE(handle, cloneID, hdr->cloneId);   /*if rw volume */
1860     VOLINT_INFO_STORE(handle, backupID, hdr->backupId);
1861     VOLINT_INFO_STORE(handle, parentID, hdr->parentId);
1862     VOLINT_INFO_STORE(handle, copyDate, hdr->copyDate);
1863     VOLINT_INFO_STORE(handle, size, hdr->diskused);
1864     VOLINT_INFO_STORE(handle, maxquota, hdr->maxquota);
1865     VOLINT_INFO_STORE(handle, filecount, hdr->filecount);
1866     now = FT_ApproxTime();
1867     if ((now - hdr->dayUseDate) > OneDay) {
1868         VOLINT_INFO_STORE(handle, dayUse, 0);
1869     } else {
1870         VOLINT_INFO_STORE(handle, dayUse, hdr->dayUse);
1871     }
1872     VOLINT_INFO_STORE(handle, creationDate, hdr->creationDate);
1873     VOLINT_INFO_STORE(handle, accessDate, hdr->accessDate);
1874     VOLINT_INFO_STORE(handle, updateDate, hdr->updateDate);
1875     VOLINT_INFO_STORE(handle, backupDate, hdr->backupDate);
1876
1877 #ifdef AFS_DEMAND_ATTACH_FS
1878     /*
1879      * for DAFS, we "lie" about volume state --
1880      * instead of returning the raw state from the disk header,
1881      * we compute state based upon the fileserver's internal
1882      * in-core state enumeration value reported to us via fssync,
1883      * along with the blessed and inService flags from the header.
1884      *   -- tkeiser 11/27/2007
1885      */
1886
1887     /* Conditions that offline status is based on: 
1888                 volume is unattached state
1889                 volume state is in (one of several error states)
1890                 volume not in service
1891                 volume is not marked as blessed (not on hold)
1892                 volume in salvage req. state
1893                 volume needsSalvaged 
1894                 next op would set volume offline
1895                 next op would not leave volume online (based on several conditions)
1896     */
1897     if (!vp ||
1898         (V_attachState(vp) == VOL_STATE_UNATTACHED) ||
1899         VIsErrorState(V_attachState(vp)) ||
1900         !hdr->inService ||
1901         !hdr->blessed || 
1902         (V_attachState(vp) == VOL_STATE_SALVSYNC_REQ) ||
1903         hdr->needsSalvaged ||
1904         (vp->pending_vol_op && 
1905                 (vp->pending_vol_op->com.command == FSYNC_VOL_OFF || 
1906                 !VVolOpLeaveOnline_r(vp, vp->pending_vol_op) )
1907         )
1908         ) {
1909         VOLINT_INFO_STORE(handle, inUse, 0);
1910     } else {
1911         VOLINT_INFO_STORE(handle, inUse, 1);
1912     }
1913 #else
1914     /* offline status based on program type, where != fileServer enum (1) is offline */
1915     if (hdr->inUse == fileServer) {
1916         VOLINT_INFO_STORE(handle, inUse, 1);
1917     } else {
1918         VOLINT_INFO_STORE(handle, inUse, 0);
1919     }
1920 #endif
1921
1922
1923     switch(handle->volinfo_type) {
1924         /* NOTE: VOLINT_INFO_STORE not used in this section because values are specific to one volinfo_type */
1925     case VOLINT_INFO_TYPE_BASE:
1926
1927 #ifdef AFS_DEMAND_ATTACH_FS
1928         /* see comment above where we set inUse bit */
1929         if (hdr->needsSalvaged || 
1930             (vp && VIsErrorState(V_attachState(vp)))) {
1931             handle->volinfo_ptr.base->needsSalvaged = 1;
1932         } else {
1933             handle->volinfo_ptr.base->needsSalvaged = 0;
1934         }
1935 #else
1936         handle->volinfo_ptr.base->needsSalvaged = hdr->needsSalvaged;
1937 #endif
1938         handle->volinfo_ptr.base->destroyMe = hdr->destroyMe;
1939         handle->volinfo_ptr.base->spare0 = hdr->minquota;
1940         handle->volinfo_ptr.base->spare1 = 
1941             (long)hdr->weekUse[0] +
1942             (long)hdr->weekUse[1] +
1943             (long)hdr->weekUse[2] +
1944             (long)hdr->weekUse[3] +
1945             (long)hdr->weekUse[4] +
1946             (long)hdr->weekUse[5] +
1947             (long)hdr->weekUse[6];
1948         handle->volinfo_ptr.base->flags = 0;
1949         handle->volinfo_ptr.base->spare2 = hdr->volUpdateCounter;
1950         handle->volinfo_ptr.base->spare3 = 0;
1951         break;
1952
1953
1954     case VOLINT_INFO_TYPE_EXT:
1955         numStatBytes =
1956             4 * ((2 * VOLINT_STATS_NUM_RWINFO_FIELDS) +
1957                  (4 * VOLINT_STATS_NUM_TIME_FIELDS));
1958
1959         /*
1960          * Copy out the stat fields in a single operation.
1961          */
1962         if ((now - hdr->dayUseDate) > OneDay) {
1963             memset((char *)&(handle->volinfo_ptr.ext->stat_reads[0]),
1964                    0, numStatBytes);
1965         } else {
1966             memcpy((char *)&(handle->volinfo_ptr.ext->stat_reads[0]),
1967                    (char *)&(hdr->stat_reads[0]), 
1968                    numStatBytes);
1969         }
1970         break;
1971     }
1972
1973     return 0;
1974 }
1975
1976 /**
1977  * get struct Volume out of the fileserver.
1978  *
1979  * @param[in] volumeId  volumeId for which we want state information
1980  * @param[in] pname     partition name string
1981  * @param[inout] vp     pointer to pointer to Volume object which 
1982  *                      will be populated (see note)
1983  *
1984  * @return operation status
1985  *   @retval 0         success
1986  *   @retval non-zero  failure
1987  *
1988  * @note if FSYNC_VolOp fails in certain ways, *vp will be set to NULL
1989  *
1990  * @internal
1991  */
1992 static int
1993 GetVolObject(afs_uint32 volumeId, char * pname, Volume ** vp)
1994 {
1995     int code;
1996     SYNC_response res;
1997
1998     res.hdr.response_len = sizeof(res.hdr);
1999     res.payload.buf = *vp;
2000     res.payload.len = sizeof(Volume);
2001
2002     code = FSYNC_VolOp(volumeId,
2003                        pname,
2004                        FSYNC_VOL_QUERY,
2005                        0,
2006                        &res);
2007
2008     if (code != SYNC_OK) {
2009         switch (res.hdr.reason) {
2010         case FSYNC_WRONG_PART:
2011         case FSYNC_UNKNOWN_VOLID:
2012             *vp = NULL;
2013             code = SYNC_OK;
2014             break;
2015         }
2016     }
2017
2018     return code;
2019 }
2020
2021 /**
2022  * mode of volume list operation.
2023  */
2024 typedef enum {
2025     VOL_INFO_LIST_SINGLE,   /**< performing a single volume list op */
2026     VOL_INFO_LIST_MULTIPLE  /**< performing a multi-volume list op */
2027 } vol_info_list_mode_t;
2028
2029 /**
2030  * abstract interface to populate wire-format volume metadata structures.
2031  *
2032  * @param[in]  partId    partition id
2033  * @param[in]  volumeId  volume id
2034  * @param[in]  pname     partition name
2035  * @param[in]  volname   volume file name
2036  * @param[in]  handle    handle to on-wire volume metadata object
2037  * @param[in]  mode      listing mode
2038  *
2039  * @return operation status
2040  *   @retval 0      success
2041  *   @retval -2     DESTROY_ME flag is set
2042  *   @retval -1     general failure; some data filled in
2043  *   @retval -3     couldn't create vtrans; some data filled in
2044  */
2045 static int
2046 GetVolInfo(afs_uint32 partId,
2047            afs_uint32 volumeId,
2048            char * pname, 
2049            char * volname, 
2050            volint_info_handle_t * handle,
2051            vol_info_list_mode_t mode)
2052 {
2053     int code = -1;
2054     afs_int32 error;
2055     struct volser_trans *ttc = NULL;
2056     struct Volume *fill_tv, *tv = NULL;
2057 #ifdef AFS_DEMAND_ATTACH_FS
2058     struct Volume fs_tv_buf, *fs_tv = &fs_tv_buf; /* Create a structure, and a pointer to that structure */
2059     SYNC_PROTO_BUF_DECL(fs_res_buf); /* Buffer for the pending_vol_op */
2060     SYNC_response fs_res; /* Response handle for the pending_vol_op */
2061     FSSYNC_VolOp_info pending_vol_op_res; /* Pending vol ops to full in volume */
2062
2063     /* Set up response handle for pending_vol_op */
2064     fs_res.hdr.response_len = sizeof(fs_res.hdr);
2065     fs_res.payload.buf = fs_res_buf;
2066     fs_res.payload.len = SYNC_PROTO_MAX_LEN;
2067 #endif
2068
2069     ttc = NewTrans(volumeId, partId);
2070     if (!ttc) {
2071         code = -3;
2072         VOLINT_INFO_STORE(handle, status, VBUSY);
2073         VOLINT_INFO_STORE(handle, volid, volumeId);
2074         goto drop;
2075     }
2076
2077     /* Get volume from volserver */
2078     tv = VAttachVolumeByName(&error, pname, volname, V_PEEK);
2079     if (error) {
2080         Log("1 Volser: GetVolInfo: Could not attach volume %u (%s:%s) error=%d\n", 
2081             volumeId, pname, volname, error);
2082         goto drop;
2083     }
2084
2085     /*
2086      * please note that destroyMe and needsSalvaged checks used to be ordered
2087      * in the opposite manner for ListVolumes and XListVolumes.  I think it's
2088      * more correct to check destroyMe before needsSalvaged.
2089      *   -- tkeiser 11/28/2007
2090      */
2091
2092     if (tv->header->diskstuff.destroyMe == DESTROY_ME) {
2093         switch (mode) {
2094         case VOL_INFO_LIST_MULTIPLE:
2095             code = -2;
2096             goto drop;
2097
2098         case VOL_INFO_LIST_SINGLE:
2099             Log("1 Volser: GetVolInfo: Volume %u (%s:%s) will be destroyed on next salvage\n", 
2100                 volumeId, pname, volname);
2101
2102         default:
2103             goto drop;
2104         }
2105     }
2106
2107     if (tv->header->diskstuff.needsSalvaged) {
2108         /*this volume will be salvaged */
2109         Log("1 Volser: GetVolInfo: Volume %u (%s:%s) needs to be salvaged\n", 
2110             volumeId, pname, volname);
2111     }
2112
2113 #ifdef AFS_DEMAND_ATTACH_FS
2114     /* If using DAFS, get volume from fsserver */
2115     if (GetVolObject(volumeId, pname, &fs_tv) != SYNC_OK) {
2116         goto drop;
2117     }
2118
2119     /* fs_tv is a shallow copy, must populate certain structures before passing along */
2120     if (FSYNC_VolOp(volumeId, pname, FSYNC_VOL_QUERY_VOP, 0, &fs_res) == SYNC_OK) { 
2121         /* If we if the pending vol op */
2122         memcpy(&pending_vol_op_res, fs_res.payload.buf, sizeof(FSSYNC_VolOp_info));
2123         fs_tv->pending_vol_op=&pending_vol_op_res;
2124     } else {
2125         fs_tv->pending_vol_op=NULL;
2126     }
2127
2128     /* populate the header from the volserver copy */
2129     fs_tv->header=tv->header;
2130
2131     /* When using DAFS, use the fs volume info, populated with required structures */
2132     fill_tv = fs_tv;
2133 #else 
2134     /* When not using DAFS, just use the local volume info */
2135     fill_tv = tv;
2136 #endif
2137
2138     /* ok, we have all the data we need; fill in the on-wire struct */
2139     code = FillVolInfo(fill_tv, handle);
2140
2141  drop:
2142     if (code == -1) {
2143         VOLINT_INFO_STORE(handle, status, 0);
2144         strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2145         VOLINT_INFO_STORE(handle, volid, volumeId);
2146     }
2147     if (tv) {
2148         VDetachVolume(&error, tv);
2149         tv = NULL;
2150         if (error) {
2151             VOLINT_INFO_STORE(handle, status, 0);
2152             strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2153             Log("1 Volser: GetVolInfo: Could not detach volume %u (%s:%s)\n",
2154                 volumeId, pname, volname);
2155         }
2156     }
2157     if (ttc) {
2158         DeleteTrans(ttc, 1);
2159         ttc = NULL;
2160     }
2161     return code;
2162 }
2163
2164
2165 /*return the header information about the <volid> */
2166 afs_int32
2167 SAFSVolListOneVolume(struct rx_call *acid, afs_int32 partid,  
2168                      afs_uint32 volumeId, volEntries *volumeInfo)
2169 {
2170     afs_int32 code;
2171
2172     code = VolListOneVolume(acid, partid, volumeId, volumeInfo);
2173     osi_auditU(acid, VS_Lst1VolEvent, code, AUD_LONG, volumeId, AUD_END);
2174     return code;
2175 }
2176
2177 afs_int32
2178 VolListOneVolume(struct rx_call *acid, afs_int32 partid, 
2179                  afs_uint32 volumeId, volEntries *volumeInfo)
2180 {
2181     volintInfo *pntr;
2182     struct DiskPartition64 *partP;
2183     char pname[9], volname[20];
2184     afs_int32 error = 0;
2185     DIR *dirp;
2186     afs_uint32 volid;
2187     int found = 0;
2188     int code;
2189     volint_info_handle_t handle;
2190
2191     volumeInfo->volEntries_val = (volintInfo *) malloc(sizeof(volintInfo));
2192     if (!volumeInfo->volEntries_val)
2193         return ENOMEM;
2194     memset(volumeInfo->volEntries_val, 0, sizeof(volintInfo)); /* Clear structure */
2195
2196     pntr = volumeInfo->volEntries_val;
2197     volumeInfo->volEntries_len = 1;
2198     if (GetPartName(partid, pname))
2199         return VOLSERILLEGAL_PARTITION;
2200     if (!(partP = VGetPartition(pname, 0)))
2201         return VOLSERILLEGAL_PARTITION;
2202     dirp = opendir(VPartitionPath(partP));
2203     if (dirp == NULL)
2204         return VOLSERILLEGAL_PARTITION;
2205
2206     strcpy(volname, "");
2207
2208     while (strcmp(volname, "EOD") && !found) {  /*while there are more volumes in the partition */
2209
2210         if (!strcmp(volname, "")) {     /* its not a volume, fetch next file */
2211             GetNextVol(dirp, volname, &volid);
2212             continue;           /*back to while loop */
2213         }
2214
2215         if (volid == volumeId) {        /*copy other things too */
2216             found = 1;
2217             break;
2218         }
2219
2220         GetNextVol(dirp, volname, &volid);
2221     }
2222
2223     if (found) {
2224 #ifndef AFS_PTHREAD_ENV
2225         IOMGR_Poll();   /*make sure that the client does not time out */
2226 #endif
2227
2228         handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2229         handle.volinfo_ptr.base = volumeInfo->volEntries_val;
2230         
2231         code = GetVolInfo(partid, 
2232                           volid, 
2233                           pname, 
2234                           volname,
2235                           &handle,
2236                           VOL_INFO_LIST_SINGLE);
2237     }
2238
2239     closedir(dirp);
2240     return (found) ? 0 : ENODEV;
2241 }
2242
2243 /*------------------------------------------------------------------------
2244  * EXPORTED SAFSVolXListOneVolume
2245  *
2246  * Description:
2247  *      Returns extended info on volume a_volID on partition a_partID.
2248  *
2249  * Arguments:
2250  *      a_rxCidP       : Pointer to the Rx call we're performing.
2251  *      a_partID       : Partition for which we want the extended list.
2252  *      a_volID        : Volume ID we wish to know about.
2253  *      a_volumeXInfoP : Ptr to the extended info blob.
2254  *
2255  * Returns:
2256  *      0                       Successful operation
2257  *      VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2258  *
2259  * Environment:
2260  *      Nothing interesting.
2261  *
2262  * Side Effects:
2263  *      As advertised.
2264  *------------------------------------------------------------------------*/
2265
2266 afs_int32
2267 SAFSVolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID, 
2268                       afs_uint32 a_volID, volXEntries *a_volumeXInfoP)
2269 {
2270     afs_int32 code;
2271
2272     code = VolXListOneVolume(a_rxCidP, a_partID, a_volID, a_volumeXInfoP);
2273     osi_auditU(a_rxCidP, VS_XLst1VlEvent, code, AUD_LONG, a_volID, AUD_END);
2274     return code;
2275 }
2276
2277 afs_int32
2278 VolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID, 
2279                   afs_uint32 a_volID, volXEntries *a_volumeXInfoP)
2280 {                               /*SAFSVolXListOneVolume */
2281
2282     volintXInfo *xInfoP;        /*Ptr to the extended vol info */
2283     struct DiskPartition64 *partP;      /*Ptr to partition */
2284     char pname[9], volname[20]; /*Partition, volume names */
2285     DIR *dirp;                  /*Partition directory ptr */
2286     afs_uint32 currVolID;               /*Current volume ID */
2287     int found = 0;              /*Did we find the volume we need? */
2288     int code;
2289     volint_info_handle_t handle;
2290
2291     /*
2292      * Set up our pointers for action, marking our structure to hold exactly
2293      * one entry.  Also, assume we'll fail in our quest.
2294      */
2295     a_volumeXInfoP->volXEntries_val =
2296         (volintXInfo *) malloc(sizeof(volintXInfo));
2297     if (!a_volumeXInfoP->volXEntries_val)
2298         return ENOMEM;
2299     memset(a_volumeXInfoP->volXEntries_val, 0, sizeof(volintXInfo)); /* Clear structure */
2300
2301     xInfoP = a_volumeXInfoP->volXEntries_val;
2302     a_volumeXInfoP->volXEntries_len = 1;
2303     code = ENODEV;
2304
2305     /*
2306      * If the partition name we've been given is bad, bogue out.
2307      */
2308     if (GetPartName(a_partID, pname))
2309         return (VOLSERILLEGAL_PARTITION);
2310
2311     /*
2312      * Open the directory representing the given AFS parttion.  If we can't
2313      * do that, we lose.
2314      */
2315     if (!(partP = VGetPartition(pname, 0)))
2316         return VOLSERILLEGAL_PARTITION;
2317     dirp = opendir(VPartitionPath(partP));
2318     if (dirp == NULL)
2319         return (VOLSERILLEGAL_PARTITION);
2320
2321     strcpy(volname, "");
2322
2323     /*
2324      * Sweep through the partition directory, looking for the desired entry.
2325      * First, of course, figure out how many stat bytes to copy out of each
2326      * volume.
2327      */
2328     while (strcmp(volname, "EOD") && !found) {
2329         /*
2330          * If this is not a volume, move on to the next entry in the
2331          * partition's directory.
2332          */
2333         if (!strcmp(volname, "")) {
2334             GetNextVol(dirp, volname, &currVolID);
2335             continue;
2336         }
2337
2338         if (currVolID == a_volID) {
2339             /*
2340              * We found the volume entry we're interested.  Pull out the
2341              * extended information, remembering to poll (so that the client
2342              * doesn't time out) and to set up a transaction on the volume.
2343              */
2344             found = 1;
2345             break;
2346         }                       /*Found desired volume */
2347
2348         GetNextVol(dirp, volname, &currVolID);
2349     }
2350
2351     if (found) {
2352 #ifndef AFS_PTHREAD_ENV
2353         IOMGR_Poll();
2354 #endif
2355
2356         handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2357         handle.volinfo_ptr.ext = a_volumeXInfoP->volXEntries_val;
2358
2359         code = GetVolInfo(a_partID,
2360                           a_volID,
2361                           pname,
2362                           volname,
2363                           &handle,
2364                           VOL_INFO_LIST_SINGLE);
2365
2366     }
2367
2368     /*
2369      * Clean up before going to dinner: close the partition directory,
2370      * return the proper value.
2371      */
2372     closedir(dirp);
2373     return (found) ? 0 : ENODEV;
2374 }                               /*SAFSVolXListOneVolume */
2375
2376 /*returns all the volumes on partition partid. If flags = 1 then all the 
2377 * relevant info about the volumes  is also returned */
2378 afs_int32
2379 SAFSVolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags, 
2380                    volEntries *volumeInfo)
2381 {
2382     afs_int32 code;
2383
2384     code = VolListVolumes(acid, partid, flags, volumeInfo);
2385     osi_auditU(acid, VS_ListVolEvent, code, AUD_END);
2386     return code;
2387 }
2388
2389 afs_int32
2390 VolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags, 
2391                    volEntries *volumeInfo)
2392 {
2393     volintInfo *pntr;
2394     struct DiskPartition64 *partP;
2395     afs_int32 allocSize = 1000; /*to be changed to a larger figure */
2396     char pname[9], volname[20];
2397     afs_int32 error = 0;
2398     DIR *dirp;
2399     afs_uint32 volid;
2400     int code;
2401     volint_info_handle_t handle;
2402
2403     volumeInfo->volEntries_val =
2404         (volintInfo *) malloc(allocSize * sizeof(volintInfo));
2405     if (!volumeInfo->volEntries_val)
2406         return ENOMEM;
2407     memset(volumeInfo->volEntries_val, 0, sizeof(volintInfo)); /* Clear structure */
2408
2409     pntr = volumeInfo->volEntries_val;
2410     volumeInfo->volEntries_len = 0;
2411     if (GetPartName(partid, pname))
2412         return VOLSERILLEGAL_PARTITION;
2413     if (!(partP = VGetPartition(pname, 0)))
2414         return VOLSERILLEGAL_PARTITION;
2415     dirp = opendir(VPartitionPath(partP));
2416     if (dirp == NULL)
2417         return VOLSERILLEGAL_PARTITION;
2418     strcpy(volname, "");
2419
2420     while (strcmp(volname, "EOD")) {    /*while there are more partitions in the partition */
2421
2422         if (!strcmp(volname, "")) {     /* its not a volume, fetch next file */
2423             GetNextVol(dirp, volname, &volid);
2424             continue;           /*back to while loop */
2425         }
2426
2427         if (flags) {            /*copy other things too */
2428 #ifndef AFS_PTHREAD_ENV
2429             IOMGR_Poll();       /*make sure that the client does not time out */
2430 #endif
2431
2432             handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2433             handle.volinfo_ptr.base = pntr;
2434
2435
2436             code = GetVolInfo(partid,
2437                               volid,
2438                               pname,
2439                               volname,
2440                               &handle,
2441                               VOL_INFO_LIST_MULTIPLE);
2442             if (code == -2) { /* DESTROY_ME flag set */
2443                 goto drop2;
2444             }
2445         } else {
2446             pntr->volid = volid;
2447             /*just volids are needed */
2448         }
2449
2450       drop:
2451         pntr++;
2452         volumeInfo->volEntries_len += 1;
2453         if ((allocSize - volumeInfo->volEntries_len) < 5) {
2454             /*running out of space, allocate more space */
2455             allocSize = (allocSize * 3) / 2;
2456             pntr =
2457                 (volintInfo *) realloc((char *)volumeInfo->volEntries_val,
2458                                        allocSize * sizeof(volintInfo));
2459             if (pntr == NULL) {
2460                 closedir(dirp); 
2461                 return VOLSERNO_MEMORY;
2462             }
2463             volumeInfo->volEntries_val = pntr;  /* point to new block */
2464             /* set pntr to the right position */
2465             pntr = volumeInfo->volEntries_val + volumeInfo->volEntries_len;
2466
2467         }
2468
2469       drop2:
2470         GetNextVol(dirp, volname, &volid);
2471
2472     }
2473
2474     closedir(dirp);
2475     return 0;
2476 }
2477
2478 /*------------------------------------------------------------------------
2479  * EXPORTED SAFSVolXListVolumes
2480  *
2481  * Description:
2482  *      Returns all the volumes on partition a_partID.  If a_flags
2483  *      is set to 1, then all the relevant extended volume information
2484  *      is also returned.
2485  *
2486  * Arguments:
2487  *      a_rxCidP       : Pointer to the Rx call we're performing.
2488  *      a_partID       : Partition for which we want the extended list.
2489  *      a_flags        : Various flags.
2490  *      a_volumeXInfoP : Ptr to the extended info blob.
2491  *
2492  * Returns:
2493  *      0                       Successful operation
2494  *      VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2495  *      VOLSERNO_MEMORY         if we ran out of memory allocating
2496  *                              our return blob
2497  *
2498  * Environment:
2499  *      Nothing interesting.
2500  *
2501  * Side Effects:
2502  *      As advertised.
2503  *------------------------------------------------------------------------*/
2504
2505 afs_int32
2506 SAFSVolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2507                     afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2508 {
2509     afs_int32 code;
2510
2511     code = VolXListVolumes(a_rxCidP, a_partID, a_flags, a_volumeXInfoP);
2512     osi_auditU(a_rxCidP, VS_XLstVolEvent, code, AUD_END);
2513     return code;
2514 }
2515
2516 afs_int32
2517 VolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2518                     afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2519 {                               /*SAFSVolXListVolumes */
2520
2521     volintXInfo *xInfoP;        /*Ptr to the extended vol info */
2522     struct DiskPartition64 *partP;      /*Ptr to partition */
2523     afs_int32 allocSize = 1000; /*To be changed to a larger figure */
2524     char pname[9], volname[20]; /*Partition, volume names */
2525     afs_int32 error = 0;        /*Return code */
2526     DIR *dirp;                  /*Partition directory ptr */
2527     afs_uint32 volid;           /*Current volume ID */
2528     int code;
2529     volint_info_handle_t handle;
2530
2531     /*
2532      * Allocate a large array of extended volume info structures, then
2533      * set it up for action.
2534      */
2535     a_volumeXInfoP->volXEntries_val =
2536         (volintXInfo *) malloc(allocSize * sizeof(volintXInfo));
2537     if (!a_volumeXInfoP->volXEntries_val)
2538         return ENOMEM;
2539     memset(a_volumeXInfoP->volXEntries_val, 0, sizeof(volintXInfo)); /* Clear structure */
2540
2541     xInfoP = a_volumeXInfoP->volXEntries_val;
2542     a_volumeXInfoP->volXEntries_len = 0;
2543
2544     /*
2545      * If the partition name we've been given is bad, bogue out.
2546      */
2547     if (GetPartName(a_partID, pname))
2548         return (VOLSERILLEGAL_PARTITION);
2549
2550     /*
2551      * Open the directory representing the given AFS parttion.  If we can't
2552      * do that, we lose.
2553      */
2554     if (!(partP = VGetPartition(pname, 0)))
2555         return VOLSERILLEGAL_PARTITION;
2556     dirp = opendir(VPartitionPath(partP));
2557     if (dirp == NULL)
2558         return (VOLSERILLEGAL_PARTITION);
2559     strcpy(volname, "");
2560
2561     /*
2562      * Sweep through the partition directory, acting on each entry.  First,
2563      * of course, figure out how many stat bytes to copy out of each volume.
2564      */
2565     while (strcmp(volname, "EOD")) {
2566
2567         /*
2568          * If this is not a volume, move on to the next entry in the
2569          * partition's directory.
2570          */
2571         if (!strcmp(volname, "")) {
2572             GetNextVol(dirp, volname, &volid);
2573             continue;
2574         }
2575
2576         if (a_flags) {
2577             /*
2578              * Full info about the volume desired.  Poll to make sure the
2579              * client doesn't time out, then start up a new transaction.
2580              */
2581 #ifndef AFS_PTHREAD_ENV
2582             IOMGR_Poll();
2583 #endif
2584
2585             handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2586             handle.volinfo_ptr.ext = xInfoP;
2587
2588             code = GetVolInfo(a_partID,
2589                               volid,
2590                               pname,
2591                               volname,
2592                               &handle,
2593                               VOL_INFO_LIST_MULTIPLE);
2594             if (code == -2) { /* DESTROY_ME flag set */
2595                 goto drop2;
2596             }
2597         } else {
2598             /*
2599              * Just volume IDs are needed.
2600              */
2601             xInfoP->volid = volid;
2602         }
2603
2604       drop:
2605         /*
2606          * Bump the pointer in the data area we're building, along with
2607          * the count of the number of entries it contains.
2608          */
2609         xInfoP++;
2610         (a_volumeXInfoP->volXEntries_len)++;
2611         if ((allocSize - a_volumeXInfoP->volXEntries_len) < 5) {
2612             /*
2613              * We're running out of space in the area we've built.  Grow it.
2614              */
2615             allocSize = (allocSize * 3) / 2;
2616             xInfoP = (volintXInfo *)
2617                 realloc((char *)a_volumeXInfoP->volXEntries_val,
2618                         (allocSize * sizeof(volintXInfo)));
2619             if (xInfoP == NULL) {
2620                 /*
2621                  * Bummer, no memory. Bag it, tell our caller what went wrong.
2622                  */
2623                 closedir(dirp);
2624                 return (VOLSERNO_MEMORY);
2625             }
2626
2627             /*
2628              * Memory reallocation worked.  Correct our pointers so they
2629              * now point to the new block and the current open position within
2630              * the new block.
2631              */
2632             a_volumeXInfoP->volXEntries_val = xInfoP;
2633             xInfoP =
2634                 a_volumeXInfoP->volXEntries_val +
2635                 a_volumeXInfoP->volXEntries_len;
2636         }
2637
2638       drop2:
2639         GetNextVol(dirp, volname, &volid);
2640     }                           /*Sweep through the partition directory */
2641
2642     /*
2643      * We've examined all entries in the partition directory.  Close it,
2644      * delete our transaction (if any), and go home happy.
2645      */
2646     closedir(dirp);
2647     return (0);
2648
2649 }                               /*SAFSVolXListVolumes */
2650
2651 /*this call is used to monitor the status of volser for debugging purposes.
2652  *information about all the active transactions is returned in transInfo*/
2653 afs_int32
2654 SAFSVolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2655 {
2656     afs_int32 code;
2657
2658     code = VolMonitor(acid, transInfo);
2659     osi_auditU(acid, VS_MonitorEvent, code, AUD_END);
2660     return code;
2661 }
2662
2663 afs_int32
2664 VolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2665 {
2666     transDebugInfo *pntr;
2667     afs_int32 allocSize = 50;
2668     struct volser_trans *tt, *allTrans;
2669
2670     transInfo->transDebugEntries_val =
2671         (transDebugInfo *) malloc(allocSize * sizeof(transDebugInfo));
2672     if (!transInfo->transDebugEntries_val)
2673         return ENOMEM;
2674     pntr = transInfo->transDebugEntries_val;
2675     transInfo->transDebugEntries_len = 0;
2676     allTrans = TransList();
2677     if (allTrans == (struct volser_trans *)0)
2678         return 0;               /*no active transactions */
2679     for (tt = allTrans; tt; tt = tt->next) {    /*copy relevant info into pntr */
2680         pntr->tid = tt->tid;
2681         pntr->time = tt->time;
2682         pntr->creationTime = tt->creationTime;
2683         pntr->returnCode = tt->returnCode;
2684         pntr->volid = tt->volid;
2685         pntr->partition = tt->partition;
2686         pntr->iflags = tt->iflags;
2687         pntr->vflags = tt->vflags;
2688         pntr->tflags = tt->tflags;
2689         strcpy(pntr->lastProcName, tt->lastProcName);
2690         pntr->callValid = 0;
2691         if (tt->rxCallPtr) {    /*record call related info */
2692             pntr->callValid = 1;
2693             pntr->readNext = tt->rxCallPtr->rnext;
2694             pntr->transmitNext = tt->rxCallPtr->tnext;
2695             pntr->lastSendTime = tt->rxCallPtr->lastSendTime;
2696             pntr->lastReceiveTime = tt->rxCallPtr->lastReceiveTime;
2697         }
2698         pntr++;
2699         transInfo->transDebugEntries_len += 1;
2700         if ((allocSize - transInfo->transDebugEntries_len) < 5) {       /*alloc some more space */
2701             allocSize = (allocSize * 3) / 2;
2702             pntr =
2703                 (transDebugInfo *) realloc((char *)transInfo->
2704                                            transDebugEntries_val,
2705                                            allocSize *
2706                                            sizeof(transDebugInfo));
2707             transInfo->transDebugEntries_val = pntr;
2708             pntr =
2709                 transInfo->transDebugEntries_val +
2710                 transInfo->transDebugEntries_len;
2711             /*set pntr to right position */
2712         }
2713
2714     }
2715
2716     return 0;
2717 }
2718
2719 afs_int32
2720 SAFSVolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[], afs_int32 type, afs_uint32 pId, afs_uint32 cloneId, afs_uint32 backupId)
2721 {
2722     afs_int32 code;
2723
2724     code = VolSetIdsTypes(acid, atid, name, type, pId, cloneId, backupId);
2725     osi_auditU(acid, VS_SetIdTyEvent, code, AUD_LONG, atid, AUD_STR, name,
2726                AUD_LONG, type, AUD_LONG, pId, AUD_LONG, cloneId, AUD_LONG,
2727                backupId, AUD_END);
2728     return code;
2729 }
2730
2731 afs_int32
2732 VolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[], afs_int32 type, afs_uint32 pId, afs_uint32 cloneId, afs_uint32 backupId)
2733 {
2734     struct Volume *tv;
2735     afs_int32 error = 0;
2736     register struct volser_trans *tt;
2737     char caller[MAXKTCNAMELEN];
2738
2739     if (strlen(name) > 31)
2740         return VOLSERBADNAME;
2741     if (!afsconf_SuperUser(tdir, acid, caller))
2742         return VOLSERBAD_ACCESS;        /*not a super user */
2743     /* find the trans */
2744     tt = FindTrans(atid);
2745     if (!tt)
2746         return ENOENT;
2747     if (tt->vflags & VTDeleted) {
2748         Log("1 Volser: VolSetIds: volume %u has been deleted \n", tt->volid);
2749         TRELE(tt);
2750         return ENOENT;
2751     }
2752     strcpy(tt->lastProcName, "SetIdsTypes");
2753     tt->rxCallPtr = acid;
2754     tv = tt->volume;
2755
2756     V_type(tv) = type;
2757     V_backupId(tv) = backupId;
2758     V_cloneId(tv) = cloneId;
2759     V_parentId(tv) = pId;
2760     strcpy((&V_disk(tv))->name, name);
2761     VUpdateVolume(&error, tv);
2762     if (error) {
2763         Log("1 Volser: SetIdsTypes: VUpdate failed code %d\n", error);
2764         LogError(error);
2765         goto fail;
2766     }
2767     tt->rxCallPtr = (struct rx_call *)0;
2768     if (TRELE(tt) && !error)
2769         return VOLSERTRELE_ERROR;
2770
2771     return error;
2772   fail:
2773     tt->rxCallPtr = (struct rx_call *)0;
2774     if (TRELE(tt) && !error)
2775         return VOLSERTRELE_ERROR;
2776     return error;
2777 }
2778
2779 afs_int32
2780 SAFSVolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2781 {
2782     afs_int32 code;
2783
2784     code = VolSetDate(acid, atid, cdate);
2785     osi_auditU(acid, VS_SetDateEvent, code, AUD_LONG, atid, AUD_LONG, cdate,
2786                AUD_END);
2787     return code;
2788 }
2789
2790 afs_int32
2791 VolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2792 {
2793     struct Volume *tv;
2794     afs_int32 error = 0;
2795     register struct volser_trans *tt;
2796     char caller[MAXKTCNAMELEN];
2797
2798     if (!afsconf_SuperUser(tdir, acid, caller))
2799         return VOLSERBAD_ACCESS;        /*not a super user */
2800     /* find the trans */
2801     tt = FindTrans(atid);
2802     if (!tt)
2803         return ENOENT;
2804     if (tt->vflags & VTDeleted) {
2805         Log("1 Volser: VolSetDate: volume %u has been deleted \n", tt->volid);
2806         TRELE(tt);
2807         return ENOENT;
2808     }
2809     strcpy(tt->lastProcName, "SetDate");
2810     tt->rxCallPtr = acid;
2811     tv = tt->volume;
2812
2813     V_creationDate(tv) = cdate;
2814     VUpdateVolume(&error, tv);
2815     if (error) {
2816         Log("1 Volser: SetDate: VUpdate failed code %d\n", error);
2817         LogError(error);
2818         goto fail;
2819     }
2820     tt->rxCallPtr = (struct rx_call *)0;
2821     if (TRELE(tt) && !error)
2822         return VOLSERTRELE_ERROR;
2823
2824     return error;
2825   fail:
2826     tt->rxCallPtr = (struct rx_call *)0;
2827     if (TRELE(tt) && !error)
2828         return VOLSERTRELE_ERROR;
2829     return error;
2830 }
2831
2832 afs_int32
2833 SAFSVolConvertROtoRWvolume(struct rx_call *acid, afs_int32 partId,
2834                            afs_uint32 volumeId)
2835 {
2836 #ifdef AFS_NT40_ENV
2837     return EXDEV;
2838 #else
2839     char caller[MAXKTCNAMELEN];
2840     DIR *dirp;
2841     register struct volser_trans *ttc;
2842     char pname[16], volname[20];
2843     struct DiskPartition64 *partP;
2844     afs_int32 ret = ENODEV;
2845     afs_uint32 volid;
2846
2847     if (!afsconf_SuperUser(tdir, acid, caller))
2848         return VOLSERBAD_ACCESS;        /*not a super user */
2849     if (GetPartName(partId, pname))
2850         return VOLSERILLEGAL_PARTITION;
2851     if (!(partP = VGetPartition(pname, 0)))
2852         return VOLSERILLEGAL_PARTITION;
2853     dirp = opendir(VPartitionPath(partP));
2854     if (dirp == NULL)
2855         return VOLSERILLEGAL_PARTITION;
2856     strcpy(volname, "");
2857     ttc = (struct volser_trans *)0;
2858
2859     while (strcmp(volname, "EOD")) {
2860         if (!strcmp(volname, "")) {     /* its not a volume, fetch next file */
2861             GetNextVol(dirp, volname, &volid);
2862             continue;           /*back to while loop */
2863         }
2864         
2865         if (volid == volumeId) {        /*copy other things too */
2866 #ifndef AFS_PTHREAD_ENV
2867             IOMGR_Poll();       /*make sure that the client doesnot time out */
2868 #endif
2869             ttc = NewTrans(volumeId, partId);
2870             if (!ttc) {
2871                 return VBUSY;
2872             }
2873 #ifdef AFS_NAMEI_ENV
2874             ret = namei_ConvertROtoRWvolume(pname, volumeId);
2875 #else
2876             ret = inode_ConvertROtoRWvolume(pname, volumeId);
2877 #endif
2878             break;
2879         }
2880         GetNextVol(dirp, volname, &volid);
2881     }
2882     
2883     if (ttc) {
2884         DeleteTrans(ttc, 1);
2885         ttc = (struct volser_trans *)0;
2886     }
2887     
2888     closedir(dirp);
2889     return ret;
2890 #endif
2891 }
2892
2893 afs_int32
2894 SAFSVolGetSize(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
2895                register struct volintSize *size)
2896 {
2897     int code = 0;
2898     register struct volser_trans *tt;
2899     char caller[MAXKTCNAMELEN];
2900
2901     if (!afsconf_SuperUser(tdir, acid, caller))
2902         return VOLSERBAD_ACCESS;        /*not a super user */
2903     tt = FindTrans(fromTrans);
2904     if (!tt)
2905         return ENOENT;
2906     if (tt->vflags & VTDeleted) {
2907         TRELE(tt);
2908         return ENOENT;
2909     }
2910     strcpy(tt->lastProcName, "GetSize");
2911     tt->rxCallPtr = acid;
2912     code = SizeDumpVolume(acid, tt->volume, fromDate, 1, size); /* measure volume's data */
2913     tt->rxCallPtr = (struct rx_call *)0;
2914     if (TRELE(tt))
2915         return VOLSERTRELE_ERROR;
2916
2917 /*    osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);  */
2918     return code;
2919 }
2920
2921 afs_int32
2922 SAFSVolSplitVolume(struct rx_call *acall, afs_uint32 vid, afs_uint32 new, 
2923                    afs_uint32 where, afs_int32 verbose)
2924 {
2925     afs_int32 code, code2;
2926     Volume *vol=0, *newvol=0;
2927     struct volser_trans *tt = 0, *tt2 = 0;
2928     char caller[MAXKTCNAMELEN];
2929     char line[128];
2930
2931     if (!afsconf_SuperUser(tdir, acall, caller)) 
2932         return EPERM;
2933
2934     vol = VAttachVolume(&code, vid, V_VOLUPD);
2935     if (!vol) {
2936         if (!code)
2937             code = ENOENT;
2938         return code;
2939     }
2940     newvol = VAttachVolume(&code, new, V_VOLUPD);
2941     if (!newvol) {
2942         VDetachVolume(&code2, vol);
2943         if (!code)
2944             code = ENOENT;
2945         return code;
2946     }
2947     if (V_device(vol) != V_device(newvol) 
2948         || V_uniquifier(newvol) != 2) {
2949         if (V_device(vol) != V_device(newvol)) {
2950             sprintf(line, "Volumes %u and %u are not in the same partition, aborted.\n",
2951                     vid, new);
2952             rx_Write(acall, line, strlen(line));
2953         }
2954         if (V_uniquifier(newvol) != 2) {
2955             sprintf(line, "Volume %u is not freshly created, aborted.\n", new);
2956             rx_Write(acall, line, strlen(line));
2957         }
2958         line[0] = 0;
2959         rx_Write(acall, line, 1);
2960         VDetachVolume(&code2, vol);
2961         VDetachVolume(&code2, newvol);
2962         return EINVAL;
2963     }
2964     tt = NewTrans(vid, V_device(vol));
2965     if (!tt) {
2966         sprintf(line, "Couldn't create transaction for %u, aborted.\n", vid);
2967         rx_Write(acall, line, strlen(line));
2968         line[0] = 0;
2969         rx_Write(acall, line, 1);
2970         VDetachVolume(&code2, vol);
2971         VDetachVolume(&code2, newvol);
2972         return VOLSERVOLBUSY;
2973     } 
2974     tt->iflags = ITBusy;
2975     tt->vflags = 0;
2976     strcpy(tt->lastProcName, "SplitVolume");
2977
2978     tt2 = NewTrans(new, V_device(newvol));
2979     if (!tt2) {
2980         sprintf(line, "Couldn't create transaction for %u, aborted.\n", new);
2981         rx_Write(acall, line, strlen(line));
2982         line[0] = 0;
2983         rx_Write(acall, line, 1);
2984         DeleteTrans(tt, 1);
2985         VDetachVolume(&code2, vol);
2986         VDetachVolume(&code2, newvol);
2987         return VOLSERVOLBUSY;
2988     } 
2989     tt2->iflags = ITBusy;
2990     tt2->vflags = 0;
2991     strcpy(tt2->lastProcName, "SplitVolume");
2992
2993     code = split_volume(acall, vol, newvol, where, verbose);
2994
2995     VDetachVolume(&code2, vol);
2996     DeleteTrans(tt, 1);
2997     VDetachVolume(&code2, newvol);
2998     DeleteTrans(tt2, 1);
2999     return code;
3000 }
3001
3002 /* GetPartName - map partid (a decimal number) into pname (a string)
3003  * Since for NT we actually want to return the drive name, we map through the
3004  * partition struct.
3005  */
3006 static int
3007 GetPartName(afs_int32 partid, char *pname)
3008 {
3009     if (partid < 0)
3010         return -1;
3011     if (partid < 26) {
3012         strcpy(pname, "/vicep");
3013         pname[6] = 'a' + partid;
3014         pname[7] = '\0';
3015         return 0;
3016     } else if (partid < VOLMAXPARTS) {
3017         strcpy(pname, "/vicep");
3018         partid -= 26;
3019         pname[6] = 'a' + (partid / 26);
3020         pname[7] = 'a' + (partid % 26);
3021         pname[8] = '\0';
3022         return 0;
3023     } else
3024         return -1;
3025 }