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