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