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