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