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