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