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