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