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