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