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