volser-initialize-volume-updatedate-20080816
[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, &did, &did)));
234     DFlush();                   /* flush all modified dir buffers out */
235     DZap(&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     if (TRELE(tt) && !error)
1072         return VOLSERTRELE_ERROR;
1073
1074     return error;
1075 }
1076
1077 /* dumpS the volume associated with a particular transaction from a particular
1078  * date.  Send the dump to a different transaction (destTrans) on the server
1079  * specified by the destServer structure.
1080  */
1081 afs_int32
1082 SAFSVolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1083                struct destServer *destination, afs_int32 destTrans, 
1084                struct restoreCookie *cookie)
1085 {
1086     afs_int32 code;
1087
1088     code =
1089         VolForward(acid, fromTrans, fromDate, destination, destTrans, cookie);
1090     osi_auditU(acid, VS_ForwardEvent, code, AUD_LONG, fromTrans, AUD_HOST,
1091                destination->destHost, AUD_LONG, destTrans, AUD_END);
1092     return code;
1093 }
1094
1095 afs_int32
1096 VolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1097                struct destServer *destination, afs_int32 destTrans, 
1098                struct restoreCookie *cookie)
1099 {
1100     register struct volser_trans *tt;
1101     register afs_int32 code;
1102     register struct rx_connection *tcon;
1103     struct rx_call *tcall;
1104     register struct Volume *vp;
1105     struct rx_securityClass *securityObject;
1106     afs_int32 securityIndex;
1107     char caller[MAXKTCNAMELEN];
1108
1109     if (!afsconf_SuperUser(tdir, acid, caller))
1110         return VOLSERBAD_ACCESS;        /*not a super user */
1111     /* initialize things */
1112     tcon = (struct rx_connection *)0;
1113     tt = (struct volser_trans *)0;
1114
1115     /* find the local transaction */
1116     tt = FindTrans(fromTrans);
1117     if (!tt)
1118         return ENOENT;
1119     if (tt->vflags & VTDeleted) {
1120         Log("1 Volser: VolForward: volume %u has been deleted \n", tt->volid);
1121         TRELE(tt);
1122         return ENOENT;
1123     }
1124     vp = tt->volume;
1125     strcpy(tt->lastProcName, "Forward");
1126
1127     /* get auth info for the this connection (uses afs from ticket file) */
1128     code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
1129     if (code) {
1130         TRELE(tt);
1131         return code;
1132     }
1133
1134     /* make an rpc connection to the other server */
1135     tcon =
1136         rx_NewConnection(htonl(destination->destHost),
1137                          htons(destination->destPort), VOLSERVICE_ID,
1138                          securityObject, securityIndex);
1139     if (!tcon) {
1140         tt->rxCallPtr = (struct rx_call *)0;
1141         TRELE(tt);
1142         return ENOTCONN;
1143     }
1144     tcall = rx_NewCall(tcon);
1145     tt->rxCallPtr = tcall;
1146     /* start restore going.  fromdate == 0 --> doing an incremental dump/restore */
1147     code = StartAFSVolRestore(tcall, destTrans, (fromDate ? 1 : 0), cookie);
1148     if (code) {
1149         goto fail;
1150     }
1151
1152     /* these next calls implictly call rx_Write when writing out data */
1153     code = DumpVolume(tcall, vp, fromDate, 0);  /* last field = don't dump all dirs */
1154     if (code)
1155         goto fail;
1156     EndAFSVolRestore(tcall);    /* probably doesn't do much */
1157     tt->rxCallPtr = (struct rx_call *)0;
1158     code = rx_EndCall(tcall, 0);
1159     rx_DestroyConnection(tcon); /* done with the connection */
1160     tcon = NULL;
1161     if (code)
1162         goto fail;
1163     if (TRELE(tt))
1164         return VOLSERTRELE_ERROR;
1165
1166     return 0;
1167
1168   fail:
1169     if (tcon) {
1170         (void)rx_EndCall(tcall, 0);
1171         rx_DestroyConnection(tcon);
1172     }
1173     if (tt) {
1174         tt->rxCallPtr = (struct rx_call *)0;
1175         TRELE(tt);
1176     }
1177     return code;
1178 }
1179
1180 /* Start a dump and send it to multiple places simultaneously.
1181  * If this returns an error (eg, return ENOENT), it means that
1182  * none of the releases worked.  If this returns 0, that means 
1183  * that one or more of the releases worked, and the caller has
1184  * to examine the results array to see which one(s).
1185  * This will only do EITHER incremental or full, not both, so it's
1186  * the caller's responsibility to be sure that all the destinations
1187  * need just an incremental (and from the same time), if that's 
1188  * what we're doing. 
1189  */
1190 afs_int32
1191 SAFSVolForwardMultiple(struct rx_call *acid, afs_int32 fromTrans, afs_int32 
1192                        fromDate, manyDests *destinations, afs_int32 spare,
1193                        struct restoreCookie *cookie, manyResults *results)
1194 {
1195     afs_int32 securityIndex;
1196     struct rx_securityClass *securityObject;
1197     char caller[MAXKTCNAMELEN];
1198     struct volser_trans *tt;
1199     afs_int32 ec, code, *codes;
1200     struct rx_connection **tcons;
1201     struct rx_call **tcalls;
1202     struct Volume *vp;
1203     int i, is_incremental;
1204
1205     if (results) {
1206         memset(results, 0, sizeof(manyResults));
1207         i = results->manyResults_len = destinations->manyDests_len;
1208         results->manyResults_val = codes =
1209           (afs_int32 *) malloc(i * sizeof(afs_int32));
1210     }   
1211     if (!results || !results->manyResults_val)
1212         return ENOMEM;
1213
1214     if (!afsconf_SuperUser(tdir, acid, caller))
1215         return VOLSERBAD_ACCESS;        /*not a super user */
1216     tt = FindTrans(fromTrans);
1217     if (!tt)
1218         return ENOENT;
1219     if (tt->vflags & VTDeleted) {
1220         Log("1 Volser: VolForward: volume %u has been deleted \n", tt->volid);
1221         TRELE(tt);
1222         return ENOENT;
1223     }
1224     vp = tt->volume;
1225     strcpy(tt->lastProcName, "ForwardMulti");
1226
1227     /* (fromDate == 0) ==> full dump */
1228     is_incremental = (fromDate ? 1 : 0);
1229
1230     tcons =
1231         (struct rx_connection **)malloc(i * sizeof(struct rx_connection *));
1232     if (!tcons) {
1233         return ENOMEM;
1234     }
1235     tcalls = (struct rx_call **)malloc(i * sizeof(struct rx_call *));
1236     if (!tcalls) {
1237         free(tcons);
1238         return ENOMEM;
1239     }
1240
1241     /* get auth info for this connection (uses afs from ticket file) */
1242     code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
1243     if (code) {
1244         goto fail;              /* in order to audit each failure */
1245     }
1246
1247     /* make connections to all the other servers */
1248     for (i = 0; i < destinations->manyDests_len; i++) {
1249         struct replica *dest = &(destinations->manyDests_val[i]);
1250         tcons[i] =
1251             rx_NewConnection(htonl(dest->server.destHost),
1252                              htons(dest->server.destPort), VOLSERVICE_ID,
1253                              securityObject, securityIndex);
1254         if (!tcons[i]) {
1255             codes[i] = ENOTCONN;
1256         } else {
1257             if (!(tcalls[i] = rx_NewCall(tcons[i])))
1258                 codes[i] = ENOTCONN;
1259             else {
1260                 codes[i] =
1261                     StartAFSVolRestore(tcalls[i], dest->trans, is_incremental,
1262                                        cookie);
1263                 if (codes[i]) {
1264                     (void)rx_EndCall(tcalls[i], 0);
1265                     tcalls[i] = 0;
1266                     rx_DestroyConnection(tcons[i]);
1267                     tcons[i] = 0;
1268                 }
1269             }
1270         }
1271     }
1272
1273     /* these next calls implictly call rx_Write when writing out data */
1274     code = DumpVolMulti(tcalls, i, vp, fromDate, 0, codes);
1275
1276
1277   fail:
1278     for (i--; i >= 0; i--) {
1279         struct replica *dest = &(destinations->manyDests_val[i]);
1280
1281         if (!code && tcalls[i] && !codes[i]) {
1282             EndAFSVolRestore(tcalls[i]);
1283         }
1284         if (tcalls[i]) {
1285             ec = rx_EndCall(tcalls[i], 0);
1286             if (!codes[i])
1287                 codes[i] = ec;
1288         }
1289         if (tcons[i]) {
1290             rx_DestroyConnection(tcons[i]);     /* done with the connection */
1291         }
1292
1293         osi_auditU(acid, VS_ForwardEvent, (code ? code : codes[i]), AUD_LONG,
1294                    fromTrans, AUD_HOST, dest->server.destHost, AUD_LONG,
1295                    dest->trans, AUD_END);
1296     }
1297     free(tcons);
1298     free(tcalls);
1299
1300     if (tt) {
1301         tt->rxCallPtr = (struct rx_call *)0;
1302         if (TRELE(tt) && !code) /* return the first code if it's set */
1303             return VOLSERTRELE_ERROR;
1304     }
1305
1306     return code;
1307 }
1308
1309 afs_int32
1310 SAFSVolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate)
1311 {
1312     afs_int32 code;
1313
1314     code = VolDump(acid, fromTrans, fromDate, 0);
1315     osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1316     return code;
1317 }
1318
1319 afs_int32
1320 SAFSVolDumpV2(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate, afs_int32 flags)
1321 {
1322     afs_int32 code;
1323
1324     code = VolDump(acid, fromTrans, fromDate, flags);
1325     osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1326     return code;
1327 }
1328
1329 afs_int32
1330 VolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate, afs_int32 flags)
1331 {
1332     int code = 0;
1333     register struct volser_trans *tt;
1334     char caller[MAXKTCNAMELEN];
1335
1336     if (!afsconf_SuperUser(tdir, acid, caller))
1337         return VOLSERBAD_ACCESS;        /*not a super user */
1338     tt = FindTrans(fromTrans);
1339     if (!tt)
1340         return ENOENT;
1341     if (tt->vflags & VTDeleted) {
1342         Log("1 Volser: VolDump: volume %u has been deleted \n", tt->volid);
1343         TRELE(tt);
1344         return ENOENT;
1345     }
1346     strcpy(tt->lastProcName, "Dump");
1347     tt->rxCallPtr = acid;
1348     code = DumpVolume(acid, tt->volume, fromDate, (flags & VOLDUMPV2_OMITDIRS)
1349                       ? 0 : 1); /* squirt out the volume's data, too */
1350     if (code) {
1351         tt->rxCallPtr = (struct rx_call *)0;
1352         TRELE(tt);
1353         return code;
1354     }
1355     tt->rxCallPtr = (struct rx_call *)0;
1356
1357     if (TRELE(tt))
1358         return VOLSERTRELE_ERROR;
1359
1360     return 0;
1361 }
1362
1363 /* 
1364  * Ha!  No more helper process!
1365  */
1366 afs_int32
1367 SAFSVolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags, 
1368                struct restoreCookie *cookie)
1369 {
1370     afs_int32 code;
1371
1372     code = VolRestore(acid, atrans, aflags, cookie);
1373     osi_auditU(acid, VS_RestoreEvent, code, AUD_LONG, atrans, AUD_END);
1374     return code;
1375 }
1376
1377 afs_int32
1378 VolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags, 
1379                struct restoreCookie *cookie)
1380 {
1381     register struct volser_trans *tt;
1382     register afs_int32 code, tcode;
1383     char caller[MAXKTCNAMELEN];
1384
1385     if (!afsconf_SuperUser(tdir, acid, caller))
1386         return VOLSERBAD_ACCESS;        /*not a super user */
1387     tt = FindTrans(atrans);
1388     if (!tt)
1389         return ENOENT;
1390     if (tt->vflags & VTDeleted) {
1391         Log("1 Volser: VolRestore: volume %u has been deleted \n", tt->volid);
1392         TRELE(tt);
1393         return ENOENT;
1394     }
1395     strcpy(tt->lastProcName, "Restore");
1396     tt->rxCallPtr = acid;
1397
1398     DFlushVolume(V_parentId(tt->volume)); /* Ensure dir buffers get dropped */
1399
1400     code = RestoreVolume(acid, tt->volume, (aflags & 1), cookie);       /* last is incrementalp */
1401     FSYNC_VolOp(tt->volid, NULL, FSYNC_VOL_BREAKCBKS, 0l, NULL);
1402     tt->rxCallPtr = (struct rx_call *)0;
1403     tcode = TRELE(tt);
1404
1405     return (code ? code : tcode);
1406 }
1407
1408 /* end a transaction, returning the transaction's final error code in rcode */
1409 afs_int32
1410 SAFSVolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1411 {
1412     afs_int32 code;
1413
1414     code = VolEndTrans(acid, destTrans, rcode);
1415     osi_auditU(acid, VS_EndTrnEvent, code, AUD_LONG, destTrans, AUD_END);
1416     return code;
1417 }
1418
1419 afs_int32
1420 VolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1421 {
1422     register struct volser_trans *tt;
1423     char caller[MAXKTCNAMELEN];
1424
1425     if (!afsconf_SuperUser(tdir, acid, caller))
1426         return VOLSERBAD_ACCESS;        /*not a super user */
1427     tt = FindTrans(destTrans);
1428     if (!tt) {
1429         return ENOENT;
1430     }
1431     *rcode = tt->returnCode;
1432     DeleteTrans(tt, 1);         /* this does an implicit TRELE */
1433
1434     return 0;
1435 }
1436
1437 afs_int32
1438 SAFSVolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1439 {
1440     afs_int32 code;
1441
1442     code = VolSetForwarding(acid, atid, anewsite);
1443     osi_auditU(acid, VS_SetForwEvent, code, AUD_LONG, atid, AUD_HOST,
1444                anewsite, AUD_END);
1445     return code;
1446 }
1447
1448 afs_int32
1449 VolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1450 {
1451     register struct volser_trans *tt;
1452     char caller[MAXKTCNAMELEN];
1453     char partName[16];
1454
1455     if (!afsconf_SuperUser(tdir, acid, caller))
1456         return VOLSERBAD_ACCESS;        /*not a super user */
1457     tt = FindTrans(atid);
1458     if (!tt)
1459         return ENOENT;
1460     if (tt->vflags & VTDeleted) {
1461         Log("1 Volser: VolSetForwarding: volume %u has been deleted \n",
1462             tt->volid);
1463         TRELE(tt);
1464         return ENOENT;
1465     }
1466     strcpy(tt->lastProcName, "SetForwarding");
1467     tt->rxCallPtr = acid;
1468     if (volutil_PartitionName2_r(tt->partition, partName, sizeof(partName)) != 0) {
1469         partName[0] = '\0';
1470     }
1471     FSYNC_VolOp(tt->volid, partName, FSYNC_VOL_MOVE, anewsite, NULL);
1472     tt->rxCallPtr = (struct rx_call *)0;
1473     if (TRELE(tt))
1474         return VOLSERTRELE_ERROR;
1475
1476     return 0;
1477 }
1478
1479 afs_int32
1480 SAFSVolGetStatus(struct rx_call *acid, afs_int32 atrans, 
1481                  register struct volser_status *astatus)
1482 {
1483     afs_int32 code;
1484
1485     code = VolGetStatus(acid, atrans, astatus);
1486     osi_auditU(acid, VS_GetStatEvent, code, AUD_LONG, atrans, AUD_END);
1487     return code;
1488 }
1489
1490 afs_int32
1491 VolGetStatus(struct rx_call *acid, afs_int32 atrans, 
1492                  register struct volser_status *astatus)
1493 {
1494     register struct Volume *tv;
1495     register struct VolumeDiskData *td;
1496     struct volser_trans *tt;
1497
1498
1499     tt = FindTrans(atrans);
1500     if (!tt)
1501         return ENOENT;
1502     if (tt->vflags & VTDeleted) {
1503         Log("1 Volser: VolGetStatus: volume %u has been deleted \n",
1504             tt->volid);
1505         TRELE(tt);
1506         return ENOENT;
1507     }
1508     strcpy(tt->lastProcName, "GetStatus");
1509     tt->rxCallPtr = acid;
1510     tv = tt->volume;
1511     if (!tv) {
1512         tt->rxCallPtr = (struct rx_call *)0;
1513         TRELE(tt);
1514         return ENOENT;
1515     }
1516
1517     td = &tv->header->diskstuff;
1518     astatus->volID = td->id;
1519     astatus->nextUnique = td->uniquifier;
1520     astatus->type = td->type;
1521     astatus->parentID = td->parentId;
1522     astatus->cloneID = td->cloneId;
1523     astatus->backupID = td->backupId;
1524     astatus->restoredFromID = td->restoredFromId;
1525     astatus->maxQuota = td->maxquota;
1526     astatus->minQuota = td->minquota;
1527     astatus->owner = td->owner;
1528     astatus->creationDate = td->creationDate;
1529     astatus->accessDate = td->accessDate;
1530     astatus->updateDate = td->updateDate;
1531     astatus->expirationDate = td->expirationDate;
1532     astatus->backupDate = td->backupDate;
1533     astatus->copyDate = td->copyDate;
1534     tt->rxCallPtr = (struct rx_call *)0;
1535     if (TRELE(tt))
1536         return VOLSERTRELE_ERROR;
1537
1538     return 0;
1539 }
1540
1541 afs_int32
1542 SAFSVolSetInfo(struct rx_call *acid, afs_int32 atrans, 
1543                register struct volintInfo *astatus)
1544 {
1545     afs_int32 code;
1546
1547     code = VolSetInfo(acid, atrans, astatus);
1548     osi_auditU(acid, VS_SetInfoEvent, code, AUD_LONG, atrans, AUD_END);
1549     return code;
1550 }
1551
1552 afs_int32
1553 VolSetInfo(struct rx_call *acid, afs_int32 atrans, 
1554                register struct volintInfo *astatus)
1555 {
1556     register struct Volume *tv;
1557     register struct VolumeDiskData *td;
1558     struct volser_trans *tt;
1559     char caller[MAXKTCNAMELEN];
1560     afs_int32 error;
1561
1562     if (!afsconf_SuperUser(tdir, acid, caller))
1563         return VOLSERBAD_ACCESS;        /*not a super user */
1564     tt = FindTrans(atrans);
1565     if (!tt)
1566         return ENOENT;
1567     if (tt->vflags & VTDeleted) {
1568         Log("1 Volser: VolSetInfo: volume %u has been deleted \n", tt->volid);
1569         TRELE(tt);
1570         return ENOENT;
1571     }
1572     strcpy(tt->lastProcName, "SetStatus");
1573     tt->rxCallPtr = acid;
1574     tv = tt->volume;
1575     if (!tv) {
1576         tt->rxCallPtr = (struct rx_call *)0;
1577         TRELE(tt);
1578         return ENOENT;
1579     }
1580
1581     td = &tv->header->diskstuff;
1582     /*
1583      * Add more fields as necessary
1584      */
1585     if (astatus->maxquota != -1)
1586         td->maxquota = astatus->maxquota;
1587     if (astatus->dayUse != -1)
1588         td->dayUse = astatus->dayUse;
1589     if (astatus->creationDate != -1)
1590         td->creationDate = astatus->creationDate;
1591     if (astatus->updateDate != -1)
1592         td->updateDate = astatus->updateDate;
1593     if (astatus->spare2 != -1)
1594         td->volUpdateCounter = (unsigned int)astatus->spare2;
1595     VUpdateVolume(&error, tv);
1596     tt->rxCallPtr = (struct rx_call *)0;
1597     if (TRELE(tt))
1598         return VOLSERTRELE_ERROR;
1599     return 0;
1600 }
1601
1602
1603 afs_int32
1604 SAFSVolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1605 {
1606     afs_int32 code;
1607
1608     code = VolGetName(acid, atrans, aname);
1609     osi_auditU(acid, VS_GetNameEvent, code, AUD_LONG, atrans, AUD_END);
1610     return code;
1611 }
1612
1613 afs_int32
1614 VolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1615 {
1616     register struct Volume *tv;
1617     register struct VolumeDiskData *td;
1618     struct volser_trans *tt;
1619     register int len;
1620
1621     /* We need to at least fill it in */
1622     *aname = (char *)malloc(1);
1623     if (!*aname)
1624         return ENOMEM;
1625     tt = FindTrans(atrans);
1626     if (!tt)
1627         return ENOENT;
1628     if (tt->vflags & VTDeleted) {
1629         Log("1 Volser: VolGetName: volume %u has been deleted \n", tt->volid);
1630         TRELE(tt);
1631         return ENOENT;
1632     }
1633     strcpy(tt->lastProcName, "GetName");
1634     tt->rxCallPtr = acid;
1635     tv = tt->volume;
1636     if (!tv) {
1637         tt->rxCallPtr = (struct rx_call *)0;
1638         TRELE(tt);
1639         return ENOENT;
1640     }
1641
1642     td = &tv->header->diskstuff;
1643     len = strlen(td->name) + 1; /* don't forget the null */
1644     if (len >= SIZE) {
1645         tt->rxCallPtr = (struct rx_call *)0;
1646         TRELE(tt);
1647         return E2BIG;
1648     }
1649     *aname = (char *)realloc(*aname, len);
1650     strcpy(*aname, td->name);
1651     tt->rxCallPtr = (struct rx_call *)0;
1652     if (TRELE(tt))
1653         return VOLSERTRELE_ERROR;
1654
1655     return 0;
1656 }
1657
1658 /*this is a handshake to indicate that the next call will be SAFSVolRestore
1659  * - a noop now !*/
1660 afs_int32
1661 SAFSVolSignalRestore(struct rx_call *acid, char volname[], int volType, 
1662                      afs_int32 parentId, afs_int32 cloneId)
1663 {
1664     return 0;
1665 }
1666
1667
1668 /*return a list of all partitions on the server. The non mounted
1669  *partitions are returned as -1 in the corresponding slot in partIds*/
1670 afs_int32
1671 SAFSVolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1672 {
1673     afs_int32 code;
1674
1675     code = VolListPartitions(acid, partIds);
1676     osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1677     return code;
1678 }
1679
1680 afs_int32
1681 VolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1682 {
1683     char namehead[9];
1684     char i;
1685
1686     strcpy(namehead, "/vicep"); /*7 including null terminator */
1687
1688     /* Just return attached partitions. */
1689     namehead[7] = '\0';
1690     for (i = 0; i < 26; i++) {
1691         namehead[6] = i + 'a';
1692         partIds->partIds[i] = VGetPartition(namehead, 0) ? i : -1;
1693     }
1694
1695     return 0;
1696 }
1697
1698 /*return a list of all partitions on the server. The non mounted
1699  *partitions are returned as -1 in the corresponding slot in partIds*/
1700 afs_int32
1701 SAFSVolXListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1702 {
1703     afs_int32 code;
1704
1705     code = XVolListPartitions(acid, pEntries);
1706     osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1707     return code;
1708 }
1709
1710 afs_int32
1711 XVolListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1712 {
1713     struct stat rbuf, pbuf;
1714     char namehead[9];
1715     struct partList partList;
1716     struct DiskPartition64 *dp;
1717     int i, j = 0, k;
1718
1719     strcpy(namehead, "/vicep"); /*7 including null terminator */
1720
1721     /* Only report attached partitions */
1722     for (i = 0; i < VOLMAXPARTS; i++) {
1723 #ifdef AFS_DEMAND_ATTACH_FS
1724         dp = VGetPartitionById(i, 0);
1725 #else
1726         if (i < 26) {
1727             namehead[6] = i + 'a';
1728             namehead[7] = '\0';
1729         } else {
1730             k = i - 26;
1731             namehead[6] = 'a' + (k / 26);
1732             namehead[7] = 'a' + (k % 26);
1733             namehead[8] = '\0';
1734         }
1735         dp = VGetPartition(namehead, 0);
1736 #endif
1737         if (dp)
1738             partList.partId[j++] = i;
1739     }
1740     pEntries->partEntries_val = (afs_int32 *) malloc(j * sizeof(int));
1741     if (!pEntries->partEntries_val)
1742         return ENOMEM;
1743     memcpy((char *)pEntries->partEntries_val, (char *)&partList,
1744            j * sizeof(int));
1745     pEntries->partEntries_len = j;
1746     return 0;
1747
1748 }
1749
1750 /*extract the volume id from string vname. Its of the form " V0*<id>.vol  "*/
1751 afs_int32
1752 ExtractVolId(char vname[])
1753 {
1754     int i;
1755     char name[VOLSER_MAXVOLNAME + 1];
1756
1757     strcpy(name, vname);
1758     i = 0;
1759     while (name[i] == 'V' || name[i] == '0')
1760         i++;
1761
1762     name[11] = '\0';            /* smash the "." */
1763     return (atol(&name[i]));
1764 }
1765
1766 /*return the name of the next volume header in the directory associated with dirp and dp.
1767 *the volume id is  returned in volid, and volume header name is returned in volname*/
1768 int
1769 GetNextVol(DIR * dirp, char *volname, afs_int32 * volid)
1770 {
1771     struct dirent *dp;
1772
1773     dp = readdir(dirp);         /*read next entry in the directory */
1774     if (dp) {
1775         if ((dp->d_name[0] == 'V') && !strcmp(&(dp->d_name[11]), VHDREXT)) {
1776             *volid = ExtractVolId(dp->d_name);
1777             strcpy(volname, dp->d_name);
1778             return 0;           /*return the name of the file representing a volume */
1779         } else {
1780             strcpy(volname, "");
1781             return 0;           /*volname doesnot represent a volume */
1782         }
1783     } else {
1784         strcpy(volname, "EOD");
1785         return 0;               /*end of directory */
1786     }
1787
1788 }
1789
1790 /**
1791  * volint vol info structure type.
1792  */
1793 typedef enum {
1794     VOLINT_INFO_TYPE_BASE,  /**< volintInfo type */
1795     VOLINT_INFO_TYPE_EXT    /**< volintXInfo type */
1796 } volint_info_type_t;
1797
1798 /**
1799  * handle to various on-wire vol info types.
1800  */
1801 typedef struct {
1802     volint_info_type_t volinfo_type;
1803     union {
1804         void * opaque;
1805         volintInfo * base;
1806         volintXInfo * ext;
1807     } volinfo_ptr;
1808 } volint_info_handle_t;
1809
1810 /**
1811  * store value to a field at the appropriate location in on-wire structure.
1812  */
1813 #define VOLINT_INFO_STORE(handle, name, val) \
1814     do { \
1815         if ((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) { \
1816             (handle)->volinfo_ptr.base->name = (val); \
1817         } else { \
1818             (handle)->volinfo_ptr.ext->name = (val); \
1819         } \
1820     } while(0)
1821
1822 /**
1823  * get pointer to appropriate offset of field in on-wire structure.
1824  */
1825 #define VOLINT_INFO_PTR(handle, name) \
1826     (((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) ? \
1827      &((handle)->volinfo_ptr.base->name) : \
1828      &((handle)->volinfo_ptr.ext->name))
1829
1830 /**
1831  * fill in appropriate type of on-wire volume metadata structure.
1832  *
1833  * @param vp      pointer to volume object
1834  * @param hdr     pointer to volume disk data object
1835  * @param handle  pointer to wire format handle object
1836  *
1837  * @pre handle object must have a valid pointer and enumeration value
1838  *
1839  * @note passing a NULL value for vp means that the fileserver doesn't
1840  *       know about this particular volume, thus implying it is offline.
1841  *
1842  * @return operation status
1843  *   @retval 0 success
1844  *   @retval 1 failure
1845  */
1846 static int
1847 FillVolInfo(Volume * vp, VolumeDiskData * hdr, volint_info_handle_t * handle)
1848 {
1849     unsigned int numStatBytes, now;
1850
1851     /*read in the relevant info */
1852     strcpy(VOLINT_INFO_PTR(handle, name), hdr->name);
1853     VOLINT_INFO_STORE(handle, status, VOK);     /*its ok */
1854     VOLINT_INFO_STORE(handle, volid, hdr->id);
1855     VOLINT_INFO_STORE(handle, type, hdr->type); /*if ro volume */
1856     VOLINT_INFO_STORE(handle, cloneID, hdr->cloneId);   /*if rw volume */
1857     VOLINT_INFO_STORE(handle, backupID, hdr->backupId);
1858     VOLINT_INFO_STORE(handle, parentID, hdr->parentId);
1859     VOLINT_INFO_STORE(handle, copyDate, hdr->copyDate);
1860     VOLINT_INFO_STORE(handle, size, hdr->diskused);
1861     VOLINT_INFO_STORE(handle, maxquota, hdr->maxquota);
1862     VOLINT_INFO_STORE(handle, filecount, hdr->filecount);
1863     now = FT_ApproxTime();
1864     if ((now - hdr->dayUseDate) > OneDay) {
1865         VOLINT_INFO_STORE(handle, dayUse, 0);
1866     } else {
1867         VOLINT_INFO_STORE(handle, dayUse, hdr->dayUse);
1868     }
1869     VOLINT_INFO_STORE(handle, creationDate, hdr->creationDate);
1870     VOLINT_INFO_STORE(handle, accessDate, hdr->accessDate);
1871     VOLINT_INFO_STORE(handle, updateDate, hdr->updateDate);
1872     VOLINT_INFO_STORE(handle, backupDate, hdr->backupDate);
1873
1874 #ifdef AFS_DEMAND_ATTACH_FS
1875     /*
1876      * for DAFS, we "lie" about volume state --
1877      * instead of returning the raw state from the disk header,
1878      * we compute state based upon the fileserver's internal
1879      * in-core state enumeration value reported to us via fssync,
1880      * along with the blessed and inService flags from the header.
1881      *   -- tkeiser 11/27/2007
1882      */
1883     if (!vp ||
1884         (V_attachState(vp) == VOL_STATE_UNATTACHED) ||
1885         VIsErrorState(V_attachState(vp)) ||
1886         !hdr->inService ||
1887         !hdr->blessed) {
1888         VOLINT_INFO_STORE(handle, inUse, 0);
1889     } else {
1890         VOLINT_INFO_STORE(handle, inUse, 1);
1891     }
1892 #else
1893     VOLINT_INFO_STORE(handle, inUse, hdr->inUse);
1894 #endif
1895
1896
1897     switch(handle->volinfo_type) {
1898     case VOLINT_INFO_TYPE_BASE:
1899
1900 #ifdef AFS_DEMAND_ATTACH_FS
1901         /* see comment above where we set inUse bit */
1902         if (hdr->needsSalvaged || 
1903             (vp && VIsErrorState(V_attachState(vp)))) {
1904             handle->volinfo_ptr.base->needsSalvaged = 1;
1905         } else {
1906             handle->volinfo_ptr.base->needsSalvaged = 0;
1907         }
1908 #else
1909         handle->volinfo_ptr.base->needsSalvaged = hdr->needsSalvaged;
1910 #endif
1911         handle->volinfo_ptr.base->destroyMe = hdr->destroyMe;
1912         handle->volinfo_ptr.base->spare0 = hdr->minquota;
1913         handle->volinfo_ptr.base->spare1 = 
1914             (long)hdr->weekUse[0] +
1915             (long)hdr->weekUse[1] +
1916             (long)hdr->weekUse[2] +
1917             (long)hdr->weekUse[3] +
1918             (long)hdr->weekUse[4] +
1919             (long)hdr->weekUse[5] +
1920             (long)hdr->weekUse[6];
1921         handle->volinfo_ptr.base->flags = 0;
1922         handle->volinfo_ptr.base->spare2 = hdr->volUpdateCounter;
1923         handle->volinfo_ptr.base->spare3 = 0;
1924         break;
1925
1926
1927     case VOLINT_INFO_TYPE_EXT:
1928         numStatBytes =
1929             4 * ((2 * VOLINT_STATS_NUM_RWINFO_FIELDS) +
1930                  (4 * VOLINT_STATS_NUM_TIME_FIELDS));
1931
1932         /*
1933          * Copy out the stat fields in a single operation.
1934          */
1935         if ((now - hdr->dayUseDate) > OneDay) {
1936             memset((char *)&(handle->volinfo_ptr.ext->stat_reads[0]),
1937                    0, numStatBytes);
1938         } else {
1939             memcpy((char *)&(handle->volinfo_ptr.ext->stat_reads[0]),
1940                    (char *)&(hdr->stat_reads[0]), 
1941                    numStatBytes);
1942         }
1943         break;
1944     }
1945
1946     return 0;
1947 }
1948
1949 /**
1950  * get struct Volume out of the fileserver.
1951  *
1952  * @param[in] volumeId  volumeId for which we want state information
1953  * @param[in] pname     partition name string
1954  * @param[inout] vp     pointer to pointer to Volume object which 
1955  *                      will be populated (see note)
1956  *
1957  * @return operation status
1958  *   @retval 0         success
1959  *   @retval non-zero  failure
1960  *
1961  * @note if FSYNC_VolOp fails in certain ways, *vp will be set to NULL
1962  *
1963  * @internal
1964  */
1965 static int
1966 GetVolObject(afs_uint32 volumeId, char * pname, Volume ** vp)
1967 {
1968     int code;
1969     SYNC_response res;
1970
1971     res.hdr.response_len = sizeof(res.hdr);
1972     res.payload.buf = *vp;
1973     res.payload.len = sizeof(Volume);
1974
1975     code = FSYNC_VolOp(volumeId,
1976                        pname,
1977                        FSYNC_VOL_QUERY,
1978                        0,
1979                        &res);
1980
1981     if (code != SYNC_OK) {
1982         switch (res.hdr.reason) {
1983         case FSYNC_WRONG_PART:
1984         case FSYNC_UNKNOWN_VOLID:
1985             *vp = NULL;
1986             code = SYNC_OK;
1987             break;
1988         }
1989     }
1990
1991     return code;
1992 }
1993
1994 /**
1995  * mode of volume list operation.
1996  */
1997 typedef enum {
1998     VOL_INFO_LIST_SINGLE,   /**< performing a single volume list op */
1999     VOL_INFO_LIST_MULTIPLE  /**< performing a multi-volume list op */
2000 } vol_info_list_mode_t;
2001
2002 /**
2003  * abstract interface to populate wire-format volume metadata structures.
2004  *
2005  * @param[in]  partId    partition id
2006  * @param[in]  volumeId  volume id
2007  * @param[in]  pname     partition name
2008  * @param[in]  volname   volume file name
2009  * @param[in]  handle    handle to on-wire volume metadata object
2010  * @param[in]  mode      listing mode
2011  *
2012  * @return operation status
2013  *   @retval 0      success
2014  *   @retval -2     DESTROY_ME flag is set
2015  *   @retval -1     general failure; some data filled in
2016  *   @retval -3     couldn't create vtrans; some data filled in
2017  */
2018 static int
2019 GetVolInfo(afs_uint32 partId,
2020            afs_uint32 volumeId,
2021            char * pname, 
2022            char * volname, 
2023            volint_info_handle_t * handle,
2024            vol_info_list_mode_t mode)
2025 {
2026     int code = -1;
2027     int reason;
2028     afs_int32 error;
2029     struct volser_trans *ttc = NULL;
2030     struct Volume fs_tv_buf, *fs_tv = &fs_tv_buf, *tv = NULL;
2031
2032     ttc = NewTrans(volumeId, partId);
2033     if (!ttc) {
2034         code = -3;
2035         VOLINT_INFO_STORE(handle, status, VBUSY);
2036         VOLINT_INFO_STORE(handle, volid, volumeId);
2037         goto drop;
2038     }
2039
2040     tv = VAttachVolumeByName(&error, pname, volname, V_PEEK);
2041     if (error) {
2042         Log("1 Volser: GetVolInfo: Could not attach volume %u (%s:%s) error=%d\n", 
2043             volumeId, pname, volname, error);
2044         goto drop;
2045     }
2046
2047     /*
2048      * please note that destroyMe and needsSalvaged checks used to be ordered
2049      * in the opposite manner for ListVolumes and XListVolumes.  I think it's
2050      * more correct to check destroyMe before needsSalvaged.
2051      *   -- tkeiser 11/28/2007
2052      */
2053
2054     if (tv->header->diskstuff.destroyMe == DESTROY_ME) {
2055         switch (mode) {
2056         case VOL_INFO_LIST_MULTIPLE:
2057             code = -2;
2058             goto drop;
2059
2060         case VOL_INFO_LIST_SINGLE:
2061             Log("1 Volser: GetVolInfo: Volume %u (%s:%s) will be destroyed on next salvage\n", 
2062                 volumeId, pname, volname);
2063
2064         default:
2065             goto drop;
2066         }
2067     }
2068
2069     if (tv->header->diskstuff.needsSalvaged) {
2070         /*this volume will be salvaged */
2071         Log("1 Volser: GetVolInfo: Volume %u (%s:%s) needs to be salvaged\n", 
2072             volumeId, pname, volname);
2073         goto drop;
2074     }
2075
2076 #ifdef AFS_DEMAND_ATTACH_FS
2077     if (GetVolObject(volumeId, pname, &fs_tv) != SYNC_OK) {
2078         goto drop;
2079     }
2080 #endif
2081
2082     /* ok, we have all the data we need; fill in the on-wire struct */
2083     code = FillVolInfo(fs_tv, &tv->header->diskstuff, handle);
2084
2085
2086  drop:
2087     if (code == -1) {
2088         VOLINT_INFO_STORE(handle, status, 0);
2089         strcpy(VOLINT_INFO_PTR(handle, name), volname);
2090         VOLINT_INFO_STORE(handle, volid, volumeId);
2091     }
2092     if (tv) {
2093         VDetachVolume(&error, tv);
2094         tv = NULL;
2095         if (error) {
2096             VOLINT_INFO_STORE(handle, status, 0);
2097             strcpy(VOLINT_INFO_PTR(handle, name), volname);
2098             Log("1 Volser: GetVolInfo: Could not detach volume %u (%s:%s)\n",
2099                 volumeId, pname, volname);
2100         }
2101     }
2102     if (ttc) {
2103         DeleteTrans(ttc, 1);
2104         ttc = NULL;
2105     }
2106     return code;
2107 }
2108
2109
2110 /*return the header information about the <volid> */
2111 afs_int32
2112 SAFSVolListOneVolume(struct rx_call *acid, afs_int32 partid, afs_int32 
2113                      volumeId, volEntries *volumeInfo)
2114 {
2115     afs_int32 code;
2116
2117     code = VolListOneVolume(acid, partid, volumeId, volumeInfo);
2118     osi_auditU(acid, VS_Lst1VolEvent, code, AUD_LONG, volumeId, AUD_END);
2119     return code;
2120 }
2121
2122 afs_int32
2123 VolListOneVolume(struct rx_call *acid, afs_int32 partid, afs_int32 
2124                      volumeId, volEntries *volumeInfo)
2125 {
2126     volintInfo *pntr;
2127     struct DiskPartition64 *partP;
2128     char pname[9], volname[20];
2129     afs_int32 error = 0;
2130     DIR *dirp;
2131     afs_int32 volid;
2132     int found = 0;
2133     unsigned int now;
2134     int code;
2135     volint_info_handle_t handle;
2136
2137     volumeInfo->volEntries_val = (volintInfo *) malloc(sizeof(volintInfo));
2138     if (!volumeInfo->volEntries_val)
2139         return ENOMEM;
2140     pntr = volumeInfo->volEntries_val;
2141     volumeInfo->volEntries_len = 1;
2142     if (GetPartName(partid, pname))
2143         return VOLSERILLEGAL_PARTITION;
2144     if (!(partP = VGetPartition(pname, 0)))
2145         return VOLSERILLEGAL_PARTITION;
2146     dirp = opendir(VPartitionPath(partP));
2147     if (dirp == NULL)
2148         return VOLSERILLEGAL_PARTITION;
2149
2150     strcpy(volname, "");
2151
2152     while (strcmp(volname, "EOD") && !found) {  /*while there are more volumes in the partition */
2153
2154         if (!strcmp(volname, "")) {     /* its not a volume, fetch next file */
2155             GetNextVol(dirp, volname, &volid);
2156             continue;           /*back to while loop */
2157         }
2158
2159         if (volid == volumeId) {        /*copy other things too */
2160             found = 1;
2161             break;
2162         }
2163
2164         GetNextVol(dirp, volname, &volid);
2165     }
2166
2167     if (found) {
2168 #ifndef AFS_PTHREAD_ENV
2169         IOMGR_Poll();   /*make sure that the client does not time out */
2170 #endif
2171
2172         handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2173         handle.volinfo_ptr.base = volumeInfo->volEntries_val;
2174         
2175         code = GetVolInfo(partid, 
2176                           volid, 
2177                           pname, 
2178                           volname,
2179                           &handle,
2180                           VOL_INFO_LIST_SINGLE);
2181     }
2182
2183     closedir(dirp);
2184     return (found) ? 0 : ENODEV;
2185 }
2186
2187 /*------------------------------------------------------------------------
2188  * EXPORTED SAFSVolXListOneVolume
2189  *
2190  * Description:
2191  *      Returns extended info on volume a_volID on partition a_partID.
2192  *
2193  * Arguments:
2194  *      a_rxCidP       : Pointer to the Rx call we're performing.
2195  *      a_partID       : Partition for which we want the extended list.
2196  *      a_volID        : Volume ID we wish to know about.
2197  *      a_volumeXInfoP : Ptr to the extended info blob.
2198  *
2199  * Returns:
2200  *      0                       Successful operation
2201  *      VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2202  *
2203  * Environment:
2204  *      Nothing interesting.
2205  *
2206  * Side Effects:
2207  *      As advertised.
2208  *------------------------------------------------------------------------*/
2209
2210 afs_int32
2211 SAFSVolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID, 
2212                       afs_int32 a_volID, volXEntries *a_volumeXInfoP)
2213 {
2214     afs_int32 code;
2215
2216     code = VolXListOneVolume(a_rxCidP, a_partID, a_volID, a_volumeXInfoP);
2217     osi_auditU(a_rxCidP, VS_XLst1VlEvent, code, AUD_LONG, a_volID, AUD_END);
2218     return code;
2219 }
2220
2221 afs_int32
2222 VolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID, 
2223                       afs_int32 a_volID, volXEntries *a_volumeXInfoP)
2224 {                               /*SAFSVolXListOneVolume */
2225
2226     volintXInfo *xInfoP;        /*Ptr to the extended vol info */
2227     struct DiskPartition64 *partP;      /*Ptr to partition */
2228     char pname[9], volname[20]; /*Partition, volume names */
2229     afs_int32 error;            /*Error code */
2230     DIR *dirp;                  /*Partition directory ptr */
2231     afs_int32 currVolID;        /*Current volume ID */
2232     int found = 0;              /*Did we find the volume we need? */
2233     unsigned int now;
2234     int code;
2235     volint_info_handle_t handle;
2236
2237     /*
2238      * Set up our pointers for action, marking our structure to hold exactly
2239      * one entry.  Also, assume we'll fail in our quest.
2240      */
2241     a_volumeXInfoP->volXEntries_val =
2242         (volintXInfo *) malloc(sizeof(volintXInfo));
2243     if (!a_volumeXInfoP->volXEntries_val)
2244         return ENOMEM;
2245     xInfoP = a_volumeXInfoP->volXEntries_val;
2246     a_volumeXInfoP->volXEntries_len = 1;
2247     code = ENODEV;
2248
2249     /*
2250      * If the partition name we've been given is bad, bogue out.
2251      */
2252     if (GetPartName(a_partID, pname))
2253         return (VOLSERILLEGAL_PARTITION);
2254
2255     /*
2256      * Open the directory representing the given AFS parttion.  If we can't
2257      * do that, we lose.
2258      */
2259     if (!(partP = VGetPartition(pname, 0)))
2260         return VOLSERILLEGAL_PARTITION;
2261     dirp = opendir(VPartitionPath(partP));
2262     if (dirp == NULL)
2263         return (VOLSERILLEGAL_PARTITION);
2264
2265     strcpy(volname, "");
2266
2267     /*
2268      * Sweep through the partition directory, looking for the desired entry.
2269      * First, of course, figure out how many stat bytes to copy out of each
2270      * volume.
2271      */
2272     while (strcmp(volname, "EOD") && !found) {
2273         /*
2274          * If this is not a volume, move on to the next entry in the
2275          * partition's directory.
2276          */
2277         if (!strcmp(volname, "")) {
2278             GetNextVol(dirp, volname, &currVolID);
2279             continue;
2280         }
2281
2282         if (currVolID == a_volID) {
2283             /*
2284              * We found the volume entry we're interested.  Pull out the
2285              * extended information, remembering to poll (so that the client
2286              * doesn't time out) and to set up a transaction on the volume.
2287              */
2288             found = 1;
2289             break;
2290         }                       /*Found desired volume */
2291
2292         GetNextVol(dirp, volname, &currVolID);
2293     }
2294
2295     if (found) {
2296 #ifndef AFS_PTHREAD_ENV
2297         IOMGR_Poll();
2298 #endif
2299
2300         handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2301         handle.volinfo_ptr.ext = a_volumeXInfoP->volXEntries_val;
2302
2303         code = GetVolInfo(a_partID,
2304                           a_volID,
2305                           pname,
2306                           volname,
2307                           &handle,
2308                           VOL_INFO_LIST_SINGLE);
2309
2310     }
2311
2312     /*
2313      * Clean up before going to dinner: close the partition directory,
2314      * return the proper value.
2315      */
2316     closedir(dirp);
2317     return (found) ? 0 : ENODEV;
2318 }                               /*SAFSVolXListOneVolume */
2319
2320 /*returns all the volumes on partition partid. If flags = 1 then all the 
2321 * relevant info about the volumes  is also returned */
2322 afs_int32
2323 SAFSVolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags, 
2324                    volEntries *volumeInfo)
2325 {
2326     afs_int32 code;
2327
2328     code = VolListVolumes(acid, partid, flags, volumeInfo);
2329     osi_auditU(acid, VS_ListVolEvent, code, AUD_END);
2330     return code;
2331 }
2332
2333 afs_int32
2334 VolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags, 
2335                    volEntries *volumeInfo)
2336 {
2337     volintInfo *pntr;
2338     struct DiskPartition64 *partP;
2339     afs_int32 allocSize = 1000; /*to be changed to a larger figure */
2340     char pname[9], volname[20];
2341     afs_int32 error = 0;
2342     DIR *dirp;
2343     afs_int32 volid;
2344     unsigned int now;
2345     int code;
2346     volint_info_handle_t handle;
2347
2348     volumeInfo->volEntries_val =
2349         (volintInfo *) malloc(allocSize * sizeof(volintInfo));
2350     if (!volumeInfo->volEntries_val)
2351         return ENOMEM;
2352     pntr = volumeInfo->volEntries_val;
2353     volumeInfo->volEntries_len = 0;
2354     if (GetPartName(partid, pname))
2355         return VOLSERILLEGAL_PARTITION;
2356     if (!(partP = VGetPartition(pname, 0)))
2357         return VOLSERILLEGAL_PARTITION;
2358     dirp = opendir(VPartitionPath(partP));
2359     if (dirp == NULL)
2360         return VOLSERILLEGAL_PARTITION;
2361     strcpy(volname, "");
2362
2363     while (strcmp(volname, "EOD")) {    /*while there are more partitions in the partition */
2364
2365         if (!strcmp(volname, "")) {     /* its not a volume, fetch next file */
2366             GetNextVol(dirp, volname, &volid);
2367             continue;           /*back to while loop */
2368         }
2369
2370         if (flags) {            /*copy other things too */
2371 #ifndef AFS_PTHREAD_ENV
2372             IOMGR_Poll();       /*make sure that the client does not time out */
2373 #endif
2374
2375             handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2376             handle.volinfo_ptr.base = pntr;
2377
2378
2379             code = GetVolInfo(partid,
2380                               volid,
2381                               pname,
2382                               volname,
2383                               &handle,
2384                               VOL_INFO_LIST_MULTIPLE);
2385             if (code == -2) { /* DESTROY_ME flag set */
2386                 goto drop2;
2387             }
2388         } else {
2389             pntr->volid = volid;
2390             /*just volids are needed */
2391         }
2392
2393       drop:
2394         pntr++;
2395         volumeInfo->volEntries_len += 1;
2396         if ((allocSize - volumeInfo->volEntries_len) < 5) {
2397             /*running out of space, allocate more space */
2398             allocSize = (allocSize * 3) / 2;
2399             pntr =
2400                 (volintInfo *) realloc((char *)volumeInfo->volEntries_val,
2401                                        allocSize * sizeof(volintInfo));
2402             if (pntr == NULL) {
2403                 closedir(dirp); 
2404                 return VOLSERNO_MEMORY;
2405             }
2406             volumeInfo->volEntries_val = pntr;  /* point to new block */
2407             /* set pntr to the right position */
2408             pntr = volumeInfo->volEntries_val + volumeInfo->volEntries_len;
2409
2410         }
2411
2412       drop2:
2413         GetNextVol(dirp, volname, &volid);
2414
2415     }
2416
2417     closedir(dirp);
2418     return 0;
2419 }
2420
2421 /*------------------------------------------------------------------------
2422  * EXPORTED SAFSVolXListVolumes
2423  *
2424  * Description:
2425  *      Returns all the volumes on partition a_partID.  If a_flags
2426  *      is set to 1, then all the relevant extended volume information
2427  *      is also returned.
2428  *
2429  * Arguments:
2430  *      a_rxCidP       : Pointer to the Rx call we're performing.
2431  *      a_partID       : Partition for which we want the extended list.
2432  *      a_flags        : Various flags.
2433  *      a_volumeXInfoP : Ptr to the extended info blob.
2434  *
2435  * Returns:
2436  *      0                       Successful operation
2437  *      VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2438  *      VOLSERNO_MEMORY         if we ran out of memory allocating
2439  *                              our return blob
2440  *
2441  * Environment:
2442  *      Nothing interesting.
2443  *
2444  * Side Effects:
2445  *      As advertised.
2446  *------------------------------------------------------------------------*/
2447
2448 afs_int32
2449 SAFSVolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2450                     afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2451 {
2452     afs_int32 code;
2453
2454     code = VolXListVolumes(a_rxCidP, a_partID, a_flags, a_volumeXInfoP);
2455     osi_auditU(a_rxCidP, VS_XLstVolEvent, code, AUD_END);
2456     return code;
2457 }
2458
2459 afs_int32
2460 VolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2461                     afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2462 {                               /*SAFSVolXListVolumes */
2463
2464     volintXInfo *xInfoP;        /*Ptr to the extended vol info */
2465     struct DiskPartition64 *partP;      /*Ptr to partition */
2466     afs_int32 allocSize = 1000; /*To be changed to a larger figure */
2467     char pname[9], volname[20]; /*Partition, volume names */
2468     afs_int32 error = 0;        /*Return code */
2469     DIR *dirp;                  /*Partition directory ptr */
2470     afs_int32 volid;            /*Current volume ID */
2471     unsigned int now;
2472     int code;
2473     volint_info_handle_t handle;
2474
2475     /*
2476      * Allocate a large array of extended volume info structures, then
2477      * set it up for action.
2478      */
2479     a_volumeXInfoP->volXEntries_val =
2480         (volintXInfo *) malloc(allocSize * sizeof(volintXInfo));
2481     if (!a_volumeXInfoP->volXEntries_val)
2482         return ENOMEM;
2483     xInfoP = a_volumeXInfoP->volXEntries_val;
2484     a_volumeXInfoP->volXEntries_len = 0;
2485
2486     /*
2487      * If the partition name we've been given is bad, bogue out.
2488      */
2489     if (GetPartName(a_partID, pname))
2490         return (VOLSERILLEGAL_PARTITION);
2491
2492     /*
2493      * Open the directory representing the given AFS parttion.  If we can't
2494      * do that, we lose.
2495      */
2496     if (!(partP = VGetPartition(pname, 0)))
2497         return VOLSERILLEGAL_PARTITION;
2498     dirp = opendir(VPartitionPath(partP));
2499     if (dirp == NULL)
2500         return (VOLSERILLEGAL_PARTITION);
2501     strcpy(volname, "");
2502
2503     /*
2504      * Sweep through the partition directory, acting on each entry.  First,
2505      * of course, figure out how many stat bytes to copy out of each volume.
2506      */
2507     while (strcmp(volname, "EOD")) {
2508
2509         /*
2510          * If this is not a volume, move on to the next entry in the
2511          * partition's directory.
2512          */
2513         if (!strcmp(volname, "")) {
2514             GetNextVol(dirp, volname, &volid);
2515             continue;
2516         }
2517
2518         if (a_flags) {
2519             /*
2520              * Full info about the volume desired.  Poll to make sure the
2521              * client doesn't time out, then start up a new transaction.
2522              */
2523 #ifndef AFS_PTHREAD_ENV
2524             IOMGR_Poll();
2525 #endif
2526
2527             handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2528             handle.volinfo_ptr.ext = xInfoP;
2529
2530             code = GetVolInfo(a_partID,
2531                               volid,
2532                               pname,
2533                               volname,
2534                               &handle,
2535                               VOL_INFO_LIST_MULTIPLE);
2536             if (code == -2) { /* DESTROY_ME flag set */
2537                 goto drop2;
2538             }
2539         } else {
2540             /*
2541              * Just volume IDs are needed.
2542              */
2543             xInfoP->volid = volid;
2544         }
2545
2546       drop:
2547         /*
2548          * Bump the pointer in the data area we're building, along with
2549          * the count of the number of entries it contains.
2550          */
2551         xInfoP++;
2552         (a_volumeXInfoP->volXEntries_len)++;
2553         if ((allocSize - a_volumeXInfoP->volXEntries_len) < 5) {
2554             /*
2555              * We're running out of space in the area we've built.  Grow it.
2556              */
2557             allocSize = (allocSize * 3) / 2;
2558             xInfoP = (volintXInfo *)
2559                 realloc((char *)a_volumeXInfoP->volXEntries_val,
2560                         (allocSize * sizeof(volintXInfo)));
2561             if (xInfoP == NULL) {
2562                 /*
2563                  * Bummer, no memory. Bag it, tell our caller what went wrong.
2564                  */
2565                 closedir(dirp);
2566                 return (VOLSERNO_MEMORY);
2567             }
2568
2569             /*
2570              * Memory reallocation worked.  Correct our pointers so they
2571              * now point to the new block and the current open position within
2572              * the new block.
2573              */
2574             a_volumeXInfoP->volXEntries_val = xInfoP;
2575             xInfoP =
2576                 a_volumeXInfoP->volXEntries_val +
2577                 a_volumeXInfoP->volXEntries_len;
2578         }
2579
2580       drop2:
2581         GetNextVol(dirp, volname, &volid);
2582     }                           /*Sweep through the partition directory */
2583
2584     /*
2585      * We've examined all entries in the partition directory.  Close it,
2586      * delete our transaction (if any), and go home happy.
2587      */
2588     closedir(dirp);
2589     return (0);
2590
2591 }                               /*SAFSVolXListVolumes */
2592
2593 /*this call is used to monitor the status of volser for debugging purposes.
2594  *information about all the active transactions is returned in transInfo*/
2595 afs_int32
2596 SAFSVolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2597 {
2598     afs_int32 code;
2599
2600     code = VolMonitor(acid, transInfo);
2601     osi_auditU(acid, VS_MonitorEvent, code, AUD_END);
2602     return code;
2603 }
2604
2605 afs_int32
2606 VolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2607 {
2608     transDebugInfo *pntr;
2609     afs_int32 allocSize = 50;
2610     struct volser_trans *tt, *allTrans;
2611
2612     transInfo->transDebugEntries_val =
2613         (transDebugInfo *) malloc(allocSize * sizeof(transDebugInfo));
2614     if (!transInfo->transDebugEntries_val)
2615         return ENOMEM;
2616     pntr = transInfo->transDebugEntries_val;
2617     transInfo->transDebugEntries_len = 0;
2618     allTrans = TransList();
2619     if (allTrans == (struct volser_trans *)0)
2620         return 0;               /*no active transactions */
2621     for (tt = allTrans; tt; tt = tt->next) {    /*copy relevant info into pntr */
2622         pntr->tid = tt->tid;
2623         pntr->time = tt->time;
2624         pntr->creationTime = tt->creationTime;
2625         pntr->returnCode = tt->returnCode;
2626         pntr->volid = tt->volid;
2627         pntr->partition = tt->partition;
2628         pntr->iflags = tt->iflags;
2629         pntr->vflags = tt->vflags;
2630         pntr->tflags = tt->tflags;
2631         strcpy(pntr->lastProcName, tt->lastProcName);
2632         pntr->callValid = 0;
2633         if (tt->rxCallPtr) {    /*record call related info */
2634             pntr->callValid = 1;
2635             pntr->readNext = tt->rxCallPtr->rnext;
2636             pntr->transmitNext = tt->rxCallPtr->tnext;
2637             pntr->lastSendTime = tt->rxCallPtr->lastSendTime;
2638             pntr->lastReceiveTime = tt->rxCallPtr->lastReceiveTime;
2639         }
2640         pntr++;
2641         transInfo->transDebugEntries_len += 1;
2642         if ((allocSize - transInfo->transDebugEntries_len) < 5) {       /*alloc some more space */
2643             allocSize = (allocSize * 3) / 2;
2644             pntr =
2645                 (transDebugInfo *) realloc((char *)transInfo->
2646                                            transDebugEntries_val,
2647                                            allocSize *
2648                                            sizeof(transDebugInfo));
2649             transInfo->transDebugEntries_val = pntr;
2650             pntr =
2651                 transInfo->transDebugEntries_val +
2652                 transInfo->transDebugEntries_len;
2653             /*set pntr to right position */
2654         }
2655
2656     }
2657
2658     return 0;
2659 }
2660
2661 afs_int32
2662 SAFSVolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[], afs_int32 type, afs_int32 pId, afs_int32 cloneId, afs_int32 backupId)
2663 {
2664     afs_int32 code;
2665
2666     code = VolSetIdsTypes(acid, atid, name, type, pId, cloneId, backupId);
2667     osi_auditU(acid, VS_SetIdTyEvent, code, AUD_LONG, atid, AUD_STR, name,
2668                AUD_LONG, type, AUD_LONG, pId, AUD_LONG, cloneId, AUD_LONG,
2669                backupId, AUD_END);
2670     return code;
2671 }
2672
2673 afs_int32
2674 VolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[], afs_int32 type, afs_int32 pId, afs_int32 cloneId, afs_int32 backupId)
2675 {
2676     struct Volume *tv;
2677     afs_int32 error = 0;
2678     register struct volser_trans *tt;
2679     char caller[MAXKTCNAMELEN];
2680
2681     if (strlen(name) > 31)
2682         return VOLSERBADNAME;
2683     if (!afsconf_SuperUser(tdir, acid, caller))
2684         return VOLSERBAD_ACCESS;        /*not a super user */
2685     /* find the trans */
2686     tt = FindTrans(atid);
2687     if (!tt)
2688         return ENOENT;
2689     if (tt->vflags & VTDeleted) {
2690         Log("1 Volser: VolSetIds: volume %u has been deleted \n", tt->volid);
2691         TRELE(tt);
2692         return ENOENT;
2693     }
2694     strcpy(tt->lastProcName, "SetIdsTypes");
2695     tt->rxCallPtr = acid;
2696     tv = tt->volume;
2697
2698     V_type(tv) = type;
2699     V_backupId(tv) = backupId;
2700     V_cloneId(tv) = cloneId;
2701     V_parentId(tv) = pId;
2702     strcpy((&V_disk(tv))->name, name);
2703     VUpdateVolume(&error, tv);
2704     if (error) {
2705         Log("1 Volser: SetIdsTypes: VUpdate failed code %d\n", error);
2706         LogError(error);
2707         goto fail;
2708     }
2709     tt->rxCallPtr = (struct rx_call *)0;
2710     if (TRELE(tt) && !error)
2711         return VOLSERTRELE_ERROR;
2712
2713     return error;
2714   fail:
2715     tt->rxCallPtr = (struct rx_call *)0;
2716     if (TRELE(tt) && !error)
2717         return VOLSERTRELE_ERROR;
2718     return error;
2719 }
2720
2721 afs_int32
2722 SAFSVolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2723 {
2724     afs_int32 code;
2725
2726     code = VolSetDate(acid, atid, cdate);
2727     osi_auditU(acid, VS_SetDateEvent, code, AUD_LONG, atid, AUD_LONG, cdate,
2728                AUD_END);
2729     return code;
2730 }
2731
2732 afs_int32
2733 VolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2734 {
2735     struct Volume *tv;
2736     afs_int32 error = 0;
2737     register struct volser_trans *tt;
2738     char caller[MAXKTCNAMELEN];
2739
2740     if (!afsconf_SuperUser(tdir, acid, caller))
2741         return VOLSERBAD_ACCESS;        /*not a super user */
2742     /* find the trans */
2743     tt = FindTrans(atid);
2744     if (!tt)
2745         return ENOENT;
2746     if (tt->vflags & VTDeleted) {
2747         Log("1 Volser: VolSetDate: volume %u has been deleted \n", tt->volid);
2748         TRELE(tt);
2749         return ENOENT;
2750     }
2751     strcpy(tt->lastProcName, "SetDate");
2752     tt->rxCallPtr = acid;
2753     tv = tt->volume;
2754
2755     V_creationDate(tv) = cdate;
2756     VUpdateVolume(&error, tv);
2757     if (error) {
2758         Log("1 Volser: SetDate: VUpdate failed code %d\n", error);
2759         LogError(error);
2760         goto fail;
2761     }
2762     tt->rxCallPtr = (struct rx_call *)0;
2763     if (TRELE(tt) && !error)
2764         return VOLSERTRELE_ERROR;
2765
2766     return error;
2767   fail:
2768     tt->rxCallPtr = (struct rx_call *)0;
2769     if (TRELE(tt) && !error)
2770         return VOLSERTRELE_ERROR;
2771     return error;
2772 }
2773
2774 afs_int32
2775 SAFSVolConvertROtoRWvolume(struct rx_call *acid, afs_int32 partId,
2776                            afs_int32 volumeId)
2777 {
2778 #ifdef AFS_NT40_ENV
2779     return EXDEV;
2780 #else
2781     char caller[MAXKTCNAMELEN];
2782     DIR *dirp;
2783     register struct volser_trans *ttc;
2784     char pname[16], volname[20];
2785     struct DiskPartition64 *partP;
2786     afs_int32 ret = ENODEV;
2787     afs_int32 volid;
2788
2789     if (!afsconf_SuperUser(tdir, acid, caller))
2790         return VOLSERBAD_ACCESS;        /*not a super user */
2791     if (GetPartName(partId, pname))
2792         return VOLSERILLEGAL_PARTITION;
2793     if (!(partP = VGetPartition(pname, 0)))
2794         return VOLSERILLEGAL_PARTITION;
2795     dirp = opendir(VPartitionPath(partP));
2796     if (dirp == NULL)
2797         return VOLSERILLEGAL_PARTITION;
2798     strcpy(volname, "");
2799     ttc = (struct volser_trans *)0;
2800
2801     while (strcmp(volname, "EOD")) {
2802         if (!strcmp(volname, "")) {     /* its not a volume, fetch next file */
2803             GetNextVol(dirp, volname, &volid);
2804             continue;           /*back to while loop */
2805         }
2806         
2807         if (volid == volumeId) {        /*copy other things too */
2808 #ifndef AFS_PTHREAD_ENV
2809             IOMGR_Poll();       /*make sure that the client doesnot time out */
2810 #endif
2811             ttc = NewTrans(volumeId, partId);
2812             if (!ttc) {
2813                 return VBUSY;
2814             }
2815 #ifdef AFS_NAMEI_ENV
2816             ret = namei_ConvertROtoRWvolume(pname, volumeId);
2817 #else
2818             ret = inode_ConvertROtoRWvolume(pname, volumeId);
2819 #endif
2820             break;
2821         }
2822         GetNextVol(dirp, volname, &volid);
2823     }
2824     
2825     if (ttc) {
2826         DeleteTrans(ttc, 1);
2827         ttc = (struct volser_trans *)0;
2828     }
2829     
2830     closedir(dirp);
2831     return ret;
2832 #endif
2833 }
2834
2835 afs_int32
2836 SAFSVolGetSize(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
2837                register struct volintSize *size)
2838 {
2839     int code = 0;
2840     register struct volser_trans *tt;
2841     char caller[MAXKTCNAMELEN];
2842
2843     if (!afsconf_SuperUser(tdir, acid, caller))
2844         return VOLSERBAD_ACCESS;        /*not a super user */
2845     tt = FindTrans(fromTrans);
2846     if (!tt)
2847         return ENOENT;
2848     if (tt->vflags & VTDeleted) {
2849         TRELE(tt);
2850         return ENOENT;
2851     }
2852     strcpy(tt->lastProcName, "GetSize");
2853     tt->rxCallPtr = acid;
2854     code = SizeDumpVolume(acid, tt->volume, fromDate, 1, size); /* measure volume's data */
2855     tt->rxCallPtr = (struct rx_call *)0;
2856     if (TRELE(tt))
2857         return VOLSERTRELE_ERROR;
2858
2859 /*    osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);  */
2860     return code;
2861 }
2862
2863 /* GetPartName - map partid (a decimal number) into pname (a string)
2864  * Since for NT we actually want to return the drive name, we map through the
2865  * partition struct.
2866  */
2867 static int
2868 GetPartName(afs_int32 partid, char *pname)
2869 {
2870     if (partid < 0)
2871         return -1;
2872     if (partid < 26) {
2873         strcpy(pname, "/vicep");
2874         pname[6] = 'a' + partid;
2875         pname[7] = '\0';
2876         return 0;
2877     } else if (partid < VOLMAXPARTS) {
2878         strcpy(pname, "/vicep");
2879         partid -= 26;
2880         pname[6] = 'a' + (partid / 26);
2881         pname[7] = 'a' + (partid % 26);
2882         pname[8] = '\0';
2883         return 0;
2884     } else
2885         return -1;
2886 }