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