volser: log message for cross-device link errors
[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 %" AFS_VOLID_FMT " for parent %" AFS_VOLID_FMT "; clone aborted\n",
798                 afs_printable_VolumeId_lu(newId), afs_printable_VolumeId_lu(V_parentId(originalvp)));
799             newvp = (Volume *) 0;
800             goto fail;
801         }
802     }
803     if (newType == readonlyVolume)
804         V_cloneId(originalvp) = newId;
805     Log("1 Volser: Clone: Cloning volume %" AFS_VOLID_FMT " to new volume %" AFS_VOLID_FMT "\n", afs_printable_VolumeId_lu(tt->volid),
806         afs_printable_VolumeId_lu(newId));
807     if (purgevp)
808         Log("1 Volser: Clone: Purging old read only volume %" AFS_VOLID_FMT "\n", afs_printable_VolumeId_lu(purgeId));
809     CloneVolume(&error, originalvp, newvp, purgevp);
810     purgevp = NULL;             /* clone releases it, maybe even if error */
811     if (error) {
812         Log("1 Volser: Clone: clone operation failed with code %u\n", error);
813         LogError(error);
814         goto fail;
815     }
816     if (newType == readonlyVolume) {
817         AssignVolumeName(&V_disk(newvp), V_name(originalvp), ".readonly");
818         V_type(newvp) = readonlyVolume;
819     } else if (newType == backupVolume) {
820         AssignVolumeName(&V_disk(newvp), V_name(originalvp), ".backup");
821         V_type(newvp) = backupVolume;
822         V_backupId(originalvp) = newId;
823     }
824     strcpy(V_name(newvp), newName);
825     V_creationDate(newvp) = V_copyDate(newvp);
826     ClearVolumeStats(&V_disk(newvp));
827     V_destroyMe(newvp) = DESTROY_ME;
828     V_inService(newvp) = 0;
829     if (newType == backupVolume) {
830         V_backupDate(originalvp) = V_copyDate(newvp);
831         V_backupDate(newvp) = V_copyDate(newvp);
832     }
833     V_inUse(newvp) = 0;
834     VUpdateVolume(&error, newvp);
835     if (error) {
836         Log("1 Volser: Clone: VUpdate failed code %u\n", error);
837         LogError(error);
838         goto fail;
839     }
840     VDetachVolume(&error, newvp);       /* allow file server to get it's hands on it */
841     newvp = NULL;
842     VUpdateVolume(&error, originalvp);
843     if (error) {
844         Log("1 Volser: Clone: original update %u\n", error);
845         LogError(error);
846         goto fail;
847     }
848     TClearRxCall(tt);
849 #ifdef AFS_DEMAND_ATTACH_FS
850     salv_vp = NULL;
851 #endif
852     if (TRELE(tt)) {
853         tt = (struct volser_trans *)0;
854         error = VOLSERTRELE_ERROR;
855         goto fail;
856     }
857     DeleteTrans(ttc, 1);
858     return 0;
859
860   fail:
861     if (purgevp)
862         VDetachVolume(&code, purgevp);
863     if (newvp)
864         VDetachVolume(&code, newvp);
865     if (tt) {
866         TClearRxCall(tt);
867         TRELE(tt);
868     }
869     if (ttc)
870         DeleteTrans(ttc, 1);
871 #ifdef AFS_DEMAND_ATTACH_FS
872     if (salv_vp && error != VVOLEXISTS && error != EXDEV) {
873         V_needsSalvaged(salv_vp) = 1;
874     }
875 #endif /* AFS_DEMAND_ATTACH_FS */
876     return error;
877 }
878
879 /* reclone this volume into the specified id */
880 afs_int32
881 SAFSVolReClone(struct rx_call *acid, afs_int32 atrans, VolumeId cloneId)
882 {
883     afs_int32 code;
884
885     code = VolReClone(acid, atrans, cloneId);
886     osi_auditU(acid, VS_ReCloneEvent, code, AUD_LONG, atrans, AUD_LONG,
887                cloneId, AUD_END);
888     return code;
889 }
890
891 static afs_int32
892 VolReClone(struct rx_call *acid, afs_int32 atrans, VolumeId cloneId)
893 {
894     struct Volume *originalvp, *clonevp;
895     Error error, code;
896     afs_int32 newType;
897     struct volser_trans *tt, *ttc;
898     char caller[MAXKTCNAMELEN];
899     VolumeDiskData saved_header;
900
901     /*not a super user */
902     if (!afsconf_SuperUser(tdir, acid, caller))
903         return VOLSERBAD_ACCESS;
904     if (DoLogging) {
905         char buffer[16];
906         Log("%s on %s is executing Reclone Volume %" AFS_VOLID_FMT "\n", caller,
907             callerAddress(acid, buffer), afs_printable_VolumeId_lu(cloneId));
908     }
909     error = 0;
910     clonevp = originalvp = (Volume *) 0;
911
912     tt = FindTrans(atrans);
913     if (!tt)
914         return ENOENT;
915     if (tt->vflags & VTDeleted) {
916         Log("1 Volser: VolReClone: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
917         TRELE(tt);
918         return ENOENT;
919     }
920     ttc = NewTrans(cloneId, tt->partition);
921     if (!ttc) {                 /* someone is messing with the clone already */
922         TRELE(tt);
923         return VOLSERVOLBUSY;
924     }
925     TSetRxCall(tt, acid, "ReClone");
926
927     originalvp = tt->volume;
928     if ((V_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) {
929         Log("1 Volser: Clone: Volume %" AFS_VOLID_FMT " is offline and cannot be cloned\n",
930             afs_printable_VolumeId_lu(V_id(originalvp)));
931         error = VOFFLINE;
932         goto fail;
933     }
934
935     clonevp = VAttachVolume_retry(&error, cloneId, V_VOLUPD);
936     if (error) {
937         Log("1 Volser: can't attach clone %" AFS_VOLID_FMT "\n", afs_printable_VolumeId_lu(cloneId));
938         goto fail;
939     }
940
941     newType = V_type(clonevp);  /* type of the new volume */
942
943     if (originalvp->device != clonevp->device) {
944         Log("1 Volser: Clone: Volumes %" AFS_VOLID_FMT " and %" AFS_VOLID_FMT " are on different devices\n",
945             afs_printable_VolumeId_lu(tt->volid), afs_printable_VolumeId_lu(cloneId));
946         error = EXDEV;
947         goto fail;
948     }
949     if (V_parentId(originalvp) != V_parentId(clonevp)) {
950         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));
951         error = EXDEV;
952         goto fail;
953     }
954
955     if (DoPreserveVolumeStats) {
956         CopyVolumeStats(&V_disk(clonevp), &saved_header);
957     }
958
959     error = 0;
960     Log("1 Volser: Clone: Recloning volume %" AFS_VOLID_FMT " to volume %" AFS_VOLID_FMT "\n", afs_printable_VolumeId_lu(tt->volid),
961         afs_printable_VolumeId_lu(cloneId));
962     CloneVolume(&error, originalvp, clonevp, clonevp);
963     if (error) {
964         Log("1 Volser: Clone: reclone operation failed with code %d\n",
965             error);
966         LogError(error);
967         goto fail;
968     }
969
970     /* fix up volume name and type, CloneVolume just propagated RW's */
971     if (newType == readonlyVolume) {
972         AssignVolumeName(&V_disk(clonevp), V_name(originalvp), ".readonly");
973         V_type(clonevp) = readonlyVolume;
974     } else if (newType == backupVolume) {
975         AssignVolumeName(&V_disk(clonevp), V_name(originalvp), ".backup");
976         V_type(clonevp) = backupVolume;
977         V_backupId(originalvp) = cloneId;
978     }
979     /* don't do strcpy onto diskstuff.name, it's still OK from 1st clone */
980
981     /* update the creationDate, since this represents the last cloning date
982      * for ROs. But do not update copyDate; let it stay so we can identify
983      * when the clone was first created. */
984     V_creationDate(clonevp) = time(0);
985     if (DoPreserveVolumeStats) {
986         CopyVolumeStats(&saved_header, &V_disk(clonevp));
987     } else {
988         ClearVolumeStats(&V_disk(clonevp));
989     }
990     V_destroyMe(clonevp) = 0;
991     V_inService(clonevp) = 0;
992     if (newType == backupVolume) {
993         V_backupDate(originalvp) = V_creationDate(clonevp);
994         V_backupDate(clonevp) = V_creationDate(clonevp);
995     }
996     V_inUse(clonevp) = 0;
997     VUpdateVolume(&error, clonevp);
998     if (error) {
999         Log("1 Volser: Clone: VUpdate failed code %u\n", error);
1000         LogError(error);
1001         goto fail;
1002     }
1003     /* VUpdateVolume succeeded. Mark it in service so there's no window
1004      * between FSYNC_VOL_ON and VolSetFlags where it's offline with no
1005      * specialStatus; this is a reclone and this volume started online
1006      */
1007     V_inService(clonevp) = 1;
1008     VDetachVolume(&error, clonevp);     /* allow file server to get it's hands on it */
1009     clonevp = NULL;
1010     VUpdateVolume(&error, originalvp);
1011     if (error) {
1012         Log("1 Volser: Clone: original update %u\n", error);
1013         LogError(error);
1014         goto fail;
1015     }
1016     TClearRxCall(tt);
1017     if (TRELE(tt)) {
1018         tt = (struct volser_trans *)0;
1019         error = VOLSERTRELE_ERROR;
1020         goto fail;
1021     }
1022
1023     DeleteTrans(ttc, 1);
1024
1025     {
1026         struct DiskPartition64 *tpartp = originalvp->partition;
1027         FSYNC_VolOp(cloneId, tpartp->name, FSYNC_VOL_BREAKCBKS, 0, NULL);
1028     }
1029     return 0;
1030
1031   fail:
1032     if (clonevp)
1033         VDetachVolume(&code, clonevp);
1034     if (tt) {
1035         TClearRxCall(tt);
1036         TRELE(tt);
1037     }
1038     if (ttc)
1039         DeleteTrans(ttc, 1);
1040     return error;
1041 }
1042
1043 /* create a new transaction, associated with volume and partition.  Type of
1044  * volume transaction is spec'd by iflags.  New trans id is returned in ttid.
1045  * See volser.h for definition of iflags (the constants are named IT*).
1046  */
1047 afs_int32
1048 SAFSVolTransCreate(struct rx_call *acid, VolumeId volume, afs_int32 partition,
1049                    afs_int32 iflags, afs_int32 *ttid)
1050 {
1051     afs_int32 code;
1052
1053     code = VolTransCreate(acid, volume, partition, iflags, ttid);
1054     osi_auditU(acid, VS_TransCrEvent, code, AUD_LONG, *ttid, AUD_LONG, volume,
1055                AUD_END);
1056     return code;
1057 }
1058
1059 static afs_int32
1060 VolTransCreate(struct rx_call *acid, VolumeId volume, afs_int32 partition,
1061                    afs_int32 iflags, afs_int32 *ttid)
1062 {
1063     struct volser_trans *tt;
1064     Volume *tv;
1065     afs_int32 error;
1066     Error code;
1067     afs_int32 mode;
1068     char caller[MAXKTCNAMELEN];
1069
1070     if (!afsconf_SuperUser(tdir, acid, caller))
1071         return VOLSERBAD_ACCESS;        /*not a super user */
1072     if (iflags & ITCreate)
1073         mode = V_SECRETLY;
1074     else if (iflags & ITBusy)
1075         mode = V_CLONE;
1076     else if (iflags & ITReadOnly)
1077         mode = V_READONLY;
1078     else if (iflags & ITOffline)
1079         mode = V_VOLUPD;
1080     else {
1081         Log("1 Volser: TransCreate: Could not create trans, error %u\n",
1082             EINVAL);
1083         LogError(EINVAL);
1084         return EINVAL;
1085     }
1086     tt = NewTrans(volume, partition);
1087     if (!tt) {
1088         /* can't create a transaction? put the volume back */
1089         Log("1 transcreate: can't create transaction\n");
1090         return VOLSERVOLBUSY;
1091     }
1092     tv = XAttachVolume(&error, volume, partition, mode);
1093     if (error) {
1094         /* give up */
1095         if (tv)
1096             VDetachVolume(&code, tv);
1097         DeleteTrans(tt, 1);
1098         return error;
1099     }
1100     VTRANS_OBJ_LOCK(tt);
1101     tt->volume = tv;
1102     *ttid = tt->tid;
1103     tt->iflags = iflags;
1104     tt->vflags = 0;
1105     TSetRxCall_r(tt, NULL, "TransCreate");
1106     VTRANS_OBJ_UNLOCK(tt);
1107     if (TRELE(tt))
1108         return VOLSERTRELE_ERROR;
1109
1110     return 0;
1111 }
1112
1113 /* using aindex as a 0-based index, return the aindex'th volume on this server
1114  * Both the volume number and partition number (one-based) are returned.
1115  */
1116 afs_int32
1117 SAFSVolGetNthVolume(struct rx_call *acid, afs_int32 aindex, VolumeId *avolume,
1118                     afs_int32 *apart)
1119 {
1120     afs_int32 code;
1121
1122     code = VolGetNthVolume(acid, aindex, avolume, apart);
1123     osi_auditU(acid, VS_GetNVolEvent, code, AUD_LONG, *avolume, AUD_END);
1124     return code;
1125 }
1126
1127 static afs_int32
1128 VolGetNthVolume(struct rx_call *acid, afs_int32 aindex, afs_uint32 *avolume,
1129                     afs_int32 *apart)
1130 {
1131     if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
1132         return VOLSERBAD_ACCESS;
1133
1134     Log("1 Volser: GetNthVolume: Not yet implemented\n");
1135     return VOLSERNO_OP;
1136 }
1137
1138 /* return the volume flags (VT* constants in volser.h) associated with this
1139  * transaction.
1140  */
1141 afs_int32
1142 SAFSVolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
1143 {
1144     afs_int32 code;
1145
1146     code = VolGetFlags(acid, atid, aflags);
1147     osi_auditU(acid, VS_GetFlgsEvent, code, AUD_LONG, atid, AUD_END);
1148     return code;
1149 }
1150
1151 static afs_int32
1152 VolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
1153 {
1154     struct volser_trans *tt;
1155
1156     if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
1157         return VOLSERBAD_ACCESS;
1158
1159     tt = FindTrans(atid);
1160     if (!tt)
1161         return ENOENT;
1162     if (tt->vflags & VTDeleted) {
1163         Log("1 Volser: VolGetFlags: volume %" AFS_VOLID_FMT " has been deleted \n",
1164             afs_printable_VolumeId_lu(tt->volid));
1165         TRELE(tt);
1166         return ENOENT;
1167     }
1168     TSetRxCall(tt, acid, "GetFlags");
1169     *aflags = tt->vflags;
1170     TClearRxCall(tt);
1171     if (TRELE(tt))
1172         return VOLSERTRELE_ERROR;
1173
1174     return 0;
1175 }
1176
1177 /* Change the volume flags (VT* constants in volser.h) associated with this
1178  * transaction.  Effects take place immediately on volume, although volume
1179  * remains attached as usual by the transaction.
1180  */
1181 afs_int32
1182 SAFSVolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1183 {
1184     afs_int32 code;
1185
1186     code = VolSetFlags(acid, atid, aflags);
1187     osi_auditU(acid, VS_SetFlgsEvent, code, AUD_LONG, atid, AUD_LONG, aflags,
1188                AUD_END);
1189     return code;
1190 }
1191
1192 static afs_int32
1193 VolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1194 {
1195     struct volser_trans *tt;
1196     struct Volume *vp;
1197     Error error;
1198     char caller[MAXKTCNAMELEN];
1199
1200     if (!afsconf_SuperUser(tdir, acid, caller))
1201         return VOLSERBAD_ACCESS;        /*not a super user */
1202     /* find the trans */
1203     tt = FindTrans(atid);
1204     if (!tt)
1205         return ENOENT;
1206     if (tt->vflags & VTDeleted) {
1207         Log("1 Volser: VolSetFlags: volume %" AFS_VOLID_FMT " has been deleted \n",
1208             afs_printable_VolumeId_lu(tt->volid));
1209         TRELE(tt);
1210         return ENOENT;
1211     }
1212     TSetRxCall(tt, acid, "SetFlags");
1213     vp = tt->volume;            /* pull volume out of transaction */
1214
1215     /* check if we're allowed to make any updates */
1216     if (tt->iflags & ITReadOnly) {
1217         TRELE(tt);
1218         return EROFS;
1219     }
1220
1221     /* handle delete-on-salvage flag */
1222     if (aflags & VTDeleteOnSalvage) {
1223         V_destroyMe(tt->volume) = DESTROY_ME;
1224     } else {
1225         V_destroyMe(tt->volume) = 0;
1226     }
1227
1228     if (aflags & VTOutOfService) {
1229         V_inService(vp) = 0;
1230     } else {
1231         V_inService(vp) = 1;
1232     }
1233     VUpdateVolume(&error, vp);
1234     VTRANS_OBJ_LOCK(tt);
1235     tt->vflags = aflags;
1236     TClearRxCall_r(tt);
1237     VTRANS_OBJ_UNLOCK(tt);
1238     if (TRELE(tt) && !error)
1239         return VOLSERTRELE_ERROR;
1240
1241     return error;
1242 }
1243
1244 /* dumpS the volume associated with a particular transaction from a particular
1245  * date.  Send the dump to a different transaction (destTrans) on the server
1246  * specified by the destServer structure.
1247  */
1248 afs_int32
1249 SAFSVolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1250                struct destServer *destination, afs_int32 destTrans,
1251                struct restoreCookie *cookie)
1252 {
1253     afs_int32 code;
1254
1255     code =
1256         VolForward(acid, fromTrans, fromDate, destination, destTrans, cookie);
1257     osi_auditU(acid, VS_ForwardEvent, code, AUD_LONG, fromTrans, AUD_HOST,
1258                htonl(destination->destHost), AUD_LONG, destTrans, AUD_END);
1259     return code;
1260 }
1261
1262 static afs_int32
1263 VolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1264                struct destServer *destination, afs_int32 destTrans,
1265                struct restoreCookie *cookie)
1266 {
1267     struct volser_trans *tt;
1268     afs_int32 code;
1269     struct rx_connection *tcon;
1270     struct rx_call *tcall;
1271     struct Volume *vp;
1272     struct rx_securityClass *securityObject;
1273     afs_int32 securityIndex;
1274     char caller[MAXKTCNAMELEN];
1275
1276     if (!afsconf_SuperUser(tdir, acid, caller))
1277         return VOLSERBAD_ACCESS;        /*not a super user */
1278
1279     /* find the local transaction */
1280     tt = FindTrans(fromTrans);
1281     if (!tt)
1282         return ENOENT;
1283     if (tt->vflags & VTDeleted) {
1284         Log("1 Volser: VolForward: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
1285         TRELE(tt);
1286         return ENOENT;
1287     }
1288     vp = tt->volume;
1289     TSetRxCall(tt, NULL, "Forward");
1290
1291     /* get auth info for the this connection (uses afs from ticket file) */
1292     code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
1293     if (code) {
1294         TRELE(tt);
1295         return code;
1296     }
1297
1298     /* make an rpc connection to the other server */
1299     tcon =
1300         rx_NewConnection(htonl(destination->destHost),
1301                          htons(destination->destPort), VOLSERVICE_ID,
1302                          securityObject, securityIndex);
1303     if (!tcon) {
1304         TClearRxCall(tt);
1305         TRELE(tt);
1306         return ENOTCONN;
1307     }
1308     tcall = rx_NewCall(tcon);
1309     TSetRxCall(tt, tcall, "Forward");
1310     /* start restore going.  fromdate == 0 --> doing an incremental dump/restore */
1311     code = StartAFSVolRestore(tcall, destTrans, (fromDate ? 1 : 0), cookie);
1312     if (code) {
1313         goto fail;
1314     }
1315
1316     /* these next calls implictly call rx_Write when writing out data */
1317     code = DumpVolume(tcall, vp, fromDate, 0);  /* last field = don't dump all dirs */
1318     if (code)
1319         goto fail;
1320     EndAFSVolRestore(tcall);    /* probably doesn't do much */
1321     TClearRxCall(tt);
1322     code = rx_EndCall(tcall, 0);
1323     rx_DestroyConnection(tcon); /* done with the connection */
1324     tcon = NULL;
1325     if (code)
1326         goto fail;
1327     if (TRELE(tt))
1328         return VOLSERTRELE_ERROR;
1329
1330     return 0;
1331
1332   fail:
1333     if (tcon) {
1334         (void)rx_EndCall(tcall, 0);
1335         rx_DestroyConnection(tcon);
1336     }
1337     if (tt) {
1338         TClearRxCall(tt);
1339         TRELE(tt);
1340     }
1341     return code;
1342 }
1343
1344 /* Start a dump and send it to multiple places simultaneously.
1345  * If this returns an error (eg, return ENOENT), it means that
1346  * none of the releases worked.  If this returns 0, that means
1347  * that one or more of the releases worked, and the caller has
1348  * to examine the results array to see which one(s).
1349  * This will only do EITHER incremental or full, not both, so it's
1350  * the caller's responsibility to be sure that all the destinations
1351  * need just an incremental (and from the same time), if that's
1352  * what we're doing.
1353  */
1354 afs_int32
1355 SAFSVolForwardMultiple(struct rx_call *acid, afs_int32 fromTrans, afs_int32
1356                        fromDate, manyDests *destinations, afs_int32 spare,
1357                        struct restoreCookie *cookie, manyResults *results)
1358 {
1359     afs_int32 securityIndex;
1360     struct rx_securityClass *securityObject;
1361     char caller[MAXKTCNAMELEN];
1362     struct volser_trans *tt;
1363     afs_int32 ec, code, *codes;
1364     struct rx_connection **tcons;
1365     struct rx_call **tcalls;
1366     struct Volume *vp;
1367     int i, is_incremental;
1368
1369     if (results) {
1370         memset(results, 0, sizeof(manyResults));
1371         i = results->manyResults_len = destinations->manyDests_len;
1372         results->manyResults_val = codes = malloc(i * sizeof(afs_int32));
1373     }
1374     if (!results || !results->manyResults_val)
1375         return ENOMEM;
1376
1377     if (!afsconf_SuperUser(tdir, acid, caller))
1378         return VOLSERBAD_ACCESS;        /*not a super user */
1379     tt = FindTrans(fromTrans);
1380     if (!tt)
1381         return ENOENT;
1382     if (tt->vflags & VTDeleted) {
1383         Log("1 Volser: VolForward: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
1384         TRELE(tt);
1385         return ENOENT;
1386     }
1387     vp = tt->volume;
1388     TSetRxCall(tt, NULL, "ForwardMulti");
1389
1390     /* (fromDate == 0) ==> full dump */
1391     is_incremental = (fromDate ? 1 : 0);
1392
1393     tcons = malloc(i * sizeof(struct rx_connection *));
1394     if (!tcons) {
1395         return ENOMEM;
1396     }
1397     tcalls = malloc(i * sizeof(struct rx_call *));
1398     if (!tcalls) {
1399         free(tcons);
1400         return ENOMEM;
1401     }
1402
1403     /* get auth info for this connection (uses afs from ticket file) */
1404     code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
1405     if (code) {
1406         goto fail;              /* in order to audit each failure */
1407     }
1408
1409     /* make connections to all the other servers */
1410     for (i = 0; i < destinations->manyDests_len; i++) {
1411         struct replica *dest = &(destinations->manyDests_val[i]);
1412         tcons[i] =
1413             rx_NewConnection(htonl(dest->server.destHost),
1414                              htons(dest->server.destPort), VOLSERVICE_ID,
1415                              securityObject, securityIndex);
1416         if (!tcons[i]) {
1417             codes[i] = ENOTCONN;
1418         } else {
1419             if (!(tcalls[i] = rx_NewCall(tcons[i])))
1420                 codes[i] = ENOTCONN;
1421             else {
1422                 codes[i] =
1423                     StartAFSVolRestore(tcalls[i], dest->trans, is_incremental,
1424                                        cookie);
1425                 if (codes[i]) {
1426                     (void)rx_EndCall(tcalls[i], 0);
1427                     tcalls[i] = 0;
1428                     rx_DestroyConnection(tcons[i]);
1429                     tcons[i] = 0;
1430                 }
1431             }
1432         }
1433     }
1434
1435     /* these next calls implictly call rx_Write when writing out data */
1436     code = DumpVolMulti(tcalls, i, vp, fromDate, 0, codes);
1437
1438
1439   fail:
1440     for (i--; i >= 0; i--) {
1441         struct replica *dest = &(destinations->manyDests_val[i]);
1442
1443         if (!code && tcalls[i] && !codes[i]) {
1444             EndAFSVolRestore(tcalls[i]);
1445         }
1446         if (tcalls[i]) {
1447             ec = rx_EndCall(tcalls[i], 0);
1448             if (!codes[i])
1449                 codes[i] = ec;
1450         }
1451         if (tcons[i]) {
1452             rx_DestroyConnection(tcons[i]);     /* done with the connection */
1453         }
1454
1455         osi_auditU(acid, VS_ForwardEvent, (code ? code : codes[i]), AUD_LONG,
1456                    fromTrans, AUD_HOST, htonl(dest->server.destHost), AUD_LONG,
1457                    dest->trans, AUD_END);
1458     }
1459     free(tcons);
1460     free(tcalls);
1461
1462     if (tt) {
1463         TClearRxCall(tt);
1464         if (TRELE(tt) && !code) /* return the first code if it's set */
1465             return VOLSERTRELE_ERROR;
1466     }
1467
1468     return code;
1469 }
1470
1471 afs_int32
1472 SAFSVolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate)
1473 {
1474     afs_int32 code;
1475
1476     code = VolDump(acid, fromTrans, fromDate, 0);
1477     osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1478     return code;
1479 }
1480
1481 afs_int32
1482 SAFSVolDumpV2(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1483               afs_int32 flags)
1484 {
1485     afs_int32 code;
1486
1487     code = VolDump(acid, fromTrans, fromDate, flags);
1488     osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1489     return code;
1490 }
1491
1492 static afs_int32
1493 VolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1494         afs_int32 flags)
1495 {
1496     int code = 0;
1497     struct volser_trans *tt;
1498     char caller[MAXKTCNAMELEN];
1499
1500     if (!afsconf_SuperUser(tdir, acid, caller))
1501         return VOLSERBAD_ACCESS;        /*not a super user */
1502     tt = FindTrans(fromTrans);
1503     if (!tt)
1504         return ENOENT;
1505     if (tt->vflags & VTDeleted) {
1506         Log("1 Volser: VolDump: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
1507         TRELE(tt);
1508         return ENOENT;
1509     }
1510     TSetRxCall(tt, acid, "Dump");
1511     code = DumpVolume(acid, tt->volume, fromDate, (flags & VOLDUMPV2_OMITDIRS)
1512                       ? 0 : 1); /* squirt out the volume's data, too */
1513     if (code) {
1514         TClearRxCall(tt);
1515         TRELE(tt);
1516         return code;
1517     }
1518     TClearRxCall(tt);
1519
1520     if (TRELE(tt))
1521         return VOLSERTRELE_ERROR;
1522
1523     return 0;
1524 }
1525
1526 /*
1527  * Ha!  No more helper process!
1528  */
1529 afs_int32
1530 SAFSVolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
1531                struct restoreCookie *cookie)
1532 {
1533     afs_int32 code;
1534
1535     code = VolRestore(acid, atrans, aflags, cookie);
1536     osi_auditU(acid, VS_RestoreEvent, code, AUD_LONG, atrans, AUD_END);
1537     return code;
1538 }
1539
1540 static afs_int32
1541 VolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
1542            struct restoreCookie *cookie)
1543 {
1544     struct volser_trans *tt;
1545     afs_int32 code, tcode;
1546     char caller[MAXKTCNAMELEN];
1547
1548     if (!afsconf_SuperUser(tdir, acid, caller))
1549         return VOLSERBAD_ACCESS;        /*not a super user */
1550     tt = FindTrans(atrans);
1551     if (!tt)
1552         return ENOENT;
1553     if (tt->vflags & VTDeleted) {
1554         Log("1 Volser: VolRestore: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
1555         TRELE(tt);
1556         return ENOENT;
1557     }
1558     if (DoLogging) {
1559         char buffer[16];
1560         Log("%s on %s is executing Restore %" AFS_VOLID_FMT "\n", caller,
1561             callerAddress(acid, buffer), afs_printable_VolumeId_lu(tt->volid));
1562     }
1563     TSetRxCall(tt, acid, "Restore");
1564
1565     DFlushVolume(V_parentId(tt->volume)); /* Ensure dir buffers get dropped */
1566
1567     code = RestoreVolume(acid, tt->volume, (aflags & 1), cookie);       /* last is incrementalp */
1568     FSYNC_VolOp(tt->volid, NULL, FSYNC_VOL_BREAKCBKS, 0l, NULL);
1569     TClearRxCall(tt);
1570     tcode = TRELE(tt);
1571
1572     return (code ? code : tcode);
1573 }
1574
1575 /* end a transaction, returning the transaction's final error code in rcode */
1576 afs_int32
1577 SAFSVolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1578 {
1579     afs_int32 code;
1580
1581     code = VolEndTrans(acid, destTrans, rcode);
1582     osi_auditU(acid, VS_EndTrnEvent, code, AUD_LONG, destTrans, AUD_END);
1583     return code;
1584 }
1585
1586 static afs_int32
1587 VolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1588 {
1589     struct volser_trans *tt;
1590     char caller[MAXKTCNAMELEN];
1591
1592     if (!afsconf_SuperUser(tdir, acid, caller))
1593         return VOLSERBAD_ACCESS;        /*not a super user */
1594     tt = FindTrans(destTrans);
1595     if (!tt) {
1596         return ENOENT;
1597     }
1598     *rcode = tt->returnCode;
1599     DeleteTrans(tt, 1);         /* this does an implicit TRELE */
1600
1601     return 0;
1602 }
1603
1604 afs_int32
1605 SAFSVolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1606 {
1607     afs_int32 code;
1608
1609     code = VolSetForwarding(acid, atid, anewsite);
1610     osi_auditU(acid, VS_SetForwEvent, code, AUD_LONG, atid, AUD_HOST,
1611                htonl(anewsite), AUD_END);
1612     return code;
1613 }
1614
1615 static afs_int32
1616 VolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1617 {
1618     struct volser_trans *tt;
1619     char caller[MAXKTCNAMELEN];
1620     char partName[16];
1621
1622     if (!afsconf_SuperUser(tdir, acid, caller))
1623         return VOLSERBAD_ACCESS;        /*not a super user */
1624     tt = FindTrans(atid);
1625     if (!tt)
1626         return ENOENT;
1627     if (tt->vflags & VTDeleted) {
1628         Log("1 Volser: VolSetForwarding: volume %" AFS_VOLID_FMT " has been deleted \n",
1629             afs_printable_VolumeId_lu(tt->volid));
1630         TRELE(tt);
1631         return ENOENT;
1632     }
1633     TSetRxCall(tt, acid, "SetForwarding");
1634     if (volutil_PartitionName2_r(tt->partition, partName, sizeof(partName)) != 0) {
1635         partName[0] = '\0';
1636     }
1637     FSYNC_VolOp(tt->volid, partName, FSYNC_VOL_MOVE, anewsite, NULL);
1638     TClearRxCall(tt);
1639     if (TRELE(tt))
1640         return VOLSERTRELE_ERROR;
1641
1642     return 0;
1643 }
1644
1645 afs_int32
1646 SAFSVolGetStatus(struct rx_call *acid, afs_int32 atrans,
1647                  struct volser_status *astatus)
1648 {
1649     afs_int32 code;
1650
1651     code = VolGetStatus(acid, atrans, astatus);
1652     osi_auditU(acid, VS_GetStatEvent, code, AUD_LONG, atrans, AUD_END);
1653     return code;
1654 }
1655
1656 static afs_int32
1657 VolGetStatus(struct rx_call *acid, afs_int32 atrans,
1658              struct volser_status *astatus)
1659 {
1660     struct Volume *tv;
1661     struct VolumeDiskData *td;
1662     struct volser_trans *tt;
1663
1664     if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
1665         return VOLSERBAD_ACCESS;
1666
1667     tt = FindTrans(atrans);
1668     if (!tt)
1669         return ENOENT;
1670     if (tt->vflags & VTDeleted) {
1671         Log("1 Volser: VolGetStatus: volume %" AFS_VOLID_FMT " has been deleted \n",
1672             afs_printable_VolumeId_lu(tt->volid));
1673         TRELE(tt);
1674         return ENOENT;
1675     }
1676     TSetRxCall(tt, acid, "GetStatus");
1677     tv = tt->volume;
1678     if (!tv) {
1679         TClearRxCall(tt);
1680         TRELE(tt);
1681         return ENOENT;
1682     }
1683
1684     td = &(V_disk(tv));
1685     astatus->volID = td->id;
1686     astatus->nextUnique = td->uniquifier;
1687     astatus->type = td->type;
1688     astatus->parentID = td->parentId;
1689     astatus->cloneID = td->cloneId;
1690     astatus->backupID = td->backupId;
1691     astatus->restoredFromID = td->restoredFromId;
1692     astatus->maxQuota = td->maxquota;
1693     astatus->minQuota = td->minquota;
1694     astatus->owner = td->owner;
1695     astatus->creationDate = td->creationDate;
1696     astatus->accessDate = td->accessDate;
1697     astatus->updateDate = td->updateDate;
1698     astatus->expirationDate = td->expirationDate;
1699     astatus->backupDate = td->backupDate;
1700     astatus->copyDate = td->copyDate;
1701     TClearRxCall(tt);
1702     if (TRELE(tt))
1703         return VOLSERTRELE_ERROR;
1704
1705     return 0;
1706 }
1707
1708 afs_int32
1709 SAFSVolSetInfo(struct rx_call *acid, afs_int32 atrans,
1710                struct volintInfo *astatus)
1711 {
1712     afs_int32 code;
1713
1714     code = VolSetInfo(acid, atrans, astatus);
1715     osi_auditU(acid, VS_SetInfoEvent, code, AUD_LONG, atrans, AUD_END);
1716     return code;
1717 }
1718
1719 static afs_int32
1720 VolSetInfo(struct rx_call *acid, afs_int32 atrans,
1721                struct volintInfo *astatus)
1722 {
1723     struct Volume *tv;
1724     struct VolumeDiskData *td;
1725     struct volser_trans *tt;
1726     char caller[MAXKTCNAMELEN];
1727     Error error;
1728
1729     if (!afsconf_SuperUser(tdir, acid, caller))
1730         return VOLSERBAD_ACCESS;        /*not a super user */
1731     tt = FindTrans(atrans);
1732     if (!tt)
1733         return ENOENT;
1734     if (tt->vflags & VTDeleted) {
1735         Log("1 Volser: VolSetInfo: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
1736         TRELE(tt);
1737         return ENOENT;
1738     }
1739     TSetRxCall(tt, acid, "SetStatus");
1740     tv = tt->volume;
1741     if (!tv) {
1742         TClearRxCall(tt);
1743         TRELE(tt);
1744         return ENOENT;
1745     }
1746
1747     td = &(V_disk(tv));
1748     /*
1749      * Add more fields as necessary
1750      */
1751     if (astatus->maxquota != -1)
1752         td->maxquota = astatus->maxquota;
1753     if (astatus->dayUse != -1)
1754         td->dayUse = astatus->dayUse;
1755     if (astatus->creationDate != -1)
1756         td->creationDate = astatus->creationDate;
1757     if (astatus->updateDate != -1)
1758         td->updateDate = astatus->updateDate;
1759     if (astatus->spare2 != -1)
1760         td->volUpdateCounter = (unsigned int)astatus->spare2;
1761     VUpdateVolume(&error, tv);
1762     TClearRxCall(tt);
1763     if (TRELE(tt))
1764         return VOLSERTRELE_ERROR;
1765     return 0;
1766 }
1767
1768
1769 afs_int32
1770 SAFSVolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1771 {
1772     afs_int32 code;
1773
1774     code = VolGetName(acid, atrans, aname);
1775     osi_auditU(acid, VS_GetNameEvent, code, AUD_LONG, atrans, AUD_END);
1776     return code;
1777 }
1778
1779 static afs_int32
1780 VolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1781 {
1782     struct Volume *tv;
1783     struct VolumeDiskData *td;
1784     struct volser_trans *tt;
1785     int len;
1786
1787     if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
1788         return VOLSERBAD_ACCESS;
1789
1790     /* We need to at least fill it in */
1791     *aname = malloc(1);
1792     if (!*aname)
1793         return ENOMEM;
1794     tt = FindTrans(atrans);
1795     if (!tt)
1796         return ENOENT;
1797     if (tt->vflags & VTDeleted) {
1798         Log("1 Volser: VolGetName: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
1799         TRELE(tt);
1800         return ENOENT;
1801     }
1802     TSetRxCall(tt, acid, "GetName");
1803     tv = tt->volume;
1804     if (!tv) {
1805         TClearRxCall(tt);
1806         TRELE(tt);
1807         return ENOENT;
1808     }
1809
1810     td = &(V_disk(tv));
1811     len = strlen(td->name) + 1; /* don't forget the null */
1812     if (len >= SIZE) {
1813         TClearRxCall(tt);
1814         TRELE(tt);
1815         return E2BIG;
1816     }
1817     *aname = realloc(*aname, len);
1818     strcpy(*aname, td->name);
1819     TClearRxCall(tt);
1820     if (TRELE(tt))
1821         return VOLSERTRELE_ERROR;
1822
1823     return 0;
1824 }
1825
1826 /*this is a handshake to indicate that the next call will be SAFSVolRestore
1827  * - a noop now !*/
1828 afs_int32
1829 SAFSVolSignalRestore(struct rx_call *acid, char volname[], int volType,
1830                      VolumeId parentId, VolumeId cloneId)
1831 {
1832     return 0;
1833 }
1834
1835
1836 /*return a list of all partitions on the server. The non mounted
1837  *partitions are returned as -1 in the corresponding slot in partIds*/
1838 afs_int32
1839 SAFSVolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1840 {
1841     afs_int32 code;
1842
1843     code = VolListPartitions(acid, partIds);
1844     osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1845     return code;
1846 }
1847
1848 static afs_int32
1849 VolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1850 {
1851     char namehead[9];
1852     int i;
1853
1854     if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
1855         return VOLSERBAD_ACCESS;
1856
1857     strcpy(namehead, "/vicep"); /*7 including null terminator */
1858
1859     /* Just return attached partitions. */
1860     namehead[7] = '\0';
1861     for (i = 0; i < 26; i++) {
1862         namehead[6] = i + 'a';
1863         partIds->partIds[i] = VGetPartition(namehead, 0) ? i : -1;
1864     }
1865
1866     return 0;
1867 }
1868
1869 /*return a list of all partitions on the server. The non mounted
1870  *partitions are returned as -1 in the corresponding slot in partIds*/
1871 afs_int32
1872 SAFSVolXListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1873 {
1874     afs_int32 code;
1875
1876     code = XVolListPartitions(acid, pEntries);
1877     osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1878     return code;
1879 }
1880
1881 static afs_int32
1882 XVolListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1883 {
1884     char namehead[9];
1885     struct partList partList;
1886     struct DiskPartition64 *dp;
1887     int i, j = 0;
1888
1889     if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
1890         return VOLSERBAD_ACCESS;
1891
1892     strcpy(namehead, "/vicep"); /*7 including null terminator */
1893
1894     /* Only report attached partitions */
1895     for (i = 0; i < VOLMAXPARTS; i++) {
1896 #ifdef AFS_DEMAND_ATTACH_FS
1897         dp = VGetPartitionById(i, 0);
1898 #else
1899         if (i < 26) {
1900             namehead[6] = i + 'a';
1901             namehead[7] = '\0';
1902         } else {
1903             int k;
1904
1905             k = i - 26;
1906             namehead[6] = 'a' + (k / 26);
1907             namehead[7] = 'a' + (k % 26);
1908             namehead[8] = '\0';
1909         }
1910         dp = VGetPartition(namehead, 0);
1911 #endif
1912         if (dp)
1913             partList.partId[j++] = i;
1914     }
1915     if (j > 0) {
1916         pEntries->partEntries_val = malloc(j * sizeof(int));
1917         if (!pEntries->partEntries_val)
1918             return ENOMEM;
1919         memcpy(pEntries->partEntries_val, partList.partId,
1920                 j * sizeof(int));
1921         pEntries->partEntries_len = j;
1922     } else {
1923         pEntries->partEntries_val = NULL;
1924         pEntries->partEntries_len = 0;
1925     }
1926     return 0;
1927
1928 }
1929
1930 /*
1931  * Scan a directory for possible volume headers.
1932  * in: DIR *dirp                -- a directory handle from opendir()
1933  * out: char *volname           -- set to name of directory entry
1934  *      afs_uint32 *volid       -- set to volume ID parsed from name
1935  * returns:
1936  *  true if volname and volid have been set to valid values
1937  *  false if we got to the end of the directory
1938  */
1939 static int
1940 GetNextVol(DIR *dirp, char *volname, VolumeId *volid)
1941 {
1942     struct dirent *dp;
1943
1944     while ((dp = readdir(dirp)) != NULL) {
1945         /* could be optimized on platforms with dp->d_namlen */
1946         if (dp->d_name[0] == 'V' && strlen(dp->d_name) == VHDRNAMELEN
1947                 && strcmp(&(dp->d_name[VFORMATDIGITS + 1]), VHDREXT) == 0) {
1948             *volid = VolumeNumber(dp->d_name);
1949             strcpy(volname, dp->d_name);
1950             return 1;
1951         }
1952     }
1953     return 0;
1954 }
1955
1956 /**
1957  * volint vol info structure type.
1958  */
1959 typedef enum {
1960     VOLINT_INFO_TYPE_BASE,  /**< volintInfo type */
1961     VOLINT_INFO_TYPE_EXT    /**< volintXInfo type */
1962 } volint_info_type_t;
1963
1964 /**
1965  * handle to various on-wire vol info types.
1966  */
1967 typedef struct {
1968     volint_info_type_t volinfo_type;
1969     union {
1970         void * opaque;
1971         volintInfo * base;
1972         volintXInfo * ext;
1973     } volinfo_ptr;
1974 } volint_info_handle_t;
1975
1976 /**
1977  * store value to a field at the appropriate location in on-wire structure.
1978  */
1979 #define VOLINT_INFO_STORE(handle, name, val) \
1980     do { \
1981         if ((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) { \
1982             (handle)->volinfo_ptr.base->name = (val); \
1983         } else { \
1984             (handle)->volinfo_ptr.ext->name = (val); \
1985         } \
1986     } while(0)
1987
1988 /**
1989  * get pointer to appropriate offset of field in on-wire structure.
1990  */
1991 #define VOLINT_INFO_PTR(handle, name) \
1992     (((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) ? \
1993      &((handle)->volinfo_ptr.base->name) : \
1994      &((handle)->volinfo_ptr.ext->name))
1995
1996 /**
1997  * fill in appropriate type of on-wire volume metadata structure.
1998  *
1999  * @param vp      pointer to volume object
2000  * @param handle  pointer to wire format handle object
2001  *
2002  * @pre vp object must contain header & pending_vol_op structurs (populate if from RPC)
2003  * @pre handle object must have a valid pointer and enumeration value
2004  *
2005  * @note passing a NULL value for vp means that the fileserver doesn't
2006  *       know about this particular volume, thus implying it is offline.
2007  *
2008  * @return operation status
2009  *   @retval 0 success
2010  *   @retval 1 failure
2011  */
2012 static int
2013 FillVolInfo(Volume * vp, volint_info_handle_t * handle)
2014 {
2015     unsigned int numStatBytes, now;
2016     struct VolumeDiskData *hdr = &(V_disk(vp));
2017
2018     /*read in the relevant info */
2019     strcpy((char *)VOLINT_INFO_PTR(handle, name), hdr->name);
2020     VOLINT_INFO_STORE(handle, status, VOK);     /*its ok */
2021     VOLINT_INFO_STORE(handle, volid, hdr->id);
2022     VOLINT_INFO_STORE(handle, type, hdr->type); /*if ro volume */
2023     VOLINT_INFO_STORE(handle, cloneID, hdr->cloneId);   /*if rw volume */
2024     VOLINT_INFO_STORE(handle, backupID, hdr->backupId);
2025     VOLINT_INFO_STORE(handle, parentID, hdr->parentId);
2026     VOLINT_INFO_STORE(handle, copyDate, hdr->copyDate);
2027     VOLINT_INFO_STORE(handle, size, hdr->diskused);
2028     VOLINT_INFO_STORE(handle, maxquota, hdr->maxquota);
2029     VOLINT_INFO_STORE(handle, filecount, hdr->filecount);
2030     now = FT_ApproxTime();
2031     if ((now - hdr->dayUseDate) > OneDay) {
2032         VOLINT_INFO_STORE(handle, dayUse, 0);
2033     } else {
2034         VOLINT_INFO_STORE(handle, dayUse, hdr->dayUse);
2035     }
2036     VOLINT_INFO_STORE(handle, creationDate, hdr->creationDate);
2037     VOLINT_INFO_STORE(handle, accessDate, hdr->accessDate);
2038     VOLINT_INFO_STORE(handle, updateDate, hdr->updateDate);
2039     VOLINT_INFO_STORE(handle, backupDate, hdr->backupDate);
2040
2041 #ifdef AFS_DEMAND_ATTACH_FS
2042     /*
2043      * for DAFS, we "lie" about volume state --
2044      * instead of returning the raw state from the disk header,
2045      * we compute state based upon the fileserver's internal
2046      * in-core state enumeration value reported to us via fssync,
2047      * along with the blessed and inService flags from the header.
2048      *   -- tkeiser 11/27/2007
2049      */
2050
2051     /* Conditions that offline status is based on:
2052                 volume is unattached state
2053                 volume state is in (one of several error states)
2054                 volume not in service
2055                 volume is not marked as blessed (not on hold)
2056                 volume in salvage req. state
2057                 volume needsSalvaged
2058                 next op would set volume offline
2059                 next op would not leave volume online (based on several conditions)
2060     */
2061     if (!vp ||
2062         (V_attachState(vp) == VOL_STATE_UNATTACHED) ||
2063         VIsErrorState(V_attachState(vp)) ||
2064         !hdr->inService ||
2065         !hdr->blessed ||
2066         (V_attachState(vp) == VOL_STATE_SALVSYNC_REQ) ||
2067         hdr->needsSalvaged ||
2068         (vp->pending_vol_op &&
2069                 (vp->pending_vol_op->com.command == FSYNC_VOL_OFF ||
2070                 !VVolOpLeaveOnline_r(vp, vp->pending_vol_op) )
2071         )
2072         ) {
2073         VOLINT_INFO_STORE(handle, inUse, 0);
2074     } else {
2075         VOLINT_INFO_STORE(handle, inUse, 1);
2076     }
2077 #else
2078     /* offline status based on program type, where != fileServer enum (1) is offline */
2079     if (hdr->inUse == fileServer) {
2080         VOLINT_INFO_STORE(handle, inUse, 1);
2081     } else {
2082         VOLINT_INFO_STORE(handle, inUse, 0);
2083     }
2084 #endif
2085
2086
2087     switch(handle->volinfo_type) {
2088         /* NOTE: VOLINT_INFO_STORE not used in this section because values are specific to one volinfo_type */
2089     case VOLINT_INFO_TYPE_BASE:
2090
2091 #ifdef AFS_DEMAND_ATTACH_FS
2092         /* see comment above where we set inUse bit */
2093         if (hdr->needsSalvaged ||
2094             (vp && VIsErrorState(V_attachState(vp)))) {
2095             handle->volinfo_ptr.base->needsSalvaged = 1;
2096         } else {
2097             handle->volinfo_ptr.base->needsSalvaged = 0;
2098         }
2099 #else
2100         handle->volinfo_ptr.base->needsSalvaged = hdr->needsSalvaged;
2101 #endif
2102         handle->volinfo_ptr.base->destroyMe = hdr->destroyMe;
2103         handle->volinfo_ptr.base->spare0 = hdr->minquota;
2104         handle->volinfo_ptr.base->spare1 =
2105             (long)hdr->weekUse[0] +
2106             (long)hdr->weekUse[1] +
2107             (long)hdr->weekUse[2] +
2108             (long)hdr->weekUse[3] +
2109             (long)hdr->weekUse[4] +
2110             (long)hdr->weekUse[5] +
2111             (long)hdr->weekUse[6];
2112         handle->volinfo_ptr.base->flags = 0;
2113         handle->volinfo_ptr.base->spare2 = hdr->volUpdateCounter;
2114         handle->volinfo_ptr.base->spare3 = 0;
2115         break;
2116
2117
2118     case VOLINT_INFO_TYPE_EXT:
2119         numStatBytes =
2120             4 * ((2 * VOLINT_STATS_NUM_RWINFO_FIELDS) +
2121                  (4 * VOLINT_STATS_NUM_TIME_FIELDS));
2122
2123         /*
2124          * Copy out the stat fields in a single operation.
2125          */
2126         if ((now - hdr->dayUseDate) > OneDay) {
2127             memset(&(handle->volinfo_ptr.ext->stat_reads[0]),
2128                    0, numStatBytes);
2129         } else {
2130             memcpy((char *)&(handle->volinfo_ptr.ext->stat_reads[0]),
2131                    (char *)&(hdr->stat_reads[0]),
2132                    numStatBytes);
2133         }
2134         break;
2135     }
2136
2137     return 0;
2138 }
2139
2140 #ifdef AFS_DEMAND_ATTACH_FS
2141
2142 /**
2143  * get struct Volume out of the fileserver.
2144  *
2145  * @param[in] volumeId  volumeId for which we want state information
2146  * @param[in] pname     partition name string
2147  * @param[inout] vp     pointer to pointer to Volume object which
2148  *                      will be populated (see note)
2149  *
2150  * @return operation status
2151  *   @retval 0         success
2152  *   @retval non-zero  failure
2153  *
2154  * @note if FSYNC_VolOp fails in certain ways, *vp will be set to NULL
2155  *
2156  * @internal
2157  */
2158 static int
2159 GetVolObject(VolumeId volumeId, char * pname, Volume ** vp)
2160 {
2161     int code;
2162     SYNC_response res;
2163
2164     res.hdr.response_len = sizeof(res.hdr);
2165     res.payload.buf = *vp;
2166     res.payload.len = sizeof(Volume);
2167
2168     code = FSYNC_VolOp(volumeId,
2169                        pname,
2170                        FSYNC_VOL_QUERY,
2171                        0,
2172                        &res);
2173
2174     if (code != SYNC_OK) {
2175         switch (res.hdr.reason) {
2176         case FSYNC_WRONG_PART:
2177         case FSYNC_UNKNOWN_VOLID:
2178             *vp = NULL;
2179             code = SYNC_OK;
2180             break;
2181         }
2182     }
2183
2184     return code;
2185 }
2186
2187 #endif
2188
2189 /**
2190  * mode of volume list operation.
2191  */
2192 typedef enum {
2193     VOL_INFO_LIST_SINGLE,   /**< performing a single volume list op */
2194     VOL_INFO_LIST_MULTIPLE  /**< performing a multi-volume list op */
2195 } vol_info_list_mode_t;
2196
2197 /**
2198  * abstract interface to populate wire-format volume metadata structures.
2199  *
2200  * @param[in]  partId    partition id
2201  * @param[in]  volumeId  volume id
2202  * @param[in]  pname     partition name
2203  * @param[in]  volname   volume file name
2204  * @param[in]  handle    handle to on-wire volume metadata object
2205  * @param[in]  mode      listing mode
2206  *
2207  * @return operation status
2208  *   @retval 0      success
2209  *   @retval -2     DESTROY_ME flag is set
2210  *   @retval -1     general failure; some data filled in
2211  *   @retval -3     couldn't create vtrans; some data filled in
2212  */
2213 static int
2214 GetVolInfo(afs_uint32 partId,
2215            VolumeId volumeId,
2216            char * pname,
2217            char * volname,
2218            volint_info_handle_t * handle,
2219            vol_info_list_mode_t mode)
2220 {
2221     int code = -1;
2222     Error error;
2223     struct volser_trans *ttc = NULL;
2224     struct Volume *fill_tv, *tv = NULL;
2225 #ifdef AFS_DEMAND_ATTACH_FS
2226     struct Volume fs_tv_buf, *fs_tv = &fs_tv_buf; /* Create a structure, and a pointer to that structure */
2227     SYNC_PROTO_BUF_DECL(fs_res_buf); /* Buffer for the pending_vol_op */
2228     SYNC_response fs_res; /* Response handle for the pending_vol_op */
2229     FSSYNC_VolOp_info pending_vol_op_res; /* Pending vol ops to full in volume */
2230
2231     /* Set up response handle for pending_vol_op */
2232     fs_res.hdr.response_len = sizeof(fs_res.hdr);
2233     fs_res.payload.buf = fs_res_buf;
2234     fs_res.payload.len = SYNC_PROTO_MAX_LEN;
2235 #endif
2236
2237     ttc = NewTrans(volumeId, partId);
2238     if (!ttc) {
2239         code = -3;
2240         VOLINT_INFO_STORE(handle, status, VBUSY);
2241         VOLINT_INFO_STORE(handle, volid, volumeId);
2242         goto drop;
2243     }
2244
2245     /* Get volume from volserver */
2246     if (mode == VOL_INFO_LIST_MULTIPLE)
2247         tv = VAttachVolumeByName(&error, pname, volname, V_PEEK);
2248     else {
2249 #ifdef AFS_DEMAND_ATTACH_FS
2250         int mode = V_PEEK;
2251 #else
2252         int mode = V_READONLY;   /* informs the fileserver to update the volume headers. */
2253 #endif
2254         tv = VAttachVolumeByName_retry(&error, pname, volname, mode);
2255     }
2256
2257     if (error) {
2258         Log("1 Volser: GetVolInfo: Could not attach volume %" AFS_VOLID_FMT " (%s:%s) error=%d\n",
2259             afs_printable_VolumeId_lu(volumeId), pname, volname, error);
2260         goto drop;
2261     }
2262
2263     /*
2264      * please note that destroyMe and needsSalvaged checks used to be ordered
2265      * in the opposite manner for ListVolumes and XListVolumes.  I think it's
2266      * more correct to check destroyMe before needsSalvaged.
2267      *   -- tkeiser 11/28/2007
2268      */
2269
2270     if (V_destroyMe(tv) == DESTROY_ME) {
2271         switch (mode) {
2272         case VOL_INFO_LIST_MULTIPLE:
2273             code = -2;
2274             goto drop;
2275
2276         case VOL_INFO_LIST_SINGLE:
2277             Log("1 Volser: GetVolInfo: Volume %" AFS_VOLID_FMT " (%s:%s) will be destroyed on next salvage\n",
2278                 afs_printable_VolumeId_lu(volumeId), pname, volname);
2279
2280         default:
2281             goto drop;
2282         }
2283     }
2284
2285     if (V_needsSalvaged(tv)) {
2286         /*this volume will be salvaged */
2287         Log("1 Volser: GetVolInfo: Volume %" AFS_VOLID_FMT " (%s:%s) needs to be salvaged\n",
2288             afs_printable_VolumeId_lu(volumeId), pname, volname);
2289     }
2290
2291 #ifdef AFS_DEMAND_ATTACH_FS
2292     /* If using DAFS, get volume from fsserver */
2293     if (GetVolObject(volumeId, pname, &fs_tv) != SYNC_OK || fs_tv == NULL) {
2294
2295         goto drop;
2296     }
2297
2298     /* fs_tv is a shallow copy, must populate certain structures before passing along */
2299     if (FSYNC_VolOp(volumeId, pname, FSYNC_VOL_QUERY_VOP, 0, &fs_res) == SYNC_OK) {
2300         /* If we if the pending vol op */
2301         memcpy(&pending_vol_op_res, fs_res.payload.buf, sizeof(FSSYNC_VolOp_info));
2302         fs_tv->pending_vol_op=&pending_vol_op_res;
2303     } else {
2304         fs_tv->pending_vol_op=NULL;
2305     }
2306
2307     /* populate the header from the volserver copy */
2308     fs_tv->header=tv->header;
2309
2310     /* When using DAFS, use the fs volume info, populated with required structures */
2311     fill_tv = fs_tv;
2312 #else
2313     /* When not using DAFS, just use the local volume info */
2314     fill_tv = tv;
2315 #endif
2316
2317     /* ok, we have all the data we need; fill in the on-wire struct */
2318     code = FillVolInfo(fill_tv, handle);
2319
2320  drop:
2321     if (code == -1) {
2322         VOLINT_INFO_STORE(handle, status, 0);
2323         strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2324         VOLINT_INFO_STORE(handle, volid, volumeId);
2325     }
2326     if (tv) {
2327         VDetachVolume(&error, tv);
2328         tv = NULL;
2329         if (error) {
2330             VOLINT_INFO_STORE(handle, status, 0);
2331             strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2332             Log("1 Volser: GetVolInfo: Could not detach volume %" AFS_VOLID_FMT " (%s:%s)\n",
2333                 afs_printable_VolumeId_lu(volumeId), pname, volname);
2334         }
2335     }
2336     if (ttc) {
2337         DeleteTrans(ttc, 1);
2338         ttc = NULL;
2339     }
2340     return code;
2341 }
2342
2343
2344 /*return the header information about the <volid> */
2345 afs_int32
2346 SAFSVolListOneVolume(struct rx_call *acid, afs_int32 partid,
2347                      VolumeId volumeId, volEntries *volumeInfo)
2348 {
2349     afs_int32 code;
2350
2351     code = VolListOneVolume(acid, partid, volumeId, volumeInfo);
2352     osi_auditU(acid, VS_Lst1VolEvent, code, AUD_LONG, volumeId, AUD_END);
2353     return code;
2354 }
2355
2356 static afs_int32
2357 VolListOneVolume(struct rx_call *acid, afs_int32 partid,
2358                  VolumeId volumeId, volEntries *volumeInfo)
2359 {
2360     struct DiskPartition64 *partP;
2361     char pname[9], volname[20];
2362     DIR *dirp;
2363     VolumeId volid;
2364     int found = 0;
2365     volint_info_handle_t handle;
2366
2367     if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
2368         return VOLSERBAD_ACCESS;
2369
2370     volumeInfo->volEntries_val = calloc(1, sizeof(volintInfo));
2371     if (!volumeInfo->volEntries_val)
2372         return ENOMEM;
2373
2374     volumeInfo->volEntries_len = 1;
2375     if (GetPartName(partid, pname))
2376         return VOLSERILLEGAL_PARTITION;
2377     if (!(partP = VGetPartition(pname, 0)))
2378         return VOLSERILLEGAL_PARTITION;
2379     dirp = opendir(VPartitionPath(partP));
2380     if (dirp == NULL)
2381         return VOLSERILLEGAL_PARTITION;
2382
2383     while (GetNextVol(dirp, volname, &volid)) {
2384         if (volid == volumeId) {        /*copy other things too */
2385             found = 1;
2386             break;
2387         }
2388     }
2389
2390     if (found) {
2391 #ifndef AFS_PTHREAD_ENV
2392         IOMGR_Poll();   /*make sure that the client does not time out */
2393 #endif
2394
2395         handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2396         handle.volinfo_ptr.base = volumeInfo->volEntries_val;
2397
2398         /* The return code from GetVolInfo is ignored; there is no error from
2399          * it that results in the whole call being aborted. Any volume
2400          * attachment failures are reported in 'status' field in the
2401          * volumeInfo payload. */
2402         GetVolInfo(partid,
2403                    volid,
2404                    pname,
2405                    volname,
2406                    &handle,
2407                    VOL_INFO_LIST_SINGLE);
2408     }
2409
2410     closedir(dirp);
2411     return (found) ? 0 : ENODEV;
2412 }
2413
2414 /*------------------------------------------------------------------------
2415  * EXPORTED SAFSVolXListOneVolume
2416  *
2417  * Description:
2418  *      Returns extended info on volume a_volID on partition a_partID.
2419  *
2420  * Arguments:
2421  *      a_rxCidP       : Pointer to the Rx call we're performing.
2422  *      a_partID       : Partition for which we want the extended list.
2423  *      a_volID        : Volume ID we wish to know about.
2424  *      a_volumeXInfoP : Ptr to the extended info blob.
2425  *
2426  * Returns:
2427  *      0                       Successful operation
2428  *      VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2429  *
2430  * Environment:
2431  *      Nothing interesting.
2432  *
2433  * Side Effects:
2434  *      As advertised.
2435  *------------------------------------------------------------------------*/
2436
2437 afs_int32
2438 SAFSVolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2439                       VolumeId a_volID, volXEntries *a_volumeXInfoP)
2440 {
2441     afs_int32 code;
2442
2443     code = VolXListOneVolume(a_rxCidP, a_partID, a_volID, a_volumeXInfoP);
2444     osi_auditU(a_rxCidP, VS_XLst1VlEvent, code, AUD_LONG, a_volID, AUD_END);
2445     return code;
2446 }
2447
2448 static afs_int32
2449 VolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2450                   VolumeId a_volID, volXEntries *a_volumeXInfoP)
2451 {                               /*SAFSVolXListOneVolume */
2452
2453     struct DiskPartition64 *partP;      /*Ptr to partition */
2454     char pname[9], volname[20]; /*Partition, volume names */
2455     DIR *dirp;                  /*Partition directory ptr */
2456     VolumeId currVolID;         /*Current volume ID */
2457     int found = 0;              /*Did we find the volume we need? */
2458     volint_info_handle_t handle;
2459
2460     if (!afsconf_CheckRestrictedQuery(tdir, a_rxCidP, restrictedQueryLevel))
2461         return VOLSERBAD_ACCESS;
2462
2463     /*
2464      * Set up our pointers for action, marking our structure to hold exactly
2465      * one entry.  Also, assume we'll fail in our quest.
2466      */
2467     a_volumeXInfoP->volXEntries_val = calloc(1, sizeof(volintXInfo));
2468     if (!a_volumeXInfoP->volXEntries_val)
2469         return ENOMEM;
2470
2471     a_volumeXInfoP->volXEntries_len = 1;
2472
2473     /*
2474      * If the partition name we've been given is bad, bogue out.
2475      */
2476     if (GetPartName(a_partID, pname))
2477         return (VOLSERILLEGAL_PARTITION);
2478
2479     /*
2480      * Open the directory representing the given AFS parttion.  If we can't
2481      * do that, we lose.
2482      */
2483     if (!(partP = VGetPartition(pname, 0)))
2484         return VOLSERILLEGAL_PARTITION;
2485     dirp = opendir(VPartitionPath(partP));
2486     if (dirp == NULL)
2487         return (VOLSERILLEGAL_PARTITION);
2488
2489
2490     /*
2491      * Sweep through the partition directory, looking for the desired entry.
2492      * First, of course, figure out how many stat bytes to copy out of each
2493      * volume.
2494      */
2495     while (GetNextVol(dirp, volname, &currVolID)) {
2496         if (currVolID == a_volID) {
2497             /*
2498              * We found the volume entry we're interested.  Pull out the
2499              * extended information, remembering to poll (so that the client
2500              * doesn't time out) and to set up a transaction on the volume.
2501              */
2502             found = 1;
2503             break;
2504         }                       /*Found desired volume */
2505     }
2506
2507     if (found) {
2508 #ifndef AFS_PTHREAD_ENV
2509         IOMGR_Poll();
2510 #endif
2511
2512         handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2513         handle.volinfo_ptr.ext = a_volumeXInfoP->volXEntries_val;
2514
2515         /* The return code from GetVolInfo is ignored; there is no error from
2516          * it that results in the whole call being aborted. Any volume
2517          * attachment failures are reported in 'status' field in the
2518          * volumeInfo payload. */
2519         GetVolInfo(a_partID,
2520                    a_volID,
2521                    pname,
2522                    volname,
2523                    &handle,
2524                    VOL_INFO_LIST_SINGLE);
2525     }
2526
2527     /*
2528      * Clean up before going to dinner: close the partition directory,
2529      * return the proper value.
2530      */
2531     closedir(dirp);
2532     return (found) ? 0 : ENODEV;
2533 }                               /*SAFSVolXListOneVolume */
2534
2535 /*returns all the volumes on partition partid. If flags = 1 then all the
2536 * relevant info about the volumes  is also returned */
2537 afs_int32
2538 SAFSVolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2539                    volEntries *volumeInfo)
2540 {
2541     afs_int32 code;
2542
2543     code = VolListVolumes(acid, partid, flags, volumeInfo);
2544     osi_auditU(acid, VS_ListVolEvent, code, AUD_END);
2545     return code;
2546 }
2547
2548 static afs_int32
2549 VolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2550                    volEntries *volumeInfo)
2551 {
2552     volintInfo *pntr;
2553     struct DiskPartition64 *partP;
2554     afs_int32 allocSize = 1000; /*to be changed to a larger figure */
2555     char pname[9], volname[20];
2556     DIR *dirp;
2557     VolumeId volid;
2558     int code;
2559     volint_info_handle_t handle;
2560
2561     if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
2562         return VOLSERBAD_ACCESS;
2563
2564     volumeInfo->volEntries_val = calloc(allocSize, sizeof(volintInfo));
2565     if (!volumeInfo->volEntries_val)
2566         return ENOMEM;
2567
2568     pntr = volumeInfo->volEntries_val;
2569     volumeInfo->volEntries_len = 0;
2570     if (GetPartName(partid, pname))
2571         return VOLSERILLEGAL_PARTITION;
2572     if (!(partP = VGetPartition(pname, 0)))
2573         return VOLSERILLEGAL_PARTITION;
2574     dirp = opendir(VPartitionPath(partP));
2575     if (dirp == NULL)
2576         return VOLSERILLEGAL_PARTITION;
2577
2578     while (GetNextVol(dirp, volname, &volid)) {
2579         if (flags) {            /*copy other things too */
2580 #ifndef AFS_PTHREAD_ENV
2581             IOMGR_Poll();       /*make sure that the client does not time out */
2582 #endif
2583
2584             handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2585             handle.volinfo_ptr.base = pntr;
2586
2587
2588             code = GetVolInfo(partid,
2589                               volid,
2590                               pname,
2591                               volname,
2592                               &handle,
2593                               VOL_INFO_LIST_MULTIPLE);
2594             if (code == -2)     /* DESTROY_ME flag set */
2595                 continue;
2596         } else {
2597             pntr->volid = volid;
2598             /*just volids are needed */
2599         }
2600
2601         pntr++;
2602         volumeInfo->volEntries_len += 1;
2603         if ((allocSize - volumeInfo->volEntries_len) < 5) {
2604             /*running out of space, allocate more space */
2605             allocSize = (allocSize * 3) / 2;
2606             pntr = realloc(volumeInfo->volEntries_val,
2607                            allocSize * sizeof(volintInfo));
2608             if (pntr == NULL) {
2609                 closedir(dirp);
2610                 return VOLSERNO_MEMORY;
2611             }
2612             volumeInfo->volEntries_val = pntr;  /* point to new block */
2613             /* set pntr to the right position */
2614             pntr = volumeInfo->volEntries_val + volumeInfo->volEntries_len;
2615         }
2616     }
2617
2618     closedir(dirp);
2619     return 0;
2620 }
2621
2622 /*------------------------------------------------------------------------
2623  * EXPORTED SAFSVolXListVolumes
2624  *
2625  * Description:
2626  *      Returns all the volumes on partition a_partID.  If a_flags
2627  *      is set to 1, then all the relevant extended volume information
2628  *      is also returned.
2629  *
2630  * Arguments:
2631  *      a_rxCidP       : Pointer to the Rx call we're performing.
2632  *      a_partID       : Partition for which we want the extended list.
2633  *      a_flags        : Various flags.
2634  *      a_volumeXInfoP : Ptr to the extended info blob.
2635  *
2636  * Returns:
2637  *      0                       Successful operation
2638  *      VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2639  *      VOLSERNO_MEMORY         if we ran out of memory allocating
2640  *                              our return blob
2641  *
2642  * Environment:
2643  *      Nothing interesting.
2644  *
2645  * Side Effects:
2646  *      As advertised.
2647  *------------------------------------------------------------------------*/
2648
2649 afs_int32
2650 SAFSVolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2651                     afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2652 {
2653     afs_int32 code;
2654
2655     code = VolXListVolumes(a_rxCidP, a_partID, a_flags, a_volumeXInfoP);
2656     osi_auditU(a_rxCidP, VS_XLstVolEvent, code, AUD_END);
2657     return code;
2658 }
2659
2660 static afs_int32
2661 VolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2662                     afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2663 {                               /*SAFSVolXListVolumes */
2664
2665     volintXInfo *xInfoP;        /*Ptr to the extended vol info */
2666     struct DiskPartition64 *partP;      /*Ptr to partition */
2667     afs_int32 allocSize = 1000; /*To be changed to a larger figure */
2668     char pname[9], volname[20]; /*Partition, volume names */
2669     DIR *dirp;                  /*Partition directory ptr */
2670     VolumeId volid;             /*Current volume ID */
2671     int code;
2672     volint_info_handle_t handle;
2673
2674     if (!afsconf_CheckRestrictedQuery(tdir, a_rxCidP, restrictedQueryLevel))
2675         return VOLSERBAD_ACCESS;
2676
2677     /*
2678      * Allocate a large array of extended volume info structures, then
2679      * set it up for action.
2680      */
2681     a_volumeXInfoP->volXEntries_val = calloc(allocSize, sizeof(volintXInfo));
2682     if (!a_volumeXInfoP->volXEntries_val)
2683         return ENOMEM;
2684
2685     xInfoP = a_volumeXInfoP->volXEntries_val;
2686     a_volumeXInfoP->volXEntries_len = 0;
2687
2688     /*
2689      * If the partition name we've been given is bad, bogue out.
2690      */
2691     if (GetPartName(a_partID, pname))
2692         return (VOLSERILLEGAL_PARTITION);
2693
2694     /*
2695      * Open the directory representing the given AFS parttion.  If we can't
2696      * do that, we lose.
2697      */
2698     if (!(partP = VGetPartition(pname, 0)))
2699         return VOLSERILLEGAL_PARTITION;
2700     dirp = opendir(VPartitionPath(partP));
2701     if (dirp == NULL)
2702         return (VOLSERILLEGAL_PARTITION);
2703     while (GetNextVol(dirp, volname, &volid)) {
2704         if (a_flags) {
2705             /*
2706              * Full info about the volume desired.  Poll to make sure the
2707              * client doesn't time out, then start up a new transaction.
2708              */
2709 #ifndef AFS_PTHREAD_ENV
2710             IOMGR_Poll();
2711 #endif
2712
2713             handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2714             handle.volinfo_ptr.ext = xInfoP;
2715
2716             code = GetVolInfo(a_partID,
2717                               volid,
2718                               pname,
2719                               volname,
2720                               &handle,
2721                               VOL_INFO_LIST_MULTIPLE);
2722             if (code == -2)     /* DESTROY_ME flag set */
2723                 continue;
2724         } else {
2725             /*
2726              * Just volume IDs are needed.
2727              */
2728             xInfoP->volid = volid;
2729         }
2730
2731         /*
2732          * Bump the pointer in the data area we're building, along with
2733          * the count of the number of entries it contains.
2734          */
2735         xInfoP++;
2736         (a_volumeXInfoP->volXEntries_len)++;
2737         if ((allocSize - a_volumeXInfoP->volXEntries_len) < 5) {
2738             /*
2739              * We're running out of space in the area we've built.  Grow it.
2740              */
2741             allocSize = (allocSize * 3) / 2;
2742             xInfoP = (volintXInfo *)
2743                 realloc((char *)a_volumeXInfoP->volXEntries_val,
2744                         (allocSize * sizeof(volintXInfo)));
2745             if (xInfoP == NULL) {
2746                 /*
2747                  * Bummer, no memory. Bag it, tell our caller what went wrong.
2748                  */
2749                 closedir(dirp);
2750                 return (VOLSERNO_MEMORY);
2751             }
2752
2753             /*
2754              * Memory reallocation worked.  Correct our pointers so they
2755              * now point to the new block and the current open position within
2756              * the new block.
2757              */
2758             a_volumeXInfoP->volXEntries_val = xInfoP;
2759             xInfoP =
2760                 a_volumeXInfoP->volXEntries_val +
2761                 a_volumeXInfoP->volXEntries_len;
2762         }
2763     }
2764
2765     /*
2766      * We've examined all entries in the partition directory.  Close it,
2767      * delete our transaction (if any), and go home happy.
2768      */
2769     closedir(dirp);
2770     return (0);
2771
2772 }                               /*SAFSVolXListVolumes */
2773
2774 /*this call is used to monitor the status of volser for debugging purposes.
2775  *information about all the active transactions is returned in transInfo*/
2776 afs_int32
2777 SAFSVolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2778 {
2779     afs_int32 code;
2780
2781     code = VolMonitor(acid, transInfo);
2782     osi_auditU(acid, VS_MonitorEvent, code, AUD_END);
2783     return code;
2784 }
2785
2786 static afs_int32
2787 VolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2788 {
2789     transDebugInfo *pntr;
2790     afs_int32 allocSize = 50;
2791     struct volser_trans *tt, *nt, *allTrans;
2792
2793     if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
2794         return VOLSERBAD_ACCESS;
2795
2796     transInfo->transDebugEntries_val =
2797         malloc(allocSize * sizeof(transDebugInfo));
2798     if (!transInfo->transDebugEntries_val)
2799         return ENOMEM;
2800     pntr = transInfo->transDebugEntries_val;
2801     transInfo->transDebugEntries_len = 0;
2802
2803     VTRANS_LOCK;
2804     allTrans = TransList();
2805     if (allTrans == (struct volser_trans *)0)
2806         goto done;              /*no active transactions */
2807     for (tt = allTrans; tt; tt = nt) {  /*copy relevant info into pntr */
2808         nt = tt->next;
2809         VTRANS_OBJ_LOCK(tt);
2810         pntr->tid = tt->tid;
2811         pntr->time = tt->time;
2812         pntr->creationTime = tt->creationTime;
2813         pntr->returnCode = tt->returnCode;
2814         pntr->volid = tt->volid;
2815         pntr->partition = tt->partition;
2816         pntr->iflags = tt->iflags;
2817         pntr->vflags = tt->vflags;
2818         pntr->tflags = tt->tflags;
2819         strcpy(pntr->lastProcName, tt->lastProcName);
2820         pntr->callValid = 0;
2821         if (tt->rxCallPtr) {    /*record call related info */
2822             pntr->callValid = 1;
2823 #if 0
2824             pntr->readNext = tt->rxCallPtr->rnext;
2825             pntr->transmitNext = tt->rxCallPtr->tnext;
2826             pntr->lastSendTime = tt->rxCallPtr->lastSendTime;
2827             pntr->lastReceiveTime = tt->rxCallPtr->lastReceiveTime;
2828 #endif
2829         }
2830         VTRANS_OBJ_UNLOCK(tt);
2831         pntr++;
2832         transInfo->transDebugEntries_len += 1;
2833         if ((allocSize - transInfo->transDebugEntries_len) < 5) {       /*alloc some more space */
2834             allocSize = (allocSize * 3) / 2;
2835             pntr = realloc(transInfo->transDebugEntries_val,
2836                            allocSize * sizeof(transDebugInfo));
2837             transInfo->transDebugEntries_val = pntr;
2838             pntr =
2839                 transInfo->transDebugEntries_val +
2840                 transInfo->transDebugEntries_len;
2841             /*set pntr to right position */
2842         }
2843
2844     }
2845 done:
2846     VTRANS_UNLOCK;
2847
2848     return 0;
2849 }
2850
2851 afs_int32
2852 SAFSVolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2853                    afs_int32 type, afs_uint32 pId, VolumeId cloneId,
2854                    VolumeId backupId)
2855 {
2856     afs_int32 code;
2857
2858     code = VolSetIdsTypes(acid, atid, name, type, pId, cloneId, backupId);
2859     osi_auditU(acid, VS_SetIdTyEvent, code, AUD_LONG, atid, AUD_STR, name,
2860                AUD_LONG, type, AUD_LONG, pId, AUD_LONG, cloneId, AUD_LONG,
2861                backupId, AUD_END);
2862     return code;
2863 }
2864
2865 static afs_int32
2866 VolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2867                afs_int32 type, VolumeId pId, VolumeId cloneId,
2868                VolumeId backupId)
2869 {
2870     struct Volume *tv;
2871     Error error = 0;
2872     struct volser_trans *tt;
2873     char caller[MAXKTCNAMELEN];
2874
2875     if (strlen(name) > 31)
2876         return VOLSERBADNAME;
2877     if (!afsconf_SuperUser(tdir, acid, caller))
2878         return VOLSERBAD_ACCESS;        /*not a super user */
2879     /* find the trans */
2880     tt = FindTrans(atid);
2881     if (!tt)
2882         return ENOENT;
2883     if (tt->vflags & VTDeleted) {
2884         Log("1 Volser: VolSetIds: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
2885         TRELE(tt);
2886         return ENOENT;
2887     }
2888     TSetRxCall(tt, acid, "SetIdsTypes");
2889     tv = tt->volume;
2890
2891     V_type(tv) = type;
2892     V_backupId(tv) = backupId;
2893     V_cloneId(tv) = cloneId;
2894     V_parentId(tv) = pId;
2895     strcpy((&V_disk(tv))->name, name);
2896     VUpdateVolume(&error, tv);
2897     if (error) {
2898         Log("1 Volser: SetIdsTypes: VUpdate failed code %d\n", error);
2899         LogError(error);
2900         goto fail;
2901     }
2902     TClearRxCall(tt);
2903     if (TRELE(tt) && !error)
2904         return VOLSERTRELE_ERROR;
2905
2906     return error;
2907   fail:
2908     TClearRxCall(tt);
2909     if (TRELE(tt) && !error)
2910         return VOLSERTRELE_ERROR;
2911     return error;
2912 }
2913
2914 afs_int32
2915 SAFSVolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2916 {
2917     afs_int32 code;
2918
2919     code = VolSetDate(acid, atid, cdate);
2920     osi_auditU(acid, VS_SetDateEvent, code, AUD_LONG, atid, AUD_LONG, cdate,
2921                AUD_END);
2922     return code;
2923 }
2924
2925 static afs_int32
2926 VolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2927 {
2928     struct Volume *tv;
2929     Error error = 0;
2930     struct volser_trans *tt;
2931     char caller[MAXKTCNAMELEN];
2932
2933     if (!afsconf_SuperUser(tdir, acid, caller))
2934         return VOLSERBAD_ACCESS;        /*not a super user */
2935     /* find the trans */
2936     tt = FindTrans(atid);
2937     if (!tt)
2938         return ENOENT;
2939     if (tt->vflags & VTDeleted) {
2940         Log("1 Volser: VolSetDate: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
2941         TRELE(tt);
2942         return ENOENT;
2943     }
2944     TSetRxCall(tt, acid, "SetDate");
2945     tv = tt->volume;
2946
2947     V_creationDate(tv) = cdate;
2948     VUpdateVolume(&error, tv);
2949     if (error) {
2950         Log("1 Volser: SetDate: VUpdate failed code %d\n", error);
2951         LogError(error);
2952         goto fail;
2953     }
2954     TClearRxCall(tt);
2955     if (TRELE(tt) && !error)
2956         return VOLSERTRELE_ERROR;
2957
2958     return error;
2959   fail:
2960     TClearRxCall(tt);
2961     if (TRELE(tt) && !error)
2962         return VOLSERTRELE_ERROR;
2963     return error;
2964 }
2965
2966 afs_int32
2967 SAFSVolConvertROtoRWvolume(struct rx_call *acid, afs_int32 partId,
2968                            VolumeId volumeId)
2969 {
2970 #ifdef AFS_NT40_ENV
2971     return EXDEV;
2972 #else
2973     char caller[MAXKTCNAMELEN];
2974     DIR *dirp;
2975     struct volser_trans *ttc;
2976     char pname[16], volname[20];
2977     struct DiskPartition64 *partP;
2978     afs_int32 ret = ENODEV;
2979     VolumeId volid;
2980
2981     if (!afsconf_SuperUser(tdir, acid, caller))
2982         return VOLSERBAD_ACCESS;        /*not a super user */
2983     if (GetPartName(partId, pname))
2984         return VOLSERILLEGAL_PARTITION;
2985     if (!(partP = VGetPartition(pname, 0)))
2986         return VOLSERILLEGAL_PARTITION;
2987     dirp = opendir(VPartitionPath(partP));
2988     if (dirp == NULL)
2989         return VOLSERILLEGAL_PARTITION;
2990     ttc = (struct volser_trans *)0;
2991
2992     while (GetNextVol(dirp, volname, &volid)) {
2993         if (volid == volumeId) {        /*copy other things too */
2994 #ifndef AFS_PTHREAD_ENV
2995             IOMGR_Poll();       /*make sure that the client doesnot time out */
2996 #endif
2997             ttc = NewTrans(volumeId, partId);
2998             if (!ttc) {
2999                 return VOLSERVOLBUSY;
3000             }
3001 #ifdef AFS_NAMEI_ENV
3002             ret = namei_ConvertROtoRWvolume(pname, volumeId);
3003 #else
3004             ret = inode_ConvertROtoRWvolume(pname, volumeId);
3005 #endif
3006             break;
3007         }
3008     }
3009
3010     if (ttc)
3011         DeleteTrans(ttc, 1);
3012
3013     closedir(dirp);
3014     return ret;
3015 #endif
3016 }
3017
3018 afs_int32
3019 SAFSVolGetSize(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
3020                struct volintSize *size)
3021 {
3022     int code = 0;
3023     struct volser_trans *tt;
3024     char caller[MAXKTCNAMELEN];
3025
3026     if (!afsconf_SuperUser(tdir, acid, caller))
3027         return VOLSERBAD_ACCESS;        /*not a super user */
3028     tt = FindTrans(fromTrans);
3029     if (!tt)
3030         return ENOENT;
3031     if (tt->vflags & VTDeleted) {
3032         TRELE(tt);
3033         return ENOENT;
3034     }
3035     TSetRxCall(tt, acid, "GetSize");
3036     code = SizeDumpVolume(acid, tt->volume, fromDate, 1, size); /* measure volume's data */
3037     TClearRxCall(tt);
3038     if (TRELE(tt))
3039         return VOLSERTRELE_ERROR;
3040
3041 /*    osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);  */
3042     return code;
3043 }
3044
3045 afs_int32
3046 SAFSVolSplitVolume(struct rx_call *acall, afs_uint32 vid, afs_uint32 new,
3047                    afs_uint32 where, afs_int32 verbose)
3048 {
3049 #if defined(AFS_NAMEI_ENV) && !defined(AFS_NT40_ENV)
3050     Error code, code2;
3051     Volume *vol=0, *newvol=0;
3052     struct volser_trans *tt = 0, *tt2 = 0;
3053     char caller[MAXKTCNAMELEN];
3054     char line[128];
3055
3056     if (!afsconf_SuperUser(tdir, acall, caller))
3057         return EPERM;
3058
3059     vol = VAttachVolume(&code, vid, V_VOLUPD);
3060     if (!vol) {
3061         if (!code)
3062             code = ENOENT;
3063         return code;
3064     }
3065     newvol = VAttachVolume(&code, new, V_VOLUPD);
3066     if (!newvol) {
3067         VDetachVolume(&code2, vol);
3068         if (!code)
3069             code = ENOENT;
3070         return code;
3071     }
3072     if (V_device(vol) != V_device(newvol)
3073         || V_uniquifier(newvol) != 2) {
3074         if (V_device(vol) != V_device(newvol)) {
3075             sprintf(line, "Volumes %u and %u are not in the same partition, aborted.\n",
3076                     vid, new);
3077             rx_Write(acall, line, strlen(line));
3078         }
3079         if (V_uniquifier(newvol) != 2) {
3080             sprintf(line, "Volume %u is not freshly created, aborted.\n", new);
3081             rx_Write(acall, line, strlen(line));
3082         }
3083         line[0] = 0;
3084         rx_Write(acall, line, 1);
3085         VDetachVolume(&code2, vol);
3086         VDetachVolume(&code2, newvol);
3087         return EINVAL;
3088     }
3089     tt = NewTrans(vid, V_device(vol));
3090     if (!tt) {
3091         sprintf(line, "Couldn't create transaction for %u, aborted.\n", vid);
3092         rx_Write(acall, line, strlen(line));
3093         line[0] = 0;
3094         rx_Write(acall, line, 1);
3095         VDetachVolume(&code2, vol);
3096         VDetachVolume(&code2, newvol);
3097         return VOLSERVOLBUSY;
3098     }
3099     VTRANS_OBJ_LOCK(tt);
3100     tt->iflags = ITBusy;
3101     tt->vflags = 0;
3102     TSetRxCall_r(tt, NULL, "SplitVolume");
3103     VTRANS_OBJ_UNLOCK(tt);
3104
3105     tt2 = NewTrans(new, V_device(newvol));
3106     if (!tt2) {
3107         sprintf(line, "Couldn't create transaction for %u, aborted.\n", new);
3108         rx_Write(acall, line, strlen(line));
3109         line[0] = 0;
3110         rx_Write(acall, line, 1);
3111         DeleteTrans(tt, 1);
3112         VDetachVolume(&code2, vol);
3113         VDetachVolume(&code2, newvol);
3114         return VOLSERVOLBUSY;
3115     }
3116     VTRANS_OBJ_LOCK(tt2);
3117     tt2->iflags = ITBusy;
3118     tt2->vflags = 0;
3119     TSetRxCall_r(tt2, NULL, "SplitVolume");
3120     VTRANS_OBJ_UNLOCK(tt2);
3121
3122     code = split_volume(acall, vol, newvol, where, verbose);
3123
3124     VDetachVolume(&code2, vol);
3125     DeleteTrans(tt, 1);
3126     VDetachVolume(&code2, newvol);
3127     DeleteTrans(tt2, 1);
3128     return code;
3129 #else
3130     return VOLSERBADOP;
3131 #endif
3132 }
3133
3134 /* GetPartName - map partid (a decimal number) into pname (a string)
3135  * Since for NT we actually want to return the drive name, we map through the
3136  * partition struct.
3137  */
3138 static int
3139 GetPartName(afs_int32 partid, char *pname)
3140 {
3141     if (partid < 0)
3142         return -1;
3143     if (partid < 26) {
3144         strcpy(pname, "/vicep");
3145         pname[6] = 'a' + partid;
3146         pname[7] = '\0';
3147         return 0;
3148     } else if (partid < VOLMAXPARTS) {
3149         strcpy(pname, "/vicep");
3150         partid -= 26;
3151         pname[6] = 'a' + (partid / 26);
3152         pname[7] = 'a' + (partid % 26);
3153         pname[8] = '\0';
3154         return 0;
3155     } else
3156         return -1;
3157 }