20dcc67402d693af392f0bc3734f11c03adfe849
[openafs.git] / src / viced / afsfileprocs.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
10 /*  afs_fileprocs.c - Complete File Server request routines              */
11 /*                                                                       */
12 /*  Information Technology Center                                        */
13 /*  Carnegie Mellon University                                           */
14 /*                                                                       */
15 /*  Date: 8/10/88                                                        */
16 /*                                                                       */
17 /*  Function    - A set of routines to handle the various file Server    */
18 /*                  requests; these routines are invoked by rxgen.       */
19 /*                                                                       */
20 /* ********************************************************************** */
21
22 /* 
23  * in Check_PermissionRights, certain privileges are afforded to the owner 
24  * of the volume, or the owner of a file.  Are these considered "use of 
25  * privilege"? 
26  */
27
28 #include <afsconfig.h>
29 #include <afs/param.h>
30
31 RCSID("$Header$");
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <errno.h>
36 #ifdef  AFS_SGI_ENV
37 #undef SHARED           /* XXX */
38 #endif
39 #ifdef AFS_NT40_ENV
40 #include <fcntl.h>
41 #else
42 #include <sys/param.h>
43 #include <sys/file.h>
44 #include <netinet/in.h>
45 #include <netdb.h>
46 #include <sys/ioctl.h>
47 #include <sys/socket.h>
48 #ifndef AFS_LINUX20_ENV
49 #include <net/if.h>
50 #include <netinet/if_ether.h>
51 #endif
52 #ifdef notdef
53 #include <nlist.h>
54 #endif
55 #endif
56 #ifdef AFS_HPUX_ENV
57 /* included early because of name conflict on IOPEN */
58 #include <sys/inode.h>
59 #ifdef IOPEN
60 #undef IOPEN
61 #endif
62 #endif /* AFS_HPUX_ENV */
63 #include <afs/stds.h>
64 #include <rx/xdr.h>
65 #include <afs/nfs.h>
66 #include <afs/assert.h>
67 #include <lwp.h>
68 #include <lock.h>
69 #include <afs/afsint.h>
70 #include <afs/vldbint.h>
71 #include <afs/errors.h>
72 #include <afs/ihandle.h>
73 #include <afs/vnode.h>
74 #include <afs/volume.h>
75 #include <afs/acl.h>
76 #include <afs/ptclient.h>
77 #include <afs/prs_fs.h>
78 #include <rx/rx.h>
79 #include <rx/rx_globals.h>
80 #include <sys/stat.h>
81 #if ! defined(AFS_SGI_ENV) && ! defined(AFS_AIX32_ENV) && ! defined(AFS_NT40_ENV) && ! defined(AFS_LINUX20_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_XBSD_ENV)
82 #include <sys/map.h>
83 #endif
84 #if !defined(AFS_NT40_ENV)
85 #include <unistd.h>
86 #endif
87 #if !defined(AFS_SGI_ENV) && !defined(AFS_NT40_ENV)
88 #ifdef  AFS_AIX_ENV
89 #include <sys/statfs.h>
90 #include <sys/lockf.h>
91 #else
92 #if !defined(AFS_SUN5_ENV) && !defined(AFS_LINUX20_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_XBSD_ENV)
93 #include <sys/dk.h>
94 #endif
95 #endif
96 #endif
97 #include <afs/cellconfig.h>
98 #include <afs/keys.h>
99
100 #include <afs/auth.h>
101 #include <signal.h>
102 #include <afs/partition.h>
103 #include "viced.h"
104 #include "host.h"
105 #include <afs/audit.h>
106 #include <afs/afsutil.h>
107
108 #ifdef AFS_PTHREAD_ENV
109 pthread_mutex_t fileproc_glock_mutex;
110 #endif /* AFS_PTHREAD_ENV */
111
112
113 /* Useful local defines used by this module */
114
115 #define DONTCHECK       0
116 #define MustNOTBeDIR    1
117 #define MustBeDIR       2
118
119 #define TVS_SDATA       1
120 #define TVS_SSTATUS     2
121 #define TVS_CFILE       4
122 #define TVS_SLINK       8
123 #define TVS_MKDIR       0x10
124
125 #define CHK_FETCH       0x10
126 #define CHK_FETCHDATA   0x10
127 #define CHK_FETCHACL    0x11
128 #define CHK_FETCHSTATUS 0x12
129 #define CHK_STOREDATA   0x00
130 #define CHK_STOREACL    0x01
131 #define CHK_STORESTATUS 0x02
132
133 #define OWNERREAD       0400
134 #define OWNERWRITE      0200
135 #define OWNEREXEC       0100
136 #ifdef USE_GROUP_PERMS
137 #define GROUPREAD       0040
138 #define GROUPWRITE      0020
139 #define GROUPREXEC      0010
140 #endif
141
142 /* The following errors were not defined in NT. They are given unique
143  * names here to avoid any potential collision.
144  */
145 #define FSERR_ELOOP              90
146 #define FSERR_EOPNOTSUPP        122
147 #define FSERR_ECONNREFUSED      130
148
149 #define NOTACTIVECALL   0
150 #define ACTIVECALL      1
151
152 extern struct afsconf_dir *confDir;
153 extern afs_int32 dataVersionHigh;
154
155 extern  int         SystemId;
156 extern  struct AFSCallStatistics AFSCallStats;
157 struct AFSCallStatistics AFSCallStats;
158 #if FS_STATS_DETAILED
159 struct fs_stats_FullPerfStats afs_FullPerfStats;
160 extern int AnonymousID;
161 #endif /* FS_STATS_DETAILED */
162 #if TRANSARC_VOL_STATS
163 static const char nullString[] = "";
164 #endif /* TRANSARC_VOL_STATS */
165
166 struct afs_FSStats {
167     afs_int32 NothingYet;
168 };
169
170 struct afs_FSStats afs_fsstats;
171
172 void    ResetDebug(), SetDebug(), GetStatus(), Terminate();
173 int     CopyOnWrite();          /* returns 0 on success */
174
175
176 void SetSystemStats(), SetAFSStats(), SetVolumeStats();
177 int     LogLevel = 0;
178 int     supported = 1;
179 int     Console = 0;
180 afs_int32 BlocksSpare = 1024;   /* allow 1 MB overruns */
181 afs_int32 PctSpare;
182 extern afs_int32 implicitAdminRights;
183
184 static TryLocalVLServer();
185
186 /*
187  * Externals used by the xstat code.
188  */
189 extern int VolumeCacheSize, VolumeGets, VolumeReplacements;
190 extern int CEs, CEBlocks;
191
192 extern int HTs, HTBlocks;
193
194 #ifdef AFS_SGI_XFS_IOPS_ENV
195 #include <afs/xfsattrs.h>
196 static int GetLinkCount(avp, astat)
197      Volume *avp;
198      struct stat *astat;
199 {
200     if (!strcmp("xfs", astat->st_fstype)) {
201         return (astat->st_mode & AFS_XFS_MODE_LINK_MASK);
202     }
203     else
204         return astat->st_nlink;
205 }
206 #else
207 #define GetLinkCount(V, S) (S)->st_nlink
208 #endif
209
210 afs_int32 SpareComp(avolp)
211     Volume *avolp;
212
213 {
214     register afs_int32 temp;
215
216     FS_LOCK
217     if (PctSpare) {
218         temp = V_maxquota(avolp);
219         if (temp == 0) {
220             /* no matter; doesn't check in this case */
221             FS_UNLOCK
222             return 0;
223         }
224         temp = (temp * PctSpare) / 100;
225         FS_UNLOCK
226         return temp;
227     }
228     else {
229         FS_UNLOCK
230         return BlocksSpare;
231     }
232
233 } /*SpareComp*/
234
235
236 /*
237  * Set the volume synchronization parameter for this volume.  If it changes,
238  * the Cache Manager knows that the volume must be purged from the stat cache.
239  */
240 static SetVolumeSync(async, avol)
241     register struct AFSVolSync *async;
242     register Volume *avol;
243
244 {
245     FS_LOCK
246     /* date volume instance was created */
247     if (async) {
248         if (avol)
249             async->spare1 = avol->header->diskstuff.creationDate;
250         else
251             async->spare1 = 0;
252         async->spare2 = 0;
253         async->spare3 = 0;
254         async->spare4 = 0;
255         async->spare5 = 0;
256         async->spare6 = 0;
257     }
258     FS_UNLOCK
259 } /*SetVolumeSync*/
260
261 /*
262  * This call overwrites the pointed-to rx_call with an rx_connection.  This
263  * is really bogus.  Note that this function always returns a held host, so
264  * that CallPostamble can block without the host's disappearing.
265  */
266 static CallPreamble(acall, activecall)
267     register struct rx_call **acall;
268     int activecall;
269
270 {
271     struct host *thost;
272     struct rx_connection *tconn;
273     struct client *tclient;
274     int retry_flag=1;
275     int code = 0;
276     char hoststr[16];
277     tconn = rx_ConnectionOf(*acall);
278     *acall = (struct rx_call *)tconn;       /* change it! */
279
280     H_LOCK
281 retry:
282     tclient = h_FindClient_r(tconn);
283     if (tclient->prfail == 1) { /* couldn't get the CPS */
284        if (!retry_flag) {
285           h_ReleaseClient_r(tclient);
286           ViceLog(0, ("CallPreamble: Couldn't get CPS. Fail\n"));
287           H_UNLOCK
288           return -1001;
289        }
290        retry_flag=0;    /* Retry once */
291
292        /* Take down the old connection and re-read the key file */
293        ViceLog(0, ("CallPreamble: Couldn't get CPS. Reconnect to ptserver\n"));
294        H_UNLOCK
295        code = pr_Initialize(2, AFSDIR_SERVER_ETC_DIRPATH, 0);
296        H_LOCK
297        if (code) {
298           h_ReleaseClient_r(tclient);
299           H_UNLOCK
300           ViceLog(0,("CallPreamble: couldn't reconnect to ptserver\n"));
301           return -1001;
302        }
303
304        tclient->prfail = 2;      /* Means re-eval client's cps */
305        h_ReleaseClient_r(tclient);
306        goto retry;
307     }
308
309     thost = tclient->host;
310     tclient->LastCall = thost->LastCall = FT_ApproxTime();
311     if (activecall) /* For all but "GetTime" calls */
312         thost->ActiveCall = thost->LastCall;
313
314     h_Lock_r(thost);
315     if (thost->hostFlags & HOSTDELETED) {
316       ViceLog(3,("Discarded a packet for deleted host %s\n",afs_inet_ntoa_r(thost->host,hoststr)));
317       code = VBUSY; /* raced, so retry */
318     }
319     else if (thost->hostFlags & VENUSDOWN) {
320       if (BreakDelayedCallBacks_r(thost)) {
321         ViceLog(0,("BreakDelayedCallbacks FAILED for host %s which IS UP.  Possible network or routing failure.\n",
322                 afs_inet_ntoa_r(thost->host, hoststr)));
323         if ( MultiProbeAlternateAddress_r (thost) ) {
324             ViceLog(0, ("MultiProbe failed to find new address for host %s:%d\n",
325                         afs_inet_ntoa_r(thost->host, hoststr), thost->port));
326             code = -1;
327         } else {
328             ViceLog(0, ("MultiProbe found new address for host %s:%d\n",
329                         afs_inet_ntoa_r(thost->host, hoststr), thost->port));
330             if (BreakDelayedCallBacks_r(thost)) {
331                 ViceLog(0,("BreakDelayedCallbacks FAILED AGAIN for host %s which IS UP.  Possible network or routing failure.\n",
332                         afs_inet_ntoa_r(thost->host, hoststr)));
333                 code = -1;
334             }
335         }
336       }
337     } else {
338        code =  0;
339     }
340
341     h_ReleaseClient_r(tclient);
342     h_Unlock_r(thost);
343     H_UNLOCK
344     return code;      
345
346 } /*CallPreamble*/
347
348
349 static CallPostamble(aconn)
350     register struct rx_connection *aconn;
351
352 {
353     struct host *thost;
354     struct client *tclient;
355
356     H_LOCK
357     tclient = h_FindClient_r(aconn);
358     thost = tclient->host;
359     h_ReleaseClient_r(tclient);
360     h_Release_r(thost);
361     H_UNLOCK
362
363 } /*CallPostamble*/
364
365
366 #define AFSV_BUFFERSIZE 16384 
367
368 static struct afs_buffer {
369     struct afs_buffer *next;
370 } *freeBufferList = 0;
371 static int afs_buffersAlloced = 0;
372
373
374 static FreeSendBuffer(adata)
375     register struct afs_buffer *adata;
376
377 {
378     FS_LOCK
379     afs_buffersAlloced--;
380     adata->next = freeBufferList;
381     freeBufferList = adata;
382     FS_UNLOCK
383     return 0;
384
385 } /*FreeSendBuffer*/
386
387
388 /* allocate space for sender */
389 static char *AllocSendBuffer()
390
391 {
392     register struct afs_buffer *tp;
393
394     FS_LOCK
395     afs_buffersAlloced++;
396     if (!freeBufferList) {
397         FS_UNLOCK
398         return malloc(AFSV_BUFFERSIZE);
399     }
400     tp = freeBufferList;
401     freeBufferList = tp->next;
402     FS_UNLOCK
403     return (char *) tp;
404
405 } /*AllocSendBuffer*/
406
407
408 static int VolumeOwner (client, targetptr)
409     register struct client *client;
410     register Vnode *targetptr;
411
412 {
413     afs_int32 owner = V_owner(targetptr->volumePtr);    /* get volume owner */
414
415     if (owner >= 0)
416         return (client->ViceId == owner);
417     else {
418         /* 
419          * We don't have to check for host's cps since only regular
420          * viceid are volume owners.
421          */
422         return (acl_IsAMember(owner, &client->CPS));
423     }
424
425 } /*VolumeOwner*/
426
427
428 static int VolumeRootVnode (targetptr)
429     Vnode *targetptr;
430
431 {
432     return ((targetptr->vnodeNumber == ROOTVNODE) &&
433             (targetptr->disk.uniquifier == 1));
434
435 } /*VolumeRootVnode*/
436
437
438 SRXAFS_FetchData (tcon, Fid, Pos, Len, OutStatus, CallBack, Sync)
439     struct rx_connection *tcon;         /* Rx connection handle */
440     struct AFSFid *Fid;                 /* Fid of file to fetch */
441     afs_int32 Pos, Len;                 /* Not implemented yet */
442     struct AFSFetchStatus *OutStatus;   /* Returned status for Fid */
443     struct AFSCallBack *CallBack;       /* If r/w return CB for Fid */
444     struct AFSVolSync *Sync;            /* synchronization info */
445
446 {
447     Vnode * targetptr = 0;                  /* pointer to vnode to fetch */
448     Vnode * parentwhentargetnotdir = 0;     /* parent vnode if vptr is a file */
449     Vnode   tparentwhentargetnotdir;        /* parent vnode for GetStatus */
450     int     errorCode = 0;                  /* return code to caller */
451     int     fileCode =  0;                  /* return code from vol package */
452     Volume * volptr = 0;                    /* pointer to the volume */
453     struct client *client;                  /* pointer to the client data */
454     struct rx_call *tcall;                  /* the call we're a part of */
455     afs_int32 rights, anyrights;                    /* rights for this and any user */
456     struct client *t_client;                /* tmp ptr to client data */
457     struct in_addr logHostAddr;             /* host ip holder for inet_ntoa */
458 #if FS_STATS_DETAILED
459     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
460     struct fs_stats_xferData *xferP;        /* Ptr to this op's byte size struct */
461     struct timeval opStartTime,
462                    opStopTime;              /* Start/stop times for RPC op*/
463     struct timeval xferStartTime,
464                    xferStopTime;            /* Start/stop times for xfer portion*/
465     struct timeval elapsedTime;             /* Transfer time */
466     afs_int32 bytesToXfer;                          /* # bytes to xfer*/
467     afs_int32 bytesXferred;                         /* # bytes actually xferred*/
468     int readIdx;                            /* Index of read stats array to bump*/
469     static afs_int32 tot_bytesXferred; /* shared access protected by FS_LOCK */
470
471     /*
472      * Set our stats pointers, remember when the RPC operation started, and
473      * tally the operation.
474      */
475     opP   = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_FETCHDATA]);
476     xferP = &(afs_FullPerfStats.det.xferOpTimes[FS_STATS_XFERIDX_FETCHDATA]);
477     FS_LOCK
478     (opP->numOps)++;
479     FS_UNLOCK
480     TM_GetTimeOfDay(&opStartTime, 0);
481 #endif /* FS_STATS_DETAILED */
482
483     ViceLog(1,("SRXAFS_FetchData, Fid = %u.%d.%d\n",
484             Fid->Volume, Fid->Vnode, Fid->Unique));     
485     FS_LOCK
486     AFSCallStats.FetchData++, AFSCallStats.TotalCalls++;
487     FS_UNLOCK
488
489     /* CallPreamble changes tcon from a call to a conn */
490     tcall = (struct rx_call *) tcon;
491     if (errorCode = CallPreamble((struct rx_call **) &tcon, ACTIVECALL))
492         goto Bad_FetchData;
493
494     /* Get ptr to client data for user Id for logging */
495     t_client = (struct client *)  rx_GetSpecific(tcon, rxcon_client_key);
496     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
497     ViceLog(5,("SRXAFS_FetchData, Fid = %u.%d.%d, Host %s, Id %d\n",
498             Fid->Volume, Fid->Vnode, Fid->Unique,
499             inet_ntoa(logHostAddr), t_client->ViceId)); 
500     /*
501      * Get volume/vnode for the fetched file; caller's access rights to
502      * it are also returned
503      */
504     if (errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
505                                      DONTCHECK, &parentwhentargetnotdir,
506                                      &client, READ_LOCK, &rights, &anyrights))
507         goto Bad_FetchData;
508
509     SetVolumeSync(Sync, volptr);
510
511 #if FS_STATS_DETAILED
512     /*
513      * Remember that another read operation was performed.
514      */
515     FS_LOCK
516     if (client->InSameNetwork)
517         readIdx = VOL_STATS_SAME_NET;
518     else
519         readIdx = VOL_STATS_DIFF_NET;
520     V_stat_reads(volptr, readIdx)++;
521     if (client->ViceId != AnonymousID) {
522         V_stat_reads(volptr, readIdx+1)++;
523     }
524     FS_UNLOCK
525 #endif /* FS_STATS_DETAILED */
526
527     /* Check whether the caller has permission access to fetch the data */
528     if (errorCode = Check_PermissionRights(targetptr, client, rights,
529                                            CHK_FETCHDATA, 0)) 
530         goto Bad_FetchData;
531
532     /*
533      * Drop the read lock on the parent directory after saving the parent
534      * vnode information we need to pass to GetStatus
535      */
536     if (parentwhentargetnotdir != NULL) {
537         tparentwhentargetnotdir = *parentwhentargetnotdir;
538         VPutVnode(&fileCode, parentwhentargetnotdir);
539         assert(!fileCode || (fileCode == VSALVAGE));
540         parentwhentargetnotdir = NULL;
541     }
542
543 #if FS_STATS_DETAILED
544     /*
545      * Remember when the data transfer started.
546      */
547     TM_GetTimeOfDay(&xferStartTime, 0);
548 #endif /* FS_STATS_DETAILED */
549
550     /* actually do the data transfer */
551 #if FS_STATS_DETAILED
552     errorCode = FetchData_RXStyle(volptr, targetptr, tcall, Pos, Len,
553                                   &bytesToXfer, &bytesXferred);
554 #else
555     if (errorCode = FetchData_RXStyle(volptr, targetptr, tcall, Pos, Len))
556         goto Bad_FetchData;
557 #endif /* FS_STATS_DETAILED */
558
559 #if FS_STATS_DETAILED
560     /*
561      * At this point, the data transfer is done, for good or ill.  Remember
562      * when the transfer ended, bump the number of successes/failures, and
563      * integrate the transfer size and elapsed time into the stats.  If the
564      * operation failed, we jump to the appropriate point.
565      */
566     TM_GetTimeOfDay(&xferStopTime, 0);
567     FS_LOCK
568     (xferP->numXfers)++;
569     if (!errorCode) {
570         (xferP->numSuccesses)++;
571
572         /*
573          * Bump the xfer sum by the number of bytes actually sent, NOT the
574          * target number.
575          */
576         tot_bytesXferred += bytesXferred;
577         (xferP->sumBytes) += (tot_bytesXferred >> 10);
578         tot_bytesXferred &= 0x3FF;
579         if (bytesXferred < xferP->minBytes)
580             xferP->minBytes = bytesXferred;
581         if (bytesXferred > xferP->maxBytes)
582             xferP->maxBytes = bytesXferred;
583
584         /*
585          * Tally the size of the object.  Note: we tally the actual size,
586          * NOT the number of bytes that made it out over the wire.
587          */
588         if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET0)
589             (xferP->count[0])++;
590         else
591             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET1)
592                 (xferP->count[1])++;
593         else
594             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET2)
595                 (xferP->count[2])++;
596         else
597             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET3)
598                 (xferP->count[3])++;
599         else
600             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET4)
601                 (xferP->count[4])++;
602         else
603             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET5)
604                 (xferP->count[5])++;
605         else
606             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET6)
607                 (xferP->count[6])++;
608         else
609             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET7)
610                 (xferP->count[7])++;
611         else
612             (xferP->count[8])++;
613
614         fs_stats_GetDiff(elapsedTime, xferStartTime, xferStopTime);
615         fs_stats_AddTo((xferP->sumTime), elapsedTime);
616         fs_stats_SquareAddTo((xferP->sqrTime), elapsedTime);
617         if (fs_stats_TimeLessThan(elapsedTime, (xferP->minTime))) {
618             fs_stats_TimeAssign((xferP->minTime), elapsedTime);
619         }
620         if (fs_stats_TimeGreaterThan(elapsedTime, (xferP->maxTime))) {
621             fs_stats_TimeAssign((xferP->maxTime), elapsedTime);
622         }
623       }
624     FS_UNLOCK
625     /*
626      * Finally, go off to tell our caller the bad news in case the
627      * fetch failed.
628      */
629     if (errorCode)
630         goto Bad_FetchData;
631 #endif /* FS_STATS_DETAILED */
632
633     /* write back  the OutStatus from the target vnode  */
634     GetStatus(targetptr, OutStatus, rights, anyrights, &tparentwhentargetnotdir);
635
636     /* if a r/w volume, promise a callback to the caller */
637     if (VolumeWriteable(volptr))
638         SetCallBackStruct(AddCallBack(client->host, Fid), CallBack);
639     else {
640       struct AFSFid myFid;              
641       memset(&myFid, 0, sizeof(struct AFSFid));
642       myFid.Volume = Fid->Volume;
643       SetCallBackStruct(AddVolCallBack(client->host, &myFid), CallBack);
644       }
645
646 Bad_FetchData: 
647     /* Update and store volume/vnode and parent vnodes back */
648     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
649     ViceLog(2, ("SRXAFS_FetchData returns %d\n", errorCode)); 
650     CallPostamble(tcon);
651
652 #if FS_STATS_DETAILED
653     TM_GetTimeOfDay(&opStopTime, 0);
654     if (errorCode == 0) {
655         FS_LOCK
656         (opP->numSuccesses)++;
657         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
658         fs_stats_AddTo((opP->sumTime), elapsedTime);
659         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
660         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
661             fs_stats_TimeAssign((opP->minTime), elapsedTime);
662         }
663         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
664             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
665         }
666         FS_UNLOCK
667       }
668
669 #endif /* FS_STATS_DETAILED */
670
671     osi_auditU (tcall, FetchDataEvent, errorCode, AUD_FID, Fid, AUD_END);
672     return(errorCode);
673
674 } /*SRXAFS_FetchData*/
675
676
677 SRXAFS_FetchACL (tcon, Fid, AccessList, OutStatus, Sync)
678     struct AFSVolSync *Sync;
679     struct rx_connection *tcon;         /* Rx connection handle */
680     struct AFSFid *Fid;                 /* Fid of target dir */
681     struct AFSOpaque *AccessList;       /* Returned contents of dir's ACL */
682     struct AFSFetchStatus *OutStatus;   /* Returned status for the dir */
683
684 {
685     Vnode * targetptr = 0;              /* pointer to vnode to fetch */
686     Vnode * parentwhentargetnotdir = 0; /* parent vnode if targetptr is a file */
687     int     errorCode = 0;              /* return error code to caller */
688     Volume * volptr = 0;                /* pointer to the volume */
689     struct client *client;              /* pointer to the client data */
690     afs_int32 rights, anyrights;                /* rights for this and any user */
691     struct rx_call *tcall = (struct rx_call *) tcon; 
692     struct client *t_client;                /* tmp ptr to client data */
693     struct in_addr logHostAddr;             /* host ip holder for inet_ntoa */
694 #if FS_STATS_DETAILED
695     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
696     struct timeval opStartTime,
697                    opStopTime;              /* Start/stop times for RPC op*/
698     struct timeval elapsedTime;             /* Transfer time */
699
700     /*
701      * Set our stats pointer, remember when the RPC operation started, and
702      * tally the operation.
703      */
704     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_FETCHACL]);
705     FS_LOCK
706     (opP->numOps)++;
707     FS_UNLOCK
708     TM_GetTimeOfDay(&opStartTime, 0);
709 #endif /* FS_STATS_DETAILED */
710
711     ViceLog(1, ("SAFS_FetchACL, Fid = %u.%d.%d\n",
712             Fid->Volume, Fid->Vnode, Fid->Unique));
713     FS_LOCK
714     AFSCallStats.FetchACL++, AFSCallStats.TotalCalls++;
715     FS_UNLOCK
716     if (errorCode = CallPreamble((struct rx_call **) &tcon, ACTIVECALL))
717         goto Bad_FetchACL;
718
719     /* Get ptr to client data for user Id for logging */
720     t_client = (struct client *)  rx_GetSpecific(tcon, rxcon_client_key);
721     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
722     ViceLog(5, ("SAFS_FetchACL, Fid = %u.%d.%d, Host %s, Id %d\n",
723             Fid->Volume, Fid->Vnode, Fid->Unique,
724             inet_ntoa(logHostAddr), t_client->ViceId));
725
726     AccessList->AFSOpaque_len = 0;
727     AccessList->AFSOpaque_val = malloc(AFSOPAQUEMAX);
728
729     /*
730      * Get volume/vnode for the fetched file; caller's access rights to it
731      * are also returned
732      */
733     if (errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
734                                      DONTCHECK, &parentwhentargetnotdir,
735                                      &client, READ_LOCK, &rights, &anyrights))
736         goto Bad_FetchACL;
737
738     SetVolumeSync(Sync, volptr);
739
740     /* Check whether we have permission to fetch the ACL */
741     if (errorCode = Check_PermissionRights(targetptr, client, rights,
742                                            CHK_FETCHACL, 0))
743         goto Bad_FetchACL;
744
745     /* Get the Access List from the dir's vnode */
746     if (errorCode = RXFetch_AccessList(targetptr, parentwhentargetnotdir,
747                                        AccessList))
748         goto Bad_FetchACL;
749
750     /* Get OutStatus back From the target Vnode  */
751     GetStatus(targetptr, OutStatus, rights, anyrights, parentwhentargetnotdir);
752
753 Bad_FetchACL: 
754     /* Update and store volume/vnode and parent vnodes back */
755     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
756     ViceLog(2, ("SAFS_FetchACL returns %d (ACL=%s)\n",
757             errorCode, AccessList->AFSOpaque_val));
758     CallPostamble(tcon);
759
760 #if FS_STATS_DETAILED
761     TM_GetTimeOfDay(&opStopTime, 0);
762     if (errorCode == 0) {
763         FS_LOCK
764         (opP->numSuccesses)++;
765         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
766         fs_stats_AddTo((opP->sumTime), elapsedTime);
767         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
768         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
769             fs_stats_TimeAssign((opP->minTime), elapsedTime);
770         }
771         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
772             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
773         }
774         FS_UNLOCK
775       }
776
777 #endif /* FS_STATS_DETAILED */
778
779     osi_auditU (tcall, FetchACLEvent, errorCode, AUD_FID, Fid, AUD_END);
780     return errorCode;
781
782 } /*SRXAFS_FetchACL*/
783
784
785 /*
786  * This routine is called exclusively by SRXAFS_FetchStatus(), and should be
787  * merged into it when possible.
788  */
789 SAFSS_FetchStatus (tcall, Fid, OutStatus, CallBack, Sync)
790     struct rx_call *tcall;
791     struct AFSFid *Fid;                 /* Fid of target file */
792     struct AFSFetchStatus *OutStatus;   /* Returned status for the fid */
793     struct AFSCallBack *CallBack;       /* if r/w, callback promise for Fid */
794     struct AFSVolSync *Sync;            /* volume synchronization parm */
795
796 {
797     Vnode * targetptr = 0;              /* pointer to vnode to fetch */
798     Vnode * parentwhentargetnotdir = 0; /* parent vnode if targetptr is a file */
799     int     errorCode = 0;              /* return code to caller */
800     Volume * volptr = 0;                /* pointer to the volume */
801     struct client *client;              /* pointer to the client data */
802     afs_int32 rights, anyrights;                /* rights for this and any user */
803     struct client *t_client;            /* tmp ptr to client data */
804     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
805     struct rx_connection *tcon = rx_ConnectionOf(tcall);
806
807     /* Get ptr to client data for user Id for logging */
808     t_client = (struct client *)  rx_GetSpecific(tcon, rxcon_client_key);
809     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
810     ViceLog(1, ("SAFS_FetchStatus,  Fid = %u.%d.%d, Host %s, Id %d\n",
811             Fid->Volume, Fid->Vnode, Fid->Unique,
812             inet_ntoa(logHostAddr), t_client->ViceId));
813     FS_LOCK
814     AFSCallStats.FetchStatus++, AFSCallStats.TotalCalls++;
815     FS_UNLOCK
816     /*
817      * Get volume/vnode for the fetched file; caller's rights to it are
818      * also returned
819      */
820     if (errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
821                                      DONTCHECK, &parentwhentargetnotdir,
822                                      &client, READ_LOCK, &rights, &anyrights))
823         goto Bad_FetchStatus;
824
825     /* set volume synchronization information */
826     SetVolumeSync(Sync, volptr);
827
828     /* Are we allowed to fetch Fid's status? */
829     if (targetptr->disk.type != vDirectory) {
830       if (errorCode = Check_PermissionRights(targetptr, client, rights,
831                                              CHK_FETCHSTATUS, 0)) {
832           if (rx_GetCallAbortCode(tcall) == errorCode) 
833               rx_SetCallAbortCode(tcall, 0);
834           goto Bad_FetchStatus;
835       }
836     }
837
838     /* set OutStatus From the Fid  */
839     GetStatus(targetptr, OutStatus, rights, anyrights, parentwhentargetnotdir);
840
841     /* If a r/w volume, also set the CallBack state */
842     if (VolumeWriteable(volptr))
843         SetCallBackStruct(AddCallBack(client->host, Fid), CallBack);
844     else {
845       struct AFSFid myFid;              
846       memset(&myFid, 0, sizeof(struct AFSFid));
847       myFid.Volume = Fid->Volume;
848       SetCallBackStruct(AddVolCallBack(client->host, &myFid), CallBack);
849       }
850
851 Bad_FetchStatus: 
852     /* Update and store volume/vnode and parent vnodes back */
853     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
854     ViceLog(2, ("SAFS_FetchStatus returns %d\n", errorCode)); 
855     return errorCode;
856
857 } /*SAFSS_FetchStatus*/
858
859
860 SRXAFS_BulkStatus(tcon, Fids, OutStats, CallBacks, Sync)
861     struct rx_connection *tcon;
862     struct AFSCBFids *Fids;
863     struct AFSBulkStats *OutStats;
864     struct AFSCBs *CallBacks;
865     struct AFSVolSync *Sync;
866
867 {
868     register int i;
869     afs_int32 nfiles;
870     Vnode * targetptr = 0;              /* pointer to vnode to fetch */
871     Vnode * parentwhentargetnotdir = 0; /* parent vnode if targetptr is a file */
872     int     errorCode = 0;              /* return code to caller */
873     Volume * volptr = 0;                /* pointer to the volume */
874     struct client *client;              /* pointer to the client data */
875     afs_int32 rights, anyrights;                /* rights for this and any user */
876     register struct AFSFid *tfid;       /* file id we're dealing with now */
877     struct rx_call *tcall = (struct rx_call *) tcon; 
878 #if FS_STATS_DETAILED
879     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
880     struct timeval opStartTime,
881                    opStopTime;              /* Start/stop times for RPC op*/
882     struct timeval elapsedTime;             /* Transfer time */
883
884     /*
885      * Set our stats pointer, remember when the RPC operation started, and
886      * tally the operation.
887      */
888     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_BULKSTATUS]);
889     FS_LOCK
890     (opP->numOps)++;
891     FS_UNLOCK
892     TM_GetTimeOfDay(&opStartTime, 0);
893 #endif /* FS_STATS_DETAILED */
894
895     ViceLog(1, ("SAFS_BulkStatus\n"));
896     FS_LOCK
897     AFSCallStats.TotalCalls++;
898     FS_UNLOCK
899
900     nfiles = Fids->AFSCBFids_len;       /* # of files in here */
901     if (nfiles <= 0) {                  /* Sanity check */
902         errorCode = EINVAL;
903         goto Audit_and_Return;
904     }
905
906     /* allocate space for return output parameters */
907     OutStats->AFSBulkStats_val = (struct AFSFetchStatus *)
908         malloc(nfiles * sizeof(struct AFSFetchStatus));
909     OutStats->AFSBulkStats_len = nfiles;
910     CallBacks->AFSCBs_val = (struct AFSCallBack *)
911         malloc(nfiles * sizeof(struct AFSCallBack));
912     CallBacks->AFSCBs_len = nfiles;
913
914     if (errorCode = CallPreamble((struct rx_call **) &tcon, ACTIVECALL))
915         goto Bad_BulkStatus;
916
917     tfid = Fids->AFSCBFids_val;
918     for (i=0; i<nfiles; i++, tfid++) {
919         /*
920          * Get volume/vnode for the fetched file; caller's rights to it
921          * are also returned
922          */
923         if (errorCode =
924             GetVolumePackage(tcon, tfid, &volptr, &targetptr,
925                              DONTCHECK, &parentwhentargetnotdir, &client,
926                              READ_LOCK, &rights, &anyrights))
927                 goto Bad_BulkStatus;
928         /* set volume synchronization information, but only once per call */
929         if (i == nfiles)
930             SetVolumeSync(Sync, volptr);
931
932         /* Are we allowed to fetch Fid's status? */
933         if (targetptr->disk.type != vDirectory) {
934             if (errorCode = Check_PermissionRights(targetptr, client, rights,
935                                                    CHK_FETCHSTATUS, 0)) {
936                 if (rx_GetCallAbortCode(tcall) == errorCode) 
937                     rx_SetCallAbortCode(tcall, 0);
938                 goto Bad_BulkStatus;
939             }
940         }
941
942         /* set OutStatus From the Fid  */
943         GetStatus(targetptr, &OutStats->AFSBulkStats_val[i],
944                   rights, anyrights, parentwhentargetnotdir);
945
946         /* If a r/w volume, also set the CallBack state */
947         if (VolumeWriteable(volptr))
948             SetCallBackStruct(AddBulkCallBack(client->host, tfid),
949                               &CallBacks->AFSCBs_val[i]);
950         else {
951           struct AFSFid myFid;          
952           memset(&myFid, 0, sizeof(struct AFSFid));
953           myFid.Volume = tfid->Volume;
954           SetCallBackStruct(AddVolCallBack(client->host, &myFid),
955                               &CallBacks->AFSCBs_val[i]);
956         }
957
958         /* put back the file ID and volume */
959         PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, volptr);
960         parentwhentargetnotdir = (Vnode *) 0;
961         targetptr = (Vnode *) 0;
962         volptr = (Volume *) 0;
963     }
964
965 Bad_BulkStatus: 
966     /* Update and store volume/vnode and parent vnodes back */
967     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
968     CallPostamble(tcon);
969
970 #if FS_STATS_DETAILED
971     TM_GetTimeOfDay(&opStopTime, 0);
972     if (errorCode == 0) {
973         FS_LOCK
974         (opP->numSuccesses)++;
975         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
976         fs_stats_AddTo((opP->sumTime), elapsedTime);
977         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
978         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
979             fs_stats_TimeAssign((opP->minTime), elapsedTime);
980         }
981         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
982             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
983         }
984         FS_UNLOCK
985     }   
986
987 #endif /* FS_STATS_DETAILED */
988
989 Audit_and_Return:
990     ViceLog(2, ("SAFS_BulkStatus        returns %d\n", errorCode)); 
991     osi_auditU (tcall, BulkFetchStatusEvent, errorCode, AUD_FIDS, Fids, AUD_END);
992     return errorCode;
993
994 } /*SRXAFS_BulkStatus*/
995
996
997 SRXAFS_InlineBulkStatus(tcon, Fids, OutStats, CallBacks, Sync)
998     struct rx_connection *tcon;
999     struct AFSCBFids *Fids;
1000     struct AFSBulkStats *OutStats;
1001     struct AFSCBs *CallBacks;
1002     struct AFSVolSync *Sync;
1003 {
1004     register int i;
1005     afs_int32 nfiles;
1006     Vnode * targetptr = 0;              /* pointer to vnode to fetch */
1007     Vnode * parentwhentargetnotdir = 0; /* parent vnode if targetptr is a file */
1008     int     errorCode = 0;              /* return code to caller */
1009     Volume * volptr = 0;                /* pointer to the volume */
1010     struct client *client;              /* pointer to the client data */
1011     afs_int32 rights, anyrights;                /* rights for this and any user */
1012     register struct AFSFid *tfid;       /* file id we're dealing with now */
1013     struct rx_call *tcall = (struct rx_call *) tcon; 
1014     AFSFetchStatus *tstatus;
1015 #if FS_STATS_DETAILED
1016     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
1017     struct timeval opStartTime,
1018                    opStopTime;              /* Start/stop times for RPC op*/
1019     struct timeval elapsedTime;             /* Transfer time */
1020
1021     /*
1022      * Set our stats pointer, remember when the RPC operation started, and
1023      * tally the operation.
1024      */
1025     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_BULKSTATUS]);
1026     FS_LOCK
1027     (opP->numOps)++;
1028     FS_UNLOCK
1029     TM_GetTimeOfDay(&opStartTime, 0);
1030 #endif /* FS_STATS_DETAILED */
1031
1032     ViceLog(1, ("SAFS_InlineBulkStatus\n"));
1033     FS_LOCK
1034     AFSCallStats.TotalCalls++;
1035     FS_UNLOCK
1036
1037     nfiles = Fids->AFSCBFids_len;       /* # of files in here */
1038     if (nfiles <= 0) {                  /* Sanity check */
1039         errorCode = EINVAL;
1040         goto Audit_and_Return;
1041     }
1042
1043     /* allocate space for return output parameters */
1044     OutStats->AFSBulkStats_val = (struct AFSFetchStatus *)
1045         malloc(nfiles * sizeof(struct AFSFetchStatus));
1046     OutStats->AFSBulkStats_len = nfiles;
1047     CallBacks->AFSCBs_val = (struct AFSCallBack *)
1048         malloc(nfiles * sizeof(struct AFSCallBack));
1049     CallBacks->AFSCBs_len = nfiles;
1050
1051     if (errorCode = CallPreamble((struct rx_call **) &tcon, ACTIVECALL)) {
1052         goto Bad_InlineBulkStatus;
1053     }
1054
1055     tfid = Fids->AFSCBFids_val;
1056     for (i=0; i<nfiles; i++, tfid++) {
1057         /*
1058          * Get volume/vnode for the fetched file; caller's rights to it
1059          * are also returned
1060          */
1061         if (errorCode =
1062             GetVolumePackage(tcon, tfid, &volptr, &targetptr,
1063                              DONTCHECK, &parentwhentargetnotdir, &client,
1064                              READ_LOCK, &rights, &anyrights)) {
1065             tstatus = &OutStats->AFSBulkStats_val[i];
1066             tstatus->errorCode = errorCode;
1067             parentwhentargetnotdir = (Vnode *) 0;
1068             targetptr = (Vnode *) 0;
1069             volptr = (Volume *) 0;
1070             continue;
1071         }
1072
1073         /* set volume synchronization information, but only once per call */
1074         if (i == nfiles)
1075             SetVolumeSync(Sync, volptr);
1076
1077         /* Are we allowed to fetch Fid's status? */
1078         if (targetptr->disk.type != vDirectory) {
1079             if (errorCode = Check_PermissionRights(targetptr, client, rights,
1080                                                    CHK_FETCHSTATUS, 0)) {
1081                 tstatus = &OutStats->AFSBulkStats_val[i];
1082                 tstatus->errorCode = errorCode;
1083                 PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, volptr);
1084                 parentwhentargetnotdir = (Vnode *) 0;
1085                 targetptr = (Vnode *) 0;
1086                 volptr = (Volume *) 0;
1087                 continue;
1088             }
1089         }
1090
1091         /* set OutStatus From the Fid  */
1092         GetStatus(targetptr, &OutStats->AFSBulkStats_val[i],
1093                   rights, anyrights, parentwhentargetnotdir);
1094
1095         /* If a r/w volume, also set the CallBack state */
1096         if (VolumeWriteable(volptr))
1097             SetCallBackStruct(AddBulkCallBack(client->host, tfid),
1098                               &CallBacks->AFSCBs_val[i]);
1099         else {
1100           struct AFSFid myFid;          
1101           memset(&myFid, 0, sizeof(struct AFSFid));
1102           myFid.Volume = tfid->Volume;
1103           SetCallBackStruct(AddVolCallBack(client->host, &myFid),
1104                               &CallBacks->AFSCBs_val[i]);
1105         }
1106
1107         /* put back the file ID and volume */
1108         PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, volptr);
1109         parentwhentargetnotdir = (Vnode *) 0;
1110         targetptr = (Vnode *) 0;
1111         volptr = (Volume *) 0;
1112     }
1113
1114 Bad_InlineBulkStatus: 
1115     /* Update and store volume/vnode and parent vnodes back */
1116     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
1117     CallPostamble(tcon);
1118
1119 #if FS_STATS_DETAILED
1120     TM_GetTimeOfDay(&opStopTime, 0);
1121     if (errorCode == 0) {
1122         FS_LOCK
1123         (opP->numSuccesses)++;
1124         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
1125         fs_stats_AddTo((opP->sumTime), elapsedTime);
1126         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
1127         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
1128             fs_stats_TimeAssign((opP->minTime), elapsedTime);
1129         }
1130         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
1131             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
1132         }
1133         FS_UNLOCK
1134     }   
1135
1136 #endif /* FS_STATS_DETAILED */
1137
1138 Audit_and_Return:
1139     ViceLog(2, ("SAFS_InlineBulkStatus  returns %d\n", errorCode)); 
1140     osi_auditU (tcall, InlineBulkFetchStatusEvent, errorCode, AUD_FIDS, Fids, AUD_END);
1141     return 0;
1142
1143 } /*SRXAFS_InlineBulkStatus*/
1144
1145
1146 SRXAFS_FetchStatus (tcon, Fid, OutStatus, CallBack, Sync)
1147     struct AFSVolSync *Sync;
1148     struct rx_connection *tcon;         /* Rx connection handle */
1149     struct AFSFid *Fid;                 /* Fid of target file */
1150     struct AFSFetchStatus *OutStatus;   /* Returned status for the fid */
1151     struct AFSCallBack *CallBack;       /* if r/w, callback promise for Fid */
1152
1153 {
1154     afs_int32 code;
1155     struct rx_call *tcall = (struct rx_call *) tcon; 
1156 #if FS_STATS_DETAILED
1157     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
1158     struct timeval opStartTime,
1159                    opStopTime;              /* Start/stop times for RPC op*/
1160     struct timeval elapsedTime;             /* Transfer time */
1161
1162     /*
1163      * Set our stats pointer, remember when the RPC operation started, and
1164      * tally the operation.
1165      */
1166     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_FETCHSTATUS]);
1167     FS_LOCK
1168     (opP->numOps)++;
1169     FS_UNLOCK
1170     TM_GetTimeOfDay(&opStartTime, 0);
1171 #endif /* FS_STATS_DETAILED */
1172
1173     if (code = CallPreamble((struct rx_call **) &tcon, ACTIVECALL))
1174         goto Bad_FetchStatus;
1175
1176     code = SAFSS_FetchStatus (tcall, Fid, OutStatus, CallBack, Sync);
1177
1178 Bad_FetchStatus:    
1179     CallPostamble(tcon);
1180
1181 #if FS_STATS_DETAILED
1182     TM_GetTimeOfDay(&opStopTime, 0);
1183     if (code == 0) {
1184         FS_LOCK
1185         (opP->numSuccesses)++;
1186         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
1187         fs_stats_AddTo((opP->sumTime), elapsedTime);
1188         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
1189         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
1190             fs_stats_TimeAssign((opP->minTime), elapsedTime);
1191         }
1192         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
1193             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
1194         }
1195         FS_UNLOCK
1196       }
1197
1198 #endif /* FS_STATS_DETAILED */
1199
1200     osi_auditU (tcall, FetchStatusEvent, code, AUD_FID, Fid, AUD_END);
1201     return code;
1202
1203 } /*SRXAFS_FetchStatus*/
1204
1205
1206 SRXAFS_StoreData (tcon, Fid, InStatus, Pos, Length, FileLength, OutStatus, Sync)
1207     struct AFSVolSync *Sync;
1208     struct rx_connection *tcon;         /* Rx connection Handle */
1209     struct AFSFid *Fid;                 /* Fid of taret file */
1210     struct AFSStoreStatus *InStatus;    /* Input Status for Fid */
1211     afs_int32 Pos;                              /* Not implemented yet */
1212     afs_int32 Length;                   /* Length of data to store */
1213     afs_int32 FileLength;                       /* Length of file after store */
1214     struct AFSFetchStatus *OutStatus;   /* Returned status for target fid */
1215
1216 {
1217     Vnode * targetptr = 0;              /* pointer to input fid */
1218     Vnode * parentwhentargetnotdir = 0; /* parent of Fid to get ACL */
1219     Vnode   tparentwhentargetnotdir;    /* parent vnode for GetStatus */
1220     int     errorCode = 0;              /* return code for caller */
1221     int     fileCode =  0;              /* return code from vol package */
1222     Volume * volptr = 0;                /* pointer to the volume header */
1223     struct client * client;             /* pointer to client structure */
1224     struct rx_call *tcall;              /* remember the call structure for ftp */
1225     afs_int32 rights, anyrights;                /* rights for this and any user */
1226     struct client *t_client;            /* tmp ptr to client data */
1227     struct in_addr logHostAddr;             /* host ip holder for inet_ntoa */
1228 #if FS_STATS_DETAILED
1229     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
1230     struct fs_stats_xferData *xferP;        /* Ptr to this op's byte size struct */
1231     struct timeval opStartTime,
1232                    opStopTime;              /* Start/stop times for RPC op*/
1233     struct timeval xferStartTime,
1234                    xferStopTime;            /* Start/stop times for xfer portion*/
1235     struct timeval elapsedTime;             /* Transfer time */
1236     afs_int32 bytesToXfer;                          /* # bytes to xfer */
1237     afs_int32 bytesXferred;                         /* # bytes actually xfer */
1238     static afs_int32 tot_bytesXferred; /* shared access protected by FS_LOCK */
1239
1240     /*
1241      * Set our stats pointers, remember when the RPC operation started, and
1242      * tally the operation.
1243      */
1244     opP   = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_STOREDATA]);
1245     xferP = &(afs_FullPerfStats.det.xferOpTimes[FS_STATS_XFERIDX_STOREDATA]);
1246     FS_LOCK
1247     (opP->numOps)++;
1248     FS_UNLOCK
1249
1250     ViceLog(1, ("StoreData: Fid = %u.%d.%d\n",
1251             Fid->Volume, Fid->Vnode, Fid->Unique));
1252     TM_GetTimeOfDay(&opStartTime, 0);
1253 #endif /* FS_STATS_DETAILED */
1254
1255     FS_LOCK
1256     AFSCallStats.StoreData++, AFSCallStats.TotalCalls++;
1257     FS_UNLOCK
1258     /* CallPreamble changes tcon from a call to a conn */
1259     tcall = (struct rx_call *) tcon;
1260     if (errorCode = CallPreamble((struct rx_call **) &tcon, ACTIVECALL))
1261         goto Bad_StoreData;
1262
1263     /* Get ptr to client data for user Id for logging */
1264     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
1265     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
1266     ViceLog(5, ("StoreData: Fid = %u.%d.%d, Host %s, Id %d\n",
1267             Fid->Volume, Fid->Vnode, Fid->Unique,
1268             inet_ntoa(logHostAddr), t_client->ViceId));
1269
1270     /*
1271      * Get associated volume/vnode for the stored file; caller's rights
1272      * are also returned
1273      */
1274     if (errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
1275                                      MustNOTBeDIR, &parentwhentargetnotdir,
1276                                      &client, WRITE_LOCK, &rights, &anyrights)) {
1277         goto Bad_StoreData;
1278     }
1279
1280     /* set volume synchronization information */
1281     SetVolumeSync(Sync, volptr);
1282
1283     if ((targetptr->disk.type == vSymlink)) {
1284         /* Should we return a better error code here??? */
1285         errorCode = EISDIR;
1286         goto Bad_StoreData;
1287     }
1288
1289     /* Check if we're allowed to store the data */
1290     if (errorCode = Check_PermissionRights(targetptr, client, rights,
1291                                            CHK_STOREDATA, InStatus)) {
1292         goto Bad_StoreData;
1293     }
1294
1295     /*
1296      * Drop the read lock on the parent directory after saving the parent
1297      * vnode information we need to pass to GetStatus
1298      */
1299     if (parentwhentargetnotdir != NULL) {
1300         tparentwhentargetnotdir = *parentwhentargetnotdir;
1301         VPutVnode(&fileCode, parentwhentargetnotdir);
1302         assert(!fileCode || (fileCode == VSALVAGE));
1303         parentwhentargetnotdir = NULL;
1304     }
1305
1306
1307
1308 #if FS_STATS_DETAILED
1309     /*
1310      * Remember when the data transfer started.
1311      */
1312     TM_GetTimeOfDay(&xferStartTime, 0);
1313 #endif /* FS_STATS_DETAILED */
1314
1315     /* Do the actual storing of the data */
1316 #if FS_STATS_DETAILED
1317     errorCode = StoreData_RXStyle(volptr, targetptr, Fid, client, tcall,
1318                                   Pos, Length, FileLength,
1319                                   (InStatus->Mask & AFS_FSYNC),
1320                                   &bytesToXfer, &bytesXferred);
1321 #else
1322     errorCode = StoreData_RXStyle(volptr, targetptr, Fid, client,
1323                                       tcall, Pos, Length, FileLength,
1324                                       (InStatus->Mask & AFS_FSYNC));
1325     if (errorCode && (!targetptr->changed_newTime))
1326             goto Bad_StoreData;
1327 #endif /* FS_STATS_DETAILED */
1328 #if FS_STATS_DETAILED
1329     /*
1330      * At this point, the data transfer is done, for good or ill.  Remember
1331      * when the transfer ended, bump the number of successes/failures, and
1332      * integrate the transfer size and elapsed time into the stats.  If the
1333      * operation failed, we jump to the appropriate point.
1334      */
1335     TM_GetTimeOfDay(&xferStopTime, 0);
1336     FS_LOCK
1337     (xferP->numXfers)++;
1338     if (!errorCode) {
1339         (xferP->numSuccesses)++;
1340
1341         /*
1342          * Bump the xfer sum by the number of bytes actually sent, NOT the
1343          * target number.
1344          */
1345         tot_bytesXferred += bytesXferred;
1346         (xferP->sumBytes) += (tot_bytesXferred >> 10);
1347         tot_bytesXferred &= 0x3FF;
1348         if (bytesXferred < xferP->minBytes)
1349             xferP->minBytes = bytesXferred;
1350         if (bytesXferred > xferP->maxBytes)
1351             xferP->maxBytes = bytesXferred;
1352       
1353         /*
1354          * Tally the size of the object.  Note: we tally the actual size,
1355          * NOT the number of bytes that made it out over the wire.
1356          */
1357         if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET0)
1358             (xferP->count[0])++;
1359         else
1360             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET1)
1361                 (xferP->count[1])++;
1362         else
1363             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET2)
1364                 (xferP->count[2])++;
1365         else
1366             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET3)
1367                 (xferP->count[3])++;
1368         else
1369             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET4)
1370                 (xferP->count[4])++;
1371         else
1372             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET5)
1373                 (xferP->count[5])++;
1374         else
1375             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET6)
1376                 (xferP->count[6])++;
1377         else
1378             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET7)
1379                 (xferP->count[7])++;
1380         else
1381             (xferP->count[8])++;
1382       
1383         fs_stats_GetDiff(elapsedTime, xferStartTime, xferStopTime);
1384         fs_stats_AddTo((xferP->sumTime), elapsedTime);
1385         fs_stats_SquareAddTo((xferP->sqrTime), elapsedTime);
1386         if (fs_stats_TimeLessThan(elapsedTime, (xferP->minTime))) {
1387             fs_stats_TimeAssign((xferP->minTime), elapsedTime);
1388         }
1389         if (fs_stats_TimeGreaterThan(elapsedTime, (xferP->maxTime))) {
1390             fs_stats_TimeAssign((xferP->maxTime), elapsedTime);
1391         }
1392     }
1393     FS_UNLOCK
1394
1395     /*
1396      * Finally, go off to tell our caller the bad news in case the
1397      * store failed.
1398      */
1399     if (errorCode && (!targetptr->changed_newTime))
1400             goto Bad_StoreData;
1401 #endif /* FS_STATS_DETAILED */
1402
1403     /* Update the status of the target's vnode */
1404     Update_TargetVnodeStatus(targetptr, TVS_SDATA, client, InStatus, targetptr,
1405                              volptr, 0);
1406
1407     /* Get the updated File's status back to the caller */
1408     GetStatus(targetptr, OutStatus, rights, anyrights, &tparentwhentargetnotdir);
1409
1410 Bad_StoreData: 
1411     /* Update and store volume/vnode and parent vnodes back */
1412     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
1413     ViceLog(2, ("SAFS_StoreData returns %d\n", errorCode));
1414
1415     CallPostamble(tcon);
1416
1417 #if FS_STATS_DETAILED
1418     TM_GetTimeOfDay(&opStopTime, 0);
1419     if (errorCode == 0) {
1420         FS_LOCK
1421         (opP->numSuccesses)++;
1422         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
1423         fs_stats_AddTo((opP->sumTime), elapsedTime);
1424         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
1425         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
1426             fs_stats_TimeAssign((opP->minTime), elapsedTime);
1427         }
1428         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
1429             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
1430         }
1431         FS_UNLOCK
1432       }
1433 #endif /* FS_STATS_DETAILED */
1434
1435     osi_auditU (tcall, StoreDataEvent, errorCode, AUD_FID, Fid, AUD_END);
1436     return(errorCode);
1437
1438 } /*SRXAFS_StoreData*/
1439
1440
1441 SRXAFS_StoreACL (tcon, Fid, AccessList, OutStatus, Sync)
1442     struct AFSVolSync *Sync;
1443     struct rx_connection *tcon;         /* Rx connection handle */
1444     struct AFSFid *Fid;                 /* Target dir's fid */
1445     struct AFSOpaque *AccessList;       /* Access List's contents */
1446     struct AFSFetchStatus *OutStatus;   /* Returned status of fid */
1447
1448 {
1449     Vnode * targetptr = 0;              /* pointer to input fid */
1450     Vnode * parentwhentargetnotdir = 0; /* parent of Fid to get ACL */
1451     int     errorCode = 0;              /* return code for caller */
1452     struct AFSStoreStatus InStatus;     /* Input status for fid */
1453     Volume * volptr = 0;                /* pointer to the volume header */
1454     struct client * client;             /* pointer to client structure */
1455     afs_int32 rights, anyrights;                /* rights for this and any user */
1456     struct rx_call *tcall = (struct rx_call *) tcon; 
1457     struct client *t_client;            /* tmp ptr to client data */
1458     struct in_addr logHostAddr;             /* host ip holder for inet_ntoa */
1459 #if FS_STATS_DETAILED
1460     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
1461     struct timeval opStartTime,
1462                    opStopTime;              /* Start/stop times for RPC op*/
1463     struct timeval elapsedTime;             /* Transfer time */
1464
1465     /*
1466      * Set our stats pointer, remember when the RPC operation started, and
1467      * tally the operation.
1468      */
1469     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_STOREACL]);
1470     FS_LOCK
1471     (opP->numOps)++;
1472     FS_UNLOCK
1473     TM_GetTimeOfDay(&opStartTime, 0);
1474 #endif /* FS_STATS_DETAILED */
1475     if (errorCode = CallPreamble((struct rx_call **) &tcon, ACTIVECALL))
1476         goto Bad_StoreACL;
1477
1478     /* Get ptr to client data for user Id for logging */
1479     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
1480     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
1481     ViceLog(1, ("SAFS_StoreACL, Fid = %u.%d.%d, ACL=%s, Host %s, Id %d\n",
1482             Fid->Volume, Fid->Vnode, Fid->Unique, AccessList->AFSOpaque_val,
1483             inet_ntoa(logHostAddr), t_client->ViceId));
1484     FS_LOCK
1485     AFSCallStats.StoreACL++, AFSCallStats.TotalCalls++;
1486     FS_UNLOCK
1487
1488     InStatus.Mask = 0;      /* not storing any status */
1489
1490     /*
1491      * Get associated volume/vnode for the target dir; caller's rights
1492      * are also returned.
1493      */
1494     if (errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
1495                                      MustBeDIR, &parentwhentargetnotdir,
1496                                      &client, WRITE_LOCK, &rights, &anyrights)) {
1497         goto Bad_StoreACL;
1498     }
1499
1500     /* set volume synchronization information */
1501     SetVolumeSync(Sync, volptr);
1502
1503     /* Check if we have permission to change the dir's ACL */
1504     if (errorCode = Check_PermissionRights(targetptr, client, rights,
1505                                            CHK_STOREACL, &InStatus)) {
1506         goto Bad_StoreACL;
1507     }
1508
1509     /* Build and store the new Access List for the dir */
1510     if (errorCode = RXStore_AccessList(targetptr, AccessList)) {
1511         goto Bad_StoreACL;
1512     }
1513     
1514     targetptr->changed_newTime = 1; /* status change of directory */
1515
1516     /* convert the write lock to a read lock before breaking callbacks */
1517     VVnodeWriteToRead(&errorCode, targetptr);
1518     assert(!errorCode || errorCode == VSALVAGE);
1519
1520     /* break call backs on the directory  */
1521     BreakCallBack(client->host, Fid, 0);
1522
1523     /* Get the updated dir's status back to the caller */
1524     GetStatus(targetptr, OutStatus, rights, anyrights, (struct vnode *)0);
1525
1526 Bad_StoreACL: 
1527     /* Update and store volume/vnode and parent vnodes back */
1528     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
1529     ViceLog(2, ("SAFS_StoreACL returns %d\n", errorCode)); 
1530     CallPostamble(tcon);
1531
1532 #if FS_STATS_DETAILED
1533     TM_GetTimeOfDay(&opStopTime, 0);
1534     if (errorCode == 0) {
1535       FS_LOCK
1536       (opP->numSuccesses)++;
1537       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
1538       fs_stats_AddTo((opP->sumTime), elapsedTime);
1539       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
1540       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
1541         fs_stats_TimeAssign((opP->minTime), elapsedTime);
1542       }
1543       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
1544         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
1545       }
1546       FS_UNLOCK
1547     }
1548 #endif /* FS_STATS_DETAILED */
1549
1550     osi_auditU (tcall, StoreACLEvent, errorCode, AUD_FID, Fid, AUD_END);
1551     return errorCode;
1552
1553 } /*SRXAFS_StoreACL*/
1554
1555
1556 /*
1557  * Note: This routine is called exclusively from SRXAFS_StoreStatus(), and
1558  * should be merged when possible.
1559  */
1560 SAFSS_StoreStatus (tcon, Fid, InStatus, OutStatus, Sync)
1561     struct rx_connection *tcon;         /* Rx connection Handle */
1562     struct AFSFid *Fid;                 /* Target file's fid */
1563     struct AFSStoreStatus *InStatus;    /* Input status for Fid */
1564     struct AFSFetchStatus *OutStatus;   /* Output status for fid */
1565     struct AFSVolSync *Sync;
1566
1567 {
1568     Vnode * targetptr = 0;              /* pointer to input fid */
1569     Vnode * parentwhentargetnotdir = 0; /* parent of Fid to get ACL */
1570     int     errorCode = 0;              /* return code for caller */
1571     Volume * volptr = 0;                /* pointer to the volume header */
1572     struct client * client;             /* pointer to client structure */
1573     afs_int32 rights, anyrights;                /* rights for this and any user */
1574     struct client *t_client;            /* tmp ptr to client data */
1575     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
1576
1577     /* Get ptr to client data for user Id for logging */
1578     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
1579     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
1580     ViceLog(1, ("SAFS_StoreStatus,  Fid = %u.%d.%d, Host %s, Id %d\n",
1581             Fid->Volume, Fid->Vnode,    Fid->Unique,
1582             inet_ntoa(logHostAddr), t_client->ViceId));
1583     FS_LOCK
1584     AFSCallStats.StoreStatus++, AFSCallStats.TotalCalls++;
1585     FS_UNLOCK
1586     /*
1587      * Get volume/vnode for the target file; caller's rights to it are
1588      * also returned
1589      */
1590     if (errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
1591                                      DONTCHECK, &parentwhentargetnotdir,
1592                                      &client, WRITE_LOCK, &rights, &anyrights)) {
1593         goto Bad_StoreStatus;
1594     }
1595
1596     /* set volume synchronization information */
1597     SetVolumeSync(Sync, volptr);
1598
1599     /* Check if the caller has proper permissions to store status to Fid */
1600     if (errorCode = Check_PermissionRights(targetptr, client, rights,
1601                                            CHK_STORESTATUS, InStatus)) {
1602         goto Bad_StoreStatus;
1603     }
1604     /*
1605      * Check for a symbolic link; we can't chmod these (otherwise could
1606      * change a symlink to a mt pt or vice versa)
1607      */
1608     if (targetptr->disk.type == vSymlink && (InStatus->Mask & AFS_SETMODE)) {
1609         errorCode = EINVAL;
1610         goto Bad_StoreStatus;
1611     }
1612
1613     /* Update the status of the target's vnode */
1614     Update_TargetVnodeStatus(targetptr, TVS_SSTATUS, client, InStatus,
1615                              (parentwhentargetnotdir ?
1616                               parentwhentargetnotdir : targetptr), volptr, 0);
1617
1618     /* convert the write lock to a read lock before breaking callbacks */
1619     VVnodeWriteToRead(&errorCode, targetptr);
1620     assert(!errorCode || errorCode == VSALVAGE);
1621
1622     /* Break call backs on Fid */
1623     BreakCallBack(client->host, Fid, 0);
1624
1625     /* Return the updated status back to caller */
1626     GetStatus(targetptr, OutStatus, rights, anyrights, parentwhentargetnotdir);
1627
1628 Bad_StoreStatus: 
1629     /* Update and store volume/vnode and parent vnodes back */
1630     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
1631     ViceLog(2, ("SAFS_StoreStatus returns %d\n", errorCode));
1632     return errorCode;
1633
1634 } /*SAFSS_StoreStatus*/
1635
1636
1637 SRXAFS_StoreStatus (tcon, Fid, InStatus, OutStatus, Sync)
1638     struct AFSVolSync *Sync;
1639     struct rx_connection *tcon;         /* Rx connection Handle */
1640     struct AFSFid *Fid;                 /* Target file's fid */
1641     struct AFSStoreStatus *InStatus;    /* Input status for Fid */
1642     struct AFSFetchStatus *OutStatus;   /* Output status for fid */
1643
1644 {
1645     afs_int32 code;
1646     struct rx_call *tcall = (struct rx_call *) tcon; 
1647 #if FS_STATS_DETAILED
1648     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
1649     struct timeval opStartTime,
1650                    opStopTime;              /* Start/stop times for RPC op*/
1651     struct timeval elapsedTime;             /* Transfer time */
1652
1653     /*
1654      * Set our stats pointer, remember when the RPC operation started, and
1655      * tally the operation.
1656      */
1657     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_STORESTATUS]);
1658     FS_LOCK
1659     (opP->numOps)++;
1660     FS_UNLOCK
1661     TM_GetTimeOfDay(&opStartTime, 0);
1662 #endif /* FS_STATS_DETAILED */
1663
1664     if (code = CallPreamble((struct rx_call **) &tcon, ACTIVECALL))
1665         goto Bad_StoreStatus;
1666
1667     code = SAFSS_StoreStatus (tcon, Fid, InStatus, OutStatus, Sync);
1668
1669 Bad_StoreStatus:
1670     CallPostamble(tcon);
1671
1672 #if FS_STATS_DETAILED
1673     TM_GetTimeOfDay(&opStopTime, 0);
1674     if (code == 0) {
1675       FS_LOCK
1676       (opP->numSuccesses)++;
1677       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
1678       fs_stats_AddTo((opP->sumTime), elapsedTime);
1679       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
1680       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
1681         fs_stats_TimeAssign((opP->minTime), elapsedTime);
1682       }
1683       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
1684         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
1685       }
1686       FS_UNLOCK
1687     }
1688
1689 #endif /* FS_STATS_DETAILED */
1690
1691     osi_auditU (tcall, StoreStatusEvent, code, AUD_FID, Fid, AUD_END);
1692     return code;
1693
1694 } /*SRXAFS_StoreStatus*/
1695
1696
1697 /*
1698  * This routine is called exclusively by SRXAFS_RemoveFile(), and should be
1699  * merged in when possible.
1700  */
1701 SAFSS_RemoveFile (tcon, DirFid, Name, OutDirStatus, Sync)
1702     struct rx_connection *tcon;          /* Rx connection handle */
1703     struct AFSFid *DirFid;               /* Dir fid for file to remove */
1704     char *Name;                          /* File name to remove */
1705     struct AFSFetchStatus *OutDirStatus; /* Output status for dir fid's */
1706     struct AFSVolSync *Sync;
1707
1708 {
1709     Vnode * parentptr = 0;              /* vnode of input Directory */
1710     Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
1711     Vnode * targetptr = 0;              /* file to be deleted */
1712     Volume * volptr = 0;                /* pointer to the volume header */
1713     AFSFid fileFid;                     /* area for Fid from the directory */
1714     int     errorCode = 0;              /* error code */
1715     DirHandle dir;                      /* Handle for dir package I/O */
1716     struct client * client;             /* pointer to client structure */
1717     afs_int32 rights, anyrights;                /* rights for this and any user */
1718     struct client *t_client;            /* tmp ptr to client data */
1719     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
1720
1721     /* Get ptr to client data for user Id for logging */
1722     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
1723     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
1724     ViceLog(1, ("SAFS_RemoveFile %s,  Did = %u.%d.%d, Host %s, Id %d\n",
1725             Name, DirFid->Volume, DirFid->Vnode, DirFid->Unique,
1726             inet_ntoa(logHostAddr), t_client->ViceId));
1727     FS_LOCK
1728     AFSCallStats.RemoveFile++, AFSCallStats.TotalCalls++;
1729     FS_UNLOCK
1730     /*
1731      * Get volume/vnode for the parent dir; caller's access rights are
1732      * also returned
1733      */
1734     if (errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr,
1735                                      MustBeDIR, &parentwhentargetnotdir,
1736                                      &client, WRITE_LOCK, &rights, &anyrights)) {
1737         goto Bad_RemoveFile;
1738     }
1739     /* set volume synchronization information */
1740     SetVolumeSync(Sync, volptr);
1741
1742     /* Does the caller has delete (& write) access to the parent directory? */
1743     if (errorCode = CheckWriteMode(parentptr, rights, PRSFS_DELETE)) {
1744         goto Bad_RemoveFile;
1745     }
1746
1747     /* Actually delete the desired file */
1748     if (errorCode = DeleteTarget(parentptr, volptr, &targetptr, &dir,
1749                                  &fileFid, Name, MustNOTBeDIR)) {
1750         goto Bad_RemoveFile;
1751     }
1752
1753     /* Update the vnode status of the parent dir */
1754 #if FS_STATS_DETAILED
1755     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
1756                              parentptr->disk.linkCount, client->InSameNetwork);
1757 #else
1758     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
1759                              parentptr->disk.linkCount);
1760 #endif /* FS_STATS_DETAILED */
1761
1762     /* Return the updated parent dir's status back to caller */
1763     GetStatus(parentptr, OutDirStatus, rights, anyrights, (struct vnode *)0);
1764
1765     /* Handle internal callback state for the parent and the deleted file */
1766     if (targetptr->disk.linkCount == 0) {
1767         /* no references left, discard entry */
1768         DeleteFileCallBacks(&fileFid);
1769         /* convert the parent lock to a read lock before breaking callbacks */
1770         VVnodeWriteToRead(&errorCode, parentptr);
1771         assert(!errorCode || errorCode == VSALVAGE);
1772     } else {
1773         /* convert the parent lock to a read lock before breaking callbacks */
1774         VVnodeWriteToRead(&errorCode, parentptr);
1775         assert(!errorCode || errorCode == VSALVAGE);
1776         /* convert the target lock to a read lock before breaking callbacks */
1777         VVnodeWriteToRead(&errorCode, targetptr);
1778         assert(!errorCode || errorCode == VSALVAGE);
1779         /* tell all the file has changed */
1780         BreakCallBack(client->host, &fileFid, 1);
1781     }
1782
1783     /* break call back on the directory */
1784     BreakCallBack(client->host, DirFid, 0);
1785
1786 Bad_RemoveFile: 
1787     /* Update and store volume/vnode and parent vnodes back */
1788     PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr);
1789     ViceLog(2, ("SAFS_RemoveFile returns %d\n", errorCode)); 
1790     return errorCode;
1791
1792 } /*SAFSS_RemoveFile*/
1793
1794
1795 SRXAFS_RemoveFile (tcon, DirFid, Name, OutDirStatus, Sync)
1796     struct AFSVolSync *Sync;
1797     struct rx_connection *tcon;          /* Rx connection handle */
1798     struct AFSFid *DirFid;               /* Dir fid for file to remove */
1799     char *Name;                          /* File name to remove */
1800     struct AFSFetchStatus *OutDirStatus; /* Output status for dir fid's */
1801
1802 {
1803     afs_int32 code;
1804     struct rx_call *tcall = (struct rx_call *) tcon; 
1805 #if FS_STATS_DETAILED
1806     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
1807     struct timeval opStartTime,
1808                    opStopTime;              /* Start/stop times for RPC op*/
1809     struct timeval elapsedTime;             /* Transfer time */
1810
1811     /*
1812      * Set our stats pointer, remember when the RPC operation started, and
1813      * tally the operation.
1814      */
1815     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_REMOVEFILE]);
1816     FS_LOCK
1817     (opP->numOps)++;
1818     FS_UNLOCK
1819     TM_GetTimeOfDay(&opStartTime, 0);
1820 #endif /* FS_STATS_DETAILED */
1821
1822     if (code = CallPreamble((struct rx_call **) &tcon, ACTIVECALL))
1823         goto Bad_RemoveFile;
1824
1825     code = SAFSS_RemoveFile (tcon, DirFid, Name, OutDirStatus, Sync);
1826
1827 Bad_RemoveFile:    
1828     CallPostamble(tcon);
1829
1830 #if FS_STATS_DETAILED
1831     TM_GetTimeOfDay(&opStopTime, 0);
1832     if (code == 0) {
1833       FS_LOCK
1834       (opP->numSuccesses)++;
1835       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
1836       fs_stats_AddTo((opP->sumTime), elapsedTime);
1837       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
1838       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
1839         fs_stats_TimeAssign((opP->minTime), elapsedTime);
1840       }
1841       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
1842         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
1843       }
1844       FS_UNLOCK
1845     }
1846
1847 #endif /* FS_STATS_DETAILED */
1848
1849     osi_auditU (tcall, RemoveFileEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_END);
1850     return code;
1851
1852 } /*SRXAFS_RemoveFile*/
1853
1854
1855 /*
1856  * This routine is called exclusively from SRXAFS_CreateFile(), and should
1857  * be merged in when possible.
1858  */
1859 SAFSS_CreateFile (tcon, DirFid, Name, InStatus, OutFid, OutFidStatus,
1860                  OutDirStatus, CallBack, Sync)
1861     struct rx_connection *tcon;          /* Rx connection handle */
1862     struct AFSFid *DirFid;               /* Parent Dir fid */
1863     char *Name;                          /* File name to be created */
1864     struct AFSStoreStatus *InStatus;     /* Input status for newly created file */
1865     struct AFSFid *OutFid;               /* Fid for newly created file */
1866     struct AFSFetchStatus *OutFidStatus; /* Output status for new file */
1867     struct AFSFetchStatus *OutDirStatus; /* Ouput status for the parent dir */
1868     struct AFSCallBack *CallBack;        /* Return callback promise for new file */
1869     struct AFSVolSync *Sync;
1870
1871 {
1872     Vnode * parentptr = 0;              /* vnode of input Directory */
1873     Vnode * targetptr = 0;              /* vnode of the new file */
1874     Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
1875     Volume * volptr = 0;                /* pointer to the volume header */
1876     int     errorCode = 0;              /* error code */
1877     DirHandle dir;                      /* Handle for dir package I/O */
1878     struct client * client;             /* pointer to client structure */
1879     afs_int32 rights, anyrights;                /* rights for this and any user */
1880     struct client *t_client;            /* tmp ptr to client data */
1881     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
1882
1883     /* Get ptr to client data for user Id for logging */
1884     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
1885     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
1886     ViceLog(1, ("SAFS_CreateFile %s,  Did = %u.%d.%d, Host %s, Id %d\n",
1887             Name, DirFid->Volume, DirFid->Vnode, DirFid->Unique,
1888             inet_ntoa(logHostAddr), t_client->ViceId));
1889     FS_LOCK
1890     AFSCallStats.CreateFile++, AFSCallStats.TotalCalls++;
1891     FS_UNLOCK
1892     if (!FileNameOK(Name)) {
1893       errorCode = EINVAL;
1894       goto Bad_CreateFile;
1895     }
1896
1897     /*
1898      * Get associated volume/vnode for the parent dir; caller long are
1899      * also returned
1900      */
1901     if (errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr,
1902                                      MustBeDIR, &parentwhentargetnotdir,
1903                                      &client, WRITE_LOCK, &rights, &anyrights)) {
1904         goto Bad_CreateFile;
1905     }
1906
1907     /* set volume synchronization information */
1908     SetVolumeSync(Sync, volptr);
1909
1910     /* Can we write (and insert) onto the parent directory? */
1911     if (errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT)) {
1912         goto Bad_CreateFile;
1913     }
1914     /* get a new vnode for the file to be created and set it up */
1915     if (errorCode = Alloc_NewVnode(parentptr, &dir, volptr, &targetptr,
1916                                    Name, OutFid, vFile, nBlocks(0))) {
1917         goto Bad_CreateFile;
1918     }
1919
1920     /* update the status of the parent vnode */
1921 #if FS_STATS_DETAILED
1922     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
1923                              parentptr->disk.linkCount, client->InSameNetwork);
1924 #else
1925     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
1926                              parentptr->disk.linkCount);
1927 #endif /* FS_STATS_DETAILED */
1928
1929     /* update the status of the new file's vnode */
1930     Update_TargetVnodeStatus(targetptr, TVS_CFILE, client, InStatus,
1931                              parentptr, volptr, 0);
1932
1933     /* set up the return status for the parent dir and the newly created file */
1934     GetStatus(targetptr, OutFidStatus, rights, anyrights, parentptr);
1935     GetStatus(parentptr, OutDirStatus, rights, anyrights, (struct vnode *)0);
1936
1937     /* convert the write lock to a read lock before breaking callbacks */
1938     VVnodeWriteToRead(&errorCode, parentptr);
1939     assert(!errorCode || errorCode == VSALVAGE);
1940     
1941     /* break call back on parent dir */
1942     BreakCallBack(client->host, DirFid, 0);
1943
1944     /* Return a callback promise for the newly created file to the caller */
1945     SetCallBackStruct(AddCallBack(client->host, OutFid), CallBack);
1946
1947 Bad_CreateFile:
1948     /* Update and store volume/vnode and parent vnodes back */
1949     PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr);
1950     ViceLog(2, ("SAFS_CreateFile returns %d\n", errorCode)); 
1951     return errorCode;
1952
1953 } /*SAFSS_CreateFile*/
1954
1955
1956 SRXAFS_CreateFile (tcon, DirFid, Name, InStatus, OutFid, OutFidStatus, OutDirStatus, CallBack, Sync)
1957     struct AFSVolSync *Sync;
1958     struct rx_connection *tcon;          /* Rx connection handle */
1959     struct AFSFid *DirFid;               /* Parent Dir fid */
1960     char *Name;                          /* File name to be created */
1961     struct AFSStoreStatus *InStatus;     /* Input status for newly created file */
1962     struct AFSFid *OutFid;               /* Fid for newly created file */
1963     struct AFSFetchStatus *OutFidStatus; /* Output status for new file */
1964     struct AFSFetchStatus *OutDirStatus; /* Ouput status for the parent dir */
1965     struct AFSCallBack *CallBack;        /* Return callback promise for new file */
1966
1967 {
1968     afs_int32 code;
1969     struct rx_call *tcall = (struct rx_call *) tcon; 
1970 #if FS_STATS_DETAILED
1971     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
1972     struct timeval opStartTime,
1973                    opStopTime;              /* Start/stop times for RPC op*/
1974     struct timeval elapsedTime;             /* Transfer time */
1975
1976     /*
1977      * Set our stats pointer, remember when the RPC operation started, and
1978      * tally the operation.
1979      */
1980     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_CREATEFILE]);
1981     FS_LOCK
1982     (opP->numOps)++;
1983     FS_UNLOCK
1984     TM_GetTimeOfDay(&opStartTime, 0);
1985 #endif /* FS_STATS_DETAILED */
1986
1987     if (code = CallPreamble((struct rx_call **) &tcon, ACTIVECALL))
1988         goto Bad_CreateFile;
1989
1990     code = SAFSS_CreateFile (tcon, DirFid, Name, InStatus, OutFid,
1991                             OutFidStatus, OutDirStatus, CallBack, Sync);
1992
1993 Bad_CreateFile:    
1994     CallPostamble(tcon);
1995
1996 #if FS_STATS_DETAILED
1997     TM_GetTimeOfDay(&opStopTime, 0);
1998     if (code == 0) {
1999       FS_LOCK
2000       (opP->numSuccesses)++;
2001       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2002       fs_stats_AddTo((opP->sumTime), elapsedTime);
2003       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2004       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2005         fs_stats_TimeAssign((opP->minTime), elapsedTime);
2006       }
2007       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2008         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2009       }
2010       FS_UNLOCK
2011     }
2012 #endif /* FS_STATS_DETAILED */
2013
2014     osi_auditU (tcall, CreateFileEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_END);
2015     return code;
2016
2017 } /*SRXAFS_CreateFile*/
2018
2019
2020 /*
2021  * This routine is called exclusively from SRXAFS_Rename(), and should be
2022  * merged in when possible.
2023  */
2024 SAFSS_Rename (tcon, OldDirFid, OldName, NewDirFid, NewName, OutOldDirStatus,
2025              OutNewDirStatus, Sync)
2026     struct rx_connection *tcon;             /* Rx connection handle */
2027     struct AFSFid *OldDirFid;               /* From parent dir's fid */
2028     char *OldName;                          /* From file name */
2029     struct AFSFid *NewDirFid;               /* To parent dir's fid */
2030     char *NewName;                          /* To new file name */
2031     struct AFSFetchStatus *OutOldDirStatus; /* Output status for From parent dir */
2032     struct AFSFetchStatus *OutNewDirStatus; /* Output status for To parent dir */
2033     struct AFSVolSync *Sync;
2034
2035 {
2036     Vnode * oldvptr = 0;        /* vnode of the old Directory */
2037     Vnode * newvptr = 0;        /* vnode of the new Directory */
2038     Vnode * fileptr = 0;        /* vnode of the file to move */
2039     Vnode * newfileptr = 0;     /* vnode of the file to delete */
2040     Vnode * testvptr = 0;       /* used in directory tree walk */
2041     Vnode * parent = 0;         /* parent for use in SetAccessList */
2042     int     errorCode = 0;      /* error code */
2043     int     fileCode = 0;       /* used when writing Vnodes */
2044     VnodeId testnode;           /* used in directory tree walk */
2045     AFSFid fileFid;             /* Fid of file to move */
2046     AFSFid newFileFid;          /* Fid of new file */
2047     DirHandle olddir;           /* Handle for dir package I/O */
2048     DirHandle newdir;           /* Handle for dir package I/O */
2049     DirHandle filedir;          /* Handle for dir package I/O */
2050     DirHandle newfiledir;       /* Handle for dir package I/O */
2051     Volume * volptr = 0;        /* pointer to the volume header */
2052     struct client * client;     /* pointer to client structure */
2053     afs_int32 rights, anyrights;        /* rights for this and any user */
2054     afs_int32 newrights;                /* rights for this user */
2055     afs_int32 newanyrights;             /* rights for any user */
2056     int doDelete;               /* deleted the rename target (ref count now 0) */
2057     int code;
2058     struct client *t_client;            /* tmp ptr to client data */
2059     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
2060
2061     /* Get ptr to client data for user Id for logging */
2062     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
2063     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
2064     ViceLog(1, ("SAFS_Rename %s to %s,  Fid = %u.%d.%d to %u.%d.%d, Host %s, Id %d\n",
2065             OldName, NewName, OldDirFid->Volume, OldDirFid->Vnode,
2066             OldDirFid->Unique, NewDirFid->Volume, NewDirFid->Vnode,
2067             NewDirFid->Unique,
2068             inet_ntoa(logHostAddr), t_client->ViceId));
2069     FS_LOCK
2070     AFSCallStats.Rename++, AFSCallStats.TotalCalls++;
2071     FS_UNLOCK
2072     if (!FileNameOK(NewName)) {
2073         errorCode = EINVAL;
2074         goto Bad_Rename;
2075     }
2076     if (OldDirFid->Volume != NewDirFid->Volume) {
2077         DFlush();
2078         errorCode = EXDEV;
2079         goto Bad_Rename;
2080     }
2081     if ( (strcmp(OldName, ".") == 0) || (strcmp(OldName, "..") == 0) ||
2082          (strcmp(NewName, ".") == 0) || (strcmp(NewName, "..") == 0) || 
2083          (strlen(NewName) == 0) || (strlen(OldName) == 0)  ) {
2084         DFlush();
2085         errorCode = EINVAL;
2086         goto Bad_Rename;
2087     }
2088
2089     if (OldDirFid->Vnode <= NewDirFid->Vnode) {
2090         if  (errorCode = GetVolumePackage(tcon, OldDirFid, &volptr,
2091                                           &oldvptr, MustBeDIR, &parent,
2092                                           &client, WRITE_LOCK, &rights,
2093                                           &anyrights)) {
2094             DFlush();
2095             goto Bad_Rename;
2096         }
2097         if (OldDirFid->Vnode == NewDirFid->Vnode) {
2098             newvptr = oldvptr;
2099             newrights = rights, newanyrights = anyrights;
2100         }
2101         else
2102             if (errorCode = GetVolumePackage(tcon, NewDirFid, &volptr,
2103                                              &newvptr, MustBeDIR, &parent,
2104                                              &client, WRITE_LOCK, &newrights,
2105                                              &newanyrights)) {
2106                 DFlush();
2107                 goto Bad_Rename;
2108             }
2109     }
2110     else {
2111         if (errorCode = GetVolumePackage(tcon, NewDirFid, &volptr,
2112                                          &newvptr, MustBeDIR, &parent,
2113                                          &client, WRITE_LOCK, &newrights,
2114                                          &newanyrights)) {
2115             DFlush();
2116             goto Bad_Rename;
2117         }
2118         if (errorCode = GetVolumePackage(tcon, OldDirFid, &volptr, &oldvptr,
2119                                          MustBeDIR, &parent, &client, WRITE_LOCK,
2120                                          &rights, &anyrights)) {
2121             DFlush();
2122             goto Bad_Rename;
2123         }
2124     }
2125
2126     /* set volume synchronization information */
2127     SetVolumeSync(Sync, volptr);
2128
2129     if (errorCode = CheckWriteMode(oldvptr, rights, PRSFS_DELETE)) {
2130         goto Bad_Rename;
2131     }
2132     if (errorCode = CheckWriteMode(newvptr, newrights, PRSFS_INSERT)) {
2133         goto Bad_Rename;
2134     }
2135
2136     /* The CopyOnWrite might return ENOSPC ( disk full). Even if the second
2137     *  call to CopyOnWrite returns error, it is not necessary to revert back
2138     *  the effects of the first call because the contents of the volume is 
2139     *  not modified, it is only replicated.
2140     */
2141     if (oldvptr->disk.cloned)
2142     {
2143         ViceLog(25, ("Rename : calling CopyOnWrite on  old dir\n"));
2144          if ( errorCode = CopyOnWrite(oldvptr, volptr) )
2145                 goto Bad_Rename;
2146     }
2147     SetDirHandle(&olddir, oldvptr);
2148     if (newvptr->disk.cloned)
2149     {
2150         ViceLog(25, ("Rename : calling CopyOnWrite on  new dir\n"));
2151         if ( errorCode = CopyOnWrite(newvptr, volptr) )
2152                 goto Bad_Rename;        
2153     }
2154
2155     SetDirHandle(&newdir, newvptr);
2156
2157     /* Lookup the file to delete its vnode */
2158     if (Lookup(&olddir, OldName, &fileFid)) {
2159         errorCode = ENOENT;
2160         goto Bad_Rename;
2161     }
2162     if (fileFid.Vnode == oldvptr->vnodeNumber ||
2163         fileFid.Vnode == newvptr->vnodeNumber) {
2164         errorCode = FSERR_ELOOP;
2165         goto Bad_Rename;
2166     }
2167     fileFid.Volume = V_id(volptr);
2168     fileptr = VGetVnode(&errorCode, volptr, fileFid.Vnode, WRITE_LOCK);
2169     if (errorCode != 0) {
2170         ViceLog (0, ("SAFSS_Rename(): Error in VGetVnode() for old file %s, code %d\n", OldName, errorCode));
2171         VTakeOffline (volptr);
2172         goto Bad_Rename;
2173     }
2174     if (fileptr->disk.uniquifier != fileFid.Unique) {
2175         ViceLog (0, ("SAFSS_Rename(): Old file %s uniquifier mismatch\n", OldName));
2176         VTakeOffline (volptr);
2177         errorCode = EIO;
2178         goto Bad_Rename;
2179     }
2180
2181     if (fileptr->disk.type != vDirectory &&
2182         oldvptr != newvptr &&
2183         fileptr->disk.linkCount != 1) {
2184         /*
2185          * Hard links exist to this file - cannot move one of the links to
2186          * a new directory because of AFS restrictions (this is the same
2187          * reason that links cannot be made across directories, i.e.
2188          * access lists)
2189          */
2190         errorCode = EXDEV;
2191         goto Bad_Rename;
2192     }
2193
2194     /* Lookup the new file  */
2195     if (!(Lookup(&newdir, NewName, &newFileFid))) {
2196         if (!(newrights & PRSFS_DELETE)) {
2197             errorCode = EACCES;
2198             goto Bad_Rename;
2199         }
2200         if (newFileFid.Vnode == oldvptr->vnodeNumber ||
2201                 newFileFid.Vnode == newvptr->vnodeNumber ||
2202                 newFileFid.Vnode == fileFid.Vnode) {
2203             errorCode = EINVAL;
2204             goto Bad_Rename;
2205         }
2206         newFileFid.Volume = V_id(volptr);
2207         newfileptr = VGetVnode(&errorCode, volptr, newFileFid.Vnode, WRITE_LOCK);
2208         if (errorCode != 0) {
2209             ViceLog (0, ("SAFSS_Rename(): Error in VGetVnode() for new file %s, code %d\n", NewName, errorCode));
2210             VTakeOffline (volptr);
2211             goto Bad_Rename;
2212         }
2213         if (fileptr->disk.uniquifier != fileFid.Unique) {
2214             ViceLog (0, ("SAFSS_Rename(): New file %s uniquifier mismatch\n", NewName));
2215             VTakeOffline (volptr);
2216             errorCode = EIO;
2217             goto Bad_Rename;
2218         }
2219         SetDirHandle(&newfiledir, newfileptr);
2220         /* Now check that we're moving directories over directories properly, etc.
2221          * return proper POSIX error codes:
2222          * if fileptr is a file and new is a dir: EISDIR.
2223          * if fileptr is a dir and new is a file: ENOTDIR.
2224          * Also, dir to be removed must be empty, of course.
2225          */
2226         if (newfileptr->disk.type == vDirectory) {
2227             if (fileptr->disk.type != vDirectory) {
2228                 errorCode = EISDIR;
2229                 goto Bad_Rename;
2230             }
2231             if ((IsEmpty(&newfiledir))) {
2232                 errorCode = EEXIST;
2233                 goto Bad_Rename;
2234             }
2235         }
2236         else {
2237             if (fileptr->disk.type == vDirectory) {
2238                 errorCode = ENOTDIR;
2239                 goto Bad_Rename;
2240             }
2241         }
2242     }
2243
2244     /*
2245      * ok - now we check that the old name is not above new name in the
2246      * directory structure.  This is to prevent removing a subtree alltogether
2247      */
2248     if ((oldvptr != newvptr) && (fileptr->disk.type == vDirectory)) {
2249         for (testnode = newvptr->disk.parent; testnode != 0;) {
2250             if (testnode == oldvptr->vnodeNumber) {
2251                 testnode = oldvptr->disk.parent;
2252                 continue;
2253             }
2254             if ((testnode == fileptr->vnodeNumber) ||
2255                 (testnode == newvptr->vnodeNumber)) {
2256                 errorCode = FSERR_ELOOP;
2257                 goto Bad_Rename;
2258             }
2259             if ((newfileptr) && (testnode == newfileptr->vnodeNumber)) {
2260                 errorCode = FSERR_ELOOP;
2261                 goto Bad_Rename;
2262             }
2263             testvptr = VGetVnode(&errorCode, volptr, testnode, READ_LOCK);
2264             assert(errorCode == 0);
2265             testnode = testvptr->disk.parent;
2266             VPutVnode(&errorCode, testvptr);
2267             assert(errorCode == 0);
2268         }
2269     }
2270     /* Do the CopyonWrite first before modifying anything else. Copying is
2271      *  required because we may have to change entries for .. 
2272      */
2273     if ((fileptr->disk.type == vDirectory ) && (fileptr->disk.cloned) )
2274     {
2275         ViceLog(25, ("Rename : calling CopyOnWrite on  target dir\n"));
2276         if ( errorCode = CopyOnWrite(fileptr, volptr) )
2277                 goto Bad_Rename;
2278     }
2279
2280     /* If the new name exists already, delete it and the file it points to */
2281     doDelete = 0;
2282     if (newfileptr) {
2283         /* Delete NewName from its directory */
2284         code = Delete(&newdir, NewName);
2285         assert(code == 0);
2286
2287         /* Drop the link count */
2288         newfileptr->disk.linkCount--;
2289         if (newfileptr->disk.linkCount == 0) {      /* Link count 0 - delete */
2290             VAdjustDiskUsage(&errorCode, volptr,
2291                              -(int)nBlocks(newfileptr->disk.length), 0);
2292             if (VN_GET_INO(newfileptr)) {
2293                 IH_REALLYCLOSE(newfileptr->handle);
2294                 errorCode = IH_DEC(V_linkHandle(volptr),
2295                                  VN_GET_INO(newfileptr),
2296                                  V_parentId(volptr));
2297                 IH_RELEASE(newfileptr->handle);
2298                 if (errorCode == -1) {
2299                     ViceLog(0, ("Del: inode=%d, name=%s, errno=%d\n",
2300                                 PrintInode(NULL, VN_GET_INO(newfileptr)),
2301                                 NewName, errno));
2302                     if ((errno != ENOENT) && (errno != EIO) && (errno != ENXIO))
2303                         ViceLog(0, ("Do we need to fsck?"));
2304                 } 
2305             }
2306             VN_SET_INO(newfileptr, (Inode)0);
2307             newfileptr->delete = 1;         /* Mark NewName vnode to delete */
2308             doDelete = 1;
2309         } else {
2310             /* Link count did not drop to zero.
2311              * Mark NewName vnode as changed - updates stime.
2312              */
2313             newfileptr->changed_newTime = 1;
2314         }
2315     }
2316     
2317     /*
2318      * If the create below fails, and the delete above worked, we have
2319      * removed the new name and not replaced it.  This is not very likely,
2320      * but possible.  We could try to put the old file back, but it is
2321      * highly unlikely that it would work since it would involve issuing
2322      * another create.
2323      */
2324     if (errorCode = Create(&newdir,(char *) NewName, &fileFid))
2325         goto Bad_Rename;
2326
2327     /* Delete the old name */
2328     assert(Delete(&olddir,(char *) OldName) == 0);
2329
2330     /* if the directory length changes, reflect it in the statistics */
2331 #if FS_STATS_DETAILED
2332     Update_ParentVnodeStatus(oldvptr, volptr, &olddir, client->ViceId,
2333                              oldvptr->disk.linkCount, client->InSameNetwork);
2334     Update_ParentVnodeStatus(newvptr, volptr, &newdir, client->ViceId,
2335                              newvptr->disk.linkCount, client->InSameNetwork);
2336 #else
2337     Update_ParentVnodeStatus(oldvptr, volptr, &olddir, client->ViceId,
2338                              oldvptr->disk.linkCount);
2339     Update_ParentVnodeStatus(newvptr, volptr, &newdir, client->ViceId,
2340                              newvptr->disk.linkCount);
2341 #endif /* FS_STATS_DETAILED */
2342
2343     if (oldvptr == newvptr)
2344         oldvptr->disk.dataVersion--;    /* Since it was bumped by 2! */
2345
2346     fileptr->disk.parent = newvptr->vnodeNumber;
2347     fileptr->changed_newTime = 1;       /* status change of moved file */
2348
2349     /* if we are dealing with a rename of a directory */
2350     if (fileptr->disk.type == vDirectory) {
2351         assert(!fileptr->disk.cloned);          
2352         SetDirHandle(&filedir, fileptr);
2353         /* fix .. to point to the correct place */
2354         Delete(&filedir, ".."); /* No assert--some directories may be bad */
2355         assert(Create(&filedir, "..", NewDirFid) == 0);
2356         fileptr->disk.dataVersion++;
2357         /* if the parent directories are different the link counts have to be   */
2358         /* changed due to .. in the renamed directory */
2359         if (oldvptr != newvptr) {
2360             oldvptr->disk.linkCount--;
2361             newvptr->disk.linkCount++;
2362         }
2363     }
2364
2365     /* set up return status */
2366     GetStatus(oldvptr, OutOldDirStatus, rights, anyrights, (struct vnode *)0);
2367     GetStatus(newvptr, OutNewDirStatus, newrights, newanyrights, (struct vnode *)0);
2368     if (newfileptr && doDelete) {
2369         DeleteFileCallBacks(&newFileFid);       /* no other references */
2370     }
2371
2372     DFlush();
2373
2374     /* convert the write locks to a read locks before breaking callbacks */
2375     VVnodeWriteToRead(&errorCode, newvptr);
2376     assert(!errorCode || errorCode == VSALVAGE);
2377     if (oldvptr != newvptr) {
2378         VVnodeWriteToRead(&errorCode, oldvptr);
2379         assert(!errorCode || errorCode == VSALVAGE);
2380     }
2381     if (newfileptr && !doDelete) {
2382         /* convert the write lock to a read lock before breaking callbacks */
2383         VVnodeWriteToRead(&errorCode, newfileptr);
2384         assert(!errorCode || errorCode == VSALVAGE);
2385     }
2386
2387     /* break call back on NewDirFid, OldDirFid, NewDirFid and newFileFid  */
2388     BreakCallBack(client->host, NewDirFid, 0);
2389     if (oldvptr != newvptr) {
2390         BreakCallBack(client->host, OldDirFid, 0);
2391         if (fileptr->disk.type == vDirectory) /* if a dir moved, .. changed */
2392             BreakCallBack(client->host, &fileFid, 0);
2393     }
2394     if (newfileptr) {
2395         /* Note:  it is not necessary to break the callback */
2396         if (doDelete)
2397             DeleteFileCallBacks(&newFileFid);   /* no other references */
2398         else
2399             /* other's still exist (with wrong link count) */
2400             BreakCallBack(client->host, &newFileFid, 1);
2401     }
2402
2403 Bad_Rename: 
2404     if (newfileptr) {
2405         VPutVnode(&fileCode, newfileptr);
2406         assert(fileCode == 0);
2407     }
2408     PutVolumePackage(fileptr, (newvptr && newvptr != oldvptr? newvptr : 0),
2409                      oldvptr, volptr);
2410     ViceLog(2, ("SAFS_Rename returns %d\n", errorCode));
2411     return errorCode;
2412
2413 } /*SAFSS_Rename*/
2414
2415
2416 SRXAFS_Rename (tcon, OldDirFid, OldName, NewDirFid, NewName, OutOldDirStatus, OutNewDirStatus, Sync)
2417     struct AFSVolSync *Sync;
2418     struct rx_connection *tcon;              /* Rx connection handle */
2419     struct AFSFid *OldDirFid;                /* From parent dir's fid */
2420     char *OldName;                           /* From file name */
2421     struct AFSFid *NewDirFid;                /* To parent dir's fid */
2422     char *NewName;                           /* To new file name */
2423     struct AFSFetchStatus *OutOldDirStatus;  /* Output status for From parent dir */
2424     struct AFSFetchStatus *OutNewDirStatus;  /* Output status for To parent dir */
2425
2426 {
2427     afs_int32 code;
2428     struct rx_call *tcall = (struct rx_call *) tcon; 
2429 #if FS_STATS_DETAILED
2430     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
2431     struct timeval opStartTime,
2432                    opStopTime;              /* Start/stop times for RPC op*/
2433     struct timeval elapsedTime;             /* Transfer time */
2434
2435     /*
2436      * Set our stats pointer, remember when the RPC operation started, and
2437      * tally the operation.
2438      */
2439     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_RENAME]);
2440     FS_LOCK
2441     (opP->numOps)++;
2442     FS_UNLOCK
2443     TM_GetTimeOfDay(&opStartTime, 0);
2444 #endif /* FS_STATS_DETAILED */
2445
2446     if (code = CallPreamble((struct rx_call **) &tcon, ACTIVECALL))
2447         goto Bad_Rename;
2448
2449     code = SAFSS_Rename (tcon, OldDirFid, OldName, NewDirFid, NewName,
2450                          OutOldDirStatus, OutNewDirStatus, Sync);
2451
2452 Bad_Rename:    
2453     CallPostamble(tcon);
2454
2455 #if FS_STATS_DETAILED
2456     TM_GetTimeOfDay(&opStopTime, 0);
2457     if (code == 0) {
2458       FS_LOCK
2459       (opP->numSuccesses)++;
2460       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2461       fs_stats_AddTo((opP->sumTime), elapsedTime);
2462       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2463       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2464         fs_stats_TimeAssign((opP->minTime), elapsedTime);
2465       }
2466       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2467         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2468       }
2469       FS_UNLOCK
2470     }
2471
2472 #endif /* FS_STATS_DETAILED */
2473
2474     osi_auditU (tcall, RenameFileEvent, code, AUD_FID, OldDirFid, AUD_STR, OldName, AUD_FID, NewDirFid, AUD_STR, NewName, AUD_END);
2475     return code;
2476
2477 } /*SRXAFS_Rename*/
2478
2479
2480 /*
2481  * This routine is called exclusively by SRXAFS_Symlink(), and should be
2482  * merged into it when possible.
2483  */
2484 SAFSS_Symlink (tcon, DirFid, Name, LinkContents, InStatus, OutFid, OutFidStatus, OutDirStatus, Sync)
2485     struct rx_connection *tcon;          /* Rx connection handle */
2486     struct AFSFid *DirFid;               /* Parent dir's fid */
2487     char *Name;                          /* File name to create */
2488     char *LinkContents;                  /* Contents of the new created file */
2489     struct AFSStoreStatus *InStatus;     /* Input status for the new symbolic link */
2490     struct AFSFid *OutFid;               /* Fid for newly created symbolic link */
2491     struct AFSFetchStatus *OutFidStatus; /* Output status for new symbolic link */
2492     struct AFSFetchStatus *OutDirStatus; /* Output status for parent dir */
2493     struct AFSVolSync *Sync;             /* volume synchronization information */
2494
2495 {
2496     Vnode * parentptr = 0;              /* vnode of input Directory */
2497     Vnode * targetptr = 0;              /* vnode of the new link */
2498     Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
2499     int     errorCode = 0;              /* error code */
2500     int code = 0;
2501     DirHandle dir;                      /* Handle for dir package I/O */
2502     Volume * volptr = 0;                /* pointer to the volume header */
2503     struct client * client;             /* pointer to client structure */
2504     afs_int32 rights, anyrights, fd;    /* rights for this and any user */
2505     struct client *t_client;            /* tmp ptr to client data */
2506     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
2507     FdHandle_t *fdP;
2508
2509     /* Get ptr to client data for user Id for logging */
2510     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
2511     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
2512     ViceLog(1, ("SAFS_Symlink %s to %s,  Did = %u.%d.%d, Host %s, Id %d\n", Name,
2513             LinkContents, DirFid->Volume, DirFid->Vnode, DirFid->Unique,
2514             inet_ntoa(logHostAddr), t_client->ViceId));
2515     FS_LOCK
2516     AFSCallStats.Symlink++, AFSCallStats.TotalCalls++;
2517     FS_UNLOCK
2518     if (!FileNameOK(Name)) {
2519         errorCode = EINVAL;
2520         goto Bad_SymLink;
2521     }
2522
2523     /*
2524      * Get the vnode and volume for the parent dir along with the caller's
2525      * rights to it
2526      */
2527     if (errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr,
2528                                      MustBeDIR, &parentwhentargetnotdir,
2529                                      &client, WRITE_LOCK, &rights, &anyrights)) {
2530         goto Bad_SymLink;
2531     }
2532
2533     /* set volume synchronization information */
2534     SetVolumeSync(Sync, volptr);
2535
2536     /* Does the caller has insert (and write) access to the parent directory? */
2537     if (errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT)) {
2538         goto Bad_SymLink;
2539     }
2540
2541     /*
2542      * If we're creating a mount point (any x bits clear), we must have
2543      * administer access to the directory, too.  Always allow sysadmins
2544      * to do this.
2545      */
2546     if ((InStatus->Mask & AFS_SETMODE) && !(InStatus->UnixModeBits & 0111)) {
2547         /*
2548          * We have a mountpoint, 'cause we're trying to set the Unix mode
2549          * bits to something with some x bits missing (default mode bits
2550          * if AFS_SETMODE is false is 0777)
2551          */
2552         if (VanillaUser(client) && !(rights & PRSFS_ADMINISTER)) {
2553             errorCode = EACCES;
2554             goto Bad_SymLink;
2555         }
2556     }
2557  
2558     /* get a new vnode for the symlink and set it up */
2559     if (errorCode = Alloc_NewVnode(parentptr, &dir, volptr, &targetptr,
2560                                    Name, OutFid, vSymlink,
2561                                    nBlocks(strlen((char *) LinkContents)))) {
2562         goto Bad_SymLink;
2563     }
2564
2565     /* update the status of the parent vnode */
2566 #if FS_STATS_DETAILED
2567     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
2568                              parentptr->disk.linkCount, client->InSameNetwork);
2569 #else
2570     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
2571                              parentptr->disk.linkCount);
2572 #endif /* FS_STATS_DETAILED */
2573
2574     /* update the status of the new symbolic link file vnode */
2575     Update_TargetVnodeStatus(targetptr, TVS_SLINK, client, InStatus, parentptr,
2576                              volptr, strlen((char *)LinkContents));
2577
2578     /* Write the contents of the symbolic link name into the target inode */
2579     fdP = IH_OPEN(targetptr->handle);
2580     assert(fdP != NULL);
2581     assert(FDH_WRITE(fdP, (char *) LinkContents, strlen((char *) LinkContents)) == strlen((char *) LinkContents));
2582     FDH_CLOSE(fdP);
2583     /*
2584      * Set up and return modified status for the parent dir and new symlink
2585      * to caller.
2586      */
2587     GetStatus(targetptr, OutFidStatus, rights, anyrights, parentptr);
2588     GetStatus(parentptr, OutDirStatus, rights, anyrights, (struct vnode *)0);
2589
2590     /* convert the write lock to a read lock before breaking callbacks */
2591     VVnodeWriteToRead(&errorCode, parentptr);
2592     assert(!errorCode || errorCode == VSALVAGE);
2593
2594     /* break call back on the parent dir */
2595     BreakCallBack(client->host, DirFid, 0);
2596
2597 Bad_SymLink: 
2598     /* Write the all modified vnodes (parent, new files) and volume back */
2599     PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr);
2600     ViceLog(2, ("SAFS_Symlink returns %d\n", errorCode));
2601     return errorCode;
2602
2603 } /*SAFSS_Symlink*/
2604
2605
2606 SRXAFS_Symlink (tcon, DirFid, Name, LinkContents, InStatus, OutFid, OutFidStatus, OutDirStatus, Sync)
2607     struct AFSVolSync *Sync;
2608     struct rx_connection *tcon;          /* Rx connection handle */
2609     struct AFSFid *DirFid;               /* Parent dir's fid */
2610     char *Name;                          /* File name to create */
2611     char *LinkContents;                  /* Contents of the new created file */
2612     struct AFSStoreStatus *InStatus;     /* Input status for the new symbolic link */
2613     struct AFSFid *OutFid;               /* Fid for newly created symbolic link */
2614     struct AFSFetchStatus *OutFidStatus; /* Output status for new symbolic link */
2615     struct AFSFetchStatus *OutDirStatus; /* Output status for parent dir */
2616
2617 {
2618     afs_int32 code;
2619     struct rx_call *tcall = (struct rx_call *) tcon; 
2620 #if FS_STATS_DETAILED
2621     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
2622     struct timeval opStartTime,
2623                    opStopTime;              /* Start/stop times for RPC op*/
2624     struct timeval elapsedTime;             /* Transfer time */
2625
2626     /*
2627      * Set our stats pointer, remember when the RPC operation started, and
2628      * tally the operation.
2629      */
2630     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_SYMLINK]);
2631     FS_LOCK
2632     (opP->numOps)++;
2633     FS_UNLOCK
2634     TM_GetTimeOfDay(&opStartTime, 0);
2635 #endif /* FS_STATS_DETAILED */
2636
2637     if (code = CallPreamble((struct rx_call **) &tcon, ACTIVECALL))
2638         goto Bad_Symlink;
2639
2640     code = SAFSS_Symlink (tcon, DirFid, Name, LinkContents, InStatus, OutFid,
2641                          OutFidStatus, OutDirStatus, Sync);
2642
2643 Bad_Symlink:    
2644     CallPostamble(tcon);
2645
2646 #if FS_STATS_DETAILED
2647     TM_GetTimeOfDay(&opStopTime, 0);
2648     if (code == 0) {
2649       FS_LOCK
2650       (opP->numSuccesses)++;
2651       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2652       fs_stats_AddTo((opP->sumTime), elapsedTime);
2653       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2654       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2655         fs_stats_TimeAssign((opP->minTime), elapsedTime);
2656       }
2657       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2658         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2659       }
2660       FS_UNLOCK
2661     }
2662
2663 #endif /* FS_STATS_DETAILED */
2664
2665     osi_auditU (tcall, SymlinkEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_END);
2666     return code;
2667
2668 } /*SRXAFS_Symlink*/
2669
2670
2671 /*
2672  * This routine is called exclusively by SRXAFS_Link(), and should be
2673  * merged into it when possible.
2674  */
2675 SAFSS_Link (tcon, DirFid, Name, ExistingFid, OutFidStatus, OutDirStatus, Sync)
2676     struct rx_connection *tcon;          /* Rx connection handle */
2677     struct AFSFid *DirFid;               /* Parent dir's fid */
2678     char *Name;                          /* File name to create */
2679     struct AFSFid *ExistingFid;          /* Fid of existing fid we'll make link to */
2680     struct AFSFetchStatus *OutFidStatus; /* Output status for newly created file */
2681     struct AFSFetchStatus *OutDirStatus; /* Outpout status for parent dir */
2682     struct AFSVolSync *Sync;
2683
2684 {
2685     Vnode * parentptr = 0;              /* vnode of input Directory */
2686     Vnode * targetptr = 0;              /* vnode of the new file */
2687     Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
2688     Volume * volptr = 0;                /* pointer to the volume header */
2689     int     errorCode = 0;              /* error code */
2690     DirHandle dir;                      /* Handle for dir package I/O */
2691     struct client * client;             /* pointer to client structure */
2692     afs_int32 rights, anyrights;                /* rights for this and any user */
2693     struct client *t_client;            /* tmp ptr to client data */
2694     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
2695
2696     /* Get ptr to client data for user Id for logging */
2697     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
2698     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
2699     ViceLog(1, ("SAFS_Link %s,  Did = %u.%d.%d, Fid = %u.%d.%d, Host %s, Id %d\n",
2700             Name, DirFid->Volume, DirFid->Vnode, DirFid->Unique,
2701             ExistingFid->Volume, ExistingFid->Vnode, ExistingFid->Unique,
2702             inet_ntoa(logHostAddr), t_client->ViceId));
2703     FS_LOCK
2704     AFSCallStats.Link++, AFSCallStats.TotalCalls++;
2705     FS_UNLOCK
2706     if (DirFid->Volume != ExistingFid->Volume) {
2707         errorCode = EXDEV;
2708         goto Bad_Link;
2709     }
2710     if (!FileNameOK(Name)) {
2711         errorCode = EINVAL;
2712         goto Bad_Link;
2713     }
2714
2715     /*
2716      * Get the vnode and volume for the parent dir along with the caller's
2717      * rights to it
2718      */
2719     if (errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr,
2720                                      MustBeDIR, &parentwhentargetnotdir,
2721                                      &client, WRITE_LOCK, &rights, &anyrights)) {
2722         goto Bad_Link;
2723     }
2724
2725     /* set volume synchronization information */
2726     SetVolumeSync(Sync, volptr);
2727
2728     /* Can the caller insert into the parent directory? */
2729     if (errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT)) {
2730         goto Bad_Link;
2731     }
2732
2733     if (((DirFid->Vnode & 1) && (ExistingFid->Vnode & 1)) ||
2734         (DirFid->Vnode == ExistingFid->Vnode)) {  /* at present, */
2735       /* AFS fileservers always have directory vnodes that are odd.   */
2736       errorCode = EISDIR;
2737       goto Bad_Link;
2738     }
2739
2740     /* get the file vnode  */
2741     if (errorCode = CheckVnode(ExistingFid, &volptr, &targetptr, WRITE_LOCK)) {
2742         goto Bad_Link;
2743     }
2744     if (targetptr->disk.type != vFile) {
2745         errorCode = EISDIR;
2746         goto Bad_Link;
2747     }
2748     if (targetptr->disk.parent != DirFid->Vnode) {
2749         errorCode = EXDEV;
2750         goto Bad_Link;
2751     }
2752     if (parentptr->disk.cloned) 
2753     {
2754         ViceLog(25, ("Link : calling CopyOnWrite on  target dir\n"));
2755         if ( errorCode = CopyOnWrite(parentptr, volptr))
2756                 goto Bad_Link;          /* disk full error */
2757     }
2758
2759     /* add the name to the directory */
2760     SetDirHandle(&dir, parentptr);
2761     if (errorCode = Create(&dir, (char *)Name, ExistingFid))
2762         goto Bad_Link;
2763     DFlush();
2764
2765     /* update the status in the parent vnode */
2766     /**WARNING** --> disk.author SHOULDN'T be modified???? */
2767 #if FS_STATS_DETAILED
2768     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
2769                              parentptr->disk.linkCount, client->InSameNetwork);
2770 #else
2771     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
2772                              parentptr->disk.linkCount);
2773 #endif /* FS_STATS_DETAILED */
2774
2775     targetptr->disk.linkCount++;
2776     targetptr->disk.author = client->ViceId;
2777     targetptr->changed_newTime = 1; /* Status change of linked-to file */
2778
2779     /* set up return status */
2780     GetStatus(targetptr, OutFidStatus, rights, anyrights, parentptr);
2781     GetStatus(parentptr, OutDirStatus, rights, anyrights, (struct vnode *)0);
2782
2783     /* convert the write locks to read locks before breaking callbacks */
2784     VVnodeWriteToRead(&errorCode, targetptr);
2785     assert(!errorCode || errorCode == VSALVAGE);
2786     VVnodeWriteToRead(&errorCode, parentptr);
2787     assert(!errorCode || errorCode == VSALVAGE);
2788     
2789     /* break call back on DirFid */
2790     BreakCallBack(client->host, DirFid, 0);
2791     /*
2792      * We also need to break the callback for the file that is hard-linked since part 
2793      * of its status (like linkcount) is changed
2794      */
2795     BreakCallBack(client->host, ExistingFid, 0);
2796
2797 Bad_Link:
2798     /* Write the all modified vnodes (parent, new files) and volume back */
2799     PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr);
2800     ViceLog(2, ("SAFS_Link returns %d\n", errorCode));
2801     return errorCode;
2802
2803 } /*SAFSS_Link*/
2804
2805
2806 SRXAFS_Link (tcon, DirFid, Name, ExistingFid, OutFidStatus, OutDirStatus, Sync)
2807     struct AFSVolSync *Sync;
2808     struct rx_connection *tcon;          /* Rx connection handle */
2809     struct AFSFid *DirFid;               /* Parent dir's fid */
2810     char *Name;                          /* File name to create */
2811     struct AFSFid *ExistingFid;          /* Fid of existing fid we'll make link to */
2812     struct AFSFetchStatus *OutFidStatus; /* Output status for newly created file */
2813     struct AFSFetchStatus *OutDirStatus; /* Outpout status for parent dir */
2814
2815 {
2816     afs_int32 code;
2817     struct rx_call *tcall = (struct rx_call *) tcon; 
2818 #if FS_STATS_DETAILED
2819     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
2820     struct timeval opStartTime,
2821                    opStopTime;              /* Start/stop times for RPC op*/
2822     struct timeval elapsedTime;             /* Transfer time */
2823
2824     /*
2825      * Set our stats pointer, remember when the RPC operation started, and
2826      * tally the operation.
2827      */
2828     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_LINK]);
2829     FS_LOCK
2830     (opP->numOps)++;
2831     FS_UNLOCK
2832     TM_GetTimeOfDay(&opStartTime, 0);
2833 #endif /* FS_STATS_DETAILED */
2834
2835     if (code = CallPreamble((struct rx_call **) &tcon, ACTIVECALL))
2836         goto Bad_Link;
2837
2838     code = SAFSS_Link (tcon, DirFid, Name, ExistingFid, OutFidStatus,
2839                       OutDirStatus, Sync);
2840     
2841 Bad_Link:
2842     CallPostamble(tcon);
2843
2844 #if FS_STATS_DETAILED
2845     TM_GetTimeOfDay(&opStopTime, 0);
2846     if (code == 0) {
2847       FS_LOCK
2848       (opP->numSuccesses)++;
2849       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2850       fs_stats_AddTo((opP->sumTime), elapsedTime);
2851       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2852       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2853         fs_stats_TimeAssign((opP->minTime), elapsedTime);
2854       }
2855       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2856         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2857       }
2858       FS_UNLOCK
2859     }
2860
2861 #endif /* FS_STATS_DETAILED */
2862
2863     osi_auditU (tcall, LinkEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_FID, ExistingFid, AUD_END);
2864     return code;
2865
2866 } /*SRXAFS_Link*/
2867
2868
2869 /*
2870  * This routine is called exclusively by SRXAFS_MakeDir(), and should be
2871  * merged into it when possible.
2872  */
2873 SAFSS_MakeDir (tcon, DirFid, Name, InStatus, OutFid, OutFidStatus,
2874               OutDirStatus, CallBack, Sync)
2875     struct rx_connection *tcon;          /* Rx connection handle */
2876     struct AFSFid *DirFid;               /* Parent dir's fid */
2877     char *Name;                          /* Name of dir to be created */
2878     struct AFSStoreStatus *InStatus;     /* Input status for new dir */
2879     struct AFSFid *OutFid;               /* Fid of new dir */
2880     struct AFSFetchStatus *OutFidStatus; /* Output status for new directory */
2881     struct AFSFetchStatus *OutDirStatus; /* Output status for parent dir */
2882     struct AFSCallBack *CallBack;        /* Returned callback promise for new dir */
2883     struct AFSVolSync *Sync;
2884
2885 {
2886     Vnode * parentptr = 0;              /* vnode of input Directory */
2887     Vnode * targetptr = 0;              /* vnode of the new file */
2888     Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
2889     Volume * volptr = 0;                /* pointer to the volume header */
2890     int     errorCode = 0;              /* error code */
2891     struct acl_accessList * newACL;     /* Access list */
2892     int     newACLSize;                 /* Size of access list */
2893     DirHandle dir;                      /* Handle for dir package I/O */
2894     DirHandle parentdir;                /* Handle for dir package I/O */
2895     struct client * client;             /* pointer to client structure */
2896     afs_int32 rights, anyrights;                /* rights for this and any user */
2897     struct client *t_client;            /* tmp ptr to client data */
2898     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
2899
2900     /* Get ptr to client data for user Id for logging */
2901     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
2902     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
2903     ViceLog(1, ("SAFS_MakeDir %s,  Did = %u.%d.%d, Host %s, Id %d\n",
2904             Name, DirFid->Volume, DirFid->Vnode, DirFid->Unique,
2905             inet_ntoa(logHostAddr), t_client->ViceId));
2906     FS_LOCK
2907     AFSCallStats.MakeDir++, AFSCallStats.TotalCalls++;    
2908     FS_UNLOCK
2909     if (!FileNameOK(Name)) {
2910         errorCode = EINVAL;
2911         goto Bad_MakeDir;
2912     }
2913
2914     /*
2915      * Get the vnode and volume for the parent dir along with the caller's
2916      * rights to it.
2917      */
2918     if (errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr,
2919                                      MustBeDIR, &parentwhentargetnotdir,
2920                                      &client, WRITE_LOCK, &rights, &anyrights)) {
2921         goto Bad_MakeDir;
2922     }
2923  
2924     /* set volume synchronization information */
2925     SetVolumeSync(Sync, volptr);
2926
2927     /* Write access to the parent directory? */
2928 #ifdef DIRCREATE_NEED_WRITE
2929     /*
2930      * requires w access for the user to create a directory. this
2931      * closes a loophole in the current security arrangement, since a
2932      * user with i access only can create a directory and get the
2933      * implcit a access that goes with dir ownership, and proceed to 
2934      * subvert quota in the volume.
2935      */
2936     if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT)) ||
2937         (errorCode = CheckWriteMode(parentptr, rights, PRSFS_WRITE))) {
2938 #else 
2939     if (errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT)) {
2940 #endif /* DIRCREATE_NEED_WRITE */ 
2941         goto Bad_MakeDir;
2942     }
2943
2944 #define EMPTYDIRBLOCKS 2
2945     /* get a new vnode and set it up */
2946     if (errorCode = Alloc_NewVnode(parentptr, &parentdir, volptr, &targetptr,
2947                                    Name, OutFid, vDirectory, EMPTYDIRBLOCKS)) {
2948         goto Bad_MakeDir;
2949     }
2950
2951     /* Update the status for the parent dir */
2952 #if FS_STATS_DETAILED
2953     Update_ParentVnodeStatus(parentptr, volptr, &parentdir, client->ViceId,
2954                              parentptr->disk.linkCount+1, client->InSameNetwork);
2955 #else
2956     Update_ParentVnodeStatus(parentptr, volptr, &parentdir, client->ViceId,
2957                              parentptr->disk.linkCount+1);
2958 #endif /* FS_STATS_DETAILED */
2959
2960     /* Point to target's ACL buffer and copy the parent's ACL contents to it */
2961     assert((SetAccessList(&targetptr, &volptr, &newACL, &newACLSize,
2962                           &parentwhentargetnotdir, (AFSFid *)0, 0)) == 0);
2963     assert(parentwhentargetnotdir == 0);
2964     memcpy((char *)newACL, (char *)VVnodeACL(parentptr), VAclSize(parentptr));
2965
2966     /* update the status for the target vnode */
2967     Update_TargetVnodeStatus(targetptr, TVS_MKDIR, client, InStatus,
2968                              parentptr, volptr, 0);
2969
2970     /* Actually create the New directory in the directory package */
2971     SetDirHandle(&dir, targetptr);
2972     assert(!(MakeDir(&dir, OutFid, DirFid)));
2973     DFlush();
2974     targetptr->disk.length = Length(&dir);
2975
2976     /* set up return status */
2977     GetStatus(targetptr, OutFidStatus, rights, anyrights, parentptr);
2978     GetStatus(parentptr, OutDirStatus, rights, anyrights, (struct Vnode *)0);
2979
2980     /* convert the write lock to a read lock before breaking callbacks */
2981     VVnodeWriteToRead(&errorCode, parentptr);
2982     assert(!errorCode || errorCode == VSALVAGE);
2983
2984     /* break call back on DirFid */
2985     BreakCallBack(client->host, DirFid, 0);
2986
2987     /* Return a callback promise to caller */
2988     SetCallBackStruct(AddCallBack(client->host, OutFid), CallBack);
2989
2990 Bad_MakeDir: 
2991     /* Write the all modified vnodes (parent, new files) and volume back */
2992     PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr);
2993     ViceLog(2, ("SAFS_MakeDir returns %d\n", errorCode)); 
2994     return errorCode;
2995
2996 } /*SAFSS_MakeDir*/
2997
2998
2999 SRXAFS_MakeDir (tcon, DirFid, Name, InStatus, OutFid, OutFidStatus, OutDirStatus, CallBack, Sync)
3000     struct AFSVolSync *Sync;
3001     struct rx_connection *tcon;          /* Rx connection handle */
3002     struct AFSFid *DirFid;               /* Parent dir's fid */
3003     char *Name;                          /* Name of dir to be created */
3004     struct AFSStoreStatus *InStatus;     /* Input status for new dir */
3005     struct AFSFid *OutFid;               /* Fid of new dir */
3006     struct AFSFetchStatus *OutFidStatus; /* Output status for new directory */
3007     struct AFSFetchStatus *OutDirStatus; /* Output status for parent dir */
3008     struct AFSCallBack *CallBack;        /* Returned callback promise for new dir */
3009
3010 {
3011     afs_int32 code;
3012     struct rx_call *tcall = (struct rx_call *) tcon; 
3013 #if FS_STATS_DETAILED
3014     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
3015     struct timeval opStartTime,
3016                    opStopTime;              /* Start/stop times for RPC op*/
3017     struct timeval elapsedTime;             /* Transfer time */
3018
3019     /*
3020      * Set our stats pointer, remember when the RPC operation started, and
3021      * tally the operation.
3022      */
3023     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_MAKEDIR]);
3024     FS_LOCK
3025     (opP->numOps)++;
3026     FS_UNLOCK
3027     TM_GetTimeOfDay(&opStartTime, 0);
3028 #endif /* FS_STATS_DETAILED */
3029     if (code = CallPreamble((struct rx_call **) &tcon, ACTIVECALL))
3030         goto Bad_MakeDir;
3031
3032     code = SAFSS_MakeDir (tcon, DirFid, Name, InStatus, OutFid,
3033                          OutFidStatus, OutDirStatus, CallBack, Sync);
3034     
3035 Bad_MakeDir:
3036     CallPostamble(tcon);
3037
3038 #if FS_STATS_DETAILED
3039     TM_GetTimeOfDay(&opStopTime, 0);
3040     if (code == 0) {
3041       FS_LOCK
3042       (opP->numSuccesses)++;
3043       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3044       fs_stats_AddTo((opP->sumTime), elapsedTime);
3045       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3046       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3047         fs_stats_TimeAssign((opP->minTime), elapsedTime);
3048       }
3049       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3050         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3051       }
3052       FS_UNLOCK
3053     }
3054
3055 #endif /* FS_STATS_DETAILED */
3056
3057     osi_auditU (tcall, MakeDirEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_END);
3058     return code;
3059
3060 } /*SRXAFS_MakeDir*/
3061
3062
3063 /*
3064  * This routine is called exclusively by SRXAFS_RemoveDir(), and should be
3065  * merged into it when possible.
3066  */
3067 SAFSS_RemoveDir (tcon, DirFid, Name, OutDirStatus, Sync)
3068     struct rx_connection *tcon;          /* Rx connection handle */
3069     struct AFSFid *DirFid;               /* Parent dir's fid */
3070     char *Name;                          /* (Empty) dir's name to be removed */
3071     struct AFSFetchStatus *OutDirStatus; /* Output status for the parent dir */
3072     struct AFSVolSync *Sync;
3073
3074 {
3075     Vnode * parentptr = 0;              /* vnode of input Directory */
3076     Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
3077     Vnode * targetptr = 0;              /* file to be deleted */
3078     AFSFid fileFid;                     /* area for Fid from the directory */
3079     int     errorCode = 0;              /* error code */
3080     DirHandle dir;                      /* Handle for dir package I/O */
3081     Volume * volptr = 0;                /* pointer to the volume header */
3082     struct client * client;             /* pointer to client structure */
3083     afs_int32 rights, anyrights;                /* rights for this and any user */
3084     Vnode debugvnode1, debugvnode2;
3085     struct client *t_client;            /* tmp ptr to client data */
3086     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
3087
3088     /* Get ptr to client data for user Id for logging */
3089     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
3090     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
3091     ViceLog(1, ("SAFS_RemoveDir %s,  Did = %u.%d.%d, Host %s, Id %d\n",
3092             Name, DirFid->Volume, DirFid->Vnode, DirFid->Unique,
3093             inet_ntoa(logHostAddr), t_client->ViceId));
3094     FS_LOCK
3095     AFSCallStats.RemoveDir++, AFSCallStats.TotalCalls++;
3096     FS_UNLOCK
3097     /*
3098      * Get the vnode and volume for the parent dir along with the caller's
3099      * rights to it
3100      */
3101     if (errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr,
3102                                      MustBeDIR, &parentwhentargetnotdir,
3103                                      &client, WRITE_LOCK, &rights, &anyrights)) {
3104         goto Bad_RemoveDir;
3105     }
3106     debugvnode1 = *parentptr;
3107
3108     /* set volume synchronization information */
3109     SetVolumeSync(Sync, volptr);
3110
3111     /* Does the caller has delete (&write) access to the parent dir? */
3112     if (errorCode = CheckWriteMode(parentptr, rights, PRSFS_DELETE)) {
3113         goto Bad_RemoveDir;
3114     }
3115
3116     debugvnode2 = *parentptr;
3117     /* Do the actual delete of the desired (empty) directory, Name */
3118     if (errorCode = DeleteTarget(parentptr, volptr, &targetptr, &dir, &fileFid,
3119                                  Name, MustBeDIR)) {
3120         goto Bad_RemoveDir;
3121     }
3122
3123     /* Update the status for the parent dir; link count is also adjusted */
3124 #if FS_STATS_DETAILED
3125     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
3126                              parentptr->disk.linkCount-1, client->InSameNetwork);
3127 #else
3128     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
3129                              parentptr->disk.linkCount-1);
3130 #endif /* FS_STATS_DETAILED */
3131
3132     /* Return to the caller the updated parent dir status */
3133     GetStatus(parentptr, OutDirStatus, rights, anyrights, (struct Vnode *)0);
3134
3135     /*
3136      * Note: it is not necessary to break the callback on fileFid, since
3137      * refcount is now 0, so no one should be able to refer to the dir
3138      * any longer
3139      */
3140     DeleteFileCallBacks(&fileFid);
3141
3142     /* convert the write lock to a read lock before breaking callbacks */
3143     VVnodeWriteToRead(&errorCode, parentptr);
3144     assert(!errorCode || errorCode == VSALVAGE);
3145
3146     /* break call back on DirFid and fileFid */
3147     BreakCallBack(client->host, DirFid, 0);
3148
3149 Bad_RemoveDir: 
3150     /* Write the all modified vnodes (parent, new files) and volume back */
3151     PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr);
3152     ViceLog(2, ("SAFS_RemoveDir returns %d\n", errorCode));
3153     return errorCode;
3154
3155 } /*SAFSS_RemoveDir*/
3156
3157
3158 SRXAFS_RemoveDir (tcon, DirFid, Name, OutDirStatus, Sync)
3159     struct AFSVolSync *Sync;
3160     struct rx_connection *tcon;          /* Rx connection handle */
3161     struct AFSFid *DirFid;               /* Parent dir's fid */
3162     char *Name;                          /* (Empty) dir's name to be removed */
3163     struct AFSFetchStatus *OutDirStatus; /* Output status for the parent dir */
3164
3165 {
3166     afs_int32 code;
3167     struct rx_call *tcall = (struct rx_call *) tcon; 
3168 #if FS_STATS_DETAILED
3169     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
3170     struct timeval opStartTime,
3171                    opStopTime;              /* Start/stop times for RPC op*/
3172     struct timeval elapsedTime;             /* Transfer time */
3173
3174     /*
3175      * Set our stats pointer, remember when the RPC operation started, and
3176      * tally the operation.
3177      */
3178     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_REMOVEDIR]);
3179     FS_LOCK
3180     (opP->numOps)++;
3181     FS_UNLOCK
3182     TM_GetTimeOfDay(&opStartTime, 0);
3183 #endif /* FS_STATS_DETAILED */
3184
3185     if (code = CallPreamble((struct rx_call **) &tcon, ACTIVECALL))
3186         goto Bad_RemoveDir;
3187
3188     code = SAFSS_RemoveDir (tcon, DirFid, Name, OutDirStatus, Sync);
3189     
3190 Bad_RemoveDir:
3191     CallPostamble(tcon);
3192
3193 #if FS_STATS_DETAILED
3194     TM_GetTimeOfDay(&opStopTime, 0);
3195     if (code == 0) {
3196       FS_LOCK
3197       (opP->numSuccesses)++;
3198       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3199       fs_stats_AddTo((opP->sumTime), elapsedTime);
3200       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3201       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3202         fs_stats_TimeAssign((opP->minTime), elapsedTime);
3203       }
3204       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3205         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3206       }
3207       FS_UNLOCK
3208     }
3209
3210 #endif /* FS_STATS_DETAILED */
3211
3212     osi_auditU (tcall, RemoveDirEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_END);
3213     return code;
3214
3215 } /*SRXAFS_RemoveDir*/
3216
3217
3218 /*
3219  * This routine is called exclusively by SRXAFS_SetLock(), and should be
3220  * merged into it when possible.
3221  */
3222 SAFSS_SetLock (tcon, Fid, type, Sync)
3223     struct rx_connection *tcon; /* Rx connection handle */
3224     struct AFSFid *Fid;         /* Fid of file to lock */
3225     ViceLockType type;          /* Type of lock (Read or write) */
3226     struct AFSVolSync *Sync;
3227
3228 {
3229     Vnode * targetptr = 0;              /* vnode of input file */
3230     Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
3231     int     errorCode = 0;              /* error code */
3232     Volume * volptr = 0;                /* pointer to the volume header */
3233     struct client * client;             /* pointer to client structure */
3234     afs_int32 rights, anyrights;                /* rights for this and any user */
3235     struct client *t_client;            /* tmp ptr to client data */
3236     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
3237     static char * locktype[2] = {"LockRead","LockWrite"};
3238
3239     if (type != LockRead && type != LockWrite) {
3240         errorCode = EINVAL;
3241         goto Bad_SetLock;
3242     }
3243     /* Get ptr to client data for user Id for logging */
3244     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
3245     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
3246     ViceLog(1,("SAFS_SetLock type = %s Fid = %u.%d.%d, Host %s, Id %d\n",
3247             locktype[(int)type], Fid->Volume, Fid->Vnode, Fid->Unique,
3248             inet_ntoa(logHostAddr), t_client->ViceId));
3249     FS_LOCK
3250     AFSCallStats.SetLock++, AFSCallStats.TotalCalls++;
3251     FS_UNLOCK
3252
3253     /*
3254      * Get the vnode and volume for the desired file along with the caller's
3255      * rights to it
3256      */
3257     if (errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
3258                                      DONTCHECK, &parentwhentargetnotdir,
3259                                      &client, WRITE_LOCK, &rights, &anyrights)) {
3260         goto Bad_SetLock;
3261     }
3262
3263     /* set volume synchronization information */
3264     SetVolumeSync(Sync, volptr);
3265
3266     /* Handle the particular type of set locking, type */
3267     errorCode = HandleLocking(targetptr, rights, type);
3268
3269 Bad_SetLock: 
3270     /* Write the all modified vnodes (parent, new files) and volume back */
3271     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
3272
3273     if ((errorCode == VREADONLY) && (type == LockRead))
3274        errorCode = 0;  /* allow read locks on RO volumes without saving state */
3275
3276     ViceLog(2,("SAFS_SetLock returns %d\n", errorCode));
3277     return(errorCode);
3278
3279 }  /*SAFSS_SetLock*/
3280
3281
3282 SRXAFS_OldSetLock(tcon, Fid, type, Sync)
3283     struct AFSVolSync *Sync;
3284     struct rx_connection *tcon; /* Rx connection handle */
3285     struct AFSFid *Fid;         /* Fid of file to lock */
3286     ViceLockType type;          /* Type of lock (Read or write) */
3287
3288 {
3289     return SRXAFS_SetLock(tcon, Fid, type, Sync);
3290
3291 } /*SRXAFS_OldSetLock*/
3292
3293
3294 SRXAFS_SetLock (tcon, Fid, type, Sync)
3295     struct AFSVolSync *Sync;
3296     struct rx_connection *tcon; /* Rx connection handle */
3297     struct AFSFid *Fid;         /* Fid of file to lock */
3298     ViceLockType type;          /* Type of lock (Read or write) */
3299
3300 {
3301     afs_int32 code;
3302     struct rx_call *tcall = (struct rx_call *) tcon; 
3303 #if FS_STATS_DETAILED
3304     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
3305     struct timeval opStartTime,
3306                    opStopTime;              /* Start/stop times for RPC op*/
3307     struct timeval elapsedTime;             /* Transfer time */
3308
3309     /*
3310      * Set our stats pointer, remember when the RPC operation started, and
3311      * tally the operation.
3312      */
3313     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_SETLOCK]);
3314     FS_LOCK
3315     (opP->numOps)++;
3316     FS_UNLOCK
3317     TM_GetTimeOfDay(&opStartTime, 0);
3318 #endif /* FS_STATS_DETAILED */
3319
3320     if (code = CallPreamble((struct rx_call **) &tcon, ACTIVECALL))
3321         goto Bad_SetLock;
3322
3323     code = SAFSS_SetLock (tcon, Fid, type, Sync);
3324     
3325 Bad_SetLock:
3326     CallPostamble(tcon);
3327
3328 #if FS_STATS_DETAILED
3329     TM_GetTimeOfDay(&opStopTime, 0); 
3330     if (code == 0) {
3331       FS_LOCK
3332       (opP->numSuccesses)++;
3333       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3334       fs_stats_AddTo((opP->sumTime), elapsedTime);
3335       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3336       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3337         fs_stats_TimeAssign((opP->minTime), elapsedTime);
3338       }
3339       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3340         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3341       }
3342       FS_UNLOCK
3343     }
3344 #endif /* FS_STATS_DETAILED */
3345
3346     osi_auditU (tcall, SetLockEvent, code, AUD_FID, Fid, AUD_LONG, type, AUD_END);
3347     return code;
3348
3349 } /*SRXAFS_SetLock*/
3350
3351
3352 /*
3353  * This routine is called exclusively by SRXAFS_ExtendLock(), and should be
3354  * merged into it when possible.
3355  */
3356 SAFSS_ExtendLock (tcon, Fid, Sync)
3357     struct rx_connection *tcon; /* Rx connection handle */
3358     struct AFSFid *Fid;         /* Fid of file whose lock we extend */
3359     struct AFSVolSync *Sync;
3360
3361 {
3362     Vnode * targetptr = 0;              /* vnode of input file */
3363     Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
3364     int     errorCode = 0;              /* error code */
3365     Volume * volptr = 0;                /* pointer to the volume header */
3366     struct client * client;             /* pointer to client structure */
3367     afs_int32 rights, anyrights;                /* rights for this and any user */
3368     struct client *t_client;            /* tmp ptr to client data */
3369     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
3370
3371     /* Get ptr to client data for user Id for logging */
3372     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
3373     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
3374     ViceLog(1,("SAFS_ExtendLock Fid = %u.%d.%d, Host %s, Id %d\n", 
3375                Fid->Volume, Fid->Vnode, Fid->Unique, 
3376                inet_ntoa(logHostAddr), t_client->ViceId));
3377     FS_LOCK
3378     AFSCallStats.ExtendLock++, AFSCallStats.TotalCalls++;    
3379     FS_UNLOCK
3380     /*
3381      * Get the vnode and volume for the desired file along with the caller's
3382      * rights to it
3383      */
3384     if (errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
3385                                      DONTCHECK, &parentwhentargetnotdir,
3386                                      &client, WRITE_LOCK, &rights, &anyrights)) {
3387         goto Bad_ExtendLock;
3388     }
3389
3390     /* set volume synchronization information */
3391     SetVolumeSync(Sync, volptr);
3392
3393     /* Handle the actual lock extension */
3394     errorCode = HandleLocking(targetptr, rights, LockExtend);
3395
3396 Bad_ExtendLock: 
3397     /* Put back file's vnode and volume */
3398     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
3399
3400     if ((errorCode == VREADONLY))  /* presumably, we already granted this lock */
3401        errorCode = 0;              /* under our generous policy re RO vols */
3402
3403     ViceLog(2,("SAFS_ExtendLock returns %d\n", errorCode));
3404     return(errorCode);
3405
3406 } /*SAFSS_ExtendLock*/
3407
3408
3409 SRXAFS_OldExtendLock (tcon, Fid, Sync)
3410     struct AFSVolSync *Sync;
3411     struct rx_connection *tcon; /* Rx connection handle */
3412     struct AFSFid *Fid;         /* Fid of file whose lock we extend */
3413
3414 {
3415     return SRXAFS_ExtendLock(tcon, Fid, Sync);
3416
3417 } /*SRXAFS_OldExtendLock*/
3418
3419
3420 SRXAFS_ExtendLock (tcon, Fid, Sync)
3421     struct AFSVolSync *Sync;
3422     struct rx_connection *tcon; /* Rx connection handle */
3423     struct AFSFid *Fid;         /* Fid of file whose lock we extend */
3424
3425 {
3426     afs_int32 code;
3427     struct rx_call *tcall = (struct rx_call *) tcon; 
3428 #if FS_STATS_DETAILED
3429     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
3430     struct timeval opStartTime,
3431                    opStopTime;              /* Start/stop times for RPC op*/
3432     struct timeval elapsedTime;             /* Transfer time */
3433
3434     /*
3435      * Set our stats pointer, remember when the RPC operation started, and
3436      * tally the operation.
3437      */
3438     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_EXTENDLOCK]);
3439     FS_LOCK
3440     (opP->numOps)++;
3441     FS_UNLOCK
3442     TM_GetTimeOfDay(&opStartTime, 0);
3443 #endif /* FS_STATS_DETAILED */
3444
3445     if (code = CallPreamble((struct rx_call **) &tcon, ACTIVECALL))
3446         goto Bad_ExtendLock;
3447
3448     code = SAFSS_ExtendLock (tcon, Fid, Sync);
3449
3450 Bad_ExtendLock:
3451     CallPostamble(tcon);
3452
3453 #if FS_STATS_DETAILED
3454     TM_GetTimeOfDay(&opStopTime, 0);
3455     if (code == 0) {
3456       FS_LOCK
3457       (opP->numSuccesses)++;
3458       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3459       fs_stats_AddTo((opP->sumTime), elapsedTime);
3460       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3461       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3462         fs_stats_TimeAssign((opP->minTime), elapsedTime);
3463       }
3464       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3465         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3466       }
3467       FS_UNLOCK
3468     }
3469
3470 #endif /* FS_STATS_DETAILED */
3471
3472     osi_auditU (tcall, ExtendLockEvent, code, AUD_FID, Fid , AUD_END);
3473     return code;
3474
3475 } /*SRXAFS_ExtendLock*/
3476
3477
3478 /*
3479  * This routine is called exclusively by SRXAFS_ReleaseLock(), and should be
3480  * merged into it when possible.
3481  */
3482 SAFSS_ReleaseLock (tcon, Fid, Sync)
3483     struct rx_connection *tcon; /* Rx connection handle */
3484     struct AFSFid *Fid;         /* Fid of file to release lock */
3485     struct AFSVolSync *Sync;
3486
3487 {
3488     Vnode * targetptr = 0;              /* vnode of input file */
3489     Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
3490     int     errorCode = 0;              /* error code */
3491     Volume * volptr = 0;                /* pointer to the volume header */
3492     struct client * client;             /* pointer to client structure */
3493     afs_int32 rights, anyrights;                /* rights for this and any user */
3494     struct client *t_client;            /* tmp ptr to client data */
3495     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
3496
3497     /* Get ptr to client data for user Id for logging */
3498     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
3499     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
3500     ViceLog(1,("SAFS_ReleaseLock Fid = %u.%d.%d, Host %s, Id %d\n",
3501             Fid->Volume, Fid->Vnode, Fid->Unique,
3502             inet_ntoa(logHostAddr), t_client->ViceId));
3503     FS_LOCK
3504     AFSCallStats.ReleaseLock++, AFSCallStats.TotalCalls++;
3505     FS_UNLOCK
3506     /*
3507      * Get the vnode and volume for the desired file along with the caller's
3508      * rights to it
3509      */
3510     if (errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
3511                                      DONTCHECK, &parentwhentargetnotdir,
3512                                      &client, WRITE_LOCK, &rights, &anyrights)) {
3513         goto Bad_ReleaseLock;
3514     }
3515
3516     /* set volume synchronization information */
3517     SetVolumeSync(Sync, volptr);
3518
3519     /* Handle the actual lock release */
3520     if (errorCode = HandleLocking(targetptr, rights, LockRelease))
3521         goto Bad_ReleaseLock;
3522
3523     /* if no more locks left, a callback would be triggered here */
3524     if (targetptr->disk.lock.lockCount <= 0) {
3525         /* convert the write lock to a read lock before breaking callbacks */
3526         VVnodeWriteToRead(&errorCode, targetptr);
3527         assert(!errorCode || errorCode == VSALVAGE);
3528         BreakCallBack(client->host, Fid, 0);
3529     }
3530
3531 Bad_ReleaseLock: 
3532     /* Put back file's vnode and volume */
3533     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
3534
3535     if ((errorCode == VREADONLY))  /* presumably, we already granted this lock */
3536        errorCode = 0;              /* under our generous policy re RO vols */
3537
3538     ViceLog(2,("SAFS_ReleaseLock returns %d\n", errorCode));
3539     return(errorCode);
3540
3541 } /*SAFSS_ReleaseLock*/
3542
3543
3544 SRXAFS_OldReleaseLock (tcon, Fid, Sync)
3545     struct AFSVolSync *Sync;
3546     struct rx_connection *tcon; /* Rx connection handle */
3547     struct AFSFid *Fid;         /* Fid of file to release lock */
3548
3549 {
3550     return SRXAFS_ReleaseLock(tcon, Fid, Sync);
3551
3552 } /*SRXAFS_OldReleaseLock*/
3553
3554
3555 SRXAFS_ReleaseLock (tcon, Fid, Sync)
3556     struct AFSVolSync *Sync;
3557     struct rx_connection *tcon; /* Rx connection handle */
3558     struct AFSFid *Fid;         /* Fid of file to release lock */
3559
3560 {
3561     afs_int32 code;
3562     struct rx_call *tcall = (struct rx_call *) tcon; 
3563 #if FS_STATS_DETAILED
3564     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
3565     struct timeval opStartTime,
3566                    opStopTime;              /* Start/stop times for RPC op*/
3567     struct timeval elapsedTime;             /* Transfer time */
3568
3569     /*
3570      * Set our stats pointer, remember when the RPC operation started, and
3571      * tally the operation.
3572      */
3573     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_RELEASELOCK]);
3574     FS_LOCK
3575     (opP->numOps)++;
3576     FS_UNLOCK
3577     TM_GetTimeOfDay(&opStartTime, 0);
3578 #endif /* FS_STATS_DETAILED */
3579
3580     if (code = CallPreamble((struct rx_call **) &tcon, ACTIVECALL))
3581         goto Bad_ReleaseLock;
3582
3583     code = SAFSS_ReleaseLock (tcon, Fid, Sync);
3584     
3585 Bad_ReleaseLock:
3586     CallPostamble(tcon);
3587
3588 #if FS_STATS_DETAILED
3589     TM_GetTimeOfDay(&opStopTime, 0);
3590     if (code == 0) {
3591       FS_LOCK
3592       (opP->numSuccesses)++;
3593       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3594       fs_stats_AddTo((opP->sumTime), elapsedTime);
3595       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3596       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3597         fs_stats_TimeAssign((opP->minTime), elapsedTime);
3598       }
3599       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3600         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3601       }
3602       FS_UNLOCK
3603     }
3604
3605 #endif /* FS_STATS_DETAILED */
3606
3607     osi_auditU (tcall, ReleaseLockEvent, code, AUD_FID, Fid , AUD_END);
3608     return code;
3609
3610 } /*SRXAFS_ReleaseLock*/
3611
3612
3613 /*
3614  * This routine is called exclusively by SRXAFS_GetStatistics(), and should be
3615  * merged into it when possible.
3616  */
3617 static GetStatistics (tcon, Statistics)
3618     struct rx_connection *tcon;       /* Rx connection handle */
3619     struct AFSStatistics *Statistics; /* Placeholder for returned AFS statistics */
3620 {
3621     ViceLog(1, ("SAFS_GetStatistics Received\n"));
3622     FS_LOCK
3623     AFSCallStats.GetStatistics++, AFSCallStats.TotalCalls++;
3624     FS_UNLOCK
3625     memset(Statistics, 0, sizeof(*Statistics));
3626     SetAFSStats(Statistics);
3627     SetVolumeStats(Statistics);
3628     SetSystemStats(Statistics);
3629
3630     return(0);
3631
3632 } /*GetStatistics*/
3633
3634
3635 SRXAFS_GetStatistics (tcon, Statistics)
3636     struct rx_connection *tcon;       /* Rx connection handle */
3637     struct AFSStatistics *Statistics; /* Placeholder for returned AFS statistics */
3638
3639 {
3640     afs_int32 code;
3641 #if FS_STATS_DETAILED
3642     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
3643     struct timeval opStartTime,
3644                    opStopTime;              /* Start/stop times for RPC op*/
3645     struct timeval elapsedTime;             /* Transfer time */
3646
3647     /*
3648      * Set our stats pointer, remember when the RPC operation started, and
3649      * tally the operation.
3650      */
3651     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETSTATISTICS]);
3652     FS_LOCK
3653     (opP->numOps)++;
3654     FS_UNLOCK
3655     TM_GetTimeOfDay(&opStartTime, 0);
3656 #endif /* FS_STATS_DETAILED */
3657
3658     if (code = CallPreamble((struct rx_call **) &tcon, NOTACTIVECALL))
3659         goto Bad_GetStatistics;
3660
3661     code = GetStatistics (tcon, Statistics);
3662     
3663 Bad_GetStatistics:
3664     CallPostamble(tcon);
3665
3666 #if FS_STATS_DETAILED
3667     TM_GetTimeOfDay(&opStopTime, 0);
3668     if (code == 0) {
3669       FS_LOCK
3670       (opP->numSuccesses)++;
3671       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3672       fs_stats_AddTo((opP->sumTime), elapsedTime);
3673       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3674       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3675         fs_stats_TimeAssign((opP->minTime), elapsedTime);
3676       }
3677       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3678         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3679       }
3680       FS_UNLOCK
3681     }
3682 #endif /* FS_STATS_DETAILED */
3683
3684     return code;
3685
3686 } /*SRXAFS_GetStatistics*/
3687
3688
3689 /*------------------------------------------------------------------------
3690  * EXPORTED SRXAFS_XStatsVersion
3691  *
3692  * Description:
3693  *      Routine called by the server-side RPC interface to implement
3694  *      pulling out the xstat version number for the File Server.
3695  *
3696  * Arguments:
3697  *      a_versionP : Ptr to the version number variable to set.
3698  *
3699  * Returns:
3700  *      0 (always)
3701  *
3702  * Environment:
3703  *      Nothing interesting.
3704  *
3705  * Side Effects:
3706  *      As advertised.
3707  *------------------------------------------------------------------------*/
3708
3709 int SRXAFS_XStatsVersion(a_call, a_versionP)
3710     struct rx_call *a_call;
3711     afs_int32 *a_versionP;
3712
3713 { /*SRXAFS_XStatsVersion*/
3714
3715 #if FS_STATS_DETAILED
3716     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
3717     struct timeval opStartTime,
3718                    opStopTime;              /* Start/stop times for RPC op*/
3719     struct timeval elapsedTime;             /* Transfer time */
3720
3721     /*
3722      * Set our stats pointer, remember when the RPC operation started, and
3723      * tally the operation.
3724      */
3725     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_XSTATSVERSION]);
3726     FS_LOCK
3727     (opP->numOps)++;
3728     FS_UNLOCK
3729     TM_GetTimeOfDay(&opStartTime, 0);
3730 #endif /* FS_STATS_DETAILED */
3731
3732     *a_versionP = AFS_XSTAT_VERSION;
3733
3734 #if FS_STATS_DETAILED
3735     TM_GetTimeOfDay(&opStopTime, 0);
3736     fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3737     fs_stats_AddTo((opP->sumTime), elapsedTime);
3738     fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3739     if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3740         fs_stats_TimeAssign((opP->minTime), elapsedTime);
3741     }
3742     if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3743         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3744     }
3745     FS_LOCK
3746     (opP->numSuccesses)++;
3747     FS_UNLOCK
3748 #endif /* FS_STATS_DETAILED */
3749
3750     return(0);
3751
3752 }  /*SRXAFS_XStatsVersion*/
3753
3754
3755 /*------------------------------------------------------------------------
3756  * PRIVATE FillPerfValues
3757  *
3758  * Description:
3759  *      Routine called to fill a regular performance data structure.
3760  *
3761  * Arguments:
3762  *      a_perfP : Ptr to perf structure to fill
3763  *
3764  * Returns:
3765  *      Nothing.
3766  *
3767  * Environment:
3768  *      Various collections need this info, so the guts were put in
3769  *      this separate routine.
3770  *
3771  * Side Effects:
3772  *      As advertised.
3773  *------------------------------------------------------------------------*/
3774
3775 static void FillPerfValues(a_perfP)
3776     struct afs_PerfStats *a_perfP;
3777
3778 { /*FillPerfValues*/
3779
3780     int dir_Buffers;            /*# buffers in use by dir package*/
3781     int dir_Calls;              /*# read calls in dir package*/
3782     int dir_IOs;                /*# I/O ops in dir package*/
3783
3784     /*
3785      * Vnode cache section.
3786      */
3787     a_perfP->vcache_L_Entries = VnodeClassInfo[vLarge].cacheSize;
3788     a_perfP->vcache_L_Allocs = VnodeClassInfo[vLarge].allocs;
3789     a_perfP->vcache_L_Gets = VnodeClassInfo[vLarge].gets;
3790     a_perfP->vcache_L_Reads = VnodeClassInfo[vLarge].reads;
3791     a_perfP->vcache_L_Writes = VnodeClassInfo[vLarge].writes;
3792     a_perfP->vcache_S_Entries = VnodeClassInfo[vSmall].cacheSize;
3793     a_perfP->vcache_S_Allocs = VnodeClassInfo[vSmall].allocs;
3794     a_perfP->vcache_S_Gets = VnodeClassInfo[vSmall].gets;
3795     a_perfP->vcache_S_Reads = VnodeClassInfo[vSmall].reads;
3796     a_perfP->vcache_S_Writes = VnodeClassInfo[vSmall].writes;
3797     a_perfP->vcache_H_Entries = VolumeCacheSize;
3798     a_perfP->vcache_H_Gets = VolumeGets;
3799     a_perfP->vcache_H_Replacements = VolumeReplacements;
3800     
3801     /*
3802      * Directory section.
3803      */
3804     DStat(&dir_Buffers, &dir_Calls, &dir_IOs);
3805     a_perfP->dir_Buffers = (afs_int32) dir_Buffers;
3806     a_perfP->dir_Calls = (afs_int32 )dir_Calls;
3807     a_perfP->dir_IOs = (afs_int32) dir_IOs;
3808     
3809     /*
3810      * Rx section.
3811      */
3812     a_perfP->rx_packetRequests =
3813         (afs_int32) rx_stats.packetRequests;
3814     a_perfP->rx_noPackets_RcvClass =
3815         (afs_int32) rx_stats.receivePktAllocFailures;
3816     a_perfP->rx_noPackets_SendClass =
3817         (afs_int32) rx_stats.sendPktAllocFailures;
3818     a_perfP->rx_noPackets_SpecialClass =
3819         (afs_int32) rx_stats.specialPktAllocFailures;
3820     a_perfP->rx_socketGreedy =
3821         (afs_int32) rx_stats.socketGreedy;
3822     a_perfP->rx_bogusPacketOnRead =
3823         (afs_int32) rx_stats.bogusPacketOnRead;
3824     a_perfP->rx_bogusHost =
3825         (afs_int32) rx_stats.bogusHost;
3826     a_perfP->rx_noPacketOnRead =
3827         (afs_int32) rx_stats.noPacketOnRead;
3828     a_perfP->rx_noPacketBuffersOnRead =
3829         (afs_int32) rx_stats.noPacketBuffersOnRead;
3830     a_perfP->rx_selects =
3831         (afs_int32) rx_stats.selects;
3832     a_perfP->rx_sendSelects =
3833         (afs_int32) rx_stats.sendSelects;
3834     a_perfP->rx_packetsRead_RcvClass =
3835         (afs_int32) rx_stats.packetsRead[RX_PACKET_CLASS_RECEIVE];
3836     a_perfP->rx_packetsRead_SendClass =
3837         (afs_int32) rx_stats.packetsRead[RX_PACKET_CLASS_SEND];
3838     a_perfP->rx_packetsRead_SpecialClass =
3839         (afs_int32) rx_stats.packetsRead[RX_PACKET_CLASS_SPECIAL];
3840     a_perfP->rx_dataPacketsRead =
3841         (afs_int32) rx_stats.dataPacketsRead;
3842     a_perfP->rx_ackPacketsRead =
3843         (afs_int32) rx_stats.ackPacketsRead;
3844     a_perfP->rx_dupPacketsRead =
3845         (afs_int32) rx_stats.dupPacketsRead;
3846     a_perfP->rx_spuriousPacketsRead =
3847         (afs_int32) rx_stats.spuriousPacketsRead;
3848     a_perfP->rx_packetsSent_RcvClass =
3849         (afs_int32) rx_stats.packetsSent[RX_PACKET_CLASS_RECEIVE];
3850     a_perfP->rx_packetsSent_SendClass =
3851         (afs_int32) rx_stats.packetsSent[RX_PACKET_CLASS_SEND];
3852     a_perfP->rx_packetsSent_SpecialClass =
3853         (afs_int32) rx_stats.packetsSent[RX_PACKET_CLASS_SPECIAL];
3854     a_perfP->rx_ackPacketsSent =
3855         (afs_int32) rx_stats.ackPacketsSent;
3856     a_perfP->rx_pingPacketsSent =
3857         (afs_int32) rx_stats.pingPacketsSent;
3858     a_perfP->rx_abortPacketsSent =
3859         (afs_int32) rx_stats.abortPacketsSent;
3860     a_perfP->rx_busyPacketsSent =
3861         (afs_int32) rx_stats.busyPacketsSent;
3862     a_perfP->rx_dataPacketsSent =
3863         (afs_int32) rx_stats.dataPacketsSent;
3864     a_perfP->rx_dataPacketsReSent =
3865         (afs_int32) rx_stats.dataPacketsReSent;
3866     a_perfP->rx_dataPacketsPushed =
3867         (afs_int32) rx_stats.dataPacketsPushed;
3868     a_perfP->rx_ignoreAckedPacket =
3869         (afs_int32) rx_stats.ignoreAckedPacket;
3870     a_perfP->rx_totalRtt_Sec =
3871         (afs_int32) rx_stats.totalRtt.sec;
3872     a_perfP->rx_totalRtt_Usec =
3873         (afs_int32) rx_stats.totalRtt.usec;
3874     a_perfP->rx_minRtt_Sec =
3875         (afs_int32) rx_stats.minRtt.sec;
3876     a_perfP->rx_minRtt_Usec =
3877         (afs_int32) rx_stats.minRtt.usec;
3878     a_perfP->rx_maxRtt_Sec =
3879         (afs_int32) rx_stats.maxRtt.sec;
3880     a_perfP->rx_maxRtt_Usec =
3881         (afs_int32) rx_stats.maxRtt.usec;
3882     a_perfP->rx_nRttSamples =
3883         (afs_int32) rx_stats.nRttSamples;
3884     a_perfP->rx_nServerConns =
3885         (afs_int32) rx_stats.nServerConns;
3886     a_perfP->rx_nClientConns =
3887         (afs_int32) rx_stats.nClientConns;
3888     a_perfP->rx_nPeerStructs =
3889         (afs_int32) rx_stats.nPeerStructs;
3890     a_perfP->rx_nCallStructs =
3891         (afs_int32) rx_stats.nCallStructs;
3892     a_perfP->rx_nFreeCallStructs =
3893         (afs_int32) rx_stats.nFreeCallStructs;
3894     
3895     a_perfP->host_NumHostEntries = HTs;
3896     a_perfP->host_HostBlocks = HTBlocks;
3897     h_GetHostNetStats(&(a_perfP->host_NonDeletedHosts),
3898                       &(a_perfP->host_HostsInSameNetOrSubnet),
3899                       &(a_perfP->host_HostsInDiffSubnet),
3900                       &(a_perfP->host_HostsInDiffNetwork));
3901     a_perfP->host_NumClients = CEs;
3902     a_perfP->host_ClientBlocks = CEBlocks;
3903     
3904     a_perfP->sysname_ID = afs_perfstats.sysname_ID;
3905
3906 } /*FillPerfValues*/
3907
3908
3909 /*------------------------------------------------------------------------
3910  * EXPORTED SRXAFS_GetXStats
3911  *
3912  * Description:
3913  *      Routine called by the server-side callback RPC interface to
3914  *      implement getting the given data collection from the extended
3915  *      File Server statistics.
3916  *
3917  * Arguments:
3918  *      a_call              : Ptr to Rx call on which this request came in.
3919  *      a_clientVersionNum  : Client version number.
3920  *      a_opCode            : Desired operation.
3921  *      a_serverVersionNumP : Ptr to version number to set.
3922  *      a_timeP             : Ptr to time value (seconds) to set.
3923  *      a_dataP             : Ptr to variable array structure to return
3924  *                            stuff in.
3925  *
3926  * Returns:
3927  *      0 (always).
3928  *
3929  * Environment:
3930  *      Nothing interesting.
3931  *
3932  * Side Effects:
3933  *      As advertised.
3934  *------------------------------------------------------------------------*/
3935
3936 int SRXAFS_GetXStats(a_call, a_clientVersionNum, a_collectionNumber, a_srvVersionNumP, a_timeP, a_dataP)
3937     struct rx_call *a_call;
3938     afs_int32 a_clientVersionNum;
3939     afs_int32 a_collectionNumber;
3940     afs_int32 *a_srvVersionNumP;
3941     afs_int32 *a_timeP;
3942     AFS_CollData *a_dataP;
3943
3944 { /*SRXAFS_GetXStats*/
3945
3946     register int code;          /*Return value*/
3947     afs_int32 *dataBuffP;               /*Ptr to data to be returned*/
3948     afs_int32 dataBytes;                /*Bytes in data buffer*/
3949 #if FS_STATS_DETAILED
3950     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
3951     struct timeval opStartTime,
3952                    opStopTime;              /* Start/stop times for RPC op*/
3953     struct timeval elapsedTime;             /* Transfer time */
3954
3955     /*
3956      * Set our stats pointer, remember when the RPC operation started, and
3957      * tally the operation.
3958      */
3959     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETXSTATS]);
3960     FS_LOCK
3961     (opP->numOps)++;
3962     FS_UNLOCK
3963     TM_GetTimeOfDay(&opStartTime, 0);
3964 #endif /* FS_STATS_DETAILED */
3965
3966     /*
3967      * Record the time of day and the server version number.
3968      */
3969     *a_srvVersionNumP = AFS_XSTAT_VERSION;
3970     *a_timeP = FT_ApproxTime();
3971
3972     /*
3973      * Stuff the appropriate data in there (assume victory)
3974      */
3975     code = 0;
3976
3977     ViceLog(1, ("Received GetXStats call for collection %d\n",  a_collectionNumber));
3978
3979 #if 0
3980     /*
3981      * We're not keeping stats, so just return successfully with
3982      * no data.
3983      */
3984     a_dataP->AFS_CollData_len = 0;
3985     a_dataP->AFS_CollData_val = (afs_int32 *)0;
3986 #endif /* 0 */
3987
3988     switch(a_collectionNumber) {
3989       case AFS_XSTATSCOLL_CALL_INFO:
3990         /*
3991          * Pass back all the call-count-related data.
3992          *
3993          * >>> We are forced to allocate a separate area in which to
3994          * >>> put this stuff in by the RPC stub generator, since it
3995          * >>> will be freed at the tail end of the server stub code.
3996          */
3997 #if 0
3998         /*
3999          * I don't think call-level stats are being collected yet
4000          * for the File Server.
4001          */
4002         dataBytes = sizeof(struct afs_Stats);
4003         dataBuffP = (afs_int32 *)malloc(dataBytes);
4004         memcpy(dataBuffP, &afs_cmstats, dataBytes);
4005         a_dataP->AFS_CollData_len = dataBytes>>2;
4006         a_dataP->AFS_CollData_val = dataBuffP;
4007 #else
4008         a_dataP->AFS_CollData_len = 0;
4009         a_dataP->AFS_CollData_val = (afs_int32 *)0;
4010 #endif /* 0 */
4011         break;
4012
4013       case AFS_XSTATSCOLL_PERF_INFO:
4014         /*
4015          * Pass back all the regular performance-related data.
4016          *
4017          * >>> We are forced to allocate a separate area in which to
4018          * >>> put this stuff in by the RPC stub generator, since it
4019          * >>> will be freed at the tail end of the server stub code.
4020          */
4021
4022         afs_perfstats.numPerfCalls++;
4023         FillPerfValues(&afs_perfstats);
4024
4025         /*
4026          * Don't overwrite the spares at the end.
4027          */
4028
4029         dataBytes = sizeof(struct afs_PerfStats);
4030         dataBuffP = (afs_int32 *)osi_Alloc(dataBytes);
4031         memcpy(dataBuffP, &afs_perfstats, dataBytes);
4032         a_dataP->AFS_CollData_len = dataBytes>>2;
4033         a_dataP->AFS_CollData_val = dataBuffP;
4034         break;
4035
4036       case AFS_XSTATSCOLL_FULL_PERF_INFO:
4037         /*
4038          * Pass back the full collection of performance-related data.
4039          * We have to stuff the basic, overall numbers in, but the
4040          * detailed numbers are kept in the structure already.
4041          *
4042          * >>> We are forced to allocate a separate area in which to
4043          * >>> put this stuff in by the RPC stub generator, since it
4044          * >>> will be freed at the tail end of the server stub code.
4045          */
4046
4047         afs_perfstats.numPerfCalls++;
4048 #if FS_STATS_DETAILED
4049         afs_FullPerfStats.overall.numPerfCalls = afs_perfstats.numPerfCalls;
4050         FillPerfValues(&afs_FullPerfStats.overall);
4051
4052         /*
4053          * Don't overwrite the spares at the end.
4054          */
4055
4056         dataBytes = sizeof(struct fs_stats_FullPerfStats);
4057         dataBuffP = (afs_int32 *)osi_Alloc(dataBytes);
4058         memcpy(dataBuffP, &afs_FullPerfStats, dataBytes);
4059         a_dataP->AFS_CollData_len = dataBytes>>2;
4060         a_dataP->AFS_CollData_val = dataBuffP;
4061 #endif
4062         break;
4063
4064       default:
4065         /*
4066          * Illegal collection number.
4067          */
4068         a_dataP->AFS_CollData_len = 0;
4069         a_dataP->AFS_CollData_val = (afs_int32 *)0;
4070         code = 1;
4071     } /*Switch on collection number*/
4072
4073 #if FS_STATS_DETAILED
4074     TM_GetTimeOfDay(&opStopTime, 0);
4075     if (code == 0) {
4076       FS_LOCK
4077       (opP->numSuccesses)++;
4078       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
4079       fs_stats_AddTo((opP->sumTime), elapsedTime);
4080       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
4081       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
4082         fs_stats_TimeAssign((opP->minTime), elapsedTime);
4083       }
4084       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
4085         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
4086       }
4087       FS_UNLOCK
4088     }
4089
4090 #endif /* FS_STATS_DETAILED */
4091
4092     return(code);
4093
4094 } /*SRXAFS_GetXStats*/
4095
4096
4097 SRXAFS_GiveUpCallBacks (tcon, FidArray, CallBackArray)
4098     struct rx_connection *tcon;         /* Rx connection handle */
4099     struct AFSCBFids *FidArray;         /* Array of Fids entries */
4100     struct AFSCBs *CallBackArray;       /* array of callbacks */
4101
4102 {
4103     afs_int32 errorCode;
4104     register int i;
4105     struct client *client;
4106 #if FS_STATS_DETAILED
4107     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
4108     struct timeval opStartTime,
4109                    opStopTime;              /* Start/stop times for RPC op*/
4110     struct timeval elapsedTime;             /* Transfer time */
4111
4112     /*
4113      * Set our stats pointer, remember when the RPC operation started, and
4114      * tally the operation.
4115      */
4116     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GIVEUPCALLBACKS]);
4117     FS_LOCK
4118     (opP->numOps)++;
4119     FS_UNLOCK
4120     TM_GetTimeOfDay(&opStartTime, 0);
4121 #endif /* FS_STATS_DETAILED */
4122
4123     ViceLog(1, ("SAFS_GiveUpCallBacks (Noffids=%d)\n", FidArray->AFSCBFids_len));
4124     FS_LOCK
4125     AFSCallStats.GiveUpCallBacks++, AFSCallStats.TotalCalls++;
4126     FS_UNLOCK
4127     if (errorCode = CallPreamble((struct rx_call **) &tcon, ACTIVECALL))
4128         goto Bad_GiveUpCallBacks;
4129
4130     if (FidArray->AFSCBFids_len < CallBackArray->AFSCBs_len) {
4131        ViceLog(0, ("GiveUpCallBacks: #Fids %d < #CallBacks %d, host=%x\n", 
4132                    FidArray->AFSCBFids_len, CallBackArray->AFSCBs_len, 
4133                    (tcon->peer ? tcon->peer->host : 0)));
4134        errorCode = EINVAL;
4135        goto Bad_GiveUpCallBacks;
4136     }
4137
4138     errorCode = GetClient(tcon, &client);
4139     if (!errorCode) {
4140        for (i=0; i < FidArray->AFSCBFids_len; i++) {
4141           register struct AFSFid *fid = &(FidArray->AFSCBFids_val[i]);
4142           DeleteCallBack(client->host, fid);
4143        }
4144     }
4145
4146 Bad_GiveUpCallBacks:
4147     CallPostamble(tcon);
4148
4149 #if FS_STATS_DETAILED
4150     TM_GetTimeOfDay(&opStopTime, 0);
4151     if (errorCode == 0) {
4152       FS_LOCK
4153       (opP->numSuccesses)++;
4154       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
4155       fs_stats_AddTo((opP->sumTime), elapsedTime);
4156       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
4157       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
4158         fs_stats_TimeAssign((opP->minTime), elapsedTime);
4159       }
4160       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
4161         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
4162       }
4163       FS_UNLOCK
4164     }
4165 #endif /* FS_STATS_DETAILED */
4166 out:
4167     return errorCode;
4168
4169 } /*SRXAFS_GiveUpCallBacks*/
4170
4171
4172 SRXAFS_NGetVolumeInfo (tcon, avolid, avolinfo)
4173     struct rx_connection *tcon;         /* Rx connection handle */
4174     char *avolid;                       /* Volume name/id */
4175     struct AFSVolumeInfo *avolinfo;     /* Returned volume's specific info */
4176
4177 {
4178     return(VNOVOL);             /* XXX Obsolete routine XXX */
4179
4180 } /*SRXAFS_NGetVolumeInfo*/
4181
4182
4183 /*
4184  * Dummy routine. Should never be called (the cache manager should only 
4185  * invoke this interface when communicating with a AFS/DFS Protocol
4186  * Translator).
4187  */
4188 SRXAFS_Lookup(call_p, afs_dfid_p, afs_name_p, afs_fid_p,
4189               afs_status_p, afs_dir_status_p, afs_callback_p, afs_sync_p)
4190   struct rx_call *call_p;               /* Rx call handle */
4191   struct AFSFid *afs_dfid_p;            /* Directory */
4192   char *afs_name_p;                     /* Name of file to lookup */
4193   struct AFSFid *afs_fid_p;             /* Place to return fid of file */
4194   struct AFSFetchStatus *afs_status_p;  /* Place to return file status */
4195   struct AFSFetchStatus *afs_dir_status_p;/* Place to return file status */
4196   struct AFSCallBack *afs_callback_p;   /* If r/w, callback promise for Fid */
4197   struct AFSVolSync *afs_sync_p;        /* Volume sync info */
4198 {
4199     return EINVAL;
4200 }
4201
4202
4203 SRXAFS_FlushCPS(tcon, vids, addrs, spare1, spare2, spare3)
4204     struct rx_connection *tcon;
4205     struct ViceIds *vids;
4206     struct IPAddrs *addrs;
4207     afs_int32 spare1, *spare2, *spare3;
4208 {
4209     int i;
4210     afs_int32 nids, naddrs;
4211     afs_int32 *vd, *addr;
4212     int     errorCode = 0;              /* return code to caller */
4213     struct client *client;
4214     struct rx_call *tcall = (struct rx_call *) tcon; 
4215
4216     ViceLog(1, ("SRXAFS_FlushCPS\n"));
4217     FS_LOCK
4218     AFSCallStats.TotalCalls++;
4219     FS_UNLOCK
4220     nids = vids->ViceIds_len;   /* # of users in here */
4221     naddrs = addrs->IPAddrs_len;        /* # of hosts in here */
4222     if (nids < 0 || naddrs < 0) {
4223         errorCode = EINVAL;
4224         goto Bad_FlushCPS;
4225     }
4226
4227     vd = vids->ViceIds_val;
4228     for (i=0; i<nids; i++, vd++) {
4229       if (!*vd)
4230         continue;
4231       client = h_ID2Client(*vd);  /* returns client locked, or NULL */
4232       if (!client)
4233         continue;
4234
4235       BoostSharedLock(&client->lock);
4236       client->prfail = 2;       /* Means re-eval client's cps */
4237 #ifdef  notdef
4238       if (client->tcon) {
4239         rx_SetRock(((struct rx_connection *) client->tcon), 0);
4240       }
4241 #endif
4242       if ((client->ViceId != ANONYMOUSID) && client->CPS.prlist_val) {
4243         free(client->CPS.prlist_val);
4244         client->CPS.prlist_val = (afs_int32 *)0;
4245       }
4246       ReleaseWriteLock(&client->lock);
4247     }
4248
4249     addr = addrs->IPAddrs_val;
4250     for (i=0; i<naddrs; i++, addr++) {
4251       if (*addr)
4252         h_flushhostcps(*addr, 7001);
4253     }
4254
4255 Bad_FlushCPS:
4256     ViceLog(2, ("SAFS_FlushCPS  returns %d\n", errorCode)); 
4257     return errorCode;
4258 } /*SRXAFS_FlushCPS */
4259
4260
4261
4262 static GetVolumeInfo (tcon, avolid, avolinfo)
4263     struct rx_connection *tcon;         /* Rx Connection handle */
4264     char *avolid;                       /* Volume name/id */
4265     struct VolumeInfo *avolinfo;        /* Returned volume's specific info */
4266
4267 {
4268     int errorCode = 0;                  /* error code */
4269
4270     FS_LOCK
4271     AFSCallStats.GetVolumeInfo++, AFSCallStats.TotalCalls++;
4272     FS_UNLOCK
4273
4274     errorCode = TryLocalVLServer(avolid, avolinfo);
4275     ViceLog(1, ("SAFS_GetVolumeInfo returns %d, Volume %u, type %x, servers %x %x %x %x...\n",
4276             errorCode, avolinfo->Vid, avolinfo->Type,
4277             avolinfo->Server0, avolinfo->Server1, avolinfo->Server2,
4278             avolinfo->Server3));
4279     return(errorCode);
4280 }
4281
4282
4283 /* worthless hack to let CS keep running ancient software */
4284 static afs_vtoi(aname)
4285     register char *aname;
4286
4287 {
4288     register afs_int32 temp;
4289     register int tc;
4290
4291     temp = 0;
4292     while(tc = *aname++) {
4293         if (tc > '9' || tc < '0') return 0; /* invalid name */
4294         temp *= 10;
4295         temp += tc - '0';
4296     }
4297     return temp;
4298 }
4299
4300 /*
4301  * may get name or #, but must handle all weird cases (recognize readonly
4302  * or backup volumes by name or #
4303  */
4304 static CopyVolumeEntry(aname, ave, av)
4305     char *aname;
4306     register struct VolumeInfo *av;
4307     register struct vldbentry *ave;
4308
4309 {
4310     register int i, j, vol;
4311     afs_int32 mask, whichType;
4312     afs_uint32 *serverHost, *typePtr;
4313     
4314     /* figure out what type we want if by name */
4315     i = strlen(aname);
4316     if (i >= 8 && strcmp(aname+i-7, ".backup") == 0)
4317         whichType = BACKVOL;
4318     else if (i >= 10 && strcmp(aname+i-9, ".readonly")==0)
4319         whichType = ROVOL;
4320     else whichType = RWVOL;
4321     
4322     vol = afs_vtoi(aname);
4323     if (vol == 0) vol = ave->volumeId[whichType];
4324     
4325     /*
4326      * Now vol has volume # we're interested in.  Next, figure out the type
4327      * of the volume by looking finding it in the vldb entry
4328      */
4329     if ((ave->flags&VLF_RWEXISTS) && vol == ave->volumeId[RWVOL]) {
4330         mask = VLSF_RWVOL;
4331         whichType = RWVOL;
4332     }
4333     else if ((ave->flags&VLF_ROEXISTS) && vol == ave->volumeId[ROVOL]) {
4334         mask = VLSF_ROVOL;
4335         whichType = ROVOL;
4336     }
4337     else if ((ave->flags&VLF_BACKEXISTS) && vol == ave->volumeId[BACKVOL]) {
4338         mask = VLSF_RWVOL;  /* backup always is on the same volume as parent */
4339         whichType = BACKVOL;
4340     }
4341     else
4342         return  EINVAL;     /* error: can't find volume in vldb entry */
4343     
4344     typePtr = &av->Type0;
4345     serverHost = &av->Server0;
4346     av->Vid = vol;
4347     av->Type = whichType;
4348     av->Type0 = av->Type1 = av->Type2 = av->Type3 = av->Type4 = 0;
4349     if (ave->flags & VLF_RWEXISTS) typePtr[RWVOL] = ave->volumeId[RWVOL];
4350     if (ave->flags & VLF_ROEXISTS) typePtr[ROVOL] = ave->volumeId[ROVOL];
4351     if (ave->flags & VLF_BACKEXISTS) typePtr[BACKVOL] = ave->volumeId[BACKVOL];
4352
4353     for(i=0,j=0; i<ave->nServers; i++) {
4354         if ((ave->serverFlags[i] & mask) == 0) continue;    /* wrong volume */
4355         serverHost[j] = ave->serverNumber[i];
4356         j++;
4357     }
4358     av->ServerCount = j;
4359     if (j < 8) serverHost[j++] = 0; /* bogus 8, but compat only now */
4360     return 0;
4361 }
4362
4363
4364 static TryLocalVLServer(avolid, avolinfo)
4365     char *avolid;
4366     struct VolumeInfo *avolinfo;
4367
4368 {
4369     static struct rx_connection *vlConn = 0;
4370     static int down = 0;
4371     static afs_int32 lastDownTime = 0;
4372     struct vldbentry tve;
4373     struct rx_securityClass *vlSec;
4374     register afs_int32 code;
4375
4376     if (!vlConn) {
4377         vlSec = (struct rx_securityClass *) rxnull_NewClientSecurityObject();
4378         vlConn = rx_NewConnection(htonl(0x7f000001), htons(7003), 52, vlSec, 0);
4379         rx_SetConnDeadTime(vlConn, 15); /* don't wait long */
4380     }
4381     if (down && (FT_ApproxTime() < lastDownTime + 180)) {
4382         return 1;   /* failure */
4383     }
4384
4385     code = VL_GetEntryByNameO(vlConn, avolid, &tve);
4386     if (code >= 0) down = 0;    /* call worked */
4387     if (code) {
4388         if (code < 0) {
4389             lastDownTime = FT_ApproxTime(); /* last time we tried an RPC */
4390             down = 1;
4391         }
4392         return code;
4393     }
4394
4395     /* otherwise convert to old format vldb entry */
4396     code = CopyVolumeEntry(avolid, &tve, avolinfo);
4397     return code;
4398 }
4399
4400
4401 SRXAFS_GetVolumeInfo (tcon, avolid, avolinfo)
4402     struct rx_connection *tcon;         /* Rx connection handle */
4403     char *avolid;                       /* Volume name/id */
4404     struct VolumeInfo *avolinfo;        /* Returned volume's specific info */
4405
4406 {
4407     afs_int32 code;
4408 #if FS_STATS_DETAILED
4409     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
4410     struct timeval opStartTime,
4411                    opStopTime;              /* Start/stop times for RPC op*/
4412     struct timeval elapsedTime;             /* Transfer time */
4413
4414     /*
4415      * Set our stats pointer, remember when the RPC operation started, and
4416      * tally the operation.
4417      */
4418     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETVOLUMEINFO]);
4419     FS_LOCK
4420     (opP->numOps)++;
4421     FS_UNLOCK
4422     TM_GetTimeOfDay(&opStartTime, 0);
4423 #endif /* FS_STATS_DETAILED */
4424     if (code = CallPreamble((struct rx_call **) &tcon, ACTIVECALL))
4425         goto Bad_GetVolumeInfo;
4426
4427     code = GetVolumeInfo (tcon, avolid, avolinfo);
4428     avolinfo->Type4     = 0xabcd9999;   /* tell us to try new vldb */
4429
4430 Bad_GetVolumeInfo:
4431     CallPostamble(tcon);
4432
4433 #if FS_STATS_DETAILED
4434     TM_GetTimeOfDay(&opStopTime, 0);
4435     if (code == 0) {
4436       FS_LOCK
4437       (opP->numSuccesses)++;
4438       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
4439       fs_stats_AddTo((opP->sumTime), elapsedTime);
4440       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
4441       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
4442         fs_stats_TimeAssign((opP->minTime), elapsedTime);
4443       }
4444       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
4445         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
4446       }
4447       FS_UNLOCK
4448     }
4449
4450 #endif /* FS_STATS_DETAILED */
4451
4452     return code;
4453
4454 } /*SRXAFS_GetVolumeInfo*/
4455
4456
4457 SRXAFS_GetVolumeStatus (tcon, avolid, FetchVolStatus, Name, OfflineMsg, Motd)
4458     struct rx_connection *tcon;           /* Rx connection handle */
4459     afs_int32 avolid;                     /* Volume's id */
4460     AFSFetchVolumeStatus *FetchVolStatus; /* Place to hold volume's status info */
4461     char **Name;                          /* Returned volume's name */
4462     char **OfflineMsg;                    /* Returned offline msg, if any */
4463     char **Motd;                          /* Returned Motd msg, if any */
4464
4465 {
4466     Vnode * targetptr = 0;              /* vnode of the new file */
4467     Vnode * parentwhentargetnotdir = 0; /* vnode of parent */
4468     int     errorCode = 0;              /* error code */
4469     Volume * volptr = 0;                /* pointer to the volume header */
4470     struct client * client;             /* pointer to client entry */
4471     afs_int32 rights, anyrights;                /* rights for this and any user */
4472     AFSFid  dummyFid;
4473 #if FS_STATS_DETAILED
4474     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
4475     struct timeval opStartTime,
4476                    opStopTime;              /* Start/stop times for RPC op*/
4477     struct timeval elapsedTime;             /* Transfer time */
4478
4479     /*
4480      * Set our stats pointer, remember when the RPC operation started, and
4481      * tally the operation.
4482      */
4483     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETVOLUMESTATUS]);
4484     FS_LOCK
4485     (opP->numOps)++;
4486     FS_UNLOCK
4487     TM_GetTimeOfDay(&opStartTime, 0);
4488 #endif /* FS_STATS_DETAILED */
4489
4490     ViceLog(1,("SAFS_GetVolumeStatus for volume %u\n", avolid));
4491     if (errorCode = CallPreamble((struct rx_call **) &tcon, ACTIVECALL))
4492         goto Bad_GetVolumeStatus;
4493
4494     FS_LOCK
4495     AFSCallStats.GetVolumeStatus++, AFSCallStats.TotalCalls++;
4496     FS_UNLOCK
4497
4498     if (avolid == 0) {
4499         errorCode = EINVAL;
4500         goto Bad_GetVolumeStatus;
4501     }
4502     dummyFid.Volume = avolid, dummyFid.Vnode = (afs_int32)ROOTVNODE, dummyFid.Unique = 1;
4503
4504     if (errorCode = GetVolumePackage(tcon, &dummyFid, &volptr, &targetptr,
4505                                      MustBeDIR, &parentwhentargetnotdir,
4506                                      &client, READ_LOCK, &rights, &anyrights))
4507         goto Bad_GetVolumeStatus;
4508
4509     if ((VanillaUser(client)) && (!(rights & PRSFS_READ))) {
4510         errorCode = EACCES;
4511         goto Bad_GetVolumeStatus;
4512     }
4513     RXGetVolumeStatus(FetchVolStatus, Name, OfflineMsg, Motd, volptr);
4514
4515 Bad_GetVolumeStatus:
4516     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
4517     ViceLog(2,("SAFS_GetVolumeStatus returns %d\n",errorCode));
4518     /* next is to guarantee out strings exist for stub */
4519     if (*Name == 0) {*Name = (char *) malloc(1); **Name = 0;}
4520     if (*Motd == 0) {*Motd = (char *) malloc(1); **Motd = 0;}
4521     if (*OfflineMsg == 0) {*OfflineMsg = (char *) malloc(1); **OfflineMsg = 0;}
4522     CallPostamble(tcon);
4523
4524 #if FS_STATS_DETAILED
4525     TM_GetTimeOfDay(&opStopTime, 0);
4526     if (errorCode == 0) {
4527       FS_LOCK
4528       (opP->numSuccesses)++;
4529       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
4530       fs_stats_AddTo((opP->sumTime), elapsedTime);
4531       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
4532       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
4533         fs_stats_TimeAssign((opP->minTime), elapsedTime);
4534       }
4535       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
4536         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
4537       }
4538       FS_UNLOCK
4539     }
4540
4541 #endif /* FS_STATS_DETAILED */
4542     return(errorCode);
4543
4544 } /*SRXAFS_GetVolumeStatus*/
4545
4546
4547 SRXAFS_SetVolumeStatus (tcon, avolid, StoreVolStatus, Name, OfflineMsg, Motd)
4548     struct rx_connection *tcon;           /* Rx connection handle */
4549     afs_int32 avolid;                     /* Volume's id */
4550     AFSStoreVolumeStatus *StoreVolStatus; /* Adjusted output volume's status */
4551     char *Name;                           /* Set new volume's name, if applicable */
4552     char *OfflineMsg;                     /* Set new offline msg, if applicable */
4553     char *Motd;                           /* Set new motd msg, if applicable */
4554
4555 {
4556     Vnode * targetptr = 0;              /* vnode of the new file */
4557     Vnode * parentwhentargetnotdir = 0; /* vnode of parent */
4558     int     errorCode = 0;              /* error code */
4559     Volume * volptr = 0;                /* pointer to the volume header */
4560     struct client * client;             /* pointer to client entry */
4561     afs_int32 rights, anyrights;                /* rights for this and any user */
4562     AFSFid  dummyFid;
4563     struct rx_call *tcall = (struct rx_call *) tcon; 
4564 #if FS_STATS_DETAILED
4565     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
4566     struct timeval opStartTime,
4567                    opStopTime;              /* Start/stop times for RPC op*/
4568     struct timeval elapsedTime;             /* Transfer time */
4569
4570     /*
4571      * Set our stats pointer, remember when the RPC operation started, and
4572      * tally the operation.
4573      */
4574     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_SETVOLUMESTATUS]);
4575     FS_LOCK
4576     (opP->numOps)++;
4577     FS_UNLOCK
4578     TM_GetTimeOfDay(&opStartTime, 0);
4579 #endif /* FS_STATS_DETAILED */
4580
4581     ViceLog(1,("SAFS_SetVolumeStatus for volume %u\n", avolid));
4582     if (errorCode = CallPreamble((struct rx_call **) &tcon, ACTIVECALL))
4583         goto Bad_SetVolumeStatus;
4584
4585     FS_LOCK
4586     AFSCallStats.SetVolumeStatus++, AFSCallStats.TotalCalls++;
4587     FS_UNLOCK
4588
4589     if (avolid == 0) {
4590         errorCode = EINVAL;
4591         goto Bad_SetVolumeStatus;
4592     }
4593     dummyFid.Volume = avolid, dummyFid.Vnode = (afs_int32)ROOTVNODE, dummyFid.Unique = 1;
4594
4595     if (errorCode = GetVolumePackage(tcon, &dummyFid, &volptr, &targetptr,
4596                                      MustBeDIR, &parentwhentargetnotdir,
4597                                      &client, READ_LOCK, &rights, &anyrights))
4598         goto Bad_SetVolumeStatus;
4599
4600     if (VanillaUser(client)) {
4601         errorCode = EACCES;
4602         goto Bad_SetVolumeStatus;
4603     }
4604
4605     errorCode = RXUpdate_VolumeStatus(volptr, StoreVolStatus, Name,
4606                                       OfflineMsg, Motd);
4607
4608  Bad_SetVolumeStatus:
4609     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
4610     ViceLog(2,("SAFS_SetVolumeStatus returns %d\n",errorCode));
4611     CallPostamble(tcon);
4612
4613 #if FS_STATS_DETAILED
4614     TM_GetTimeOfDay(&opStopTime, 0);
4615     if (errorCode == 0) {
4616       FS_LOCK
4617       (opP->numSuccesses)++;
4618       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
4619       fs_stats_AddTo((opP->sumTime), elapsedTime);
4620       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
4621       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
4622         fs_stats_TimeAssign((opP->minTime), elapsedTime);
4623       }
4624       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
4625         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
4626       }
4627       FS_UNLOCK
4628     }
4629
4630 #endif /* FS_STATS_DETAILED */
4631
4632     osi_auditU (tcall, SetVolumeStatusEvent, errorCode, AUD_LONG, avolid, AUD_STR, Name, AUD_END);
4633     return(errorCode);
4634
4635 } /*SRXAFS_SetVolumeStatus*/
4636
4637 #define DEFAULTVOLUME   "root.afs"
4638
4639
4640 SRXAFS_GetRootVolume (tcon, VolumeName)
4641     struct rx_connection * tcon; /* R-Connection handle */
4642     char **VolumeName;           /* Returned AFS's root volume name */
4643
4644 {
4645     int fd;
4646     int len;
4647     char *temp;
4648     int errorCode = 0;          /* error code */
4649 #if FS_STATS_DETAILED
4650     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
4651     struct timeval opStartTime,
4652                    opStopTime;              /* Start/stop times for RPC op*/
4653     struct timeval elapsedTime;             /* Transfer time */
4654
4655     /*
4656      * Set our stats pointer, remember when the RPC operation started, and
4657      * tally the operation.
4658      */
4659     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETROOTVOLUME]);
4660     FS_LOCK
4661     (opP->numOps)++;
4662     FS_UNLOCK
4663     TM_GetTimeOfDay(&opStartTime, 0);
4664 #endif /* FS_STATS_DETAILED */
4665
4666     return FSERR_EOPNOTSUPP;
4667
4668 #ifdef  notdef
4669     if (errorCode = CallPreamble((struct rx_call **) &tcon, ACTIVECALL))
4670         goto Bad_GetRootVolume;
4671     FS_LOCK
4672     AFSCallStats.GetRootVolume++, AFSCallStats.TotalCalls++;
4673     FS_UNLOCK
4674
4675     temp = malloc(256);
4676     fd = open(AFSDIR_SERVER_ROOTVOL_FILEPATH, O_RDONLY, 0666);
4677     if (fd <= 0)
4678         strcpy(temp, DEFAULTVOLUME);
4679     else {
4680 #if defined (AFS_AIX_ENV) || defined (AFS_HPUX_ENV)
4681         lockf(fd, F_LOCK, 0);
4682 #else
4683         flock(fd, LOCK_EX);
4684 #endif
4685         len = read(fd, temp, 256);
4686 #if defined (AFS_AIX_ENV) || defined (AFS_HPUX_ENV)
4687         lockf(fd, F_ULOCK, 0);
4688 #else
4689         flock(fd, LOCK_UN);
4690 #endif
4691         close(fd);
4692         if (temp[len-1] == '\n') len--;
4693         temp[len] = '\0';
4694     }
4695     *VolumeName = temp;     /* freed by rx server-side stub */
4696
4697 Bad_GetRootVolume:
4698     CallPostamble(tcon);
4699
4700 #if FS_STATS_DETAILED
4701     TM_GetTimeOfDay(&opStopTime, 0);
4702     if (errorCode == 0) {
4703       FS_LOCK
4704       (opP->numSuccesses)++;
4705       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
4706       fs_stats_AddTo((opP->sumTime), elapsedTime);
4707       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
4708       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
4709         fs_stats_TimeAssign((opP->minTime), elapsedTime);
4710       }
4711       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
4712         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
4713       }
4714       FS_UNLOCK
4715     }
4716 #endif /* FS_STATS_DETAILED */
4717
4718     return(errorCode);
4719 #endif  /* notdef */
4720
4721 } /*SRXAFS_GetRootVolume*/
4722
4723
4724 /* still works because a struct CBS is the same as a struct AFSOpaque */
4725 SRXAFS_CheckToken (tcon, AfsId, Token)
4726     struct rx_connection *tcon; /* Rx connection handle */
4727     afs_int32 AfsId;                    /* AFS id whose token we verify */
4728     struct CBS *Token;          /* Token value for used Afsid */
4729
4730 {
4731     afs_int32 code;
4732 #if FS_STATS_DETAILED
4733     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
4734     struct timeval opStartTime,
4735                    opStopTime;              /* Start/stop times for RPC op*/
4736     struct timeval elapsedTime;             /* Transfer time */
4737
4738     /*
4739      * Set our stats pointer, remember when the RPC operation started, and
4740      * tally the operation.
4741      */
4742     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_CHECKTOKEN]);
4743     FS_LOCK
4744     (opP->numOps)++;
4745     FS_UNLOCK
4746     TM_GetTimeOfDay(&opStartTime, 0);
4747 #endif /* FS_STATS_DETAILED */
4748
4749     if (code = CallPreamble((struct rx_call **) &tcon, ACTIVECALL))
4750         goto Bad_CheckToken;
4751
4752     code = FSERR_ECONNREFUSED;
4753     
4754 Bad_CheckToken:
4755     CallPostamble(tcon);
4756
4757 #if FS_STATS_DETAILED
4758     TM_GetTimeOfDay(&opStopTime, 0);
4759     if (code == 0) {
4760       FS_LOCK
4761       (opP->numSuccesses)++;
4762       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
4763       fs_stats_AddTo((opP->sumTime), elapsedTime);
4764       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
4765       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
4766         fs_stats_TimeAssign((opP->minTime), elapsedTime);
4767       }
4768       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
4769         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
4770       }
4771       FS_UNLOCK
4772     }
4773
4774 #endif /* FS_STATS_DETAILED */
4775
4776     return code;
4777
4778 } /*SRXAFS_CheckToken*/
4779
4780
4781 static GetTime (tcon, Seconds, USeconds)
4782     struct rx_connection *tcon;     /* R-Connection handle */
4783     afs_uint32 *Seconds;            /* Returned time in seconds */
4784     afs_uint32 *USeconds;           /* Returned leftovers in useconds */
4785
4786 {
4787     struct timeval tpl;
4788
4789     FS_LOCK
4790     AFSCallStats.GetTime++, AFSCallStats.TotalCalls++;
4791     FS_UNLOCK
4792
4793     TM_GetTimeOfDay(&tpl, 0);
4794     *Seconds = tpl.tv_sec;
4795     *USeconds = tpl.tv_usec;
4796
4797     ViceLog(2, ("SAFS_GetTime returns %d, %d\n", *Seconds, *USeconds));
4798     return(0);
4799
4800 } /*GetTime*/
4801
4802
4803 SRXAFS_GetTime (tcon, Seconds, USeconds)
4804     struct rx_connection *tcon;     /* Rx connection handle */
4805     afs_uint32 *Seconds;            /* Returned time in seconds */
4806     afs_uint32 *USeconds;           /* Returned leftovers in useconds */
4807 {
4808     afs_int32 code;
4809 #if FS_STATS_DETAILED
4810     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
4811     struct timeval opStartTime,
4812                    opStopTime;              /* Start/stop times for RPC op*/
4813     struct timeval elapsedTime;             /* Transfer time */
4814
4815     /*
4816      * Set our stats pointer, remember when the RPC operation started, and
4817      * tally the operation.
4818      */
4819     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETTIME]);
4820     FS_LOCK
4821     (opP->numOps)++;
4822     FS_UNLOCK
4823     TM_GetTimeOfDay(&opStartTime, 0);
4824 #endif /* FS_STATS_DETAILED */
4825
4826     if (code = CallPreamble((struct rx_call **) &tcon, NOTACTIVECALL))
4827         goto Bad_GetTime;
4828
4829     code = GetTime (tcon, Seconds, USeconds);
4830     
4831 Bad_GetTime:
4832     CallPostamble(tcon);
4833
4834 #if FS_STATS_DETAILED
4835     TM_GetTimeOfDay(&opStopTime, 0);
4836     fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
4837     if (code == 0) {
4838       FS_LOCK
4839       (opP->numSuccesses)++;
4840       fs_stats_AddTo((opP->sumTime), elapsedTime);
4841       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
4842       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
4843         fs_stats_TimeAssign((opP->minTime), elapsedTime);
4844       }
4845       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
4846         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
4847       }
4848       FS_UNLOCK
4849     }
4850
4851 #endif /* FS_STATS_DETAILED */
4852
4853     return code;
4854
4855 } /*SRXAFS_GetTime*/
4856
4857
4858 /*=============================================================================*/
4859 /*                                                                             */
4860 /* AUXILIARY functions that are used by the main AFS interface procedure calls */
4861 /*                                                                             */
4862 /*=============================================================================*/
4863
4864
4865 /*
4866  * This unusual afs_int32-parameter routine encapsulates all volume package related
4867  * operations together in a single function; it's called by almost all AFS
4868  * interface calls.
4869  */
4870 GetVolumePackage(tcon, Fid, volptr, targetptr, chkforDir, parent, client, locktype, rights, anyrights)
4871     struct rx_connection *tcon; /* Rx connection */
4872     AFSFid *Fid;                /* Fid that we are dealing with */
4873     Volume **volptr;            /* Returns pointer to volume associated with Fid */
4874     Vnode **targetptr;          /* Returns pointer to vnode associated with Fid */
4875     int chkforDir;               /* Flag testing whether Fid is/or not a dir */
4876     Vnode **parent;             /* If Fid not a dir, this points to the parent dir */
4877     struct client **client;     /* Returns the client associated with the conn */
4878     int locktype;               /* locktype (READ or WRITE) for the Fid vnode */
4879     afs_int32 *rights, *anyrights;   /* Returns user's & any acl rights */
4880
4881 {
4882     struct acl_accessList * aCL;    /* Internal access List */
4883     int aCLSize;            /* size of the access list */
4884     int errorCode = 0;      /* return code to caller */
4885
4886     if (errorCode = CheckVnode(Fid, volptr, targetptr, locktype))
4887         return(errorCode);
4888     if (chkforDir) {
4889         if (chkforDir == MustNOTBeDIR && ((*targetptr)->disk.type == vDirectory))
4890             return(EISDIR);
4891         else if (chkforDir == MustBeDIR && ((*targetptr)->disk.type != vDirectory))
4892             return(ENOTDIR);
4893     }
4894     if ((errorCode = SetAccessList(targetptr, volptr, &aCL, &aCLSize, parent, (chkforDir == MustBeDIR ? (AFSFid *)0 : Fid), (chkforDir == MustBeDIR ? 0 : locktype))) != 0)
4895         return(errorCode);
4896     if (chkforDir == MustBeDIR) assert((*parent) == 0);
4897     if ((errorCode = GetClient(tcon, client)) != 0)
4898         return(errorCode);
4899     if (!(*client))
4900         return(EINVAL);
4901     assert(GetRights(*client, aCL, rights, anyrights) == 0);
4902     /* ok, if this is not a dir, set the PRSFS_ADMINISTER bit iff we're the owner */
4903     if ((*targetptr)->disk.type != vDirectory) {
4904         /* anyuser can't be owner, so only have to worry about rights, not anyrights */
4905         if ((*targetptr)->disk.owner == (*client)->ViceId)
4906             (*rights) |= PRSFS_ADMINISTER;
4907         else
4908             (*rights) &= ~PRSFS_ADMINISTER;
4909     }
4910 #ifdef ADMIN_IMPLICIT_LOOKUP
4911     /* admins get automatic lookup on everything */
4912     if (!VanillaUser(*client)) (*rights) |= PRSFS_LOOKUP;
4913 #endif /* ADMIN_IMPLICIT_LOOKUP */
4914     return errorCode;
4915
4916 } /*GetVolumePackage*/
4917
4918
4919 /*
4920  * This is the opposite of GetVolumePackage(), and is always used at the end of
4921  * AFS calls to put back all used vnodes and the volume in the proper order!
4922  */
4923 PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr)
4924     Vnode *parentwhentargetnotdir, *targetptr, *parentptr;
4925     Volume *volptr;
4926
4927 {
4928     int fileCode = 0;   /* Error code returned by the volume package */
4929
4930     if (parentwhentargetnotdir) {
4931         VPutVnode(&fileCode, parentwhentargetnotdir);
4932         assert(!fileCode || (fileCode == VSALVAGE));
4933     }
4934     if (targetptr) {
4935         VPutVnode(&fileCode, targetptr);
4936         assert(!fileCode || (fileCode == VSALVAGE));
4937     }
4938     if (parentptr) {
4939         VPutVnode(&fileCode, parentptr);
4940         assert(!fileCode || (fileCode == VSALVAGE));
4941     }
4942     if (volptr) {
4943         VPutVolume(volptr);
4944     }
4945 } /*PutVolumePackage*/
4946
4947
4948 #if FS_STATS_DETAILED
4949 /*
4950  * FetchData_RXStyle
4951  *
4952  * Purpose:
4953  *      Implement a client's data fetch using Rx.
4954  *
4955  * Arguments:
4956  *      volptr          : Ptr to the given volume's info.
4957  *      targetptr       : Pointer to the vnode involved.
4958  *      Call            : Ptr to the Rx call involved.
4959  *      Pos             : Offset within the file.
4960  *      Len             : Length in bytes to read; this value is bogus!
4961  *      a_bytesToFetchP : Set to the number of bytes to be fetched from
4962  *                        the File Server.
4963  *      a_bytesFetchedP : Set to the actual number of bytes fetched from
4964  #                        the File Server.
4965  */
4966
4967 FetchData_RXStyle(volptr, targetptr, Call, Pos, Len, a_bytesToFetchP, a_bytesFetchedP)
4968 #else
4969 FetchData_RXStyle(volptr, targetptr, Call, Pos, Len)
4970 #endif /* FS_STATS_DETAILED */
4971 Volume                  * volptr;
4972 Vnode                   * targetptr;
4973 register struct rx_call         * Call;
4974 afs_int32                       Pos;
4975 afs_int32                       Len;
4976 #if FS_STATS_DETAILED
4977 afs_int32 *a_bytesToFetchP;
4978 afs_int32 *a_bytesFetchedP;
4979 #endif /* FS_STATS_DETAILED */
4980 {
4981     struct timeval StartTime, StopTime; /* used to calculate file  transfer rates */
4982     int errorCode = 0;                  /* Returned error code to caller */
4983     int code;
4984     IHandle_t *ihP;
4985     FdHandle_t *fdP;
4986 #ifdef AFS_NT40_ENV
4987     register char *tbuffer;
4988 #else /* AFS_NT40_ENV */
4989     struct iovec tiov[RX_MAXIOVECS];
4990     int tnio;
4991 #endif /* AFS_NT40_ENV */
4992     int tlen;
4993     afs_int32 optSize;
4994     struct stat tstat;
4995 #ifdef  AFS_AIX_ENV
4996     struct statfs tstatfs;
4997 #endif
4998
4999 #if FS_STATS_DETAILED
5000     /*
5001      * Initialize the byte count arguments.
5002      */
5003     (*a_bytesToFetchP) = 0;
5004     (*a_bytesFetchedP) = 0;
5005 #endif /* FS_STATS_DETAILED */
5006
5007     if (!VN_GET_INO(targetptr)) {
5008         /*
5009          * This is used for newly created files; we simply send 0 bytes
5010          * back to make the cache manager happy...
5011          */
5012         tlen = htonl(0);
5013         rx_Write(Call, &tlen, sizeof(afs_int32));       /* send 0-length  */
5014         return (0);
5015     }
5016     TM_GetTimeOfDay(&StartTime, 0);
5017     ihP = targetptr->handle;
5018     fdP = IH_OPEN(ihP);
5019     if (fdP == NULL) return EIO;
5020     optSize = AFSV_BUFFERSIZE;
5021     tlen = FDH_SIZE(fdP);
5022     if (tlen < 0) {
5023         FDH_CLOSE(fdP);
5024         return EIO;
5025     }
5026
5027     if (Pos + Len > tlen) Len = tlen - Pos;     /* get length we should send */
5028     FDH_SEEK(fdP, Pos, 0);
5029     tlen = htonl(Len);
5030     rx_Write(Call, &tlen, sizeof(afs_int32));   /* send length on fetch */
5031 #if FS_STATS_DETAILED
5032     (*a_bytesToFetchP) = Len;
5033 #endif /* FS_STATS_DETAILED */
5034 #ifdef AFS_NT40_ENV
5035     tbuffer = AllocSendBuffer();
5036 #endif /* AFS_NT40_ENV */
5037     while (Len > 0) {
5038         if (Len > optSize) tlen = optSize;
5039         else tlen = Len;
5040 #ifdef AFS_NT40_ENV
5041         errorCode = FDH_READ(fdP, tbuffer, tlen);
5042         if (errorCode != tlen) {
5043             FDH_CLOSE(fdP);
5044             FreeSendBuffer((struct afs_buffer *) tbuffer);
5045             return EIO;
5046         }
5047         errorCode = rx_Write(Call, tbuffer, tlen);
5048 #else /* AFS_NT40_ENV */
5049         errorCode = rx_WritevAlloc(Call, tiov, &tnio, RX_MAXIOVECS, tlen);
5050         if (errorCode <= 0) {
5051             FDH_CLOSE(fdP);
5052             return EIO;
5053         }
5054         tlen = errorCode;
5055         errorCode = FDH_READV(fdP, tiov, tnio);
5056         if (errorCode != tlen) {
5057             FDH_CLOSE(fdP);
5058             return EIO;
5059         }
5060         errorCode = rx_Writev(Call, tiov, tnio, tlen);
5061 #endif /* AFS_NT40_ENV */
5062 #if FS_STATS_DETAILED
5063         /*
5064           * Bump the number of bytes actually sent by the number from this
5065           * latest iteration
5066           */
5067         (*a_bytesFetchedP) += errorCode;
5068 #endif /* FS_STATS_DETAILED */
5069         if (errorCode != tlen) {
5070             FDH_CLOSE(fdP);
5071 #ifdef AFS_NT40_ENV
5072             FreeSendBuffer((struct afs_buffer *) tbuffer);
5073 #endif /* AFS_NT40_ENV */
5074             return -31;
5075         }
5076         Len -= tlen;
5077     }
5078 #ifdef AFS_NT40_ENV
5079     FreeSendBuffer((struct afs_buffer *) tbuffer);
5080 #endif /* AFS_NT40_ENV */
5081     FDH_CLOSE(fdP);
5082     TM_GetTimeOfDay(&StopTime, 0);
5083
5084     /* Adjust all Fetch Data related stats */
5085     FS_LOCK
5086     if (AFSCallStats.TotalFetchedBytes > 2000000000) /* Reset if over 2 billion */
5087         AFSCallStats.TotalFetchedBytes = AFSCallStats.AccumFetchTime = 0;
5088     AFSCallStats.AccumFetchTime += ((StopTime.tv_sec - StartTime.tv_sec) * 1000) +
5089       ((StopTime.tv_usec - StartTime.tv_usec) / 1000);
5090     AFSCallStats.TotalFetchedBytes += targetptr->disk.length;
5091     AFSCallStats.FetchSize1++;
5092     if (targetptr->disk.length < SIZE2)
5093         AFSCallStats.FetchSize2++;  
5094     else if (targetptr->disk.length < SIZE3)
5095         AFSCallStats.FetchSize3++;
5096     else if (targetptr->disk.length < SIZE4)
5097         AFSCallStats.FetchSize4++;  
5098     else
5099         AFSCallStats.FetchSize5++;
5100     FS_UNLOCK
5101     return (0);
5102
5103 } /*FetchData_RXStyle*/
5104
5105 static int GetLinkCountAndSize(Volume *vp, FdHandle_t *fdP, int *lc, int *size)
5106 {
5107 #ifdef AFS_NAMEI_ENV
5108     FdHandle_t *lhp;
5109     lhp = IH_OPEN(V_linkHandle(vp));
5110     if (!lhp)
5111         return EIO;
5112 #ifdef AFS_NT40_ENV
5113     *lc = nt_GetLinkCount(lhp, fdP->fd_ih->ih_ino, 0);
5114 #else
5115     *lc = namei_GetLinkCount(lhp, fdP->fd_ih->ih_ino, 0);
5116 #endif
5117     FDH_CLOSE(lhp);
5118     if (*lc < 0 )
5119         return -1;
5120     *size = OS_SIZE(fdP->fd_fd);
5121     return (*size == -1) ? -1 : 0;
5122 #else
5123     struct stat status;
5124
5125     if (fstat(fdP->fd_fd, &status)<0) {
5126         return -1;
5127     }
5128
5129     *lc = GetLinkCount(vp, &status);
5130     *size = status.st_size;
5131     return 0;
5132 #endif   
5133 }
5134
5135 #if FS_STATS_DETAILED
5136 /*
5137  * StoreData_RXStyle
5138  *
5139  * Purpose:
5140  *      Implement a client's data store using Rx.
5141  *
5142  * Arguments:
5143  *      volptr          : Ptr to the given volume's info.
5144  *      targetptr       : Pointer to the vnode involved.
5145  *      Call            : Ptr to the Rx call involved.
5146  *      Pos             : Offset within the file.
5147  *      Len             : Length in bytes to store; this value is bogus!
5148  *      a_bytesToStoreP : Set to the number of bytes to be stored to
5149  *                        the File Server.
5150  *      a_bytesStoredP  : Set to the actual number of bytes stored to
5151  #                        the File Server.
5152  */
5153
5154 StoreData_RXStyle(volptr, targetptr, Fid, client, Call, Pos, Length,
5155                   FileLength, sync, a_bytesToStoreP, a_bytesStoredP)
5156 #else
5157 StoreData_RXStyle(volptr, targetptr, Fid, client, Call, Pos, Length,
5158                   FileLength, sync)
5159 #endif /* FS_STATS_DETAILED */
5160
5161     Volume *volptr;
5162     Vnode *targetptr;
5163     struct AFSFid *Fid;
5164     struct client *client;
5165     register struct rx_call *Call;
5166     afs_int32 Pos;
5167     afs_int32 Length;
5168     afs_int32 FileLength;
5169     int sync;
5170 #if FS_STATS_DETAILED
5171     afs_int32 *a_bytesToStoreP;
5172     afs_int32 *a_bytesStoredP;
5173 #endif /* FS_STATS_DETAILED */
5174
5175 {
5176     int     bytesTransfered;            /* number of bytes actually transfered */
5177     struct timeval StartTime, StopTime; /* Used to measure how long the store takes */
5178     int errorCode = 0;                  /* Returned error code to caller */
5179 #ifdef AFS_NT40_ENV
5180     register char *tbuffer;             /* data copying buffer */
5181 #else /* AFS_NT40_ENV */
5182     struct iovec tiov[RX_MAXIOVECS];    /* no data copying with iovec */
5183     int tnio;                           /* temp for iovec size */
5184 #endif /* AFS_NT40_ENV */
5185     int tlen;                           /* temp for xfr length */
5186     Inode tinode;                       /* inode for I/O */
5187     afs_int32 optSize;                  /* optimal transfer size */
5188     int DataLength;                     /* size of inode */
5189     afs_int32 TruncatedLength;          /* size after ftruncate */
5190     afs_int32 NewLength;                        /* size after this store completes */
5191     afs_int32 adjustSize;                       /* bytes to call VAdjust... with */
5192     int linkCount;                      /* link count on inode */
5193     int code;
5194     FdHandle_t *fdP;
5195     struct in_addr logHostAddr;             /* host ip holder for inet_ntoa */
5196
5197 #if FS_STATS_DETAILED
5198     /*
5199      * Initialize the byte count arguments.
5200      */
5201     (*a_bytesToStoreP) = 0;
5202     (*a_bytesStoredP)  = 0;
5203 #endif /* FS_STATS_DETAILED */
5204
5205     /*
5206      * We break the callbacks here so that the following signal will not
5207      * leave a window.
5208      */
5209     BreakCallBack(client->host, Fid, 0);
5210
5211     if (Pos == -1 || VN_GET_INO(targetptr) == 0) {
5212         /* the inode should have been created in Alloc_NewVnode */
5213         logHostAddr.s_addr = rx_HostOf(rx_PeerOf(rx_ConnectionOf(Call)));
5214         ViceLog(0, ("StoreData_RXStyle : Inode non-existent Fid = %u.%d.%d, inode = %d, Pos %d Host %s\n",
5215                 Fid->Volume, Fid->Vnode, Fid->Unique, 
5216                 VN_GET_INO(targetptr), Pos, inet_ntoa(logHostAddr) ));
5217         return ENOENT;  /* is this proper error code? */
5218     }
5219     else {
5220         /*
5221          * See if the file has several links (from other volumes).  If it
5222          * does, then we have to make a copy before changing it to avoid
5223          *changing read-only clones of this dude
5224          */
5225         ViceLog(25, ("StoreData_RXStyle : Opening inode %s\n",
5226                      PrintInode(NULL, VN_GET_INO(targetptr))));
5227         fdP = IH_OPEN(targetptr->handle);
5228         if (fdP == NULL) 
5229             return ENOENT;
5230         if (GetLinkCountAndSize(volptr, fdP, &linkCount,
5231                                 &DataLength)<0) {
5232             FDH_CLOSE(fdP);
5233             return EIO;
5234         }
5235         
5236         if (linkCount != 1) {
5237             int size;
5238             ViceLog(25, ("StoreData_RXStyle : inode %s has more than onelink\n",
5239                          PrintInode(NULL, VN_GET_INO(targetptr))));
5240             /* other volumes share this data, better copy it first */
5241
5242             /* Adjust the disk block count by the creation of the new inode.
5243              * We call the special VDiskUsage so we don't adjust the volume's
5244              * quota since we don't want to penalyze the user for afs's internal
5245              * mechanisms (i.e. copy on write overhead.) Also the right size
5246              * of the disk will be recorded...
5247              */
5248             FDH_CLOSE(fdP);
5249             size = targetptr->disk.length;
5250             volptr->partition->flags &= ~PART_DONTUPDATE;
5251             VSetPartitionDiskUsage(volptr->partition);
5252             volptr->partition->flags |= PART_DONTUPDATE;
5253             if (errorCode = VDiskUsage(volptr, nBlocks(size))) {
5254                 volptr->partition->flags &= ~PART_DONTUPDATE;
5255                 return(errorCode);
5256             }
5257
5258             ViceLog(25, ("StoreData : calling CopyOnWrite on  target dir\n"));
5259             if ( errorCode = CopyOnWrite(targetptr, volptr))
5260             {
5261                 ViceLog(25, ("StoreData : CopyOnWrite failed\n"));
5262                 volptr->partition->flags &= ~PART_DONTUPDATE;
5263                 return (errorCode);
5264             }
5265             volptr->partition->flags &= ~PART_DONTUPDATE;
5266             VSetPartitionDiskUsage(volptr->partition);
5267             fdP = IH_OPEN(targetptr->handle);
5268             if (fdP == NULL)  {
5269                 ViceLog(25, ("StoreData : Reopen after CopyOnWrite failed\n"));
5270                 return ENOENT;
5271             }
5272         }
5273         tinode = VN_GET_INO(targetptr);
5274     }
5275     assert(VALID_INO(tinode));
5276
5277     /* compute new file length */
5278     NewLength = DataLength;
5279     if (FileLength < NewLength)
5280         /* simulate truncate */
5281         NewLength = FileLength; 
5282     TruncatedLength = NewLength; /* remember length after possible ftruncate */
5283     if (Pos + Length > NewLength)
5284         NewLength = Pos+Length;   /* and write */
5285
5286     /* adjust the disk block count by the difference in the files */
5287     adjustSize = (int) (nBlocks(NewLength) - nBlocks(targetptr->disk.length));
5288     if(errorCode = AdjustDiskUsage(volptr, adjustSize,
5289                                    adjustSize - SpareComp(volptr))) {
5290         FDH_CLOSE(fdP);
5291         return(errorCode);
5292     }
5293
5294     /* can signal cache manager to proceed from close now */
5295     /* this bit means that the locks are set and protections are OK */
5296     rx_SetLocalStatus(Call, 1);
5297
5298     TM_GetTimeOfDay(&StartTime, 0);
5299
5300     optSize = AFSV_BUFFERSIZE;
5301
5302     /* truncate the file iff it needs it (ftruncate is slow even when its a noop) */
5303     if (FileLength < DataLength) FDH_TRUNC(fdP, FileLength);
5304     if (Pos > 0) FDH_SEEK(fdP, Pos, 0);
5305     bytesTransfered = 0;
5306 #ifdef AFS_NT40_ENV
5307     tbuffer = AllocSendBuffer();
5308 #endif /* AFS_NT40_ENV */
5309     /* if length == 0, the loop below isn't going to do anything, including
5310      * extend the length of the inode, which it must do, since the file system
5311      * assumes that the inode length == vnode's file length.  So, we extend
5312      * the file length manually if need be.  Note that if file is bigger than
5313      * Pos+(Length==0), we dont' have to do anything, and certainly shouldn't
5314      * do what we're going to do below.
5315      */
5316     if (Length == 0 && Pos > TruncatedLength) {
5317         /* Set the file's length; we've already done an lseek to the right
5318          * spot above.
5319          */
5320         errorCode = FDH_WRITE(fdP, &tlen, 1);
5321         if (errorCode != 1) goto done;
5322         errorCode = FDH_TRUNC(fdP, Pos);
5323     }
5324     else {
5325         /* have some data to copy */
5326 #if FS_STATS_DETAILED
5327         (*a_bytesToStoreP) = Length;
5328 #endif /* FS_STATS_DETAILED */
5329         while (1) {
5330             if (bytesTransfered >= Length) {
5331                 errorCode = 0;
5332                 break;
5333             }
5334             tlen = Length -     bytesTransfered;    /* how much more to do */
5335             if (tlen > optSize) tlen = optSize; /* bound by buffer size */
5336 #ifdef AFS_NT40_ENV
5337             errorCode = rx_Read(Call, tbuffer, tlen);
5338 #else /* AFS_NT40_ENV */
5339             errorCode = rx_Readv(Call, tiov, &tnio, RX_MAXIOVECS, tlen);
5340 #endif /* AFS_NT40_ENV */
5341 #if FS_STATS_DETAILED
5342             (*a_bytesStoredP) += errorCode;
5343 #endif /* FS_STATS_DETAILED */
5344             if (errorCode <= 0) {
5345                 errorCode = -32;
5346                 break;
5347             }
5348             tlen = errorCode;
5349 #ifdef AFS_NT40_ENV
5350             errorCode = FDH_WRITE(fdP, tbuffer, tlen);
5351 #else /* AFS_NT40_ENV */
5352             errorCode = FDH_WRITEV(fdP, tiov, tnio);
5353 #endif /* AFS_NT40_ENV */
5354             if (errorCode != tlen) {
5355                 errorCode = VDISKFULL;
5356                 break;
5357             }
5358             bytesTransfered += tlen;
5359         }
5360     }
5361   done:
5362 #ifdef AFS_NT40_ENV
5363     FreeSendBuffer((struct afs_buffer *) tbuffer);
5364 #endif /* AFS_NT40_ENV */
5365     if (sync) {
5366       FDH_SYNC(fdP);
5367     }
5368     if (errorCode) {
5369         /* something went wrong: adjust size and return */
5370         targetptr->disk.length = FDH_SIZE(fdP); /* set new file size. */
5371         /* changed_newTime is tested in StoreData to detemine if we
5372          * need to update the target vnode.
5373          */
5374         targetptr->changed_newTime = 1;
5375         FDH_CLOSE(fdP);
5376         /* set disk usage to be correct */
5377         VAdjustDiskUsage(&errorCode, volptr,
5378                          (int)(nBlocks(targetptr->disk.length)
5379                                - nBlocks(NewLength)), 0);
5380         return errorCode;
5381     }
5382     FDH_CLOSE(fdP);
5383
5384     TM_GetTimeOfDay(&StopTime, 0);
5385
5386     targetptr->disk.length = NewLength;
5387
5388     /* Update all StoreData related stats */
5389     FS_LOCK
5390     if (AFSCallStats.TotalStoredBytes > 2000000000)     /* reset if over 2 billion */
5391         AFSCallStats.TotalStoredBytes = AFSCallStats.AccumStoreTime = 0;
5392     AFSCallStats.StoreSize1++;                  /* Piggybacked data */
5393     if (targetptr->disk.length < SIZE2)
5394         AFSCallStats.StoreSize2++;
5395     else if (targetptr->disk.length < SIZE3)
5396         AFSCallStats.StoreSize3++;
5397     else if (targetptr->disk.length < SIZE4)
5398         AFSCallStats.StoreSize4++;
5399     else
5400         AFSCallStats.StoreSize5++;
5401     FS_UNLOCK
5402     return(errorCode);
5403
5404 } /*StoreData_RXStyle*/
5405
5406
5407 /*
5408  * Check if target file has the proper access permissions for the Fetch
5409  * (FetchData, FetchACL, FetchStatus) and Store (StoreData, StoreACL,
5410  * StoreStatus) related calls
5411  */
5412 /* this code should probably just set a "priv" flag where all the audit events
5413  * are now, and only generate the audit event once at the end of the routine, 
5414  * thus only generating the event if all the checks succeed, but only because
5415  * of the privilege       XXX
5416  */
5417 Check_PermissionRights(targetptr, client, rights, CallingRoutine, InStatus)
5418     Vnode *targetptr;
5419     struct client *client;
5420     afs_int32 rights;
5421     int CallingRoutine;
5422     AFSStoreStatus *InStatus;
5423
5424 {
5425     int errorCode = 0;
5426 #define OWNSp(client, target) ((client)->ViceId == (target)->disk.owner)
5427 #define CHOWN(i,t) (((i)->Mask & AFS_SETOWNER) &&((i)->Owner != (t)->disk.owner))
5428 #define CHGRP(i,t) (((i)->Mask & AFS_SETGROUP) &&((i)->Group != (t)->disk.group))
5429
5430     if (CallingRoutine & CHK_FETCH) {
5431 #ifdef  CMUCS
5432         if (VanillaUser(client)) 
5433 #else
5434         if (CallingRoutine == CHK_FETCHDATA || VanillaUser(client)) 
5435 #endif
5436           {
5437             if (targetptr->disk.type == vDirectory || targetptr->disk.type == vSymlink) {
5438                 if (   !(rights & PRSFS_LOOKUP)
5439 #ifdef ADMIN_IMPLICIT_LOOKUP  
5440                     /* grant admins fetch on all directories */
5441                     && VanillaUser(client)
5442 #endif /* ADMIN_IMPLICIT_LOOKUP */
5443                     && !OWNSp(client, targetptr)
5444                     && !acl_IsAMember(targetptr->disk.owner, &client->CPS)
5445                     && !VolumeOwner(client, targetptr))
5446                     return(EACCES);
5447             } else {    /* file */
5448                 /* must have read access, or be owner and have insert access */
5449                 if (!(rights & PRSFS_READ) &&
5450                     !(OWNSp(client, targetptr) && (rights & PRSFS_INSERT)))
5451                     return(EACCES);
5452             }
5453             if (CallingRoutine == CHK_FETCHDATA && targetptr->disk.type == vFile)
5454 #ifdef USE_GROUP_PERMS
5455                 if (!OWNSp(client, targetptr) &&
5456                     !acl_IsAMember(targetptr->disk.owner, &client->CPS)) {
5457                     errorCode = (((GROUPREAD|GROUPEXEC) & targetptr->disk.modeBits)
5458                                  ? 0: EACCES);
5459                 } else {
5460                     errorCode =(((OWNERREAD|OWNEREXEC) & targetptr->disk.modeBits)
5461                                 ? 0: EACCES);
5462                 }
5463 #else
5464                 /*
5465                  * The check with the ownership below is a kludge to allow
5466                  * reading of files created with no read permission. The owner
5467                  * of the file is always allowed to read it.
5468                  */
5469                 if ((client->ViceId != targetptr->disk.owner) && VanillaUser(client))
5470                     errorCode =(((OWNERREAD|OWNEREXEC) & targetptr->disk.modeBits) ? 0: EACCES);
5471 #endif
5472         }
5473         else /*  !VanillaUser(client) && !FetchData */ {
5474           osi_audit( PrivilegeEvent, 0, AUD_INT, (client ? client->ViceId : 0), 
5475                                         AUD_INT, CallingRoutine, AUD_END);
5476         }
5477     }
5478     else { /* a store operation */
5479       if ( (rights & PRSFS_INSERT) && OWNSp(client, targetptr)
5480           && (CallingRoutine != CHK_STOREACL)
5481           && (targetptr->disk.type == vFile))
5482         {
5483           /* bypass protection checks on first store after a create
5484            * for the creator; also prevent chowns during this time
5485            * unless you are a system administrator */
5486           /******  InStatus->Owner && UnixModeBits better be SET!! */
5487           if ( CHOWN(InStatus, targetptr) || CHGRP(InStatus, targetptr)) {
5488             if (VanillaUser (client)) 
5489               return(EPERM);      /* Was EACCES */
5490             else
5491               osi_audit( PrivilegeEvent, 0, AUD_INT, (client ? client->ViceId : 0), 
5492                                             AUD_INT, CallingRoutine, AUD_END);
5493           }
5494         } else {
5495           if (CallingRoutine != CHK_STOREDATA && !VanillaUser(client)) {
5496             osi_audit( PrivilegeEvent, 0, AUD_INT, (client ? client->ViceId : 0),
5497                                           AUD_INT, CallingRoutine, AUD_END);
5498           }
5499           else {
5500             if (CallingRoutine == CHK_STOREACL) {
5501               if (!(rights & PRSFS_ADMINISTER) &&
5502                   !OWNSp(client, targetptr) && 
5503                   !acl_IsAMember(targetptr->disk.owner, &client->CPS) &&
5504                   !VolumeOwner(client, targetptr)) return(EACCES);
5505             }
5506             else {      /* store data or status */
5507               /* watch for chowns and chgrps */
5508               if (CHOWN(InStatus, targetptr) || CHGRP(InStatus, targetptr))
5509                 return(EPERM);      /* Was EACCES */
5510               /* must be sysadmin to set suid/sgid bits */
5511               if ((InStatus->Mask & AFS_SETMODE) &&
5512 #ifdef AFS_NT40_ENV
5513                   (InStatus->UnixModeBits & 0xc00) != 0) {
5514 #else
5515                   (InStatus->UnixModeBits & (S_ISUID|S_ISGID)) != 0) {
5516 #endif
5517                 if (VanillaUser(client))
5518                   return(EACCES);
5519                 else osi_audit( PrivSetID, 0, AUD_INT, (client ? client->ViceId : 0),
5520                                               AUD_INT, CallingRoutine, AUD_END);
5521               }
5522               if (CallingRoutine == CHK_STOREDATA) {
5523                 if (!(rights & PRSFS_WRITE))
5524                   return(EACCES);
5525                 /* Next thing is tricky.  We want to prevent people
5526                  * from writing files sans 0200 bit, but we want
5527                  * creating new files with 0444 mode to work.  We
5528                  * don't check the 0200 bit in the "you are the owner"
5529                  * path above, but here we check the bit.  However, if
5530                  * you're a system administrator, we ignore the 0200
5531                  * bit anyway, since you may have fchowned the file,
5532                  * too */
5533 #ifdef USE_GROUP_PERMS
5534                         if ((targetptr->disk.type == vFile)
5535                             && VanillaUser(client)) {
5536                             if (!OWNSp(client, targetptr) &&
5537                                 !acl_IsAMember(targetptr->disk.owner,
5538                                                &client->CPS)) {
5539                                 errorCode = ((GROUPWRITE & targetptr->disk.modeBits)
5540                                              ? 0: EACCES);
5541                             } else {
5542                                 errorCode = ((OWNERWRITE & targetptr->disk.modeBits)
5543                                              ? 0 : EACCES);
5544                             }
5545                         } else
5546 #endif
5547                 if ((targetptr->disk.type != vDirectory)
5548                     && (!(targetptr->disk.modeBits & OWNERWRITE)))
5549                   if (VanillaUser(client))
5550                     return(EACCES);
5551                   else osi_audit( PrivilegeEvent, 0, AUD_INT, (client ? client->ViceId : 0),
5552                                                      AUD_INT, CallingRoutine, AUD_END);
5553               }
5554               else {  /* a status store */
5555                 if (targetptr->disk.type == vDirectory) {
5556                   if (!(rights & PRSFS_DELETE) && !(rights & PRSFS_INSERT))
5557                     return(EACCES);
5558                 }
5559                 else {  /* a file  or symlink */
5560                   if (!(rights & PRSFS_WRITE)) return(EACCES);
5561                 }
5562               }
5563             }
5564           }
5565         }
5566     }
5567     return(errorCode);
5568
5569 } /*Check_PermissionRights*/
5570
5571
5572 /*
5573  * The Access List information is converted from its internal form in the
5574  * target's vnode buffer (or its parent vnode buffer if not a dir), to an
5575  * external form and returned back to the caller, via the AccessList
5576  * structure
5577  */
5578 RXFetch_AccessList(targetptr, parentwhentargetnotdir, AccessList)
5579 Vnode                   * targetptr;
5580 Vnode                   * parentwhentargetnotdir;
5581 struct AFSOpaque        * AccessList;
5582 {
5583     char * eACL;        /* External access list placeholder */
5584
5585     if (acl_Externalize((targetptr->disk.type == vDirectory ?
5586                          VVnodeACL(targetptr) :
5587                          VVnodeACL(parentwhentargetnotdir)), &eACL) != 0) {
5588         return EIO;
5589     }
5590     if ((strlen(eACL)+1) > AFSOPAQUEMAX) {
5591         acl_FreeExternalACL(&eACL);
5592         return(E2BIG);
5593     } else {
5594         strcpy((char *)(AccessList->AFSOpaque_val), (char *)eACL);
5595         AccessList->AFSOpaque_len = strlen(eACL) +1;
5596     }
5597     acl_FreeExternalACL(&eACL);
5598     return(0);
5599
5600 } /*RXFetch_AccessList*/
5601
5602
5603 /*
5604  * The Access List information is converted from its external form in the
5605  * input AccessList structure to the internal representation and copied into
5606  * the target dir's vnode storage.
5607  */
5608 RXStore_AccessList(targetptr, AccessList)
5609     Vnode *targetptr;
5610     struct AFSOpaque *AccessList;
5611
5612 {
5613     struct acl_accessList * newACL;     /* PlaceHolder for new access list */
5614
5615     if (acl_Internalize(AccessList->AFSOpaque_val, &newACL) != 0)
5616         return(EINVAL);
5617     if ((newACL->size + 4) > VAclSize(targetptr))
5618         return(E2BIG);
5619     memcpy((char *) VVnodeACL(targetptr), (char *) newACL, (int)(newACL->size));
5620     acl_FreeACL(&newACL);
5621     return(0);
5622
5623 } /*RXStore_AccessList*/
5624
5625
5626 Fetch_AccessList(targetptr, parentwhentargetnotdir, AccessList)
5627     Vnode *targetptr;
5628     Vnode *parentwhentargetnotdir;
5629     struct AFSAccessList *AccessList;
5630
5631 {
5632     char * eACL;        /* External access list placeholder */
5633
5634     assert(acl_Externalize((targetptr->disk.type == vDirectory ?
5635                             VVnodeACL(targetptr) :
5636                             VVnodeACL(parentwhentargetnotdir)), &eACL) == 0);
5637     if ((strlen(eACL)+1) > AccessList->MaxSeqLen) {
5638         acl_FreeExternalACL(&eACL);
5639         return(E2BIG);
5640     } else {
5641         strcpy((char *)(AccessList->SeqBody), (char *)eACL);
5642         AccessList->SeqLen = strlen(eACL) +1;
5643     }
5644     acl_FreeExternalACL(&eACL);
5645     return(0);
5646
5647 } /*Fetch_AccessList*/
5648
5649
5650 /*
5651  * The Access List information is converted from its external form in the
5652  * input AccessList structure to the internal representation and copied into
5653  * the target dir's vnode storage.
5654  */
5655 Store_AccessList(targetptr, AccessList)
5656     Vnode *targetptr;
5657     struct AFSAccessList *AccessList;
5658
5659 {
5660     struct acl_accessList * newACL;     /* PlaceHolder for new access list */
5661
5662     if (acl_Internalize(AccessList->SeqBody, &newACL) != 0)
5663         return(EINVAL);
5664     if ((newACL->size + 4) > VAclSize(targetptr))
5665         return(E2BIG);
5666     memcpy((char *) VVnodeACL(targetptr), (char *) newACL, (int)(newACL->size));
5667     acl_FreeACL(&newACL);
5668     return(0);
5669
5670 } /*Store_AccessList*/
5671
5672
5673 /*
5674  * Common code to handle with removing the Name (file when it's called from
5675  * SAFS_RemoveFile() or an empty dir when called from SAFS_rmdir()) from a
5676  * given directory, parentptr.
5677  */
5678 int DT1=0, DT0=0;
5679 DeleteTarget(parentptr, volptr, targetptr, dir, fileFid, Name, ChkForDir)
5680     Vnode *parentptr;
5681     Volume *volptr;
5682     Vnode **targetptr;
5683     DirHandle *dir;
5684     AFSFid *fileFid;
5685     char *Name;
5686     int ChkForDir;
5687 {
5688     DirHandle childdir;     /* Handle for dir package I/O */
5689     int errorCode = 0;
5690     int code;
5691
5692     /* watch for invalid names */
5693     if (!strcmp(Name, ".") || !strcmp(Name, ".."))
5694         return (EINVAL);
5695     if (parentptr->disk.cloned) 
5696     {
5697         ViceLog(25, ("DeleteTarget : CopyOnWrite called\n"));
5698         if ( errorCode = CopyOnWrite(parentptr, volptr))
5699         {
5700                 ViceLog(20, ("DeleteTarget %s: CopyOnWrite failed %d\n",Name,errorCode));
5701                 return errorCode;
5702         }
5703     }
5704
5705     /* check that the file is in the directory */
5706     SetDirHandle(dir, parentptr);
5707     if (Lookup(dir, Name, fileFid))
5708         return(ENOENT);
5709     fileFid->Volume = V_id(volptr);
5710
5711     /* just-in-case check for something causing deadlock */
5712     if (fileFid->Vnode == parentptr->vnodeNumber)
5713         return(EINVAL);
5714
5715     *targetptr = VGetVnode(&errorCode, volptr, fileFid->Vnode, WRITE_LOCK);
5716     if (errorCode) {
5717         return (errorCode);
5718     }
5719     if (ChkForDir == MustBeDIR) {
5720         if ((*targetptr)->disk.type != vDirectory)
5721             return(ENOTDIR);
5722     } else if ((*targetptr)->disk.type == vDirectory)
5723         return(EISDIR);
5724     
5725     /*assert((*targetptr)->disk.uniquifier == fileFid->Unique);*/
5726     /**
5727       * If the uniquifiers dont match then instead of asserting
5728       * take the volume offline and return VSALVAGE
5729       */
5730     if ( (*targetptr)->disk.uniquifier != fileFid->Unique ) {
5731         VTakeOffline(volptr);
5732         errorCode = VSALVAGE;
5733         return errorCode;
5734     }
5735         
5736     if (ChkForDir == MustBeDIR) {
5737         SetDirHandle(&childdir, *targetptr);
5738         if (IsEmpty(&childdir) != 0)
5739             return(EEXIST);
5740         DZap(&childdir);
5741         (*targetptr)->delete = 1;
5742     } else if ((--(*targetptr)->disk.linkCount) == 0) 
5743         (*targetptr)->delete = 1;
5744     if ((*targetptr)->delete) {
5745         if (VN_GET_INO(*targetptr)) {
5746             DT0++;
5747             IH_REALLYCLOSE((*targetptr)->handle);
5748             errorCode = IH_DEC(V_linkHandle(volptr),
5749                              VN_GET_INO(*targetptr),
5750                              V_parentId(volptr));
5751             IH_RELEASE((*targetptr)->handle);
5752             if (errorCode == -1) {
5753                 ViceLog(0, ("DT: inode=%s, name=%s, errno=%d\n",
5754                             PrintInode(NULL, VN_GET_INO(*targetptr)),
5755                             Name, errno));
5756 #ifdef  AFS_DEC_ENV
5757                 if ((errno != ENOENT) && (errno != EIO) && (errno != ENXIO))
5758 #else
5759                 if (errno != ENOENT) 
5760 #endif
5761                     {
5762                     ViceLog(0, ("Volume %u now offline, must be salvaged.\n", 
5763                                 volptr->hashid));
5764                     VTakeOffline(volptr);
5765                     return (EIO);
5766                     }
5767                 DT1++;
5768                 errorCode = 0;
5769             }
5770         }
5771         VN_SET_INO(*targetptr, (Inode)0);
5772         VAdjustDiskUsage(&errorCode, volptr,
5773                         -(int)nBlocks((*targetptr)->disk.length), 0);
5774     }
5775     
5776     (*targetptr)->changed_newTime = 1; /* Status change of deleted file/dir */
5777
5778     code = Delete(dir,(char *) Name);
5779     if (code) {
5780        ViceLog(0, ("Error %d deleting %s\n", code,
5781                    (((*targetptr)->disk.type== Directory)?"directory":"file")));
5782        ViceLog(0, ("Volume %u now offline, must be salvaged.\n", 
5783                   volptr->hashid));
5784        VTakeOffline(volptr);
5785        if (!errorCode) errorCode = code;
5786     }
5787
5788     DFlush();
5789     return(errorCode);
5790
5791 } /*DeleteTarget*/
5792
5793
5794 /*
5795  * This routine updates the parent directory's status block after the
5796  * specified operation (i.e. RemoveFile(), CreateFile(), Rename(),
5797  * SymLink(), Link(), MakeDir(), RemoveDir()) on one of its children has
5798  * been performed.
5799  */
5800 #if FS_STATS_DETAILED
5801 Update_ParentVnodeStatus(parentptr, volptr, dir, author, linkcount, a_inSameNetwork)
5802 #else
5803 Update_ParentVnodeStatus(parentptr, volptr, dir, author, linkcount)
5804 #endif /* FS_STATS_DETAILED */
5805     Vnode *parentptr;
5806     Volume *volptr;
5807     DirHandle *dir;
5808     int author;
5809     int linkcount;
5810 #if FS_STATS_DETAILED
5811     char a_inSameNetwork;       /*Client in the same net as File Server?*/
5812 #endif /* FS_STATS_DETAILED */
5813
5814 {
5815     int newlength;          /* Holds new directory length */
5816     int errorCode;
5817 #if FS_STATS_DETAILED
5818     Date currDate;              /*Current date*/
5819     int writeIdx;               /*Write index to bump*/
5820     int timeIdx;                /*Authorship time index to bump*/
5821 #endif /* FS_STATS_DETAILED */
5822
5823     parentptr->disk.dataVersion++;
5824     newlength = Length(dir);
5825     /* 
5826      * This is a called on both dir removals (i.e. remove, removedir, rename) but also in dir additions
5827      * (create, symlink, link, makedir) so we need to check if we have enough space
5828      * XXX But we still don't check the error since we're dealing with dirs here and really the increase
5829      * of a new entry would be too tiny to worry about failures (since we have all the existing cushion)
5830      */
5831     if (nBlocks(newlength) != nBlocks(parentptr->disk.length))
5832         VAdjustDiskUsage(&errorCode, volptr, 
5833                          (int)(nBlocks(newlength) - nBlocks(parentptr->disk.length)),
5834                          (int)(nBlocks(newlength) - nBlocks(parentptr->disk.length)));
5835     parentptr->disk.length = newlength;
5836
5837 #if FS_STATS_DETAILED
5838     /*
5839      * Update directory write stats for this volume.  Note that the auth
5840      * counter is located immediately after its associated ``distance''
5841      * counter.
5842      */
5843     if (a_inSameNetwork)
5844         writeIdx = VOL_STATS_SAME_NET;
5845     else
5846         writeIdx = VOL_STATS_DIFF_NET;
5847     V_stat_writes(volptr, writeIdx)++;
5848     if (author != AnonymousID) {
5849         V_stat_writes(volptr, writeIdx+1)++;
5850     }
5851
5852     /*
5853      * Update the volume's authorship information in response to this
5854      * directory operation.  Get the current time, decide to which time
5855      * slot this operation belongs, and bump the appropriate slot.
5856      */
5857     currDate = (FT_ApproxTime() - parentptr->disk.unixModifyTime);
5858     timeIdx = (currDate < VOL_STATS_TIME_CAP_0 ? VOL_STATS_TIME_IDX_0 :
5859                currDate < VOL_STATS_TIME_CAP_1 ? VOL_STATS_TIME_IDX_1 :
5860                currDate < VOL_STATS_TIME_CAP_2 ? VOL_STATS_TIME_IDX_2 :
5861                currDate < VOL_STATS_TIME_CAP_3 ? VOL_STATS_TIME_IDX_3 :
5862                currDate < VOL_STATS_TIME_CAP_4 ? VOL_STATS_TIME_IDX_4 :
5863                VOL_STATS_TIME_IDX_5);
5864     if (parentptr->disk.author == author) {
5865         V_stat_dirSameAuthor(volptr, timeIdx)++;
5866     }
5867     else {
5868         V_stat_dirDiffAuthor(volptr, timeIdx)++;
5869     }
5870 #endif /* FS_STATS_DETAILED */
5871
5872     parentptr->disk.author = author;
5873     parentptr->disk.linkCount = linkcount;
5874     parentptr->disk.unixModifyTime = FT_ApproxTime();   /* This should be set from CLIENT!! */
5875     parentptr->disk.serverModifyTime = FT_ApproxTime();
5876     parentptr->changed_newTime = 1; /* vnode changed, write it back. */
5877 }
5878
5879
5880 /*
5881  * Update the target file's (or dir's) status block after the specified
5882  * operation is complete. Note that some other fields maybe updated by
5883  * the individual module.
5884  */
5885
5886 /* INCOMPLETE - More attention is needed here! */
5887
5888 Update_TargetVnodeStatus(targetptr, Caller, client, InStatus, parentptr, volptr,
5889                          length)
5890     Vnode *targetptr;
5891     afs_uint32 Caller;
5892     struct client *client;
5893     AFSStoreStatus *InStatus;
5894     Vnode *parentptr;
5895     Volume *volptr;
5896     afs_int32 length;
5897
5898 {
5899 #if FS_STATS_DETAILED
5900     Date currDate;              /*Current date*/
5901     int writeIdx;               /*Write index to bump*/
5902     int timeIdx;                /*Authorship time index to bump*/
5903 #endif /* FS_STATS_DETAILED */
5904
5905     if (Caller & (TVS_CFILE|TVS_SLINK|TVS_MKDIR))       {   /* initialize new file */
5906         targetptr->disk.parent = parentptr->vnodeNumber;
5907         targetptr->disk.length = length;
5908         /* targetptr->disk.group =      0;  save some cycles */
5909         targetptr->disk.modeBits = 0777;
5910         targetptr->disk.owner = client->ViceId;
5911         targetptr->disk.dataVersion =  0 ; /* consistent with the client */
5912         targetptr->disk.linkCount = (Caller & TVS_MKDIR ? 2 : 1);
5913         /* the inode was created in Alloc_NewVnode() */
5914     }
5915
5916 #if FS_STATS_DETAILED
5917     /*
5918      * Update file write stats for this volume.  Note that the auth
5919      * counter is located immediately after its associated ``distance''
5920      * counter.
5921      */
5922     if (client->InSameNetwork)
5923         writeIdx = VOL_STATS_SAME_NET;
5924     else
5925         writeIdx = VOL_STATS_DIFF_NET;
5926     V_stat_writes(volptr, writeIdx)++;
5927     if (client->ViceId != AnonymousID) {
5928         V_stat_writes(volptr, writeIdx+1)++;
5929     }
5930
5931     /*
5932      * We only count operations that DON'T involve creating new objects
5933      * (files, symlinks, directories) or simply setting status as
5934      * authorship-change operations.
5935      */
5936     if (!(Caller & (TVS_CFILE | TVS_SLINK | TVS_MKDIR | TVS_SSTATUS))) {
5937         /*
5938          * Update the volume's authorship information in response to this
5939          * file operation.  Get the current time, decide to which time
5940          * slot this operation belongs, and bump the appropriate slot.
5941          */
5942         currDate = (FT_ApproxTime() - targetptr->disk.unixModifyTime);
5943         timeIdx = (currDate < VOL_STATS_TIME_CAP_0 ? VOL_STATS_TIME_IDX_0 :
5944                    currDate < VOL_STATS_TIME_CAP_1 ? VOL_STATS_TIME_IDX_1 :
5945                    currDate < VOL_STATS_TIME_CAP_2 ? VOL_STATS_TIME_IDX_2 :
5946                    currDate < VOL_STATS_TIME_CAP_3 ? VOL_STATS_TIME_IDX_3 :
5947                    currDate < VOL_STATS_TIME_CAP_4 ? VOL_STATS_TIME_IDX_4 :
5948                    VOL_STATS_TIME_IDX_5);
5949         if (targetptr->disk.author == client->ViceId) {
5950             V_stat_fileSameAuthor(volptr, timeIdx)++;
5951         } else {
5952             V_stat_fileDiffAuthor(volptr, timeIdx)++;
5953         }
5954       }
5955 #endif /* FS_STATS_DETAILED */
5956
5957     if (!(Caller & TVS_SSTATUS))
5958       targetptr->disk.author = client->ViceId;
5959     if (Caller & TVS_SDATA) {
5960       targetptr->disk.dataVersion++;
5961       if (VanillaUser(client))
5962           targetptr->disk.modeBits &= ~04000; /* turn off suid for file. */
5963     }
5964     if (Caller & TVS_SSTATUS) { /* update time on non-status change */
5965         /* store status, must explicitly request to change the date */
5966         if (InStatus->Mask & AFS_SETMODTIME)
5967             targetptr->disk.unixModifyTime = InStatus->ClientModTime;
5968     }
5969     else {/* other: date always changes, but perhaps to what is specified by caller */
5970         targetptr->disk.unixModifyTime = (InStatus->Mask & AFS_SETMODTIME ? InStatus->ClientModTime : FT_ApproxTime());
5971     }
5972     if (InStatus->Mask & AFS_SETOWNER) {
5973         /* admin is allowed to do chmod, chown as well as chown, chmod. */
5974         if (VanillaUser(client))
5975             targetptr->disk.modeBits &= ~04000; /* turn off suid for file. */
5976         targetptr->disk.owner = InStatus->Owner;
5977         if (VolumeRootVnode (targetptr)) {
5978             Error errorCode = 0;        /* what should be done with this? */
5979
5980             V_owner(targetptr->volumePtr) = InStatus->Owner;
5981             VUpdateVolume(&errorCode, targetptr->volumePtr);
5982         }
5983     }
5984     if (InStatus->Mask & AFS_SETMODE) {
5985         int modebits = InStatus->UnixModeBits;
5986 #define CREATE_SGUID_ADMIN_ONLY 1
5987 #ifdef CREATE_SGUID_ADMIN_ONLY
5988         if (VanillaUser(client)) 
5989             modebits = modebits & 0777;
5990 #endif
5991         if (VanillaUser(client)) {
5992           targetptr->disk.modeBits = modebits;
5993         }
5994         else {
5995           targetptr->disk.modeBits = modebits;
5996           switch ( Caller ) {
5997           case TVS_SDATA: osi_audit( PrivSetID, 0, AUD_INT, client->ViceId,
5998                                     AUD_INT, CHK_STOREDATA, AUD_END); break;
5999           case TVS_CFILE:
6000           case TVS_SSTATUS: osi_audit( PrivSetID, 0, AUD_INT, client->ViceId,
6001                                     AUD_INT, CHK_STORESTATUS, AUD_END); break;
6002           default: break;
6003           }
6004         }
6005       }
6006     targetptr->disk.serverModifyTime = FT_ApproxTime();
6007     if (InStatus->Mask & AFS_SETGROUP)
6008         targetptr->disk.group = InStatus->Group;
6009     /* vnode changed : to be written back by VPutVnode */
6010     targetptr->changed_newTime = 1;
6011
6012 } /*Update_TargetVnodeStatus*/
6013
6014
6015 /*
6016  * Fills the CallBack structure with the expiration time and type of callback
6017  * structure. Warning: this function is currently incomplete.
6018  */
6019 SetCallBackStruct(CallBackTime, CallBack)
6020     afs_uint32 CallBackTime;
6021     struct AFSCallBack *CallBack;
6022
6023 {
6024     /* CallBackTime could not be 0 */
6025     if (CallBackTime == 0) {
6026         ViceLog(0, ("WARNING: CallBackTime == 0!\n"));
6027         CallBack->ExpirationTime = 0;
6028     } else
6029         CallBack->ExpirationTime = CallBackTime - FT_ApproxTime();      
6030     CallBack->CallBackVersion = CALLBACK_VERSION;
6031     CallBack->CallBackType = CB_SHARED;             /* The default for now */
6032
6033 } /*SetCallBackStruct*/
6034
6035
6036 /*
6037  * Returns the volume and vnode pointers associated with file Fid; the lock
6038  * type on the vnode is set to lock. Note that both volume/vnode's ref counts
6039  * are incremented and they must be eventualy released.
6040  */
6041 CheckVnode(fid, volptr, vptr, lock)
6042     AFSFid *fid;
6043     Volume **volptr;
6044     Vnode **vptr;
6045     int lock;
6046
6047 {
6048     int fileCode = 0;
6049     int errorCode = -1;
6050     static struct timeval restartedat = {0,0};
6051
6052     if (fid->Volume == 0 || fid->Vnode == 0) /* not: || fid->Unique == 0) */
6053         return(EINVAL);
6054     if ((*volptr) == 0) {
6055       extern int VInit;
6056
6057       while(1) {
6058         errorCode = 0;
6059         *volptr = VGetVolume(&errorCode, (afs_int32)fid->Volume);
6060         if (!errorCode) {
6061           assert (*volptr);
6062           break;
6063         }
6064         if ((errorCode == VOFFLINE) && (VInit < 2)) {
6065             /* The volume we want may not be attached yet because
6066              * the volume initialization is not yet complete.
6067              * We can do several things: 
6068              *     1.  return -1, which will cause users to see
6069              *         "connection timed out".  This is more or
6070              *         less the same as always, except that the servers
6071              *         may appear to bounce up and down while they
6072              *         are actually restarting.
6073              *     2.  return VBUSY which will cause clients to 
6074              *         sleep and retry for 6.5 - 15 minutes, depending
6075              *         on what version of the CM they are running.  If
6076              *         the file server takes longer than that interval 
6077              *         to attach the desired volume, then the application
6078              *         will see an ENODEV or EIO.  This approach has 
6079              *         the advantage that volumes which have been attached
6080              *         are immediately available, it keeps the server's
6081              *         immediate backlog low, and the call is interruptible
6082              *         by the user.  Users see "waiting for busy volume."
6083              *     3.  sleep here and retry.  Some people like this approach
6084              *         because there is no danger of seeing errors.  However, 
6085              *         this approach only works with a bounded number of 
6086              *         clients, since the pending queues will grow without
6087              *         stopping.  It might be better to find a way to take
6088              *         this call and stick it back on a queue in order to
6089              *         recycle this thread for a different request.    
6090              *     4.  Return a new error code, which new cache managers will
6091              *         know enough to interpret as "sleep and retry", without
6092              *         the upper bound of 6-15 minutes that is imposed by the
6093              *         VBUSY handling.  Users will see "waiting for
6094              *         busy volume," so they know that something is
6095              *         happening.  Old cache managers must be able to do  
6096              *         something reasonable with this, for instance, mark the
6097              *         server down.  Fortunately, any error code < 0
6098              *         will elicit that behavior. See #1.
6099              *     5.  Some combination of the above.  I like doing #2 for 10
6100              *         minutes, followed by #4.  3.1b and 3.2 cache managers
6101              *         will be fine as long as the restart period is
6102              *         not longer than 6.5 minutes, otherwise they may
6103              *         return ENODEV to users.  3.3 cache managers will be
6104              *         fine for 10 minutes, then will return
6105              *         ETIMEDOUT.  3.4 cache managers will just wait
6106              *         until the call works or fails definitively.
6107              *  NB. The problem with 2,3,4,5 is that old clients won't
6108              *  fail over to an alternate read-only replica while this
6109              *  server is restarting.  3.4 clients will fail over right away.
6110              */
6111           if (restartedat.tv_sec == 0) {
6112             /* I'm not really worried about when we restarted, I'm   */
6113             /* just worried about when the first VBUSY was returned. */
6114             TM_GetTimeOfDay(&restartedat, 0);
6115             return(VBUSY);
6116           }
6117           else {
6118             struct timeval now;
6119             TM_GetTimeOfDay(&now, 0);
6120             if ((now.tv_sec - restartedat.tv_sec) < (11*60)) {
6121               return(VBUSY);
6122             }
6123             else {
6124               return (VRESTARTING);
6125             }
6126           }
6127         }
6128           /* allow read operations on busy volume */
6129         else if(errorCode==VBUSY && lock==READ_LOCK) {
6130           errorCode=0;
6131           break;
6132         }
6133         else if (errorCode)
6134           return(errorCode);
6135       }
6136     }
6137     assert (*volptr);
6138
6139     /* get the vnode  */
6140     *vptr = VGetVnode(&errorCode, *volptr, fid->Vnode, lock);
6141     if (errorCode)
6142         return(errorCode);
6143     if ((*vptr)->disk.uniquifier != fid->Unique) {
6144         VPutVnode(&fileCode, *vptr);
6145         assert(fileCode == 0);
6146         *vptr = 0;
6147         return(VNOVNODE);   /* return the right error code, at least */
6148     }
6149     return(0);
6150
6151 } /*CheckVnode*/
6152
6153
6154 /*
6155  * This routine returns the ACL associated with the targetptr. If the
6156  * targetptr isn't a directory, we access its parent dir and get the ACL
6157  * thru the parent; in such case the parent's vnode is returned in
6158  * READ_LOCK mode.
6159  */
6160 SetAccessList(targetptr, volume, ACL, ACLSize, parent, Fid, Lock)
6161     Vnode **targetptr;           /*Target vnode pointer; returned locked*/
6162     Volume **volume;             /*Volume ptr associated with targetptr*/
6163     struct acl_accessList **ACL; /*The returned ACL for the vnode*/
6164     int * ACLSize;               /*Returned ACL's size*/
6165     Vnode **parent;              /*If target not Dir, it's its locked parent*/
6166     AFSFid *Fid;                 /*Fid associated with targetptr*/
6167     int Lock;                    /*Lock type to be applied to targetptr*/
6168
6169 {
6170     if ((*targetptr)->disk.type == vDirectory) {
6171         *parent = 0;
6172         *ACL = VVnodeACL(*targetptr);
6173         *ACLSize = VAclSize(*targetptr);
6174         return(0);
6175     }
6176     else {
6177         assert(Fid != 0);
6178         while(1) {
6179             VnodeId parentvnode;
6180             int errorCode = 0;
6181             
6182             parentvnode = (*targetptr)->disk.parent;
6183             VPutVnode(&errorCode,*targetptr);
6184             *targetptr = 0;
6185             if (errorCode) return(errorCode);
6186             *parent = VGetVnode(&errorCode, *volume, parentvnode, READ_LOCK);
6187             if (errorCode) return(errorCode);
6188             *ACL = VVnodeACL(*parent);
6189             *ACLSize = VAclSize(*parent);
6190             if ((errorCode = CheckVnode(Fid, volume, targetptr, Lock)) != 0)
6191                 return(errorCode);
6192             if ((*targetptr)->disk.parent != parentvnode) {
6193                 VPutVnode(&errorCode, *parent);
6194                 *parent = 0;
6195                 if (errorCode) return(errorCode);
6196             } else
6197                 return(0);
6198         }
6199     }
6200
6201 } /*SetAccessList*/
6202
6203
6204 /*
6205  * Common code that handles the creation of a new file (SAFS_CreateFile and
6206  * SAFS_Symlink) or a new dir (SAFS_MakeDir)
6207  */
6208 Alloc_NewVnode(parentptr, dir, volptr, targetptr, Name, OutFid, FileType, BlocksPreallocatedForVnode)
6209     Vnode *parentptr;
6210     DirHandle *dir;
6211     Volume *volptr;
6212     Vnode **targetptr;
6213     char *Name;
6214     struct AFSFid *OutFid;
6215     int FileType;
6216     int BlocksPreallocatedForVnode;
6217
6218 {
6219     int errorCode = 0;          /* Error code returned back */
6220     int temp;
6221     Inode inode=0;
6222     Inode nearInode;            /* hint for inode allocation in solaris */
6223
6224     if (errorCode = AdjustDiskUsage(volptr, BlocksPreallocatedForVnode,
6225                                     BlocksPreallocatedForVnode)) {
6226         ViceLog(25, ("Insufficient space to allocate %d blocks\n", 
6227                      BlocksPreallocatedForVnode));
6228         return(errorCode);
6229     }
6230
6231     *targetptr = VAllocVnode(&errorCode, volptr, FileType);
6232     if (errorCode != 0) {
6233         VAdjustDiskUsage(&temp, volptr, - BlocksPreallocatedForVnode, 0);
6234         return(errorCode);
6235     }
6236     OutFid->Volume = V_id(volptr);
6237     OutFid->Vnode = (*targetptr)->vnodeNumber;
6238     OutFid->Unique = (*targetptr)->disk.uniquifier;
6239
6240     nearInode = VN_GET_INO(parentptr);   /* parent is also in same vol */
6241
6242     /* create the inode now itself */
6243     inode = IH_CREATE(V_linkHandle(volptr), V_device(volptr),
6244                       VPartitionPath(V_partition(volptr)), nearInode,
6245                       V_id(volptr), (*targetptr)->vnodeNumber,
6246                       (*targetptr)->disk.uniquifier, 1);
6247
6248     /* error in creating inode */
6249     if (!VALID_INO(inode)) 
6250     {
6251                ViceLog(0, ("Volume : %d vnode = %d Failed to create inode: errno = %d\n", 
6252                          (*targetptr)->volumePtr->header->diskstuff.id,
6253                          (*targetptr)->vnodeNumber, 
6254                          errno));
6255                 VAdjustDiskUsage(&temp, volptr, -BlocksPreallocatedForVnode,0);
6256                 (*targetptr)->delete = 1; /* delete vnode */
6257                 return ENOSPC;
6258     }
6259     VN_SET_INO(*targetptr, inode);
6260     IH_INIT(((*targetptr)->handle), V_device(volptr), V_id(volptr), inode);
6261
6262     /* copy group from parent dir */
6263     (*targetptr)->disk.group = parentptr->disk.group;
6264
6265     if (parentptr->disk.cloned) 
6266     {
6267         ViceLog(25, ("Alloc_NewVnode : CopyOnWrite called\n"));
6268         if ( errorCode = CopyOnWrite(parentptr, volptr))  /* disk full */
6269         {
6270                 ViceLog(25, ("Alloc_NewVnode : CopyOnWrite failed\n"));
6271                 /* delete the vnode previously allocated */
6272                 (*targetptr)->delete = 1;
6273                 VAdjustDiskUsage(&temp, volptr,
6274                                  -BlocksPreallocatedForVnode, 0);
6275                 IH_REALLYCLOSE((*targetptr)->handle);
6276                 if ( IH_DEC(V_linkHandle(volptr), inode, V_parentId(volptr)) )
6277                     ViceLog(0,("Alloc_NewVnode: partition %s idec %s failed\n",
6278                                 volptr->partition->name,
6279                                PrintInode(NULL, inode)));
6280                 IH_RELEASE((*targetptr)->handle);
6281                         
6282                 return errorCode;
6283         }
6284     }
6285     
6286     /* add the name to the directory */
6287     SetDirHandle(dir, parentptr);
6288     if (errorCode = Create(dir,(char *)Name, OutFid)) {
6289         (*targetptr)->delete = 1;
6290         VAdjustDiskUsage(&temp, volptr, - BlocksPreallocatedForVnode, 0);
6291         IH_REALLYCLOSE((*targetptr)->handle);
6292         if ( IH_DEC(V_linkHandle(volptr), inode, V_parentId(volptr)))
6293             ViceLog(0,("Alloc_NewVnode: partition %s idec %s failed\n",
6294                        volptr->partition->name,
6295                        PrintInode(NULL, inode)));
6296         IH_RELEASE((*targetptr)->handle);
6297         return(errorCode);
6298     }
6299     DFlush();
6300     return(0);
6301
6302 } /*Alloc_NewVnode*/
6303
6304
6305 /*
6306  * Handle all the lock-related code (SAFS_SetLock, SAFS_ExtendLock and
6307  * SAFS_ReleaseLock)
6308  */
6309 HandleLocking(targetptr, rights, LockingType)
6310     Vnode *targetptr;
6311     afs_int32 rights;
6312     ViceLockType LockingType;
6313
6314 {
6315     int Time;           /* Used for time */
6316     int writeVnode = targetptr->changed_oldTime; /* save original status */
6317
6318     /* Does the caller has Lock priviledges; root extends locks, however */
6319     if (LockingType != LockExtend && !(rights & PRSFS_LOCK))
6320         return(EACCES);
6321     targetptr->changed_oldTime = 1; /* locking doesn't affect any time stamp */
6322     Time = FT_ApproxTime();
6323     switch (LockingType) {
6324         case LockRead:
6325         case LockWrite:
6326             if (Time > targetptr->disk.lock.lockTime)
6327                 targetptr->disk.lock.lockTime = targetptr->disk.lock.lockCount = 0;
6328             Time += AFS_LOCKWAIT;
6329             if (LockingType == LockRead) {
6330                 if (targetptr->disk.lock.lockCount >= 0) {
6331                     ++(targetptr->disk.lock.lockCount);
6332                     targetptr->disk.lock.lockTime = Time;
6333                 } else return(EAGAIN);
6334             } else {
6335                 if (targetptr->disk.lock.lockCount == 0) {
6336                     targetptr->disk.lock.lockCount = -1;
6337                     targetptr->disk.lock.lockTime = Time;
6338                 } else return(EAGAIN);
6339             }
6340             break;
6341         case LockExtend:
6342             Time += AFS_LOCKWAIT;
6343             if (targetptr->disk.lock.lockCount != 0)
6344                 targetptr->disk.lock.lockTime = Time;
6345             else return(EINVAL);            
6346             break;
6347         case LockRelease:
6348             if ((--targetptr->disk.lock.lockCount) <= 0)
6349                 targetptr->disk.lock.lockCount = targetptr->disk.lock.lockTime = 0;
6350             break;
6351         default:
6352             targetptr->changed_oldTime = writeVnode; /* restore old status */
6353             ViceLog(0, ("Illegal Locking type %d\n", LockingType));
6354     }
6355     return(0);
6356
6357 } /*HandleLocking*/
6358
6359
6360 /*
6361  * This routine returns the status info associated with the targetptr vnode
6362  * in the AFSFetchStatus structure.  Some of the newer fields, such as
6363  * SegSize and Group are not yet implemented
6364  */
6365 void GetStatus(targetptr, status, rights, anyrights, parentptr)
6366     Vnode *targetptr;           /*vnode of desired Fid*/
6367     AFSFetchStatus *status;     /*the status info is returned here*/
6368     afs_int32 rights;           /*Sets the 'CallerAccess' status field*/
6369     afs_int32 anyrights;                /*Sets the 'AnonymousAccess' status field*/
6370     Vnode *parentptr;           /*target's parent vnode*/
6371
6372 {
6373     /* initialize return status from a vnode  */
6374     status->InterfaceVersion = 1;
6375     status->SyncCounter = status->dataVersionHigh = status->lockCount =
6376     status->spare3 = status->errorCode = 0;
6377     if (targetptr->disk.type == vFile)
6378         status->FileType = File;
6379     else if (targetptr->disk.type == vDirectory)
6380         status->FileType = Directory;
6381     else if (targetptr->disk.type == vSymlink)
6382         status->FileType = SymbolicLink;
6383     else
6384         status->FileType = Invalid;                     /*invalid type field */
6385     status->LinkCount = targetptr->disk.linkCount;
6386     status->Length = targetptr->disk.length;
6387     status->DataVersion = targetptr->disk.dataVersion;
6388     status->Author = targetptr->disk.author;
6389     status->Owner = targetptr->disk.owner;
6390     status->CallerAccess = rights;
6391     status->AnonymousAccess = anyrights;
6392     status->UnixModeBits = targetptr->disk.modeBits;
6393     status->ClientModTime = targetptr->disk.unixModifyTime;     /* This might need rework */
6394     status->ParentVnode = (status->FileType == Directory ? targetptr->vnodeNumber : parentptr->vnodeNumber);
6395     status->ParentUnique = (status->FileType == Directory ? targetptr->disk.uniquifier : parentptr->disk.uniquifier);
6396     status->SegSize = 0;
6397     status->ServerModTime = targetptr->disk.serverModifyTime;                   
6398     status->Group = targetptr->disk.group;
6399     status->lockCount = targetptr->disk.lock.lockCount;
6400     status->errorCode = 0;
6401
6402 } /*GetStatus*/
6403
6404
6405 /*
6406  * Compare the directory's ACL with the user's access rights in the client
6407  * connection and return the user's and everybody else's access permissions
6408  * in rights and anyrights, respectively
6409  */
6410 GetRights (client, ACL, rights, anyrights)
6411     struct client *client;      /* Client struct */
6412     struct acl_accessList *ACL; /* Access List for the current directory */
6413     afs_int32 *rights;          /* Returns access rights for caller */
6414     afs_int32 *anyrights;               /* Returns access rights for 'anyuser' */
6415
6416 {
6417     extern prlist SystemAnyUserCPS;
6418     afs_int32 hrights = 0;
6419     int code;
6420
6421     if (acl_CheckRights(ACL, &SystemAnyUserCPS, anyrights) != 0) {
6422
6423         ViceLog(0,("CheckRights failed\n"));
6424         *anyrights = 0;
6425     }
6426     *rights = 0;
6427     acl_CheckRights(ACL, &client->CPS, rights);
6428
6429         /* wait if somebody else is already doing the getCPS call */
6430     H_LOCK
6431     while ( client->host->hostFlags & HPCS_INPROGRESS )
6432     {
6433         client->host->hostFlags |= HPCS_WAITING;  /* I am waiting */
6434 #ifdef AFS_PTHREAD_ENV
6435         pthread_cond_wait(&client->host->cond, &host_glock_mutex);
6436 #else /* AFS_PTHREAD_ENV */
6437         if ((code=LWP_WaitProcess( &(client->host->hostFlags))) !=LWP_SUCCESS)
6438                 ViceLog(0, ("LWP_WaitProcess returned %d\n", code));
6439 #endif /* AFS_PTHREAD_ENV */
6440     }
6441
6442     if (client->host->hcps.prlist_len && !client->host->hcps.prlist_val) {
6443         ViceLog(0,("CheckRights: len=%d, for host=0x%x\n", client->host->hcps.prlist_len, client->host->host));
6444     } else
6445         acl_CheckRights(ACL, &client->host->hcps, &hrights);
6446     H_UNLOCK
6447     /* Allow system:admin the rights given with the -implicit option */
6448     if (acl_IsAMember(SystemId, &client->CPS))
6449         *rights |= implicitAdminRights;
6450     *rights |= hrights;
6451     *anyrights |= hrights;
6452
6453     return(0);
6454
6455 } /*GetRights*/
6456
6457
6458 /* Checks if caller has the proper AFS and Unix (WRITE) access permission to the target directory; Prfs_Mode refers to the AFS Mode operation while rights contains the caller's access permissions to the directory. */
6459
6460 CheckWriteMode(targetptr, rights, Prfs_Mode)
6461 Vnode       * targetptr;
6462 afs_int32           rights;
6463 int         Prfs_Mode;
6464 {
6465     if (!(rights & Prfs_Mode))
6466         return(EACCES);
6467     if ((targetptr->disk.type != vDirectory) && (!(targetptr->disk.modeBits & OWNERWRITE)))
6468         return(EACCES);
6469     return(0);
6470 }
6471         
6472
6473 /* In our current implementation, each successive data store (new file
6474  * data version) creates a new inode. This function creates the new
6475  * inode, copies the old inode's contents to the new one, remove the old
6476  * inode (i.e. decrement inode count -- if it's currently used the delete
6477  * will be delayed), and modify some fields (i.e. vnode's
6478  * disk.inodeNumber and cloned)
6479  */
6480 #define COPYBUFFSIZE    8192
6481 int CopyOnWrite(targetptr, volptr)
6482     Vnode *targetptr;
6483     Volume *volptr;
6484
6485 {
6486     Inode       ino, nearInode;
6487     int         rdlen;
6488     int         wrlen;
6489     register int size, length;
6490     int ifd, ofd;
6491     char        *buff;
6492     int         rc;             /* return code */
6493     IHandle_t   *newH;  /* Use until finished copying, then cp to vnode.*/
6494     FdHandle_t  *targFdP;  /* Source Inode file handle */
6495     FdHandle_t  *newFdP; /* Dest Inode file handle */
6496
6497     if (targetptr->disk.type == vDirectory) DFlush();   /* just in case? */
6498
6499     size = targetptr->disk.length;
6500     buff = (char *)malloc(COPYBUFFSIZE);
6501     if (buff == NULL) {
6502         return EIO;
6503     }
6504
6505     ino = VN_GET_INO(targetptr);
6506     assert(VALID_INO(ino));
6507     targFdP = IH_OPEN(targetptr->handle);
6508     if (targFdP == NULL) {
6509         rc = errno;
6510         ViceLog(0, ("CopyOnWrite failed: Failed to open target vnode %u in volume %u (errno = %d)\n", targetptr->vnodeNumber, V_id(volptr), rc));
6511         free(buff);
6512         VTakeOffline (volptr);
6513         return rc;
6514     }
6515
6516     nearInode = VN_GET_INO(targetptr);
6517     ino = IH_CREATE(V_linkHandle(volptr), V_device(volptr),
6518                     VPartitionPath(V_partition(volptr)),nearInode, V_id(volptr),
6519                     targetptr->vnodeNumber, targetptr->disk.uniquifier,
6520                     (int)targetptr->disk.dataVersion);
6521     if (!VALID_INO(ino))
6522     {
6523         ViceLog(0,("CopyOnWrite failed: Partition %s that contains volume %u may be out of free inodes(errno = %d)\n", volptr->partition->name, V_id(volptr), errno));
6524         FDH_CLOSE(targFdP);
6525         free(buff);
6526         return ENOSPC;
6527     }
6528     IH_INIT(newH, V_device(volptr), V_id(volptr), ino);
6529     newFdP = IH_OPEN(newH);
6530     assert(newFdP != NULL);
6531
6532     while(size > 0) {
6533         if (size > COPYBUFFSIZE) { /* more than a buffer */
6534             length = COPYBUFFSIZE;
6535             size -= COPYBUFFSIZE;
6536         } else {
6537             length = size;
6538             size = 0;
6539         }
6540         rdlen = FDH_READ(targFdP, buff, length); 
6541         if (rdlen == length)
6542             wrlen = FDH_WRITE(newFdP, buff, length);
6543         else
6544             wrlen = 0;
6545         /*  Callers of this function are not prepared to recover
6546          *  from error that put the filesystem in an inconsistent
6547          *  state. Make sure that we force the volume off-line if
6548          *  we some error other than ENOSPC - 4.29.99)
6549          *
6550          *  In case we are unable to write the required bytes, and the
6551          *  error code indicates that the disk is full, we roll-back to
6552          *  the initial state.
6553          */
6554         if((rdlen != length) || (wrlen != length))
6555                 if ( (wrlen < 0) && (errno == ENOSPC) ) /* disk full */
6556                 {
6557                         ViceLog(0,("CopyOnWrite failed: Partition %s containing volume %u is full\n",
6558                                         volptr->partition->name, V_id(volptr)));
6559                         /* remove destination inode which was partially copied till now*/
6560                         FDH_REALLYCLOSE(newFdP);
6561                         IH_RELEASE(newH);
6562                         FDH_REALLYCLOSE(targFdP);
6563                         rc = IH_DEC(V_linkHandle(volptr), ino,
6564                                   V_parentId(volptr));
6565                         if (!rc ) {
6566                             ViceLog(0,("CopyOnWrite failed: error %u after i_dec on disk full, volume %u in partition %s needs salvage\n",
6567                                        rc, V_id(volptr), 
6568                                        volptr->partition->name));
6569                             VTakeOffline (volptr);
6570                         }
6571                         free(buff);
6572                         return ENOSPC;
6573                 }
6574                 else {
6575                     ViceLog(0,("CopyOnWrite failed: volume %u in partition %s  (tried reading %u, read %u, wrote %u, errno %u) volume needs salvage\n",
6576                                V_id(volptr), volptr->partition->name, length,
6577                                rdlen, wrlen, errno));
6578                     /* Decrement this inode so salvager doesn't find it. */
6579                     FDH_REALLYCLOSE(newFdP);
6580                     IH_RELEASE(newH);
6581                     FDH_REALLYCLOSE(targFdP);
6582                     rc = IH_DEC(V_linkHandle(volptr), ino,
6583                                 V_parentId(volptr));
6584                     free(buff);
6585                     VTakeOffline (volptr);
6586                     return EIO;
6587                 }
6588 #ifndef AFS_PTHREAD_ENV
6589         IOMGR_Poll();
6590 #endif /* !AFS_PTHREAD_ENV */
6591     }
6592     FDH_REALLYCLOSE(targFdP);
6593     rc = IH_DEC(V_linkHandle(volptr), VN_GET_INO(targetptr),
6594               V_parentId(volptr)) ;
6595     assert(!rc);
6596     IH_RELEASE(targetptr->handle);
6597
6598     rc = FDH_SYNC(newFdP);
6599     assert(rc == 0);
6600     FDH_CLOSE(newFdP);
6601     targetptr->handle = newH;
6602     VN_SET_INO(targetptr, ino);
6603     targetptr->disk.cloned = 0;
6604     /* Internal change to vnode, no user level change to volume - def 5445 */
6605     targetptr->changed_oldTime = 1;
6606     free(buff);
6607     return 0;                           /* success */
6608 } /*CopyOnWrite*/
6609
6610
6611 /*
6612  * VanillaUser returns 1 (true) if the user is a vanilla user (i.e., not
6613  * a System:Administrator)
6614  */
6615 VanillaUser(client)
6616     struct client *client;
6617
6618 {
6619     if (acl_IsAMember(SystemId, &client->CPS))
6620         return(0);  /* not a system administrator, then you're "vanilla" */
6621     return(1);
6622
6623 } /*VanillaUser*/
6624
6625
6626 /*
6627  * Adjusts (Subtract) "length" number of blocks from the volume's disk
6628  * allocation; if some error occured (exceeded volume quota or partition
6629  * was full, or whatever), it frees the space back and returns the code.
6630  * We usually pre-adjust the volume space to make sure that there's
6631  * enough space before consuming some.
6632  */
6633 AdjustDiskUsage(volptr, length, checkLength)
6634     Volume      * volptr;
6635     afs_int32   checkLength;
6636     afs_int32   length;
6637
6638 {
6639     int rc;
6640     int nc;
6641
6642     VAdjustDiskUsage(&rc, volptr, length, checkLength);
6643     if (rc) {
6644         VAdjustDiskUsage(&nc, volptr, -length, 0);
6645         if (rc == VOVERQUOTA) {
6646             ViceLog(2,("Volume %u (%s) is full\n",
6647                     V_id(volptr), V_name(volptr)));
6648             return(rc);
6649         }
6650         if (rc == VDISKFULL) {
6651             ViceLog(0,("Partition %s that contains volume %u is full\n",
6652                     volptr->partition->name, V_id(volptr)));
6653             return(rc);
6654         }
6655         ViceLog(0,("Got error return %d from VAdjustDiskUsage\n",rc));
6656         return(rc);
6657     }
6658     return(0);
6659
6660 } /*AdjustDiskUsage*/
6661
6662
6663 /*
6664  * If some flags (i.e. min or max quota) are set, the volume's in disk
6665  * label is updated; Name, OfflineMsg, and Motd are also reflected in the
6666  * update, if applicable.
6667  */
6668 RXUpdate_VolumeStatus(volptr, StoreVolStatus, Name, OfflineMsg, Motd)
6669     Volume *volptr;
6670     AFSStoreVolumeStatus* StoreVolStatus;
6671     char *Name;
6672     char *OfflineMsg;
6673     char *Motd;
6674
6675 {
6676     Error errorCode = 0;
6677
6678     if (StoreVolStatus->Mask & AFS_SETMINQUOTA)
6679         V_minquota(volptr) = StoreVolStatus->MinQuota;
6680     if (StoreVolStatus->Mask & AFS_SETMAXQUOTA)
6681         V_maxquota(volptr) = StoreVolStatus->MaxQuota;
6682     if (strlen(OfflineMsg) > 0) {
6683         strcpy(V_offlineMessage(volptr), OfflineMsg);
6684     }
6685     if (strlen(Name) > 0) {
6686         strcpy(V_name(volptr), Name);
6687     }
6688 #if TRANSARC_VOL_STATS
6689     /*
6690      * We don't overwrite the motd field, since it's now being used
6691      * for stats
6692      */
6693 #else
6694     if (strlen(Motd) > 0) {
6695         strcpy(V_motd(volptr), Motd);
6696     }
6697 #endif /* FS_STATS_DETAILED */
6698     VUpdateVolume(&errorCode, volptr);
6699     return(errorCode);
6700
6701 } /*RXUpdate_VolumeStatus*/
6702
6703
6704 /* old interface */
6705 Update_VolumeStatus(volptr, StoreVolStatus, Name, OfflineMsg, Motd)
6706     Volume *volptr;
6707     VolumeStatus *StoreVolStatus;
6708     struct BBS *Name;
6709     struct BBS *OfflineMsg;
6710     struct BBS *Motd;
6711
6712 {
6713     Error errorCode = 0;
6714
6715     if (StoreVolStatus->MinQuota > -1)
6716         V_minquota(volptr) = StoreVolStatus->MinQuota;
6717     if (StoreVolStatus->MaxQuota > -1)
6718         V_maxquota(volptr) = StoreVolStatus->MaxQuota;
6719     if (OfflineMsg->SeqLen > 1)
6720         strcpy(V_offlineMessage(volptr), OfflineMsg->SeqBody);
6721     if (Name->SeqLen > 1)
6722         strcpy(V_name(volptr), Name->SeqBody);
6723 #if TRANSARC_VOL_STATS
6724     /*
6725      * We don't overwrite the motd field, since it's now being used
6726      * for stats
6727      */
6728 #else
6729     if (Motd->SeqLen > 1)
6730         strcpy(V_motd(volptr), Motd->SeqBody);
6731 #endif /* FS_STATS_DETAILED */
6732     VUpdateVolume(&errorCode, volptr);
6733     return(errorCode);
6734
6735 } /*Update_VolumeStatus*/
6736
6737
6738 /*
6739  * Get internal volume-related statistics from the Volume disk label
6740  * structure and put it into the VolumeStatus structure, status; it's
6741  * used by both SAFS_GetVolumeStatus and SAFS_SetVolumeStatus to return
6742  * the volume status to the caller.
6743  */
6744 GetVolumeStatus(status, name, offMsg, motd, volptr)
6745 VolumeStatus    * status;
6746 struct BBS              * name;
6747 struct BBS              * offMsg;
6748 struct BBS              * motd;
6749 Volume                  * volptr;
6750
6751 {
6752     status->Vid = V_id(volptr);
6753     status->ParentId = V_parentId(volptr);
6754     status->Online = V_inUse(volptr);
6755     status->InService = V_inService(volptr);
6756     status->Blessed = V_blessed(volptr);
6757     status->NeedsSalvage = V_needsSalvaged(volptr);
6758     if (VolumeWriteable(volptr))
6759         status->Type = ReadWrite;
6760     else
6761         status->Type = ReadOnly;
6762     status->MinQuota = V_minquota(volptr);
6763     status->MaxQuota = V_maxquota(volptr);
6764     status->BlocksInUse = V_diskused(volptr);
6765     status->PartBlocksAvail = volptr->partition->free;
6766     status->PartMaxBlocks = volptr->partition->totalUsable;
6767     strncpy(name->SeqBody, V_name(volptr), (int)name->MaxSeqLen);
6768     name->SeqLen = strlen(V_name(volptr)) + 1;
6769     if (name->SeqLen > name->MaxSeqLen) name->SeqLen = name -> MaxSeqLen;
6770     strncpy(offMsg->SeqBody, V_offlineMessage(volptr), (int)name->MaxSeqLen);
6771     offMsg->SeqLen = strlen(V_offlineMessage(volptr)) + 1;
6772     if (offMsg->SeqLen > offMsg->MaxSeqLen)
6773         offMsg->SeqLen = offMsg -> MaxSeqLen;
6774 #ifdef notdef
6775     /*Don't do anything with the motd field*/
6776     strncpy(motd->SeqBody, nullString, (int)offMsg->MaxSeqLen);
6777     motd->SeqLen = strlen(nullString) + 1;
6778 #endif
6779     if (motd->SeqLen > motd->MaxSeqLen)
6780         motd->SeqLen = motd -> MaxSeqLen;
6781
6782 } /*GetVolumeStatus*/
6783
6784
6785 RXGetVolumeStatus(status, name, offMsg, motd, volptr)
6786     AFSFetchVolumeStatus *status;
6787     char **name;
6788     char **offMsg;
6789     char **motd;
6790     Volume *volptr;
6791
6792 {
6793     int temp;
6794
6795     status->Vid = V_id(volptr);
6796     status->ParentId = V_parentId(volptr);
6797     status->Online = V_inUse(volptr);
6798     status->InService = V_inService(volptr);
6799     status->Blessed = V_blessed(volptr);
6800     status->NeedsSalvage = V_needsSalvaged(volptr);
6801     if (VolumeWriteable(volptr))
6802         status->Type = ReadWrite;
6803     else
6804         status->Type = ReadOnly;
6805     status->MinQuota = V_minquota(volptr);
6806     status->MaxQuota = V_maxquota(volptr);
6807     status->BlocksInUse = V_diskused(volptr);
6808     status->PartBlocksAvail = volptr->partition->free;
6809     status->PartMaxBlocks = volptr->partition->totalUsable;
6810
6811     /* now allocate and copy these things; they're freed by the RXGEN stub */
6812     temp = strlen(V_name(volptr)) + 1;
6813     *name = malloc(temp);
6814     strcpy(*name, V_name(volptr));
6815     temp = strlen(V_offlineMessage(volptr)) + 1;
6816     *offMsg = malloc(temp);
6817     strcpy(*offMsg, V_offlineMessage(volptr));
6818 #if TRANSARC_VOL_STATS
6819     *motd = malloc(1);
6820     strcpy(*motd, nullString);
6821 #else
6822     temp = strlen(V_motd(volptr)) + 1;
6823     *motd = malloc(temp);
6824     strcpy(*motd, V_motd(volptr));
6825 #endif /* FS_STATS_DETAILED */
6826
6827 } /*RXGetVolumeStatus*/
6828
6829
6830 /* Set AFS Data Fetch/Store related statistics. */
6831
6832 void SetAFSStats(stats)
6833     struct AFSStatistics *stats;
6834
6835 {
6836     extern afs_int32 StartTime, CurrentConnections;
6837     int seconds;
6838
6839     FS_LOCK
6840     stats->CurrentMsgNumber = 0;
6841     stats->OldestMsgNumber = 0;
6842     stats->StartTime = StartTime;
6843     stats->CurrentConnections = CurrentConnections;
6844     stats->TotalAFSCalls = AFSCallStats.TotalCalls;
6845     stats->TotalFetchs = AFSCallStats.FetchData+AFSCallStats.FetchACL+AFSCallStats.FetchStatus;
6846     stats->FetchDatas = AFSCallStats.FetchData;
6847     stats->FetchedBytes = AFSCallStats.TotalFetchedBytes;
6848     seconds = AFSCallStats.AccumFetchTime/1000;
6849     if (seconds <= 0) seconds = 1;
6850     stats->FetchDataRate = AFSCallStats.TotalFetchedBytes/seconds;
6851     stats->TotalStores = AFSCallStats.StoreData+AFSCallStats.StoreACL+AFSCallStats.StoreStatus;
6852     stats->StoreDatas = AFSCallStats.StoreData;
6853     stats->StoredBytes = AFSCallStats.TotalStoredBytes;
6854     seconds = AFSCallStats.AccumStoreTime/1000;
6855     if (seconds <= 0) seconds = 1;
6856     stats->StoreDataRate = AFSCallStats.TotalStoredBytes/seconds;
6857 #ifdef AFS_NT40_ENV
6858     stats->ProcessSize = -1; /* TODO: */
6859 #else
6860     stats->ProcessSize = (afs_int32)((long) sbrk(0) >> 10);
6861 #endif
6862     FS_UNLOCK
6863     h_GetWorkStats((int *)&(stats->WorkStations),(int *)&(stats->ActiveWorkStations),
6864             (int *)0, (afs_int32)(FT_ApproxTime())-(15*60));
6865
6866 } /*SetAFSStats*/
6867
6868
6869 /* Get disk related information from all AFS partitions. */
6870
6871 void SetVolumeStats(stats)
6872     struct AFSStatistics *stats;
6873
6874 {
6875     struct DiskPartition * part;
6876     int i = 0;
6877
6878     for (part = DiskPartitionList; part && i < AFS_MSTATDISKS; part = part->next) {
6879         stats->Disks[i].TotalBlocks = part->totalUsable;
6880         stats->Disks[i].BlocksAvailable = part->free;
6881         memset(stats->Disks[i].Name, 0, AFS_DISKNAMESIZE);
6882         strncpy(stats->Disks[i].Name, part->name, AFS_DISKNAMESIZE);
6883         i++;
6884     }
6885     while (i < AFS_MSTATDISKS) {
6886         stats->Disks[i].TotalBlocks = -1;
6887         i++;
6888     }
6889 } /*SetVolumeStats*/
6890
6891
6892 #ifdef notdef
6893 struct nlist RawStats[] = {
6894 #define CPTIME 0
6895     {   "_cp_time"    },
6896 #define BOOT 1
6897     {   "_boottime"    },
6898 #define DISK 2
6899     {   "_dk_xfer"    },
6900 #ifndef AFS_SUN_ENV
6901 #define SWAPMAP 3
6902     {   "_swapmap"    },
6903 #define NSWAPMAP 4
6904     {   "_nswapmap"    },
6905 #define NSWAPBLKS 5
6906     {   "_nswap"    },
6907 #define DMMAX 6
6908     {   "_dmmax"    },
6909 #else /* AFS_SUN_ENV */
6910 #define SANON 3
6911     {   "_anoninfo" },
6912 #endif
6913     {   ""   },
6914
6915 };
6916 #endif
6917
6918 /* Get some kernel specific related statistics */
6919
6920 void SetSystemStats(stats)
6921     struct AFSStatistics * stats;
6922
6923 {
6924 /* Fix this sometime soon.. */
6925 #ifdef notdef
6926     static      int     kmem = 0;
6927     static      struct  mapent  *swapMap = 0;
6928     static      int     swapMapAddr = 0;
6929     static      int     swapMapSize = 0;
6930     static      int     numSwapBlks = 0;
6931     int         numSwapEntries,
6932                 dmmax;
6933     register    int     i;
6934     struct      mapent  * sp;
6935     afs_int32   busy[CPUSTATES];
6936     afs_int32   xfer[DK_NDRIVE];
6937     struct      timeval bootTime;
6938 #endif
6939     struct      timeval time;
6940
6941     /* this works on all system types */
6942     TM_GetTimeOfDay(&time, 0);
6943     stats->CurrentTime = time.tv_sec;
6944
6945 #ifdef notdef
6946     stats->UserCPU =stats->SystemCPU =stats->NiceCPU =stats->IdleCPU =stats->BootTime =0;
6947     stats->TotalIO =stats->ActiveVM =stats->TotalVM = 0;
6948     for (i=0; i < AFS_MSTATSPARES; i++) stats->Spares[i] = 0;
6949
6950     if (kmem == -1) return;
6951     if (kmem == 0) {
6952         nlist("/vmunix", RawStats);
6953         if (RawStats[0].n_type == 0) {
6954             ViceLog(0, ("Could not get a namelist from VMUNIX\n"));
6955             kmem = -1;
6956             return;
6957         }
6958         kmem = open("/dev/kmem",O_RDONLY,0);
6959         if (kmem <= 0) {
6960             ViceLog(0, ("Could not open /dev/kmem\n"));
6961             kmem = -1;
6962             return;
6963         }
6964     }
6965     lseek(kmem, (afs_int32) RawStats[CPTIME].n_value,0);
6966     read(kmem, (char *)busy, sizeof(busy));
6967     stats->SystemCPU = busy[CP_SYS];
6968     stats->UserCPU = busy[CP_USER];
6969     stats->NiceCPU = busy[CP_NICE];
6970     stats->IdleCPU = busy[CP_IDLE];
6971     lseek(kmem, (afs_int32) RawStats[BOOT].n_value,0);
6972     read(kmem, (char *)&bootTime, sizeof(bootTime));
6973     stats->BootTime = bootTime.tv_sec;
6974     lseek(kmem, (afs_int32) RawStats[DISK].n_value,0);
6975     read(kmem, (char *)xfer, sizeof(xfer));
6976     stats->TotalIO = 0;
6977     for(i = 0; i < DK_NDRIVE; i++) {
6978         stats->TotalIO += xfer[i];
6979     }
6980 #ifdef  AFS_SUN_ENV
6981     {
6982 #include <vm/anon.h>
6983         struct anoninfo ai;
6984 #define ctok(x)     ((ctob(x)) >> 10)
6985
6986         lseek(kmem, (afs_int32)RawStats[SANON].n_value,0);
6987         read(kmem, (char *)&ai, sizeof (struct anoninfo));
6988         stats->TotalVM = ctok(ai.ani_max - ai.ani_resv);    /* available */
6989         stats->ActiveVM = ctok(ai.ani_resv);    /*  used */
6990     }
6991 #else
6992     if (!swapMap) {
6993         lseek(kmem, (afs_int32)RawStats[SWAPMAP].n_value,0);
6994         read(kmem, (char *)&swapMapAddr, sizeof(swapMapAddr));
6995         swapMapAddr += sizeof(struct map);
6996         lseek(kmem, (afs_int32)RawStats[NSWAPMAP].n_value,0);
6997         read(kmem, (char *)&numSwapEntries, sizeof(numSwapEntries));
6998         swapMapSize = (--numSwapEntries)*sizeof(struct mapent);
6999         lseek(kmem, (afs_int32)RawStats[NSWAPBLKS].n_value,0);
7000         read(kmem, (char *)&numSwapBlks, sizeof(numSwapBlks));
7001         lseek(kmem, (afs_int32)RawStats[DMMAX].n_value,0);
7002         read(kmem, (char *)&dmmax, sizeof(dmmax));
7003         numSwapBlks -= dmmax/2;
7004         swapMap = (struct mapent *)malloc(swapMapSize);
7005     }
7006     sp = (struct mapent *)swapMap;
7007     lseek(kmem, (afs_int32)swapMapAddr, 0);
7008     read(kmem, (char *)sp, swapMapSize);
7009     for(stats->TotalVM = stats->ActiveVM = numSwapBlks; sp->m_size; sp++) {
7010         stats->ActiveVM -= sp->m_size;
7011     }
7012 #endif /* AFS_SUN_ENV */
7013 #endif
7014
7015 } /*SetSystemStats*/
7016
7017
7018 /* Validate target file */
7019
7020
7021 FileNameOK(aname)
7022     register char *aname;
7023
7024 {
7025     register afs_int32 i, tc;
7026     i = strlen(aname);
7027     if (i >= 4) {
7028         /* watch for @sys on the right */
7029         if (strcmp(aname+i-4, "@sys") == 0) return 0;
7030     }
7031     while (tc = *aname++) {
7032         if (tc == '/') return 0;    /* very bad character to encounter */
7033     }
7034     return 1;   /* file name is ok */
7035
7036 } /*FileNameOK*/
7037
7038
7039 /* Debugging tool to print Volume Statu's contents */
7040
7041 PrintVolumeStatus(status)
7042     VolumeStatus *status;
7043
7044 {
7045     ViceLog(5,("Volume header contains:\n"));
7046     ViceLog(5,("Vid = %u, Parent = %u, Online = %d, InService = %d, Blessed = %d, NeedsSalvage = %d\n",
7047             status->Vid, status->ParentId, status->Online, status->InService,
7048             status->Blessed, status->NeedsSalvage));
7049     ViceLog(5,("MinQuota = %d, MaxQuota = %d\n", status->MinQuota, status->MaxQuota));
7050     ViceLog(5,("Type = %d, BlocksInUse = %d, PartBlocksAvail = %d, PartMaxBlocks = %d\n",
7051             status->Type, status->BlocksInUse, status->PartBlocksAvail, status->PartMaxBlocks));
7052
7053 } /*PrintVolumeStatus*/
7054
7055
7056 /*
7057  * This variant of symlink is expressly to support the AFS/DFS translator
7058  * and is not supported by the AFS fileserver. We just return EINVAL.
7059  * The cache manager should not generate this call to an AFS cache manager.
7060  */
7061 SRXAFS_DFSSymlink (tcon, DirFid, Name, LinkContents, InStatus, OutFid, OutFidStatus, OutDirStatus, CallBack, Sync)
7062     struct rx_connection *tcon;          /* Rx connection handle */
7063     struct AFSFid *DirFid;               /* Parent dir's fid */
7064     char *Name;                          /* File name to create */
7065     char *LinkContents;                  /* Contents of the new created file */
7066     struct AFSStoreStatus *InStatus;     /* Input status for the new symbolic link */
7067     struct AFSFid *OutFid;               /* Fid for newly created symbolic link */
7068     struct AFSFetchStatus *OutFidStatus; /* Output status for new symbolic link */
7069     struct AFSFetchStatus *OutDirStatus; /* Output status for parent dir */
7070     struct AFSCallBack *CallBack;        /* Callback on link */
7071     struct AFSVolSync *Sync;
7072 {
7073     return EINVAL;
7074 }
7075
7076 SRXAFS_ResidencyCmd (tcon, Fid, Inputs, Outputs)
7077     struct rx_connection *tcon;
7078     struct AFSFid *Fid;
7079     struct ResidencyCmdInputs *Inputs;
7080     struct ResidencyCmdOutputs *Outputs;
7081 {
7082     return EINVAL;
7083 }