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