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