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