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