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