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