viced-ubik-clientdestroy-null-20090703
[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
32     ("$Header$");
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <errno.h>
37 #ifdef  AFS_SGI_ENV
38 #undef SHARED                   /* XXX */
39 #endif
40 #ifdef AFS_NT40_ENV
41 #include <fcntl.h>
42 #else
43 #include <sys/param.h>
44 #include <sys/file.h>
45 #include <sys/ioctl.h>
46 #include <sys/socket.h>
47 #include <netinet/in.h>
48 #include <arpa/inet.h>
49 #include <netdb.h>
50 #include <string.h>
51
52 #ifndef AFS_LINUX20_ENV
53 #include <net/if.h>
54 #include <netinet/if_ether.h>
55 #endif
56 #endif
57 #ifdef AFS_HPUX_ENV
58 /* included early because of name conflict on IOPEN */
59 #include <sys/inode.h>
60 #ifdef IOPEN
61 #undef IOPEN
62 #endif
63 #endif /* AFS_HPUX_ENV */
64 #include <afs/stds.h>
65 #include <rx/xdr.h>
66 #include <afs/nfs.h>
67 #include <afs/assert.h>
68 #include <lwp.h>
69 #include <lock.h>
70 #include <afs/afsint.h>
71 #include <afs/vldbint.h>
72 #include <afs/errors.h>
73 #include <afs/ihandle.h>
74 #include <afs/vnode.h>
75 #include <afs/volume.h>
76 #include <afs/ptclient.h>
77 #include <afs/ptuser.h>
78 #include <afs/prs_fs.h>
79 #include <afs/acl.h>
80 #include <rx/rx.h>
81 #include <rx/rx_globals.h>
82 #include <sys/stat.h>
83 #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)
84 #include <sys/map.h>
85 #endif
86 #if !defined(AFS_NT40_ENV)
87 #include <unistd.h>
88 #endif
89 #if !defined(AFS_SGI_ENV) && !defined(AFS_NT40_ENV)
90 #ifdef  AFS_AIX_ENV
91 #include <sys/statfs.h>
92 #include <sys/lockf.h>
93 #else
94 #if !defined(AFS_SUN5_ENV) && !defined(AFS_LINUX20_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_XBSD_ENV)
95 #include <sys/dk.h>
96 #endif
97 #endif
98 #endif
99 #include <afs/cellconfig.h>
100 #include <afs/keys.h>
101
102 #include <signal.h>
103 #include <afs/partition.h>
104 #include "viced_prototypes.h"
105 #include "viced.h"
106 #include "host.h"
107 #include "callback.h"
108 #include <afs/unified_afs.h>
109 #include <afs/audit.h>
110 #include <afs/afsutil.h>
111 #include <afs/dir.h>
112
113 extern void SetDirHandle(register DirHandle * dir, register Vnode * vnode);
114 extern void FidZap(DirHandle * file);
115 extern void FidZero(DirHandle * file);
116
117 #ifdef AFS_PTHREAD_ENV
118 pthread_mutex_t fileproc_glock_mutex;
119 #endif /* AFS_PTHREAD_ENV */
120
121 #ifdef O_LARGEFILE
122 #define afs_stat        stat64
123 #define afs_fstat       fstat64
124 #define afs_open        open64
125 #else /* !O_LARGEFILE */
126 #define afs_stat        stat
127 #define afs_fstat       fstat
128 #define afs_open        open
129 #endif /* !O_LARGEFILE */
130
131
132 /* Useful local defines used by this module */
133
134 #define DONTCHECK       0
135 #define MustNOTBeDIR    1
136 #define MustBeDIR       2
137
138 #define TVS_SDATA       1
139 #define TVS_SSTATUS     2
140 #define TVS_CFILE       4
141 #define TVS_SLINK       8
142 #define TVS_MKDIR       0x10
143
144 #define CHK_FETCH       0x10
145 #define CHK_FETCHDATA   0x10
146 #define CHK_FETCHACL    0x11
147 #define CHK_FETCHSTATUS 0x12
148 #define CHK_STOREDATA   0x00
149 #define CHK_STOREACL    0x01
150 #define CHK_STORESTATUS 0x02
151
152 #define OWNERREAD       0400
153 #define OWNERWRITE      0200
154 #define OWNEREXEC       0100
155 #ifdef USE_GROUP_PERMS
156 #define GROUPREAD       0040
157 #define GROUPWRITE      0020
158 #define GROUPREXEC      0010
159 #endif
160
161 /* The following errors were not defined in NT. They are given unique
162  * names here to avoid any potential collision.
163  */
164 #define FSERR_ELOOP              90
165 #define FSERR_EOPNOTSUPP        122
166 #define FSERR_ECONNREFUSED      130
167
168 #define NOTACTIVECALL   0
169 #define ACTIVECALL      1
170
171 #define CREATE_SGUID_ADMIN_ONLY 1
172
173 extern struct afsconf_dir *confDir;
174 extern afs_int32 dataVersionHigh;
175
176 extern int SystemId;
177 static struct AFSCallStatistics AFSCallStats;
178 #if FS_STATS_DETAILED
179 struct fs_stats_FullPerfStats afs_FullPerfStats;
180 extern int AnonymousID;
181 #endif /* FS_STATS_DETAILED */
182 #if OPENAFS_VOL_STATS
183 static const char nullString[] = "";
184 #endif /* OPENAFS_VOL_STATS */
185
186 struct afs_FSStats {
187     afs_int32 NothingYet;
188 };
189
190 struct afs_FSStats afs_fsstats;
191
192 void ResetDebug(), SetDebug(), Terminate();
193
194 int LogLevel = 0;
195 int supported = 1;
196 int Console = 0;
197 afs_int32 BlocksSpare = 1024;   /* allow 1 MB overruns */
198 afs_int32 PctSpare;
199 extern afs_int32 implicitAdminRights;
200 extern afs_int32 readonlyServer;
201 extern int CopyOnWrite_calls, CopyOnWrite_off0, CopyOnWrite_size0;
202 extern afs_fsize_t CopyOnWrite_maxsize;
203
204 /*
205  * Externals used by the xstat code.
206  */
207 extern VolPkgStats VStats;
208 extern int CEs, CEBlocks;
209
210 extern int HTs, HTBlocks;
211
212 afs_int32 FetchData_RXStyle(Volume * volptr, Vnode * targetptr,
213                             register struct rx_call *Call, afs_sfsize_t Pos,
214                             afs_sfsize_t Len, afs_int32 Int64Mode,
215 #if FS_STATS_DETAILED
216                             afs_sfsize_t * a_bytesToFetchP,
217                             afs_sfsize_t * a_bytesFetchedP
218 #endif                          /* FS_STATS_DETAILED */
219     );
220
221 afs_int32 StoreData_RXStyle(Volume * volptr, Vnode * targetptr,
222                             struct AFSFid *Fid, struct client *client,
223                             register struct rx_call *Call, afs_fsize_t Pos,
224                             afs_fsize_t Length, afs_fsize_t FileLength,
225                             int sync,
226 #if FS_STATS_DETAILED
227                             afs_sfsize_t * a_bytesToStoreP,
228                             afs_sfsize_t * a_bytesStoredP
229 #endif                          /* FS_STATS_DETAILED */
230     );
231
232 #ifdef AFS_SGI_XFS_IOPS_ENV
233 #include <afs/xfsattrs.h>
234 static int
235 GetLinkCount(Volume * avp, struct stat *astat)
236 {
237     if (!strcmp("xfs", astat->st_fstype)) {
238         return (astat->st_mode & AFS_XFS_MODE_LINK_MASK);
239     } else
240         return astat->st_nlink;
241 }
242 #else
243 #define GetLinkCount(V, S) (S)->st_nlink
244 #endif
245
246 afs_int32
247 SpareComp(Volume * avolp)
248 {
249     register afs_int32 temp;
250
251     FS_LOCK;
252     if (PctSpare) {
253         temp = V_maxquota(avolp);
254         if (temp == 0) {
255             /* no matter; doesn't check in this case */
256             FS_UNLOCK;
257             return 0;
258         }
259         temp = (temp * PctSpare) / 100;
260         FS_UNLOCK;
261         return temp;
262     } else {
263         FS_UNLOCK;
264         return BlocksSpare;
265     }
266
267 }                               /*SpareComp */
268
269 /*
270  * Set the volume synchronization parameter for this volume.  If it changes,
271  * the Cache Manager knows that the volume must be purged from the stat cache.
272  */
273 static void
274 SetVolumeSync(register struct AFSVolSync *async, register Volume * avol)
275 {
276     FS_LOCK;
277     /* date volume instance was created */
278     if (async) {
279         if (avol)
280             async->spare1 = avol->header->diskstuff.creationDate;
281         else
282             async->spare1 = 0;
283         async->spare2 = 0;
284         async->spare3 = 0;
285         async->spare4 = 0;
286         async->spare5 = 0;
287         async->spare6 = 0;
288     }
289     FS_UNLOCK;
290 }                               /*SetVolumeSync */
291
292 /*
293  * Note that this function always returns a held host, so
294  * that CallPostamble can block without the host's disappearing.
295  * Call returns rx connection in passed in *tconn
296  */
297 static int
298 CallPreamble(register struct rx_call *acall, int activecall,
299              struct rx_connection **tconn, struct host **ahostp)
300 {
301     struct host *thost;
302     struct client *tclient;
303     int retry_flag = 1;
304     int code = 0;
305     char hoststr[16], hoststr2[16];
306     struct ubik_client *uclient;
307
308     *ahostp = NULL;
309
310     if (!tconn) {
311         ViceLog(0, ("CallPreamble: unexpected null tconn!\n"));
312         return -1;
313     }
314     *tconn = rx_ConnectionOf(acall);
315
316     H_LOCK;
317   retry:
318     tclient = h_FindClient_r(*tconn);
319     if (!tclient) {
320         ViceLog(0, ("CallPreamble: Couldn't get CPS. Too many lockers\n"));
321         H_UNLOCK;
322         return VBUSY;
323     }
324     thost = tclient->host;
325     if (tclient->prfail == 1) { /* couldn't get the CPS */
326         if (!retry_flag) {
327             h_ReleaseClient_r(tclient);
328             h_Release_r(thost);
329             ViceLog(0, ("CallPreamble: Couldn't get CPS. Fail\n"));
330             H_UNLOCK;
331             return -1001;
332         }
333         retry_flag = 0;         /* Retry once */
334
335         /* Take down the old connection and re-read the key file */
336         ViceLog(0,
337                 ("CallPreamble: Couldn't get CPS. Reconnect to ptserver\n"));
338 #ifdef AFS_PTHREAD_ENV
339         uclient = (struct ubik_client *)pthread_getspecific(viced_uclient_key);
340
341         /* Is it still necessary to drop this? We hit the net, we should... */
342         H_UNLOCK;
343         if (uclient) {
344             hpr_End(uclient);
345             uclient = NULL;
346         }
347         code = hpr_Initialize(&uclient);
348
349         if (!code)
350             assert(pthread_setspecific(viced_uclient_key, (void *)uclient) == 0);
351         H_LOCK;
352 #else
353         code = pr_Initialize(2, AFSDIR_SERVER_ETC_DIRPATH, 0);
354 #endif
355         if (code) {
356             h_ReleaseClient_r(tclient);
357             h_Release_r(thost);
358             H_UNLOCK;
359             ViceLog(0, ("CallPreamble: couldn't reconnect to ptserver\n"));
360             return -1001;
361         }
362
363         tclient->prfail = 2;    /* Means re-eval client's cps */
364         h_ReleaseClient_r(tclient);
365         h_Release_r(thost);
366         goto retry;
367     }
368
369     tclient->LastCall = thost->LastCall = FT_ApproxTime();
370     if (activecall)             /* For all but "GetTime", "GetStats", and "GetCaps" calls */
371         thost->ActiveCall = thost->LastCall;
372
373     h_Lock_r(thost);
374     if (thost->hostFlags & HOSTDELETED) {
375         ViceLog(3,
376                 ("Discarded a packet for deleted host %s:%d\n",
377                  afs_inet_ntoa_r(thost->host, hoststr), ntohs(thost->port)));
378         code = VBUSY;           /* raced, so retry */
379     } else if ((thost->hostFlags & VENUSDOWN)
380                || (thost->hostFlags & HFE_LATER)) {
381         if (BreakDelayedCallBacks_r(thost)) {
382             ViceLog(0,
383                     ("BreakDelayedCallbacks FAILED for host %s:%d which IS UP.  Connection from %s:%d.  Possible network or routing failure.\n",
384                      afs_inet_ntoa_r(thost->host, hoststr), ntohs(thost->port), afs_inet_ntoa_r(rxr_HostOf(*tconn), hoststr2), 
385                      ntohs(rxr_PortOf(*tconn))));
386             if (MultiProbeAlternateAddress_r(thost)) {
387                 ViceLog(0,
388                         ("MultiProbe failed to find new address for host %s:%d\n",
389                          afs_inet_ntoa_r(thost->host, hoststr),
390                          ntohs(thost->port)));
391                 code = -1;
392             } else {
393                 ViceLog(0,
394                         ("MultiProbe found new address for host %s:%d\n",
395                          afs_inet_ntoa_r(thost->host, hoststr),
396                          ntohs(thost->port)));
397                 if (BreakDelayedCallBacks_r(thost)) {
398                     ViceLog(0,
399                             ("BreakDelayedCallbacks FAILED AGAIN for host %s:%d which IS UP.  Connection from %s:%d.  Possible network or routing failure.\n",
400                               afs_inet_ntoa_r(thost->host, hoststr), ntohs(thost->port), afs_inet_ntoa_r(rxr_HostOf(*tconn), hoststr2), 
401                               ntohs(rxr_PortOf(*tconn))));
402                     code = -1;
403                 }
404             }
405         }
406     } else {
407         code = 0;
408     }
409
410     h_ReleaseClient_r(tclient);
411     h_Unlock_r(thost);
412     H_UNLOCK;
413     *ahostp = thost;
414     return code;
415
416 }                               /*CallPreamble */
417
418
419 static afs_int32
420 CallPostamble(register struct rx_connection *aconn, afs_int32 ret,
421               struct host *ahost)
422 {
423     struct host *thost;
424     struct client *tclient;
425     int translate = 0;
426     int held;
427
428     H_LOCK;
429     tclient = h_FindClient_r(aconn);
430     if (!tclient) 
431         goto busyout;
432     thost = tclient->host;
433     if (thost->hostFlags & HERRORTRANS)
434         translate = 1;
435     h_ReleaseClient_r(tclient);
436     held = h_Held_r(thost);
437     if (held)
438         h_Release_r(thost);
439     if (ahost && ahost != thost) {
440         char hoststr[16], hoststr2[16]; 
441         ViceLog(0, ("CallPostamble: ahost %s:%d (%x) != thost %s:%d (%x)\n",
442                 afs_inet_ntoa_r(ahost->host, hoststr), ntohs(ahost->port),
443                 ahost, 
444                 afs_inet_ntoa_r(thost->host, hoststr2), ntohs(thost->port),
445                 thost));
446         h_Release_r(ahost);
447     } else if (!ahost) {
448         char hoststr[16];       
449         ViceLog(0, ("CallPostamble: null ahost for thost %s:%d (%x)\n",
450                 afs_inet_ntoa_r(thost->host, hoststr), ntohs(thost->port),
451                 thost));
452     }
453  busyout:
454     H_UNLOCK;
455     return (translate ? sys_error_to_et(ret) : ret);
456 }                               /*CallPostamble */
457
458 /*
459  * Returns the volume and vnode pointers associated with file Fid; the lock
460  * type on the vnode is set to lock. Note that both volume/vnode's ref counts
461  * are incremented and they must be eventualy released.
462  */
463 static afs_int32
464 CheckVnode(AFSFid * fid, Volume ** volptr, Vnode ** vptr, int lock)
465 {
466     int fileCode = 0;
467     afs_int32 local_errorCode, errorCode = -1;
468     static struct timeval restartedat = { 0, 0 };
469
470     if (fid->Volume == 0 || fid->Vnode == 0)    /* not: || fid->Unique == 0) */
471         return (EINVAL);
472     if ((*volptr) == 0) {
473         extern int VInit;
474
475         while (1) {
476             int restarting = 
477 #ifdef AFS_DEMAND_ATTACH_FS
478                 VSALVAGE
479 #else
480                 VRESTARTING
481 #endif
482                 ;
483
484             errorCode = 0;
485             *volptr = VGetVolume(&local_errorCode, &errorCode, (afs_int32) fid->Volume);
486             if (!errorCode) {
487                 assert(*volptr);
488                 break;
489             }
490             if ((errorCode == VOFFLINE) && (VInit < 2)) {
491                 /* The volume we want may not be attached yet because
492                  * the volume initialization is not yet complete.
493                  * We can do several things: 
494                  *     1.  return -1, which will cause users to see
495                  *         "connection timed out".  This is more or
496                  *         less the same as always, except that the servers
497                  *         may appear to bounce up and down while they
498                  *         are actually restarting.
499                  *     2.  return VBUSY which will cause clients to 
500                  *         sleep and retry for 6.5 - 15 minutes, depending
501                  *         on what version of the CM they are running.  If
502                  *         the file server takes longer than that interval 
503                  *         to attach the desired volume, then the application
504                  *         will see an ENODEV or EIO.  This approach has 
505                  *         the advantage that volumes which have been attached
506                  *         are immediately available, it keeps the server's
507                  *         immediate backlog low, and the call is interruptible
508                  *         by the user.  Users see "waiting for busy volume."
509                  *     3.  sleep here and retry.  Some people like this approach
510                  *         because there is no danger of seeing errors.  However, 
511                  *         this approach only works with a bounded number of 
512                  *         clients, since the pending queues will grow without
513                  *         stopping.  It might be better to find a way to take
514                  *         this call and stick it back on a queue in order to
515                  *         recycle this thread for a different request.    
516                  *     4.  Return a new error code, which new cache managers will
517                  *         know enough to interpret as "sleep and retry", without
518                  *         the upper bound of 6-15 minutes that is imposed by the
519                  *         VBUSY handling.  Users will see "waiting for
520                  *         busy volume," so they know that something is
521                  *         happening.  Old cache managers must be able to do  
522                  *         something reasonable with this, for instance, mark the
523                  *         server down.  Fortunately, any error code < 0
524                  *         will elicit that behavior. See #1.
525                  *     5.  Some combination of the above.  I like doing #2 for 10
526                  *         minutes, followed by #4.  3.1b and 3.2 cache managers
527                  *         will be fine as long as the restart period is
528                  *         not longer than 6.5 minutes, otherwise they may
529                  *         return ENODEV to users.  3.3 cache managers will be
530                  *         fine for 10 minutes, then will return
531                  *         ETIMEDOUT.  3.4 cache managers will just wait
532                  *         until the call works or fails definitively.
533                  *  NB. The problem with 2,3,4,5 is that old clients won't
534                  *  fail over to an alternate read-only replica while this
535                  *  server is restarting.  3.4 clients will fail over right away.
536                  */
537                 if (restartedat.tv_sec == 0) {
538                     /* I'm not really worried about when we restarted, I'm   */
539                     /* just worried about when the first VBUSY was returned. */
540                     FT_GetTimeOfDay(&restartedat, 0);
541                     if (busyonrst) {
542                         FS_LOCK;
543                         afs_perfstats.fs_nBusies++;
544                         FS_UNLOCK;
545                     }
546                     return (busyonrst ? VBUSY : restarting);
547                 } else {
548                     struct timeval now;
549                     FT_GetTimeOfDay(&now, 0);
550                     if ((now.tv_sec - restartedat.tv_sec) < (11 * 60)) {
551                         if (busyonrst) {
552                             FS_LOCK;
553                             afs_perfstats.fs_nBusies++;
554                             FS_UNLOCK;
555                         }
556                         return (busyonrst ? VBUSY : restarting);
557                     } else {
558                         return (restarting);
559                     }
560                 }
561             }
562             /* allow read operations on busy volume. 
563              * must check local_errorCode because demand attach fs
564              * can have local_errorCode == VSALVAGING, errorCode == VBUSY */
565             else if (local_errorCode == VBUSY && lock == READ_LOCK) {
566 #ifdef AFS_DEMAND_ATTACH_FS
567                 /* DAFS case is complicated by the fact that local_errorCode can
568                  * be VBUSY in cases where the volume is truly offline */
569                 if (!*volptr) {
570                     /* volume is in VOL_STATE_UNATTACHED */
571                     return (errorCode);
572                 }
573 #endif /* AFS_DEMAND_ATTACH_FS */
574                 errorCode = 0;
575                 break;
576             } else if (errorCode)
577                 return (errorCode);
578         }
579     }
580     assert(*volptr);
581
582     /* get the vnode  */
583     *vptr = VGetVnode(&errorCode, *volptr, fid->Vnode, lock);
584     if (errorCode)
585         return (errorCode);
586     if ((*vptr)->disk.uniquifier != fid->Unique) {
587         VPutVnode(&fileCode, *vptr);
588         assert(fileCode == 0);
589         *vptr = 0;
590         return (VNOVNODE);      /* return the right error code, at least */
591     }
592     return (0);
593 }                               /*CheckVnode */
594
595 /*
596  * This routine returns the ACL associated with the targetptr. If the
597  * targetptr isn't a directory, we access its parent dir and get the ACL
598  * thru the parent; in such case the parent's vnode is returned in
599  * READ_LOCK mode.
600  */
601 static afs_int32
602 SetAccessList(Vnode ** targetptr, Volume ** volume,
603               struct acl_accessList **ACL, int *ACLSize, Vnode ** parent,
604               AFSFid * Fid, int Lock)
605 {
606     if ((*targetptr)->disk.type == vDirectory) {
607         *parent = 0;
608         *ACL = VVnodeACL(*targetptr);
609         *ACLSize = VAclSize(*targetptr);
610         return (0);
611     } else {
612         assert(Fid != 0);
613         while (1) {
614             VnodeId parentvnode;
615             int errorCode = 0;
616
617             parentvnode = (*targetptr)->disk.parent;
618             VPutVnode(&errorCode, *targetptr);
619             *targetptr = 0;
620             if (errorCode)
621                 return (errorCode);
622             *parent = VGetVnode(&errorCode, *volume, parentvnode, READ_LOCK);
623             if (errorCode)
624                 return (errorCode);
625             *ACL = VVnodeACL(*parent);
626             *ACLSize = VAclSize(*parent);
627             if ((errorCode = CheckVnode(Fid, volume, targetptr, Lock)) != 0)
628                 return (errorCode);
629             if ((*targetptr)->disk.parent != parentvnode) {
630                 VPutVnode(&errorCode, *parent);
631                 *parent = 0;
632                 if (errorCode)
633                     return (errorCode);
634             } else
635                 return (0);
636         }
637     }
638
639 }                               /*SetAccessList */
640
641 /* Must not be called with H_LOCK held */
642 static void
643 client_CheckRights(struct client *client, struct acl_accessList *ACL, 
644                    afs_int32 *rights)
645 {
646     *rights = 0;
647     ObtainReadLock(&client->lock);
648     if (client->CPS.prlist_len > 0 && !client->deleted &&
649         client->host && !(client->host->hostFlags & HOSTDELETED))
650         acl_CheckRights(ACL, &client->CPS, rights);
651     ReleaseReadLock(&client->lock);
652 }
653
654 /* Must not be called with H_LOCK held */
655 static afs_int32
656 client_HasAsMember(struct client *client, afs_int32 id)
657 {
658     afs_int32 code = 0;
659
660     ObtainReadLock(&client->lock);
661     if (client->CPS.prlist_len > 0 && !client->deleted && 
662         client->host && !(client->host->hostFlags & HOSTDELETED))
663         code = acl_IsAMember(id, &client->CPS);
664     ReleaseReadLock(&client->lock);
665     return code;
666 }
667
668 /*
669  * Compare the directory's ACL with the user's access rights in the client
670  * connection and return the user's and everybody else's access permissions
671  * in rights and anyrights, respectively
672  */
673 static afs_int32
674 GetRights(struct client *client, struct acl_accessList *ACL,
675           afs_int32 * rights, afs_int32 * anyrights)
676 {
677     extern prlist SystemAnyUserCPS;
678     afs_int32 hrights = 0;
679 #ifndef AFS_PTHREAD_ENV
680     int code;
681 #endif
682
683     if (acl_CheckRights(ACL, &SystemAnyUserCPS, anyrights) != 0) {
684         ViceLog(0, ("CheckRights failed\n"));
685         *anyrights = 0;
686     }
687     *rights = 0;
688
689     client_CheckRights(client, ACL, rights);
690
691     /* wait if somebody else is already doing the getCPS call */
692     H_LOCK;
693     while (client->host->hostFlags & HCPS_INPROGRESS) {
694         client->host->hostFlags |= HCPS_WAITING;        /* I am waiting */
695 #ifdef AFS_PTHREAD_ENV
696         pthread_cond_wait(&client->host->cond, &host_glock_mutex);
697 #else /* AFS_PTHREAD_ENV */
698         if ((code =
699              LWP_WaitProcess(&(client->host->hostFlags))) != LWP_SUCCESS)
700             ViceLog(0, ("LWP_WaitProcess returned %d\n", code));
701 #endif /* AFS_PTHREAD_ENV */
702     }
703
704     if (!client->host->hcps.prlist_len || !client->host->hcps.prlist_val) {
705         char hoststr[16];
706         ViceLog(5,
707                 ("CheckRights: len=%u, for host=%s:%d\n",
708                  client->host->hcps.prlist_len, 
709                  afs_inet_ntoa_r(client->host->host, hoststr),
710                  ntohs(client->host->port)));
711     } else
712         acl_CheckRights(ACL, &client->host->hcps, &hrights);
713     H_UNLOCK;
714     /* Allow system:admin the rights given with the -implicit option */
715     if (client_HasAsMember(client, SystemId))
716         *rights |= implicitAdminRights;
717
718     *rights |= hrights;
719     *anyrights |= hrights;
720
721     return (0);
722
723 }                               /*GetRights */
724
725 /*
726  * VanillaUser returns 1 (true) if the user is a vanilla user (i.e., not
727  * a System:Administrator)
728  */
729 static afs_int32
730 VanillaUser(struct client *client)
731 {
732     if (client_HasAsMember(client, SystemId))
733         return (0);             /* not a system administrator, then you're "vanilla" */
734     return (1);
735
736 }                               /*VanillaUser */
737
738
739 /*
740  * This unusual afs_int32-parameter routine encapsulates all volume package related
741  * operations together in a single function; it's called by almost all AFS
742  * interface calls.
743  */
744 static afs_int32
745 GetVolumePackage(struct rx_connection *tcon, AFSFid * Fid, Volume ** volptr,
746                  Vnode ** targetptr, int chkforDir, Vnode ** parent,
747                  struct client **client, int locktype, afs_int32 * rights,
748                  afs_int32 * anyrights)
749 {
750     struct acl_accessList *aCL; /* Internal access List */
751     int aCLSize;                /* size of the access list */
752     int errorCode = 0;          /* return code to caller */
753
754     if ((errorCode = CheckVnode(Fid, volptr, targetptr, locktype)))
755         return (errorCode);
756     if (chkforDir) {
757         if (chkforDir == MustNOTBeDIR
758             && ((*targetptr)->disk.type == vDirectory))
759             return (EISDIR);
760         else if (chkforDir == MustBeDIR
761                  && ((*targetptr)->disk.type != vDirectory))
762             return (ENOTDIR);
763     }
764     if ((errorCode =
765          SetAccessList(targetptr, volptr, &aCL, &aCLSize, parent,
766                        (chkforDir == MustBeDIR ? (AFSFid *) 0 : Fid),
767                        (chkforDir == MustBeDIR ? 0 : locktype))) != 0)
768         return (errorCode);
769     if (chkforDir == MustBeDIR)
770         assert((*parent) == 0);
771     if (!(*client)) {
772         if ((errorCode = GetClient(tcon, client)) != 0)
773             return (errorCode);
774         if (!(*client))
775             return (EINVAL);
776     }
777     GetRights(*client, aCL, rights, anyrights);
778     /* ok, if this is not a dir, set the PRSFS_ADMINISTER bit iff we're the owner */
779     if ((*targetptr)->disk.type != vDirectory) {
780         /* anyuser can't be owner, so only have to worry about rights, not anyrights */
781         if ((*targetptr)->disk.owner == (*client)->ViceId)
782             (*rights) |= PRSFS_ADMINISTER;
783         else
784             (*rights) &= ~PRSFS_ADMINISTER;
785     }
786 #ifdef ADMIN_IMPLICIT_LOOKUP
787     /* admins get automatic lookup on everything */
788     if (!VanillaUser(*client))
789         (*rights) |= PRSFS_LOOKUP;
790 #endif /* ADMIN_IMPLICIT_LOOKUP */
791     return errorCode;
792
793 }                               /*GetVolumePackage */
794
795
796 /*
797  * This is the opposite of GetVolumePackage(), and is always used at the end of
798  * AFS calls to put back all used vnodes and the volume in the proper order!
799  */
800 static void
801 PutVolumePackage(Vnode * parentwhentargetnotdir, Vnode * targetptr,
802                  Vnode * parentptr, Volume * volptr, struct client **client)
803 {
804     int fileCode = 0;           /* Error code returned by the volume package */
805
806     if (parentwhentargetnotdir) {
807         VPutVnode(&fileCode, parentwhentargetnotdir);
808         assert(!fileCode || (fileCode == VSALVAGE));
809     }
810     if (targetptr) {
811         VPutVnode(&fileCode, targetptr);
812         assert(!fileCode || (fileCode == VSALVAGE));
813     }
814     if (parentptr) {
815         VPutVnode(&fileCode, parentptr);
816         assert(!fileCode || (fileCode == VSALVAGE));
817     }
818     if (volptr) {
819         VPutVolume(volptr);
820     }
821     if (*client) {
822         PutClient(client);
823     }
824 }                               /*PutVolumePackage */
825
826 static int
827 VolumeOwner(register struct client *client, register Vnode * targetptr)
828 {
829     afs_int32 owner = V_owner(targetptr->volumePtr);    /* get volume owner */
830
831     if (owner >= 0)
832         return (client->ViceId == owner);
833     else {
834         /* 
835          * We don't have to check for host's cps since only regular
836          * viceid are volume owners.
837          */
838         return (client_HasAsMember(client, owner));
839     }
840
841 }                               /*VolumeOwner */
842
843 static int
844 VolumeRootVnode(Vnode * targetptr)
845 {
846     return ((targetptr->vnodeNumber == ROOTVNODE)
847             && (targetptr->disk.uniquifier == 1));
848
849 }                               /*VolumeRootVnode */
850
851 /*
852  * Check if target file has the proper access permissions for the Fetch
853  * (FetchData, FetchACL, FetchStatus) and Store (StoreData, StoreACL,
854  * StoreStatus) related calls
855  */
856 /* this code should probably just set a "priv" flag where all the audit events
857  * are now, and only generate the audit event once at the end of the routine, 
858  * thus only generating the event if all the checks succeed, but only because
859  * of the privilege       XXX
860  */
861 static afs_int32
862 Check_PermissionRights(Vnode * targetptr, struct client *client,
863                        afs_int32 rights, int CallingRoutine,
864                        AFSStoreStatus * InStatus)
865 {
866     int errorCode = 0;
867 #define OWNSp(client, target) ((client)->ViceId == (target)->disk.owner)
868 #define CHOWN(i,t) (((i)->Mask & AFS_SETOWNER) &&((i)->Owner != (t)->disk.owner))
869 #define CHGRP(i,t) (((i)->Mask & AFS_SETGROUP) &&((i)->Group != (t)->disk.group))
870
871     if (CallingRoutine & CHK_FETCH) {
872         if (CallingRoutine == CHK_FETCHDATA || VanillaUser(client)) {
873             if (targetptr->disk.type == vDirectory
874                 || targetptr->disk.type == vSymlink) {
875                 if (!(rights & PRSFS_LOOKUP)
876 #ifdef ADMIN_IMPLICIT_LOOKUP
877                     /* grant admins fetch on all directories */
878                     && VanillaUser(client)
879 #endif /* ADMIN_IMPLICIT_LOOKUP */
880                     && !VolumeOwner(client, targetptr))
881                     return (EACCES);
882             } else {            /* file */
883                 /* must have read access, or be owner and have insert access */
884                 if (!(rights & PRSFS_READ)
885                     && !(OWNSp(client, targetptr) && (rights & PRSFS_INSERT)))
886                     return (EACCES);
887             }
888             if (CallingRoutine == CHK_FETCHDATA
889                 && targetptr->disk.type == vFile)
890 #ifdef USE_GROUP_PERMS
891                 if (!OWNSp(client, targetptr)
892                     && !client_HasAsMember(client, targetptr->disk.owner)) {
893                     errorCode =
894                         (((GROUPREAD | GROUPEXEC) & targetptr->disk.modeBits)
895                          ? 0 : EACCES);
896                 } else {
897                     errorCode =
898                         (((OWNERREAD | OWNEREXEC) & targetptr->disk.modeBits)
899                          ? 0 : EACCES);
900                 }
901 #else
902                 /*
903                  * The check with the ownership below is a kludge to allow
904                  * reading of files created with no read permission. The owner
905                  * of the file is always allowed to read it.
906                  */
907                 if ((client->ViceId != targetptr->disk.owner)
908                     && VanillaUser(client))
909                     errorCode =
910                         (((OWNERREAD | OWNEREXEC) & targetptr->disk.
911                           modeBits) ? 0 : EACCES);
912 #endif
913         } else {                /*  !VanillaUser(client) && !FetchData */
914
915             osi_audit(PrivilegeEvent, 0, AUD_ID,
916                       (client ? client->ViceId : 0), AUD_INT, CallingRoutine,
917                       AUD_END);
918         }
919     } else {                    /* a store operation */
920         if ((rights & PRSFS_INSERT) && OWNSp(client, targetptr)
921             && (CallingRoutine != CHK_STOREACL)
922             && (targetptr->disk.type == vFile)) {
923             /* bypass protection checks on first store after a create
924              * for the creator; also prevent chowns during this time
925              * unless you are a system administrator */
926           /******  InStatus->Owner && UnixModeBits better be SET!! */
927             if (CHOWN(InStatus, targetptr) || CHGRP(InStatus, targetptr)) {
928                 if (readonlyServer)
929                     return (VREADONLY);
930                 else if (VanillaUser(client))
931                     return (EPERM);     /* Was EACCES */
932                 else
933                     osi_audit(PrivilegeEvent, 0, AUD_ID,
934                               (client ? client->ViceId : 0), AUD_INT,
935                               CallingRoutine, AUD_END);
936             }
937         } else {
938             if (CallingRoutine != CHK_STOREDATA && !VanillaUser(client)) {
939                 osi_audit(PrivilegeEvent, 0, AUD_ID,
940                           (client ? client->ViceId : 0), AUD_INT,
941                           CallingRoutine, AUD_END);
942             } else {
943                 if (readonlyServer) {
944                     return (VREADONLY);
945                 }
946                 if (CallingRoutine == CHK_STOREACL) {
947                     if (!(rights & PRSFS_ADMINISTER)
948                         && !VolumeOwner(client, targetptr))
949                         return (EACCES);
950                 } else {        /* store data or status */
951                     /* watch for chowns and chgrps */
952                     if (CHOWN(InStatus, targetptr)
953                         || CHGRP(InStatus, targetptr)) {
954                         if (readonlyServer)
955                             return (VREADONLY);
956                         else if (VanillaUser(client))
957                             return (EPERM);     /* Was EACCES */
958                         else
959                             osi_audit(PrivilegeEvent, 0, AUD_ID,
960                                       (client ? client->ViceId : 0), AUD_INT,
961                                       CallingRoutine, AUD_END);
962                     }
963                     /* must be sysadmin to set suid/sgid bits */
964                     if ((InStatus->Mask & AFS_SETMODE) &&
965 #ifdef AFS_NT40_ENV
966                         (InStatus->UnixModeBits & 0xc00) != 0) {
967 #else
968                         (InStatus->UnixModeBits & (S_ISUID | S_ISGID)) != 0) {
969 #endif
970                         if (readonlyServer)
971                             return (VREADONLY);
972                         if (VanillaUser(client))
973                             return (EACCES);
974                         else
975                             osi_audit(PrivSetID, 0, AUD_ID,
976                                       (client ? client->ViceId : 0), AUD_INT,
977                                       CallingRoutine, AUD_END);
978                     }
979                     if (CallingRoutine == CHK_STOREDATA) {
980                         if (readonlyServer)
981                             return (VREADONLY);
982                         if (!(rights & PRSFS_WRITE))
983                             return (EACCES);
984                         /* Next thing is tricky.  We want to prevent people
985                          * from writing files sans 0200 bit, but we want
986                          * creating new files with 0444 mode to work.  We
987                          * don't check the 0200 bit in the "you are the owner"
988                          * path above, but here we check the bit.  However, if
989                          * you're a system administrator, we ignore the 0200
990                          * bit anyway, since you may have fchowned the file,
991                          * too */
992 #ifdef USE_GROUP_PERMS
993                         if ((targetptr->disk.type == vFile)
994                             && VanillaUser(client)) {
995                             if (!OWNSp(client, targetptr)
996                                 && !client_HasAsMember(client, targetptr->disk.owner)) {
997                                 errorCode =
998                                     ((GROUPWRITE & targetptr->disk.modeBits)
999                                      ? 0 : EACCES);
1000                             } else {
1001                                 errorCode =
1002                                     ((OWNERWRITE & targetptr->disk.modeBits)
1003                                      ? 0 : EACCES);
1004                             }
1005                         } else
1006 #endif
1007                             if ((targetptr->disk.type != vDirectory)
1008                                 && (!(targetptr->disk.modeBits & OWNERWRITE))) {
1009                             if (readonlyServer)
1010                                 return (VREADONLY);
1011                             if (VanillaUser(client))
1012                                 return (EACCES);
1013                             else
1014                                 osi_audit(PrivilegeEvent, 0, AUD_ID,
1015                                           (client ? client->ViceId : 0),
1016                                           AUD_INT, CallingRoutine, AUD_END);
1017                         }
1018                     } else {    /* a status store */
1019                         if (readonlyServer)
1020                             return (VREADONLY);
1021                         if (targetptr->disk.type == vDirectory) {
1022                             if (!(rights & PRSFS_DELETE)
1023                                 && !(rights & PRSFS_INSERT))
1024                                 return (EACCES);
1025                         } else {        /* a file  or symlink */
1026                             if (!(rights & PRSFS_WRITE))
1027                                 return (EACCES);
1028                         }
1029                     }
1030                 }
1031             }
1032         }
1033     }
1034     return (errorCode);
1035
1036 }                               /*Check_PermissionRights */
1037
1038
1039 /*
1040  * The Access List information is converted from its internal form in the
1041  * target's vnode buffer (or its parent vnode buffer if not a dir), to an
1042  * external form and returned back to the caller, via the AccessList
1043  * structure
1044  */
1045 static afs_int32
1046 RXFetch_AccessList(Vnode * targetptr, Vnode * parentwhentargetnotdir,
1047                    struct AFSOpaque *AccessList)
1048 {
1049     char *eACL;                 /* External access list placeholder */
1050
1051     if (acl_Externalize
1052         ((targetptr->disk.type ==
1053           vDirectory ? VVnodeACL(targetptr) :
1054           VVnodeACL(parentwhentargetnotdir)), &eACL) != 0) {
1055         return EIO;
1056     }
1057     if ((strlen(eACL) + 1) > AFSOPAQUEMAX) {
1058         acl_FreeExternalACL(&eACL);
1059         return (E2BIG);
1060     } else {
1061         strcpy((char *)(AccessList->AFSOpaque_val), (char *)eACL);
1062         AccessList->AFSOpaque_len = strlen(eACL) + 1;
1063     }
1064     acl_FreeExternalACL(&eACL);
1065     return (0);
1066
1067 }                               /*RXFetch_AccessList */
1068
1069
1070 /*
1071  * The Access List information is converted from its external form in the
1072  * input AccessList structure to the internal representation and copied into
1073  * the target dir's vnode storage.
1074  */
1075 static afs_int32
1076 RXStore_AccessList(Vnode * targetptr, struct AFSOpaque *AccessList)
1077 {
1078     struct acl_accessList *newACL;      /* PlaceHolder for new access list */
1079
1080     if (acl_Internalize(AccessList->AFSOpaque_val, &newACL) != 0)
1081         return (EINVAL);
1082     if ((newACL->size + 4) > VAclSize(targetptr))
1083         return (E2BIG);
1084     memcpy((char *)VVnodeACL(targetptr), (char *)newACL, (int)(newACL->size));
1085     acl_FreeACL(&newACL);
1086     return (0);
1087
1088 }                               /*RXStore_AccessList */
1089
1090
1091 /* In our current implementation, each successive data store (new file
1092  * data version) creates a new inode. This function creates the new
1093  * inode, copies the old inode's contents to the new one, remove the old
1094  * inode (i.e. decrement inode count -- if it's currently used the delete
1095  * will be delayed), and modify some fields (i.e. vnode's
1096  * disk.inodeNumber and cloned)
1097  */
1098 #define COPYBUFFSIZE    8192
1099 #define MAXFSIZE (~(afs_fsize_t) 0)
1100 static int
1101 CopyOnWrite(Vnode * targetptr, Volume * volptr, afs_fsize_t off, afs_fsize_t len)
1102 {
1103     Inode ino, nearInode;
1104     int rdlen;
1105     int wrlen;
1106     register afs_fsize_t size;
1107     register int length;
1108     char *buff;
1109     int rc;                     /* return code */
1110     IHandle_t *newH;            /* Use until finished copying, then cp to vnode. */
1111     FdHandle_t *targFdP;        /* Source Inode file handle */
1112     FdHandle_t *newFdP;         /* Dest Inode file handle */
1113
1114     if (targetptr->disk.type == vDirectory)
1115         DFlush();               /* just in case? */
1116
1117     VN_GET_LEN(size, targetptr);
1118     if (size > off) 
1119         size -= off;
1120     else 
1121         size = 0;
1122     if (size > len)
1123         size = len;
1124
1125     buff = (char *)malloc(COPYBUFFSIZE);
1126     if (buff == NULL) {
1127         return EIO;
1128     }
1129
1130     ino = VN_GET_INO(targetptr);
1131     if (!VALID_INO(ino)) {
1132         free(buff);
1133         VTakeOffline(volptr);
1134         ViceLog(0, ("Volume %u now offline, must be salvaged.\n",
1135                     volptr->hashid));
1136         return EIO;
1137     }    
1138     targFdP = IH_OPEN(targetptr->handle);
1139     if (targFdP == NULL) {
1140         rc = errno;
1141         ViceLog(0,
1142                 ("CopyOnWrite failed: Failed to open target vnode %u in volume %u (errno = %d)\n",
1143                  targetptr->vnodeNumber, V_id(volptr), rc));
1144         free(buff);
1145         VTakeOffline(volptr);
1146         return rc;
1147     }
1148
1149     nearInode = VN_GET_INO(targetptr);
1150     ino =
1151         IH_CREATE(V_linkHandle(volptr), V_device(volptr),
1152                   VPartitionPath(V_partition(volptr)), nearInode,
1153                   V_id(volptr), targetptr->vnodeNumber,
1154                   targetptr->disk.uniquifier,
1155                   (int)targetptr->disk.dataVersion);
1156     if (!VALID_INO(ino)) {
1157         ViceLog(0,
1158                 ("CopyOnWrite failed: Partition %s that contains volume %u may be out of free inodes(errno = %d)\n",
1159                  volptr->partition->name, V_id(volptr), errno));
1160         FDH_CLOSE(targFdP);
1161         free(buff);
1162         return ENOSPC;
1163     }
1164     IH_INIT(newH, V_device(volptr), V_id(volptr), ino);
1165     newFdP = IH_OPEN(newH);
1166     assert(newFdP != NULL);
1167
1168     FDH_SEEK(targFdP, off, SEEK_SET);
1169     FDH_SEEK(newFdP, off, SEEK_SET);
1170     while (size > 0) {
1171         if (size > COPYBUFFSIZE) {      /* more than a buffer */
1172             length = COPYBUFFSIZE;
1173             size -= COPYBUFFSIZE;
1174         } else {
1175             length = (int)size;
1176             size = 0;
1177         }
1178         rdlen = FDH_READ(targFdP, buff, length);
1179         if (rdlen == length)
1180             wrlen = FDH_WRITE(newFdP, buff, length);
1181         else
1182             wrlen = 0;
1183         /*  Callers of this function are not prepared to recover
1184          *  from error that put the filesystem in an inconsistent
1185          *  state. Make sure that we force the volume off-line if
1186          *  we some error other than ENOSPC - 4.29.99)
1187          *
1188          *  In case we are unable to write the required bytes, and the
1189          *  error code indicates that the disk is full, we roll-back to
1190          *  the initial state.
1191          */
1192         if ((rdlen != length) || (wrlen != length))
1193             if ((wrlen < 0) && (errno == ENOSPC)) {     /* disk full */
1194                 ViceLog(0,
1195                         ("CopyOnWrite failed: Partition %s containing volume %u is full\n",
1196                          volptr->partition->name, V_id(volptr)));
1197                 /* remove destination inode which was partially copied till now */
1198                 FDH_REALLYCLOSE(newFdP);
1199                 IH_RELEASE(newH);
1200                 FDH_REALLYCLOSE(targFdP);
1201                 rc = IH_DEC(V_linkHandle(volptr), ino, V_parentId(volptr));
1202                 if (!rc) {
1203                     ViceLog(0,
1204                             ("CopyOnWrite failed: error %u after i_dec on disk full, volume %u in partition %s needs salvage\n",
1205                              rc, V_id(volptr), volptr->partition->name));
1206                     VTakeOffline(volptr);
1207                 }
1208                 free(buff);
1209                 return ENOSPC;
1210             } else {
1211                 ViceLog(0,
1212                         ("CopyOnWrite failed: volume %u in partition %s  (tried reading %u, read %u, wrote %u, errno %u) volume needs salvage\n",
1213                          V_id(volptr), volptr->partition->name, length, rdlen,
1214                          wrlen, errno));
1215 #if defined(AFS_DEMAND_ATTACH_FS)
1216                 ViceLog(0, ("CopyOnWrite failed: requesting salvage\n"));
1217 #else
1218                 ViceLog(0, ("CopyOnWrite failed: taking volume offline\n"));
1219 #endif
1220                 /* Decrement this inode so salvager doesn't find it. */
1221                 FDH_REALLYCLOSE(newFdP);
1222                 IH_RELEASE(newH);
1223                 FDH_REALLYCLOSE(targFdP);
1224                 rc = IH_DEC(V_linkHandle(volptr), ino, V_parentId(volptr));
1225                 free(buff);
1226                 VTakeOffline(volptr);
1227                 return EIO;
1228             }
1229 #ifndef AFS_PTHREAD_ENV
1230         IOMGR_Poll();
1231 #endif /* !AFS_PTHREAD_ENV */
1232     }
1233     FDH_REALLYCLOSE(targFdP);
1234     rc = IH_DEC(V_linkHandle(volptr), VN_GET_INO(targetptr),
1235                 V_parentId(volptr));
1236     assert(!rc);
1237     IH_RELEASE(targetptr->handle);
1238
1239     rc = FDH_SYNC(newFdP);
1240     assert(rc == 0);
1241     FDH_CLOSE(newFdP);
1242     targetptr->handle = newH;
1243     VN_SET_INO(targetptr, ino);
1244     targetptr->disk.cloned = 0;
1245     /* Internal change to vnode, no user level change to volume - def 5445 */
1246     targetptr->changed_oldTime = 1;
1247     free(buff);
1248     return 0;                   /* success */
1249 }                               /*CopyOnWrite */
1250
1251 static int
1252 CopyOnWrite2(FdHandle_t *targFdP, FdHandle_t *newFdP, afs_fsize_t off, afs_fsize_t size) {
1253     char *buff = (char *)malloc(COPYBUFFSIZE);
1254     register int length;
1255     int rdlen;
1256     int wrlen;
1257     int rc;
1258
1259     FDH_SEEK(targFdP, off, SEEK_SET);
1260     FDH_SEEK(newFdP, off, SEEK_SET);
1261
1262     if (size > FDH_SIZE(targFdP) - off) size = FDH_SIZE(targFdP) - off;
1263     while (size > 0) {
1264         if (size > COPYBUFFSIZE) {      /* more than a buffer */
1265             length = COPYBUFFSIZE;
1266             size -= COPYBUFFSIZE;
1267         } else {
1268             length = (int)size;
1269             size = 0;
1270         }
1271         rdlen = FDH_READ(targFdP, buff, length);
1272         if (rdlen == length)
1273             wrlen = FDH_WRITE(newFdP, buff, length);
1274         else
1275             wrlen = 0;
1276
1277         if ((rdlen != length) || (wrlen != length)) {
1278             /* no error recovery, at the worst we'll have a "hole" in the file */
1279             rc = 1;
1280             break;
1281         }
1282     }
1283     free(buff);
1284     return rc;
1285 }
1286
1287
1288 /*
1289  * Common code to handle with removing the Name (file when it's called from
1290  * SAFS_RemoveFile() or an empty dir when called from SAFS_rmdir()) from a
1291  * given directory, parentptr.
1292  */
1293 int DT1 = 0, DT0 = 0;
1294 static afs_int32
1295 DeleteTarget(Vnode * parentptr, Volume * volptr, Vnode ** targetptr,
1296              DirHandle * dir, AFSFid * fileFid, char *Name, int ChkForDir)
1297 {
1298     DirHandle childdir;         /* Handle for dir package I/O */
1299     int errorCode = 0;
1300     int code;
1301
1302     /* watch for invalid names */
1303     if (!strcmp(Name, ".") || !strcmp(Name, ".."))
1304         return (EINVAL);
1305     if (parentptr->disk.cloned) {
1306         ViceLog(25, ("DeleteTarget : CopyOnWrite called\n"));
1307         if ((errorCode = CopyOnWrite(parentptr, volptr, 0, MAXFSIZE))) {
1308             ViceLog(20,
1309                     ("DeleteTarget %s: CopyOnWrite failed %d\n", Name,
1310                      errorCode));
1311             return errorCode;
1312         }
1313     }
1314
1315     /* check that the file is in the directory */
1316     SetDirHandle(dir, parentptr);
1317     if (Lookup(dir, Name, fileFid))
1318         return (ENOENT);
1319     fileFid->Volume = V_id(volptr);
1320
1321     /* just-in-case check for something causing deadlock */
1322     if (fileFid->Vnode == parentptr->vnodeNumber)
1323         return (EINVAL);
1324
1325     *targetptr = VGetVnode(&errorCode, volptr, fileFid->Vnode, WRITE_LOCK);
1326     if (errorCode) {
1327         return (errorCode);
1328     }
1329     if (ChkForDir == MustBeDIR) {
1330         if ((*targetptr)->disk.type != vDirectory)
1331             return (ENOTDIR);
1332     } else if ((*targetptr)->disk.type == vDirectory)
1333         return (EISDIR);
1334
1335     /*assert((*targetptr)->disk.uniquifier == fileFid->Unique); */
1336     /**
1337       * If the uniquifiers dont match then instead of asserting
1338       * take the volume offline and return VSALVAGE
1339       */
1340     if ((*targetptr)->disk.uniquifier != fileFid->Unique) {
1341         VTakeOffline(volptr);
1342         ViceLog(0,
1343                 ("Volume %u now offline, must be salvaged.\n",
1344                  volptr->hashid));
1345         errorCode = VSALVAGE;
1346         return errorCode;
1347     }
1348
1349     if (ChkForDir == MustBeDIR) {
1350         SetDirHandle(&childdir, *targetptr);
1351         if (IsEmpty(&childdir) != 0)
1352             return (EEXIST);
1353         DZap(&childdir);
1354         FidZap(&childdir);
1355         (*targetptr)->delete = 1;
1356     } else if ((--(*targetptr)->disk.linkCount) == 0)
1357         (*targetptr)->delete = 1;
1358     if ((*targetptr)->delete) {
1359         if (VN_GET_INO(*targetptr)) {
1360             DT0++;
1361             IH_REALLYCLOSE((*targetptr)->handle);
1362             errorCode =
1363                 IH_DEC(V_linkHandle(volptr), VN_GET_INO(*targetptr),
1364                        V_parentId(volptr));
1365             IH_RELEASE((*targetptr)->handle);
1366             if (errorCode == -1) {
1367                 ViceLog(0,
1368                         ("DT: inode=%s, name=%s, errno=%d\n",
1369                          PrintInode(NULL, VN_GET_INO(*targetptr)), Name,
1370                          errno));
1371                 if (errno != ENOENT)
1372                 {
1373                     VTakeOffline(volptr);
1374                     ViceLog(0,
1375                             ("Volume %u now offline, must be salvaged.\n",
1376                              volptr->hashid));
1377                     return (EIO);
1378                 }
1379                 DT1++;
1380                 errorCode = 0;
1381             }
1382         }
1383         VN_SET_INO(*targetptr, (Inode) 0);
1384         {
1385             afs_fsize_t adjLength;
1386             VN_GET_LEN(adjLength, *targetptr);
1387             VAdjustDiskUsage(&errorCode, volptr, -(int)nBlocks(adjLength), 0);
1388         }
1389     }
1390
1391     (*targetptr)->changed_newTime = 1;  /* Status change of deleted file/dir */
1392
1393     code = Delete(dir, (char *)Name);
1394     if (code) {
1395         ViceLog(0,
1396                 ("Error %d deleting %s\n", code,
1397                  (((*targetptr)->disk.type ==
1398                    Directory) ? "directory" : "file")));
1399         VTakeOffline(volptr);
1400         ViceLog(0,
1401                 ("Volume %u now offline, must be salvaged.\n",
1402                  volptr->hashid));
1403         if (!errorCode)
1404             errorCode = code;
1405     }
1406
1407     DFlush();
1408     return (errorCode);
1409
1410 }                               /*DeleteTarget */
1411
1412
1413 /*
1414  * This routine updates the parent directory's status block after the
1415  * specified operation (i.e. RemoveFile(), CreateFile(), Rename(),
1416  * SymLink(), Link(), MakeDir(), RemoveDir()) on one of its children has
1417  * been performed.
1418  */
1419 static void
1420 Update_ParentVnodeStatus(Vnode * parentptr, Volume * volptr, DirHandle * dir,
1421                          int author, int linkcount,
1422 #if FS_STATS_DETAILED
1423                          char a_inSameNetwork
1424 #endif                          /* FS_STATS_DETAILED */
1425     )
1426 {
1427     afs_fsize_t newlength;      /* Holds new directory length */
1428     afs_fsize_t parentLength;
1429     int errorCode;
1430 #if FS_STATS_DETAILED
1431     Date currDate;              /*Current date */
1432     int writeIdx;               /*Write index to bump */
1433     int timeIdx;                /*Authorship time index to bump */
1434 #endif /* FS_STATS_DETAILED */
1435
1436     parentptr->disk.dataVersion++;
1437     newlength = (afs_fsize_t) Length(dir);
1438     /* 
1439      * This is a called on both dir removals (i.e. remove, removedir, rename) but also in dir additions
1440      * (create, symlink, link, makedir) so we need to check if we have enough space
1441      * XXX But we still don't check the error since we're dealing with dirs here and really the increase
1442      * of a new entry would be too tiny to worry about failures (since we have all the existing cushion)
1443      */
1444     VN_GET_LEN(parentLength, parentptr);
1445     if (nBlocks(newlength) != nBlocks(parentLength)) {
1446         VAdjustDiskUsage(&errorCode, volptr,
1447                          (nBlocks(newlength) - nBlocks(parentLength)),
1448                          (nBlocks(newlength) - nBlocks(parentLength)));
1449     }
1450     VN_SET_LEN(parentptr, newlength);
1451
1452 #if FS_STATS_DETAILED
1453     /*
1454      * Update directory write stats for this volume.  Note that the auth
1455      * counter is located immediately after its associated ``distance''
1456      * counter.
1457      */
1458     if (a_inSameNetwork)
1459         writeIdx = VOL_STATS_SAME_NET;
1460     else
1461         writeIdx = VOL_STATS_DIFF_NET;
1462     V_stat_writes(volptr, writeIdx)++;
1463     if (author != AnonymousID) {
1464         V_stat_writes(volptr, writeIdx + 1)++;
1465     }
1466
1467     /*
1468      * Update the volume's authorship information in response to this
1469      * directory operation.  Get the current time, decide to which time
1470      * slot this operation belongs, and bump the appropriate slot.
1471      */
1472     currDate = (FT_ApproxTime() - parentptr->disk.unixModifyTime);
1473     timeIdx =
1474         (currDate < VOL_STATS_TIME_CAP_0 ? VOL_STATS_TIME_IDX_0 : currDate <
1475          VOL_STATS_TIME_CAP_1 ? VOL_STATS_TIME_IDX_1 : currDate <
1476          VOL_STATS_TIME_CAP_2 ? VOL_STATS_TIME_IDX_2 : currDate <
1477          VOL_STATS_TIME_CAP_3 ? VOL_STATS_TIME_IDX_3 : currDate <
1478          VOL_STATS_TIME_CAP_4 ? VOL_STATS_TIME_IDX_4 : VOL_STATS_TIME_IDX_5);
1479     if (parentptr->disk.author == author) {
1480         V_stat_dirSameAuthor(volptr, timeIdx)++;
1481     } else {
1482         V_stat_dirDiffAuthor(volptr, timeIdx)++;
1483     }
1484 #endif /* FS_STATS_DETAILED */
1485
1486     parentptr->disk.author = author;
1487     parentptr->disk.linkCount = linkcount;
1488     parentptr->disk.unixModifyTime = FT_ApproxTime();   /* This should be set from CLIENT!! */
1489     parentptr->disk.serverModifyTime = FT_ApproxTime();
1490     parentptr->changed_newTime = 1;     /* vnode changed, write it back. */
1491 }
1492
1493
1494 /*
1495  * Update the target file's (or dir's) status block after the specified
1496  * operation is complete. Note that some other fields maybe updated by
1497  * the individual module.
1498  */
1499
1500 /* XXX INCOMPLETE - More attention is needed here! */
1501 static void
1502 Update_TargetVnodeStatus(Vnode * targetptr, afs_uint32 Caller,
1503                          struct client *client, AFSStoreStatus * InStatus,
1504                          Vnode * parentptr, Volume * volptr,
1505                          afs_fsize_t length)
1506 {
1507 #if FS_STATS_DETAILED
1508     Date currDate;              /*Current date */
1509     int writeIdx;               /*Write index to bump */
1510     int timeIdx;                /*Authorship time index to bump */
1511 #endif /* FS_STATS_DETAILED */
1512
1513     if (Caller & (TVS_CFILE | TVS_SLINK | TVS_MKDIR)) { /* initialize new file */
1514         targetptr->disk.parent = parentptr->vnodeNumber;
1515         VN_SET_LEN(targetptr, length);
1516         /* targetptr->disk.group =      0;  save some cycles */
1517         targetptr->disk.modeBits = 0777;
1518         targetptr->disk.owner = client->ViceId;
1519         targetptr->disk.dataVersion = 0;        /* consistent with the client */
1520         targetptr->disk.linkCount = (Caller & TVS_MKDIR ? 2 : 1);
1521         /* the inode was created in Alloc_NewVnode() */
1522     }
1523 #if FS_STATS_DETAILED
1524     /*
1525      * Update file write stats for this volume.  Note that the auth
1526      * counter is located immediately after its associated ``distance''
1527      * counter.
1528      */
1529     if (client->InSameNetwork)
1530         writeIdx = VOL_STATS_SAME_NET;
1531     else
1532         writeIdx = VOL_STATS_DIFF_NET;
1533     V_stat_writes(volptr, writeIdx)++;
1534     if (client->ViceId != AnonymousID) {
1535         V_stat_writes(volptr, writeIdx + 1)++;
1536     }
1537
1538     /*
1539      * We only count operations that DON'T involve creating new objects
1540      * (files, symlinks, directories) or simply setting status as
1541      * authorship-change operations.
1542      */
1543     if (!(Caller & (TVS_CFILE | TVS_SLINK | TVS_MKDIR | TVS_SSTATUS))) {
1544         /*
1545          * Update the volume's authorship information in response to this
1546          * file operation.  Get the current time, decide to which time
1547          * slot this operation belongs, and bump the appropriate slot.
1548          */
1549         currDate = (FT_ApproxTime() - targetptr->disk.unixModifyTime);
1550         timeIdx =
1551             (currDate <
1552              VOL_STATS_TIME_CAP_0 ? VOL_STATS_TIME_IDX_0 : currDate <
1553              VOL_STATS_TIME_CAP_1 ? VOL_STATS_TIME_IDX_1 : currDate <
1554              VOL_STATS_TIME_CAP_2 ? VOL_STATS_TIME_IDX_2 : currDate <
1555              VOL_STATS_TIME_CAP_3 ? VOL_STATS_TIME_IDX_3 : currDate <
1556              VOL_STATS_TIME_CAP_4 ? VOL_STATS_TIME_IDX_4 :
1557              VOL_STATS_TIME_IDX_5);
1558         if (targetptr->disk.author == client->ViceId) {
1559             V_stat_fileSameAuthor(volptr, timeIdx)++;
1560         } else {
1561             V_stat_fileDiffAuthor(volptr, timeIdx)++;
1562         }
1563     }
1564 #endif /* FS_STATS_DETAILED */
1565
1566     if (!(Caller & TVS_SSTATUS))
1567         targetptr->disk.author = client->ViceId;
1568     if (Caller & TVS_SDATA) {
1569         targetptr->disk.dataVersion++;
1570         if (VanillaUser(client)) {
1571             targetptr->disk.modeBits &= ~04000; /* turn off suid for file. */
1572 #ifdef CREATE_SGUID_ADMIN_ONLY
1573             targetptr->disk.modeBits &= ~02000; /* turn off sgid for file. */
1574 #endif
1575         }
1576     }
1577     if (Caller & TVS_SSTATUS) { /* update time on non-status change */
1578         /* store status, must explicitly request to change the date */
1579         if (InStatus->Mask & AFS_SETMODTIME)
1580             targetptr->disk.unixModifyTime = InStatus->ClientModTime;
1581     } else {                    /* other: date always changes, but perhaps to what is specified by caller */
1582         targetptr->disk.unixModifyTime =
1583             (InStatus->Mask & AFS_SETMODTIME ? InStatus->
1584              ClientModTime : FT_ApproxTime());
1585     }
1586     if (InStatus->Mask & AFS_SETOWNER) {
1587         /* admin is allowed to do chmod, chown as well as chown, chmod. */
1588         if (VanillaUser(client)) {
1589             targetptr->disk.modeBits &= ~04000; /* turn off suid for file. */
1590 #ifdef CREATE_SGUID_ADMIN_ONLY
1591             targetptr->disk.modeBits &= ~02000; /* turn off sgid for file. */
1592 #endif
1593         }
1594         targetptr->disk.owner = InStatus->Owner;
1595         if (VolumeRootVnode(targetptr)) {
1596             Error errorCode = 0;        /* what should be done with this? */
1597
1598             V_owner(targetptr->volumePtr) = InStatus->Owner;
1599             VUpdateVolume(&errorCode, targetptr->volumePtr);
1600         }
1601     }
1602     if (InStatus->Mask & AFS_SETMODE) {
1603         int modebits = InStatus->UnixModeBits;
1604 #define CREATE_SGUID_ADMIN_ONLY 1
1605 #ifdef CREATE_SGUID_ADMIN_ONLY
1606         if (VanillaUser(client))
1607             modebits = modebits & 0777;
1608 #endif
1609         if (VanillaUser(client)) {
1610             targetptr->disk.modeBits = modebits;
1611         } else {
1612             targetptr->disk.modeBits = modebits;
1613             switch (Caller) {
1614             case TVS_SDATA:
1615                 osi_audit(PrivSetID, 0, AUD_ID, client->ViceId, AUD_INT,
1616                           CHK_STOREDATA, AUD_END);
1617                 break;
1618             case TVS_CFILE:
1619             case TVS_SSTATUS:
1620                 osi_audit(PrivSetID, 0, AUD_ID, client->ViceId, AUD_INT,
1621                           CHK_STORESTATUS, AUD_END);
1622                 break;
1623             default:
1624                 break;
1625             }
1626         }
1627     }
1628     targetptr->disk.serverModifyTime = FT_ApproxTime();
1629     if (InStatus->Mask & AFS_SETGROUP)
1630         targetptr->disk.group = InStatus->Group;
1631     /* vnode changed : to be written back by VPutVnode */
1632     targetptr->changed_newTime = 1;
1633
1634 }                               /*Update_TargetVnodeStatus */
1635
1636
1637 /*
1638  * Fills the CallBack structure with the expiration time and type of callback
1639  * structure. Warning: this function is currently incomplete.
1640  */
1641 static void
1642 SetCallBackStruct(afs_uint32 CallBackTime, struct AFSCallBack *CallBack)
1643 {
1644     /* CallBackTime could not be 0 */
1645     if (CallBackTime == 0) {
1646         ViceLog(0, ("WARNING: CallBackTime == 0!\n"));
1647         CallBack->ExpirationTime = 0;
1648     } else
1649         CallBack->ExpirationTime = CallBackTime - FT_ApproxTime();
1650     CallBack->CallBackVersion = CALLBACK_VERSION;
1651     CallBack->CallBackType = CB_SHARED; /* The default for now */
1652
1653 }                               /*SetCallBackStruct */
1654
1655
1656 /*
1657  * Adjusts (Subtract) "length" number of blocks from the volume's disk
1658  * allocation; if some error occured (exceeded volume quota or partition
1659  * was full, or whatever), it frees the space back and returns the code.
1660  * We usually pre-adjust the volume space to make sure that there's
1661  * enough space before consuming some.
1662  */
1663 static afs_int32
1664 AdjustDiskUsage(Volume * volptr, afs_sfsize_t length,
1665                 afs_sfsize_t checkLength)
1666 {
1667     int rc;
1668     int nc;
1669
1670     VAdjustDiskUsage(&rc, volptr, length, checkLength);
1671     if (rc) {
1672         VAdjustDiskUsage(&nc, volptr, -length, 0);
1673         if (rc == VOVERQUOTA) {
1674             ViceLog(2,
1675                     ("Volume %u (%s) is full\n", V_id(volptr),
1676                      V_name(volptr)));
1677             return (rc);
1678         }
1679         if (rc == VDISKFULL) {
1680             ViceLog(0,
1681                     ("Partition %s that contains volume %u is full\n",
1682                      volptr->partition->name, V_id(volptr)));
1683             return (rc);
1684         }
1685         ViceLog(0, ("Got error return %d from VAdjustDiskUsage\n", rc));
1686         return (rc);
1687     }
1688     return (0);
1689
1690 }                               /*AdjustDiskUsage */
1691
1692 /*
1693  * Common code that handles the creation of a new file (SAFS_CreateFile and
1694  * SAFS_Symlink) or a new dir (SAFS_MakeDir)
1695  */
1696 static afs_int32
1697 Alloc_NewVnode(Vnode * parentptr, DirHandle * dir, Volume * volptr,
1698                Vnode ** targetptr, char *Name, struct AFSFid *OutFid,
1699                int FileType, afs_sfsize_t BlocksPreallocatedForVnode)
1700 {
1701     int errorCode = 0;          /* Error code returned back */
1702     int temp;
1703     Inode inode = 0;
1704     Inode nearInode;            /* hint for inode allocation in solaris */
1705
1706     if ((errorCode =
1707          AdjustDiskUsage(volptr, BlocksPreallocatedForVnode,
1708                          BlocksPreallocatedForVnode))) {
1709         ViceLog(25,
1710                 ("Insufficient space to allocate %" AFS_INT64_FMT " blocks\n",
1711                  (afs_intmax_t) BlocksPreallocatedForVnode));
1712         return (errorCode);
1713     }
1714
1715     *targetptr = VAllocVnode(&errorCode, volptr, FileType);
1716     if (errorCode != 0) {
1717         VAdjustDiskUsage(&temp, volptr, -BlocksPreallocatedForVnode, 0);
1718         return (errorCode);
1719     }
1720     OutFid->Volume = V_id(volptr);
1721     OutFid->Vnode = (*targetptr)->vnodeNumber;
1722     OutFid->Unique = (*targetptr)->disk.uniquifier;
1723
1724     nearInode = VN_GET_INO(parentptr);  /* parent is also in same vol */
1725
1726     /* create the inode now itself */
1727     inode =
1728         IH_CREATE(V_linkHandle(volptr), V_device(volptr),
1729                   VPartitionPath(V_partition(volptr)), nearInode,
1730                   V_id(volptr), (*targetptr)->vnodeNumber,
1731                   (*targetptr)->disk.uniquifier, 1);
1732
1733     /* error in creating inode */
1734     if (!VALID_INO(inode)) {
1735         ViceLog(0,
1736                 ("Volume : %u vnode = %u Failed to create inode: errno = %d\n",
1737                  (*targetptr)->volumePtr->header->diskstuff.id,
1738                  (*targetptr)->vnodeNumber, errno));
1739         VAdjustDiskUsage(&temp, volptr, -BlocksPreallocatedForVnode, 0);
1740         (*targetptr)->delete = 1;       /* delete vnode */
1741         return ENOSPC;
1742     }
1743     VN_SET_INO(*targetptr, inode);
1744     IH_INIT(((*targetptr)->handle), V_device(volptr), V_id(volptr), inode);
1745
1746     /* copy group from parent dir */
1747     (*targetptr)->disk.group = parentptr->disk.group;
1748
1749     if (parentptr->disk.cloned) {
1750         ViceLog(25, ("Alloc_NewVnode : CopyOnWrite called\n"));
1751         if ((errorCode = CopyOnWrite(parentptr, volptr, 0, MAXFSIZE))) {        /* disk full */
1752             ViceLog(25, ("Alloc_NewVnode : CopyOnWrite failed\n"));
1753             /* delete the vnode previously allocated */
1754             (*targetptr)->delete = 1;
1755             VAdjustDiskUsage(&temp, volptr, -BlocksPreallocatedForVnode, 0);
1756             IH_REALLYCLOSE((*targetptr)->handle);
1757             if (IH_DEC(V_linkHandle(volptr), inode, V_parentId(volptr)))
1758                 ViceLog(0,
1759                         ("Alloc_NewVnode: partition %s idec %s failed\n",
1760                          volptr->partition->name, PrintInode(NULL, inode)));
1761             IH_RELEASE((*targetptr)->handle);
1762
1763             return errorCode;
1764         }
1765     }
1766
1767     /* add the name to the directory */
1768     SetDirHandle(dir, parentptr);
1769     if ((errorCode = Create(dir, (char *)Name, OutFid))) {
1770         (*targetptr)->delete = 1;
1771         VAdjustDiskUsage(&temp, volptr, -BlocksPreallocatedForVnode, 0);
1772         IH_REALLYCLOSE((*targetptr)->handle);
1773         if (IH_DEC(V_linkHandle(volptr), inode, V_parentId(volptr)))
1774             ViceLog(0,
1775                     ("Alloc_NewVnode: partition %s idec %s failed\n",
1776                      volptr->partition->name, PrintInode(NULL, inode)));
1777         IH_RELEASE((*targetptr)->handle);
1778         return (errorCode);
1779     }
1780     DFlush();
1781     return (0);
1782
1783 }                               /*Alloc_NewVnode */
1784
1785
1786 /*
1787  * Handle all the lock-related code (SAFS_SetLock, SAFS_ExtendLock and
1788  * SAFS_ReleaseLock)
1789  */
1790 static afs_int32
1791 HandleLocking(Vnode * targetptr, struct client *client, afs_int32 rights, ViceLockType LockingType)
1792 {
1793     int Time;                   /* Used for time */
1794     int writeVnode = targetptr->changed_oldTime;        /* save original status */
1795
1796     targetptr->changed_oldTime = 1;     /* locking doesn't affect any time stamp */
1797     Time = FT_ApproxTime();
1798     switch (LockingType) {
1799     case LockRead:
1800     case LockWrite:
1801         if (Time > targetptr->disk.lock.lockTime)
1802             targetptr->disk.lock.lockTime = targetptr->disk.lock.lockCount =
1803                 0;
1804         Time += AFS_LOCKWAIT;
1805         if (LockingType == LockRead) {
1806             if ( !(rights & PRSFS_LOCK) && 
1807                  !(rights & PRSFS_WRITE) &&
1808                  !(OWNSp(client, targetptr) && (rights & PRSFS_INSERT)) )
1809                     return(EACCES);
1810
1811             if (targetptr->disk.lock.lockCount >= 0) {
1812                 ++(targetptr->disk.lock.lockCount);
1813                 targetptr->disk.lock.lockTime = Time;
1814             } else
1815                 return (EAGAIN);
1816         } else if (LockingType == LockWrite) {
1817             if ( !(rights & PRSFS_WRITE) && 
1818                  !(OWNSp(client, targetptr) && (rights & PRSFS_INSERT)) )
1819                 return(EACCES);
1820
1821             if (targetptr->disk.lock.lockCount == 0) {
1822                 targetptr->disk.lock.lockCount = -1;
1823                 targetptr->disk.lock.lockTime = Time;
1824             } else
1825                 return (EAGAIN);
1826         }
1827         break;
1828     case LockExtend:
1829         Time += AFS_LOCKWAIT;
1830         if (targetptr->disk.lock.lockCount != 0)
1831             targetptr->disk.lock.lockTime = Time;
1832         else
1833             return (EINVAL);
1834         break;
1835     case LockRelease:
1836         if ((--targetptr->disk.lock.lockCount) <= 0)
1837             targetptr->disk.lock.lockCount = targetptr->disk.lock.lockTime =
1838                 0;
1839         break;
1840     default:
1841         targetptr->changed_oldTime = writeVnode;        /* restore old status */
1842         ViceLog(0, ("Illegal Locking type %d\n", LockingType));
1843     }
1844     return (0);
1845 }                               /*HandleLocking */
1846
1847 /* 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. */
1848
1849 static afs_int32
1850 CheckWriteMode(Vnode * targetptr, afs_int32 rights, int Prfs_Mode)
1851 {
1852     if (readonlyServer)
1853         return (VREADONLY);
1854     if (!(rights & Prfs_Mode))
1855         return (EACCES);
1856     if ((targetptr->disk.type != vDirectory)
1857         && (!(targetptr->disk.modeBits & OWNERWRITE)))
1858         return (EACCES);
1859     return (0);
1860 }
1861
1862 /*
1863  * If some flags (i.e. min or max quota) are set, the volume's in disk
1864  * label is updated; Name, OfflineMsg, and Motd are also reflected in the
1865  * update, if applicable.
1866  */
1867 static afs_int32
1868 RXUpdate_VolumeStatus(Volume * volptr, AFSStoreVolumeStatus * StoreVolStatus,
1869                       char *Name, char *OfflineMsg, char *Motd)
1870 {
1871     Error errorCode = 0;
1872
1873     if (StoreVolStatus->Mask & AFS_SETMINQUOTA)
1874         V_minquota(volptr) = StoreVolStatus->MinQuota;
1875     if (StoreVolStatus->Mask & AFS_SETMAXQUOTA)
1876         V_maxquota(volptr) = StoreVolStatus->MaxQuota;
1877     if (strlen(OfflineMsg) > 0) {
1878         strcpy(V_offlineMessage(volptr), OfflineMsg);
1879     }
1880     if (strlen(Name) > 0) {
1881         strcpy(V_name(volptr), Name);
1882     }
1883 #if OPENAFS_VOL_STATS
1884     /*
1885      * We don't overwrite the motd field, since it's now being used
1886      * for stats
1887      */
1888 #else
1889     if (strlen(Motd) > 0) {
1890         strcpy(V_motd(volptr), Motd);
1891     }
1892 #endif /* FS_STATS_DETAILED */
1893     VUpdateVolume(&errorCode, volptr);
1894     return (errorCode);
1895
1896 }                               /*RXUpdate_VolumeStatus */
1897
1898
1899 static afs_int32
1900 RXGetVolumeStatus(AFSFetchVolumeStatus * status, char **name, char **offMsg,
1901                   char **motd, Volume * volptr)
1902 {
1903     int temp;
1904
1905     status->Vid = V_id(volptr);
1906     status->ParentId = V_parentId(volptr);
1907     status->Online = V_inUse(volptr);
1908     status->InService = V_inService(volptr);
1909     status->Blessed = V_blessed(volptr);
1910     status->NeedsSalvage = V_needsSalvaged(volptr);
1911     if (VolumeWriteable(volptr))
1912         status->Type = ReadWrite;
1913     else
1914         status->Type = ReadOnly;
1915     status->MinQuota = V_minquota(volptr);
1916     status->MaxQuota = V_maxquota(volptr);
1917     status->BlocksInUse = V_diskused(volptr);
1918     status->PartBlocksAvail = RoundInt64ToInt32(volptr->partition->free);
1919     status->PartMaxBlocks = RoundInt64ToInt32(volptr->partition->totalUsable);
1920
1921     /* now allocate and copy these things; they're freed by the RXGEN stub */
1922     temp = strlen(V_name(volptr)) + 1;
1923     *name = malloc(temp);
1924     if (!*name) {
1925         ViceLog(0, ("Failed malloc in RXGetVolumeStatus\n"));
1926         assert(0);
1927     }
1928     strcpy(*name, V_name(volptr));
1929     temp = strlen(V_offlineMessage(volptr)) + 1;
1930     *offMsg = malloc(temp);
1931     if (!*offMsg) {
1932         ViceLog(0, ("Failed malloc in RXGetVolumeStatus\n"));
1933         assert(0);
1934     }
1935     strcpy(*offMsg, V_offlineMessage(volptr));
1936 #if OPENAFS_VOL_STATS
1937     *motd = malloc(1);
1938     if (!*motd) {
1939         ViceLog(0, ("Failed malloc in RXGetVolumeStatus\n"));
1940         assert(0);
1941     }
1942     strcpy(*motd, nullString);
1943 #else
1944     temp = strlen(V_motd(volptr)) + 1;
1945     *motd = malloc(temp);
1946     if (!*motd) {
1947         ViceLog(0, ("Failed malloc in RXGetVolumeStatus\n"));
1948         assert(0);
1949     }
1950     strcpy(*motd, V_motd(volptr));
1951 #endif /* FS_STATS_DETAILED */
1952     return 0;
1953 }                               /*RXGetVolumeStatus */
1954
1955
1956 static afs_int32
1957 FileNameOK(register char *aname)
1958 {
1959     register afs_int32 i, tc;
1960     i = strlen(aname);
1961     if (i >= 4) {
1962         /* watch for @sys on the right */
1963         if (strcmp(aname + i - 4, "@sys") == 0)
1964             return 0;
1965     }
1966     while ((tc = *aname++)) {
1967         if (tc == '/')
1968             return 0;           /* very bad character to encounter */
1969     }
1970     return 1;                   /* file name is ok */
1971
1972 }                               /*FileNameOK */
1973
1974
1975 /*
1976  * This variant of symlink is expressly to support the AFS/DFS translator
1977  * and is not supported by the AFS fileserver. We just return EINVAL.
1978  * The cache manager should not generate this call to an AFS cache manager.
1979  */
1980 afs_int32
1981 SRXAFS_DFSSymlink(struct rx_call *acall, struct AFSFid *DirFid, char *Name,
1982                   char *LinkContents, struct AFSStoreStatus *InStatus,
1983                   struct AFSFid *OutFid, struct AFSFetchStatus *OutFidStatus,
1984                   struct AFSFetchStatus *OutDirStatus,
1985                   struct AFSCallBack *CallBack, struct AFSVolSync *Sync)
1986 {
1987     return EINVAL;
1988 }
1989
1990 afs_int32
1991 SRXAFS_FsCmd(struct rx_call * acall, struct AFSFid * Fid,
1992                     struct FsCmdInputs * Inputs,
1993                     struct FsCmdOutputs * Outputs)
1994 {
1995     afs_int32 code = 0;
1996     struct AFSCallBack callback;
1997     struct AFSVolSync sync;
1998
1999     switch (Inputs->command) {
2000     default:
2001         code = EINVAL;
2002     }
2003     ViceLog(1,("FsCmd: cmd = %d, code=%d\n", 
2004                         Inputs->command, Outputs->code));
2005     return code;
2006 }
2007
2008 #ifdef AFS_NT40_ENV
2009 static struct afs_buffer {
2010     struct afs_buffer *next;
2011 } *freeBufferList = 0;
2012 static int afs_buffersAlloced = 0;
2013
2014 static
2015 FreeSendBuffer(register struct afs_buffer *adata)
2016 {
2017     FS_LOCK;
2018     afs_buffersAlloced--;
2019     adata->next = freeBufferList;
2020     freeBufferList = adata;
2021     FS_UNLOCK;
2022     return 0;
2023
2024 }                               /*FreeSendBuffer */
2025
2026 /* allocate space for sender */
2027 static char *
2028 AllocSendBuffer()
2029 {
2030     register struct afs_buffer *tp;
2031
2032     FS_LOCK;
2033     afs_buffersAlloced++;
2034     if (!freeBufferList) {
2035         char *tmp;
2036         FS_UNLOCK;
2037         tmp = malloc(sendBufSize);
2038         if (!tmp) {
2039             ViceLog(0, ("Failed malloc in AllocSendBuffer\n"));
2040             assert(0);
2041         }
2042         return tmp;
2043     }
2044     tp = freeBufferList;
2045     freeBufferList = tp->next;
2046     FS_UNLOCK;
2047     return (char *)tp;
2048
2049 }                               /*AllocSendBuffer */
2050 #endif /* AFS_NT40_ENV */
2051
2052 /*
2053  * This routine returns the status info associated with the targetptr vnode
2054  * in the AFSFetchStatus structure.  Some of the newer fields, such as
2055  * SegSize and Group are not yet implemented
2056  */
2057 static
2058     void
2059 GetStatus(Vnode * targetptr, AFSFetchStatus * status, afs_int32 rights,
2060           afs_int32 anyrights, Vnode * parentptr)
2061 {
2062     /* initialize return status from a vnode  */
2063     status->InterfaceVersion = 1;
2064     status->SyncCounter = status->dataVersionHigh = status->lockCount =
2065         status->errorCode = 0;
2066     status->ResidencyMask = 1;  /* means for MR-AFS: file in /vicepr-partition */
2067     if (targetptr->disk.type == vFile)
2068         status->FileType = File;
2069     else if (targetptr->disk.type == vDirectory)
2070         status->FileType = Directory;
2071     else if (targetptr->disk.type == vSymlink)
2072         status->FileType = SymbolicLink;
2073     else
2074         status->FileType = Invalid;     /*invalid type field */
2075     status->LinkCount = targetptr->disk.linkCount;
2076     {
2077         afs_fsize_t targetLen;
2078         VN_GET_LEN(targetLen, targetptr);
2079         SplitOffsetOrSize(targetLen, status->Length_hi, status->Length);
2080     }
2081     status->DataVersion = targetptr->disk.dataVersion;
2082     status->Author = targetptr->disk.author;
2083     status->Owner = targetptr->disk.owner;
2084     status->CallerAccess = rights;
2085     status->AnonymousAccess = anyrights;
2086     status->UnixModeBits = targetptr->disk.modeBits;
2087     status->ClientModTime = targetptr->disk.unixModifyTime;     /* This might need rework */
2088     status->ParentVnode =
2089         (status->FileType ==
2090          Directory ? targetptr->vnodeNumber : parentptr->vnodeNumber);
2091     status->ParentUnique =
2092         (status->FileType ==
2093          Directory ? targetptr->disk.uniquifier : parentptr->disk.uniquifier);
2094     status->ServerModTime = targetptr->disk.serverModifyTime;
2095     status->Group = targetptr->disk.group;
2096     status->lockCount = targetptr->disk.lock.lockCount;
2097     status->errorCode = 0;
2098
2099 }                               /*GetStatus */
2100
2101 static
2102   afs_int32
2103 common_FetchData64(struct rx_call *acall, struct AFSFid *Fid,
2104                    afs_sfsize_t Pos, afs_sfsize_t Len,
2105                    struct AFSFetchStatus *OutStatus,
2106                    struct AFSCallBack *CallBack, struct AFSVolSync *Sync,
2107                    int type)
2108 {
2109     Vnode *targetptr = 0;       /* pointer to vnode to fetch */
2110     Vnode *parentwhentargetnotdir = 0;  /* parent vnode if vptr is a file */
2111     Vnode tparentwhentargetnotdir;      /* parent vnode for GetStatus */
2112     int errorCode = 0;          /* return code to caller */
2113     int fileCode = 0;           /* return code from vol package */
2114     Volume *volptr = 0;         /* pointer to the volume */
2115     struct client *client = 0;  /* pointer to the client data */
2116     struct rx_connection *tcon; /* the connection we're part of */
2117     struct host *thost;
2118     afs_int32 rights, anyrights;        /* rights for this and any user */
2119     struct client *t_client = NULL;     /* tmp ptr to client data */
2120     struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
2121 #if FS_STATS_DETAILED
2122     struct fs_stats_opTimingData *opP;  /* Ptr to this op's timing struct */
2123     struct fs_stats_xferData *xferP;    /* Ptr to this op's byte size struct */
2124     struct timeval opStartTime, opStopTime;     /* Start/stop times for RPC op */
2125     struct timeval xferStartTime, xferStopTime; /* Start/stop times for xfer portion */
2126     struct timeval elapsedTime; /* Transfer time */
2127     afs_sfsize_t bytesToXfer;   /* # bytes to xfer */
2128     afs_sfsize_t bytesXferred;  /* # bytes actually xferred */
2129     int readIdx;                /* Index of read stats array to bump */
2130     static afs_int32 tot_bytesXferred;  /* shared access protected by FS_LOCK */
2131
2132     /*
2133      * Set our stats pointers, remember when the RPC operation started, and
2134      * tally the operation.
2135      */
2136     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_FETCHDATA]);
2137     xferP = &(afs_FullPerfStats.det.xferOpTimes[FS_STATS_XFERIDX_FETCHDATA]);
2138     FS_LOCK;
2139     (opP->numOps)++;
2140     FS_UNLOCK;
2141     FT_GetTimeOfDay(&opStartTime, 0);
2142 #endif /* FS_STATS_DETAILED */
2143
2144     ViceLog(1,
2145             ("SRXAFS_FetchData, Fid = %u.%u.%u\n", Fid->Volume, Fid->Vnode,
2146              Fid->Unique));
2147     FS_LOCK;
2148     AFSCallStats.FetchData++, AFSCallStats.TotalCalls++;
2149     FS_UNLOCK;
2150     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
2151         goto Bad_FetchData;
2152
2153     /* Get ptr to client data for user Id for logging */
2154     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
2155     logHostAddr.s_addr = rxr_HostOf(tcon);
2156     ViceLog(5,
2157             ("SRXAFS_FetchData, Fid = %u.%u.%u, Host %s:%d, Id %d\n",
2158              Fid->Volume, Fid->Vnode, Fid->Unique, inet_ntoa(logHostAddr),
2159              ntohs(rxr_PortOf(tcon)), t_client->ViceId));
2160     /*
2161      * Get volume/vnode for the fetched file; caller's access rights to
2162      * it are also returned
2163      */
2164     if ((errorCode =
2165          GetVolumePackage(tcon, Fid, &volptr, &targetptr, DONTCHECK,
2166                           &parentwhentargetnotdir, &client, READ_LOCK,
2167                           &rights, &anyrights)))
2168         goto Bad_FetchData;
2169
2170     SetVolumeSync(Sync, volptr);
2171
2172 #if FS_STATS_DETAILED
2173     /*
2174      * Remember that another read operation was performed.
2175      */
2176     FS_LOCK;
2177     if (client->InSameNetwork)
2178         readIdx = VOL_STATS_SAME_NET;
2179     else
2180         readIdx = VOL_STATS_DIFF_NET;
2181     V_stat_reads(volptr, readIdx)++;
2182     if (client->ViceId != AnonymousID) {
2183         V_stat_reads(volptr, readIdx + 1)++;
2184     }
2185     FS_UNLOCK;
2186 #endif /* FS_STATS_DETAILED */
2187     /* Check whether the caller has permission access to fetch the data */
2188     if ((errorCode =
2189          Check_PermissionRights(targetptr, client, rights, CHK_FETCHDATA, 0)))
2190         goto Bad_FetchData;
2191
2192     /*
2193      * Drop the read lock on the parent directory after saving the parent
2194      * vnode information we need to pass to GetStatus
2195      */
2196     if (parentwhentargetnotdir != NULL) {
2197         tparentwhentargetnotdir = *parentwhentargetnotdir;
2198         VPutVnode(&fileCode, parentwhentargetnotdir);
2199         assert(!fileCode || (fileCode == VSALVAGE));
2200         parentwhentargetnotdir = NULL;
2201     }
2202 #if FS_STATS_DETAILED
2203     /*
2204      * Remember when the data transfer started.
2205      */
2206     FT_GetTimeOfDay(&xferStartTime, 0);
2207 #endif /* FS_STATS_DETAILED */
2208
2209     /* actually do the data transfer */
2210 #if FS_STATS_DETAILED
2211     errorCode =
2212         FetchData_RXStyle(volptr, targetptr, acall, Pos, Len, type,
2213                           &bytesToXfer, &bytesXferred);
2214 #else
2215     if ((errorCode =
2216          FetchData_RXStyle(volptr, targetptr, acall, Pos, Len, type)))
2217         goto Bad_FetchData;
2218 #endif /* FS_STATS_DETAILED */
2219
2220 #if FS_STATS_DETAILED
2221     /*
2222      * At this point, the data transfer is done, for good or ill.  Remember
2223      * when the transfer ended, bump the number of successes/failures, and
2224      * integrate the transfer size and elapsed time into the stats.  If the
2225      * operation failed, we jump to the appropriate point.
2226      */
2227     FT_GetTimeOfDay(&xferStopTime, 0);
2228     FS_LOCK;
2229     (xferP->numXfers)++;
2230     if (!errorCode) {
2231         (xferP->numSuccesses)++;
2232
2233         /*
2234          * Bump the xfer sum by the number of bytes actually sent, NOT the
2235          * target number.
2236          */
2237         tot_bytesXferred += bytesXferred;
2238         (xferP->sumBytes) += (tot_bytesXferred >> 10);
2239         tot_bytesXferred &= 0x3FF;
2240         if (bytesXferred < xferP->minBytes)
2241             xferP->minBytes = bytesXferred;
2242         if (bytesXferred > xferP->maxBytes)
2243             xferP->maxBytes = bytesXferred;
2244
2245         /*
2246          * Tally the size of the object.  Note: we tally the actual size,
2247          * NOT the number of bytes that made it out over the wire.
2248          */
2249         if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET0)
2250             (xferP->count[0])++;
2251         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET1)
2252             (xferP->count[1])++;
2253         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET2)
2254             (xferP->count[2])++;
2255         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET3)
2256             (xferP->count[3])++;
2257         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET4)
2258             (xferP->count[4])++;
2259         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET5)
2260             (xferP->count[5])++;
2261         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET6)
2262             (xferP->count[6])++;
2263         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET7)
2264             (xferP->count[7])++;
2265         else
2266             (xferP->count[8])++;
2267
2268         fs_stats_GetDiff(elapsedTime, xferStartTime, xferStopTime);
2269         fs_stats_AddTo((xferP->sumTime), elapsedTime);
2270         fs_stats_SquareAddTo((xferP->sqrTime), elapsedTime);
2271         if (fs_stats_TimeLessThan(elapsedTime, (xferP->minTime))) {
2272             fs_stats_TimeAssign((xferP->minTime), elapsedTime);
2273         }
2274         if (fs_stats_TimeGreaterThan(elapsedTime, (xferP->maxTime))) {
2275             fs_stats_TimeAssign((xferP->maxTime), elapsedTime);
2276         }
2277     }
2278     FS_UNLOCK;
2279     /*
2280      * Finally, go off to tell our caller the bad news in case the
2281      * fetch failed.
2282      */
2283     if (errorCode)
2284         goto Bad_FetchData;
2285 #endif /* FS_STATS_DETAILED */
2286
2287     /* write back  the OutStatus from the target vnode  */
2288     GetStatus(targetptr, OutStatus, rights, anyrights,
2289               &tparentwhentargetnotdir);
2290
2291     /* if a r/w volume, promise a callback to the caller */
2292     if (VolumeWriteable(volptr))
2293         SetCallBackStruct(AddCallBack(client->host, Fid), CallBack);
2294     else {
2295         struct AFSFid myFid;
2296         memset(&myFid, 0, sizeof(struct AFSFid));
2297         myFid.Volume = Fid->Volume;
2298         SetCallBackStruct(AddVolCallBack(client->host, &myFid), CallBack);
2299     }
2300
2301   Bad_FetchData:
2302     /* Update and store volume/vnode and parent vnodes back */
2303     (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
2304                            volptr, &client);
2305     ViceLog(2, ("SRXAFS_FetchData returns %d\n", errorCode));
2306     errorCode = CallPostamble(tcon, errorCode, thost);
2307
2308 #if FS_STATS_DETAILED
2309     FT_GetTimeOfDay(&opStopTime, 0);
2310     if (errorCode == 0) {
2311         FS_LOCK;
2312         (opP->numSuccesses)++;
2313         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2314         fs_stats_AddTo((opP->sumTime), elapsedTime);
2315         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2316         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2317             fs_stats_TimeAssign((opP->minTime), elapsedTime);
2318         }
2319         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2320             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2321         }
2322         FS_UNLOCK;
2323     }
2324 #endif /* FS_STATS_DETAILED */
2325
2326     osi_auditU(acall, FetchDataEvent, errorCode, 
2327                AUD_ID, t_client ? t_client->ViceId : 0,
2328                AUD_FID, Fid, AUD_END);
2329     return (errorCode);
2330
2331 }                               /*SRXAFS_FetchData */
2332
2333 afs_int32
2334 SRXAFS_FetchData(struct rx_call * acall, struct AFSFid * Fid, afs_int32 Pos,
2335                  afs_int32 Len, struct AFSFetchStatus * OutStatus,
2336                  struct AFSCallBack * CallBack, struct AFSVolSync * Sync)
2337 {
2338     return common_FetchData64(acall, Fid, Pos, Len, OutStatus, CallBack, 
2339                               Sync, 0);
2340 }
2341
2342 afs_int32
2343 SRXAFS_FetchData64(struct rx_call * acall, struct AFSFid * Fid, afs_int64 Pos,
2344                    afs_int64 Len, struct AFSFetchStatus * OutStatus,
2345                    struct AFSCallBack * CallBack, struct AFSVolSync * Sync)
2346 {
2347     int code;
2348     afs_sfsize_t tPos, tLen;
2349
2350 #ifdef AFS_64BIT_ENV
2351 #ifndef AFS_LARGEFILE_ENV
2352     if (Pos + Len > 0x7fffffff)
2353         return EFBIG;
2354 #endif /* !AFS_LARGEFILE_ENV */
2355     tPos = (afs_sfsize_t) Pos;
2356     tLen = (afs_sfsize_t) Len;
2357 #else /* AFS_64BIT_ENV */
2358     if (Pos.high || Len.high)
2359         return EFBIG;
2360     tPos = Pos.low;
2361     tLen = Len.low;
2362 #endif /* AFS_64BIT_ENV */
2363
2364     code =
2365         common_FetchData64(acall, Fid, tPos, tLen, OutStatus, CallBack, Sync,
2366                            1);
2367     return code;
2368 }
2369
2370 afs_int32
2371 SRXAFS_FetchACL(struct rx_call * acall, struct AFSFid * Fid,
2372                 struct AFSOpaque * AccessList,
2373                 struct AFSFetchStatus * OutStatus, struct AFSVolSync * Sync)
2374 {
2375     Vnode *targetptr = 0;       /* pointer to vnode to fetch */
2376     Vnode *parentwhentargetnotdir = 0;  /* parent vnode if targetptr is a file */
2377     int errorCode = 0;          /* return error code to caller */
2378     Volume *volptr = 0;         /* pointer to the volume */
2379     struct client *client = 0;  /* pointer to the client data */
2380     afs_int32 rights, anyrights;        /* rights for this and any user */
2381     struct rx_connection *tcon = rx_ConnectionOf(acall);
2382     struct host *thost;
2383     struct client *t_client = NULL;     /* tmp ptr to client data */
2384     struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
2385 #if FS_STATS_DETAILED
2386     struct fs_stats_opTimingData *opP;  /* Ptr to this op's timing struct */
2387     struct timeval opStartTime, opStopTime;     /* Start/stop times for RPC op */
2388     struct timeval elapsedTime; /* Transfer time */
2389
2390     /*
2391      * Set our stats pointer, remember when the RPC operation started, and
2392      * tally the operation.
2393      */
2394     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_FETCHACL]);
2395     FS_LOCK;
2396     (opP->numOps)++;
2397     FS_UNLOCK;
2398     FT_GetTimeOfDay(&opStartTime, 0);
2399 #endif /* FS_STATS_DETAILED */
2400
2401     ViceLog(1,
2402             ("SAFS_FetchACL, Fid = %u.%u.%u\n", Fid->Volume, Fid->Vnode,
2403              Fid->Unique));
2404     FS_LOCK;
2405     AFSCallStats.FetchACL++, AFSCallStats.TotalCalls++;
2406     FS_UNLOCK;
2407     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
2408         goto Bad_FetchACL;
2409
2410     /* Get ptr to client data for user Id for logging */
2411     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
2412     logHostAddr.s_addr = rxr_HostOf(tcon);
2413     ViceLog(5,
2414             ("SAFS_FetchACL, Fid = %u.%u.%u, Host %s:%d, Id %d\n", Fid->Volume,
2415              Fid->Vnode, Fid->Unique, inet_ntoa(logHostAddr),
2416              ntohs(rxr_PortOf(tcon)), t_client->ViceId));
2417
2418     AccessList->AFSOpaque_len = 0;
2419     AccessList->AFSOpaque_val = malloc(AFSOPAQUEMAX);
2420     if (!AccessList->AFSOpaque_val) {
2421         ViceLog(0, ("Failed malloc in SRXAFS_FetchACL\n"));
2422         assert(0);
2423     }
2424
2425     /*
2426      * Get volume/vnode for the fetched file; caller's access rights to it
2427      * are also returned
2428      */
2429     if ((errorCode =
2430          GetVolumePackage(tcon, Fid, &volptr, &targetptr, DONTCHECK,
2431                           &parentwhentargetnotdir, &client, READ_LOCK,
2432                           &rights, &anyrights)))
2433         goto Bad_FetchACL;
2434
2435     SetVolumeSync(Sync, volptr);
2436
2437     /* Check whether we have permission to fetch the ACL */
2438     if ((errorCode =
2439          Check_PermissionRights(targetptr, client, rights, CHK_FETCHACL, 0)))
2440         goto Bad_FetchACL;
2441
2442     /* Get the Access List from the dir's vnode */
2443     if ((errorCode =
2444          RXFetch_AccessList(targetptr, parentwhentargetnotdir, AccessList)))
2445         goto Bad_FetchACL;
2446
2447     /* Get OutStatus back From the target Vnode  */
2448     GetStatus(targetptr, OutStatus, rights, anyrights,
2449               parentwhentargetnotdir);
2450
2451   Bad_FetchACL:
2452     /* Update and store volume/vnode and parent vnodes back */
2453     (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
2454                            volptr, &client);
2455     ViceLog(2,
2456             ("SAFS_FetchACL returns %d (ACL=%s)\n", errorCode,
2457              AccessList->AFSOpaque_val));
2458     errorCode = CallPostamble(tcon, errorCode, thost);
2459
2460 #if FS_STATS_DETAILED
2461     FT_GetTimeOfDay(&opStopTime, 0);
2462     if (errorCode == 0) {
2463         FS_LOCK;
2464         (opP->numSuccesses)++;
2465         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2466         fs_stats_AddTo((opP->sumTime), elapsedTime);
2467         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2468         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2469             fs_stats_TimeAssign((opP->minTime), elapsedTime);
2470         }
2471         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2472             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2473         }
2474         FS_UNLOCK;
2475     }
2476 #endif /* FS_STATS_DETAILED */
2477
2478     osi_auditU(acall, FetchACLEvent, errorCode, 
2479                AUD_ID, t_client ? t_client->ViceId : 0,
2480                AUD_FID, Fid, 
2481                AUD_ACL, AccessList->AFSOpaque_val, AUD_END);
2482     return errorCode;
2483 }                               /*SRXAFS_FetchACL */
2484
2485
2486 /*
2487  * This routine is called exclusively by SRXAFS_FetchStatus(), and should be
2488  * merged into it when possible.
2489  */
2490 static
2491   afs_int32
2492 SAFSS_FetchStatus(struct rx_call *acall, struct AFSFid *Fid,
2493                   struct AFSFetchStatus *OutStatus,
2494                   struct AFSCallBack *CallBack, struct AFSVolSync *Sync)
2495 {
2496     Vnode *targetptr = 0;       /* pointer to vnode to fetch */
2497     Vnode *parentwhentargetnotdir = 0;  /* parent vnode if targetptr is a file */
2498     int errorCode = 0;          /* return code to caller */
2499     Volume *volptr = 0;         /* pointer to the volume */
2500     struct client *client = 0;  /* pointer to the client data */
2501     afs_int32 rights, anyrights;        /* rights for this and any user */
2502     struct client *t_client = NULL;     /* tmp ptr to client data */
2503     struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
2504     struct rx_connection *tcon = rx_ConnectionOf(acall);
2505
2506     /* Get ptr to client data for user Id for logging */
2507     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
2508     logHostAddr.s_addr = rxr_HostOf(tcon);
2509     ViceLog(1,
2510             ("SAFS_FetchStatus,  Fid = %u.%u.%u, Host %s:%d, Id %d\n",
2511              Fid->Volume, Fid->Vnode, Fid->Unique, inet_ntoa(logHostAddr),
2512              ntohs(rxr_PortOf(tcon)), t_client->ViceId));
2513     FS_LOCK;
2514     AFSCallStats.FetchStatus++, AFSCallStats.TotalCalls++;
2515     FS_UNLOCK;
2516     /*
2517      * Get volume/vnode for the fetched file; caller's rights to it are
2518      * also returned
2519      */
2520     if ((errorCode =
2521          GetVolumePackage(tcon, Fid, &volptr, &targetptr, DONTCHECK,
2522                           &parentwhentargetnotdir, &client, READ_LOCK,
2523                           &rights, &anyrights)))
2524         goto Bad_FetchStatus;
2525
2526     /* set volume synchronization information */
2527     SetVolumeSync(Sync, volptr);
2528
2529     /* Are we allowed to fetch Fid's status? */
2530     if (targetptr->disk.type != vDirectory) {
2531         if ((errorCode =
2532              Check_PermissionRights(targetptr, client, rights,
2533                                     CHK_FETCHSTATUS, 0))) {
2534             if (rx_GetCallAbortCode(acall) == errorCode)
2535                 rx_SetCallAbortCode(acall, 0);
2536             goto Bad_FetchStatus;
2537         }
2538     }
2539
2540     /* set OutStatus From the Fid  */
2541     GetStatus(targetptr, OutStatus, rights, anyrights,
2542               parentwhentargetnotdir);
2543
2544     /* If a r/w volume, also set the CallBack state */
2545     if (VolumeWriteable(volptr))
2546         SetCallBackStruct(AddCallBack(client->host, Fid), CallBack);
2547     else {
2548         struct AFSFid myFid;
2549         memset(&myFid, 0, sizeof(struct AFSFid));
2550         myFid.Volume = Fid->Volume;
2551         SetCallBackStruct(AddVolCallBack(client->host, &myFid), CallBack);
2552     }
2553
2554   Bad_FetchStatus:
2555     /* Update and store volume/vnode and parent vnodes back */
2556     (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
2557                            volptr, &client);
2558     ViceLog(2, ("SAFS_FetchStatus returns %d\n", errorCode));
2559     return errorCode;
2560
2561 }                               /*SAFSS_FetchStatus */
2562
2563
2564 afs_int32
2565 SRXAFS_BulkStatus(struct rx_call * acall, struct AFSCBFids * Fids,
2566                   struct AFSBulkStats * OutStats, struct AFSCBs * CallBacks,
2567                   struct AFSVolSync * Sync)
2568 {
2569     register int i;
2570     afs_int32 nfiles;
2571     Vnode *targetptr = 0;       /* pointer to vnode to fetch */
2572     Vnode *parentwhentargetnotdir = 0;  /* parent vnode if targetptr is a file */
2573     int errorCode = 0;          /* return code to caller */
2574     Volume *volptr = 0;         /* pointer to the volume */
2575     struct client *client = 0;  /* pointer to the client data */
2576     afs_int32 rights, anyrights;        /* rights for this and any user */
2577     register struct AFSFid *tfid;       /* file id we're dealing with now */
2578     struct rx_connection *tcon = rx_ConnectionOf(acall);
2579     struct host *thost;
2580     struct client *t_client = NULL;     /* tmp pointer to the client data */
2581 #if FS_STATS_DETAILED
2582     struct fs_stats_opTimingData *opP;  /* Ptr to this op's timing struct */
2583     struct timeval opStartTime, opStopTime;     /* Start/stop times for RPC op */
2584     struct timeval elapsedTime; /* Transfer time */
2585
2586     /*
2587      * Set our stats pointer, remember when the RPC operation started, and
2588      * tally the operation.
2589      */
2590     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_BULKSTATUS]);
2591     FS_LOCK;
2592     (opP->numOps)++;
2593     FS_UNLOCK;
2594     FT_GetTimeOfDay(&opStartTime, 0);
2595 #endif /* FS_STATS_DETAILED */
2596
2597     ViceLog(1, ("SAFS_BulkStatus\n"));
2598     FS_LOCK;
2599     AFSCallStats.TotalCalls++;
2600     FS_UNLOCK;
2601     nfiles = Fids->AFSCBFids_len;       /* # of files in here */
2602     if (nfiles <= 0) {          /* Sanity check */
2603         errorCode = EINVAL;
2604         goto Audit_and_Return;
2605     }
2606
2607     /* allocate space for return output parameters */
2608     OutStats->AFSBulkStats_val = (struct AFSFetchStatus *)
2609         malloc(nfiles * sizeof(struct AFSFetchStatus));
2610     if (!OutStats->AFSBulkStats_val) {
2611         ViceLog(0, ("Failed malloc in SRXAFS_BulkStatus\n"));
2612         assert(0);
2613     }
2614     OutStats->AFSBulkStats_len = nfiles;
2615     CallBacks->AFSCBs_val = (struct AFSCallBack *)
2616         malloc(nfiles * sizeof(struct AFSCallBack));
2617     if (!CallBacks->AFSCBs_val) {
2618         ViceLog(0, ("Failed malloc in SRXAFS_BulkStatus\n"));
2619         assert(0);
2620     }
2621     CallBacks->AFSCBs_len = nfiles;
2622
2623     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
2624         goto Bad_BulkStatus;
2625
2626     tfid = Fids->AFSCBFids_val;
2627     for (i = 0; i < nfiles; i++, tfid++) {
2628         /*
2629          * Get volume/vnode for the fetched file; caller's rights to it
2630          * are also returned
2631          */
2632         if ((errorCode =
2633              GetVolumePackage(tcon, tfid, &volptr, &targetptr, DONTCHECK,
2634                               &parentwhentargetnotdir, &client, READ_LOCK,
2635                               &rights, &anyrights)))
2636             goto Bad_BulkStatus;
2637         /* set volume synchronization information, but only once per call */
2638         if (i == nfiles)
2639             SetVolumeSync(Sync, volptr);
2640
2641         /* Are we allowed to fetch Fid's status? */
2642         if (targetptr->disk.type != vDirectory) {
2643             if ((errorCode =
2644                  Check_PermissionRights(targetptr, client, rights,
2645                                         CHK_FETCHSTATUS, 0))) {
2646                 if (rx_GetCallAbortCode(acall) == errorCode)
2647                     rx_SetCallAbortCode(acall, 0);
2648                 goto Bad_BulkStatus;
2649             }
2650         }
2651
2652         /* set OutStatus From the Fid  */
2653         GetStatus(targetptr, &OutStats->AFSBulkStats_val[i], rights,
2654                   anyrights, parentwhentargetnotdir);
2655
2656         /* If a r/w volume, also set the CallBack state */
2657         if (VolumeWriteable(volptr))
2658             SetCallBackStruct(AddBulkCallBack(client->host, tfid),
2659                               &CallBacks->AFSCBs_val[i]);
2660         else {
2661             struct AFSFid myFid;
2662             memset(&myFid, 0, sizeof(struct AFSFid));
2663             myFid.Volume = tfid->Volume;
2664             SetCallBackStruct(AddVolCallBack(client->host, &myFid),
2665                               &CallBacks->AFSCBs_val[i]);
2666         }
2667
2668         /* put back the file ID and volume */
2669         (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
2670                                volptr, &client);
2671         parentwhentargetnotdir = (Vnode *) 0;
2672         targetptr = (Vnode *) 0;
2673         volptr = (Volume *) 0;
2674         client = (struct client *)0;
2675     }
2676
2677   Bad_BulkStatus:
2678     /* Update and store volume/vnode and parent vnodes back */
2679     (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
2680                            volptr, &client);
2681     errorCode = CallPostamble(tcon, errorCode, thost);
2682
2683     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
2684
2685 #if FS_STATS_DETAILED
2686     FT_GetTimeOfDay(&opStopTime, 0);
2687     if (errorCode == 0) {
2688         FS_LOCK;
2689         (opP->numSuccesses)++;
2690         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2691         fs_stats_AddTo((opP->sumTime), elapsedTime);
2692         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2693         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2694             fs_stats_TimeAssign((opP->minTime), elapsedTime);
2695         }
2696         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2697             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2698         }
2699         FS_UNLOCK;
2700     }
2701 #endif /* FS_STATS_DETAILED */
2702
2703   Audit_and_Return:
2704     ViceLog(2, ("SAFS_BulkStatus        returns %d\n", errorCode));
2705     osi_auditU(acall, BulkFetchStatusEvent, errorCode, 
2706                AUD_ID, t_client ? t_client->ViceId : 0,
2707                AUD_FIDS, Fids, AUD_END);
2708     return errorCode;
2709
2710 }                               /*SRXAFS_BulkStatus */
2711
2712
2713 afs_int32
2714 SRXAFS_InlineBulkStatus(struct rx_call * acall, struct AFSCBFids * Fids,
2715                         struct AFSBulkStats * OutStats,
2716                         struct AFSCBs * CallBacks, struct AFSVolSync * Sync)
2717 {
2718     register int i;
2719     afs_int32 nfiles;
2720     Vnode *targetptr = 0;       /* pointer to vnode to fetch */
2721     Vnode *parentwhentargetnotdir = 0;  /* parent vnode if targetptr is a file */
2722     int errorCode = 0;          /* return code to caller */
2723     Volume *volptr = 0;         /* pointer to the volume */
2724     struct client *client = 0;  /* pointer to the client data */
2725     afs_int32 rights, anyrights;        /* rights for this and any user */
2726     register struct AFSFid *tfid;       /* file id we're dealing with now */
2727     struct rx_connection *tcon;
2728     struct host *thost;
2729     struct client *t_client = NULL;     /* tmp ptr to client data */
2730     AFSFetchStatus *tstatus;
2731 #if FS_STATS_DETAILED
2732     struct fs_stats_opTimingData *opP;  /* Ptr to this op's timing struct */
2733     struct timeval opStartTime, opStopTime;     /* Start/stop times for RPC op */
2734     struct timeval elapsedTime; /* Transfer time */
2735
2736     /*
2737      * Set our stats pointer, remember when the RPC operation started, and
2738      * tally the operation.
2739      */
2740     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_BULKSTATUS]);
2741     FS_LOCK;
2742     (opP->numOps)++;
2743     FS_UNLOCK;
2744     FT_GetTimeOfDay(&opStartTime, 0);
2745 #endif /* FS_STATS_DETAILED */
2746
2747     ViceLog(1, ("SAFS_InlineBulkStatus\n"));
2748     FS_LOCK;
2749     AFSCallStats.TotalCalls++;
2750     FS_UNLOCK;
2751     nfiles = Fids->AFSCBFids_len;       /* # of files in here */
2752     if (nfiles <= 0) {          /* Sanity check */
2753         errorCode = EINVAL;
2754         goto Audit_and_Return;
2755     }
2756
2757     /* allocate space for return output parameters */
2758     OutStats->AFSBulkStats_val = (struct AFSFetchStatus *)
2759         malloc(nfiles * sizeof(struct AFSFetchStatus));
2760     if (!OutStats->AFSBulkStats_val) {
2761         ViceLog(0, ("Failed malloc in SRXAFS_FetchStatus\n"));
2762         assert(0);
2763     }
2764     OutStats->AFSBulkStats_len = nfiles;
2765     CallBacks->AFSCBs_val = (struct AFSCallBack *)
2766         malloc(nfiles * sizeof(struct AFSCallBack));
2767     if (!CallBacks->AFSCBs_val) {
2768         ViceLog(0, ("Failed malloc in SRXAFS_FetchStatus\n"));
2769         assert(0);
2770     }
2771     CallBacks->AFSCBs_len = nfiles;
2772
2773     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon, &thost))) {
2774         goto Bad_InlineBulkStatus;
2775     }
2776
2777     tfid = Fids->AFSCBFids_val;
2778     for (i = 0; i < nfiles; i++, tfid++) {
2779         /*
2780          * Get volume/vnode for the fetched file; caller's rights to it
2781          * are also returned
2782          */
2783         if ((errorCode =
2784              GetVolumePackage(tcon, tfid, &volptr, &targetptr, DONTCHECK,
2785                               &parentwhentargetnotdir, &client, READ_LOCK,
2786                               &rights, &anyrights))) {
2787             tstatus = &OutStats->AFSBulkStats_val[i];
2788             tstatus->errorCode = errorCode;
2789             PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, 
2790                              volptr, &client);
2791             parentwhentargetnotdir = (Vnode *) 0;
2792             targetptr = (Vnode *) 0;
2793             volptr = (Volume *) 0;
2794             client = (struct client *)0;
2795             continue;
2796         }
2797
2798         /* set volume synchronization information, but only once per call */
2799         if (i == nfiles)
2800             SetVolumeSync(Sync, volptr);
2801
2802         /* Are we allowed to fetch Fid's status? */
2803         if (targetptr->disk.type != vDirectory) {
2804             if ((errorCode =
2805                  Check_PermissionRights(targetptr, client, rights,
2806                                         CHK_FETCHSTATUS, 0))) {
2807                 tstatus = &OutStats->AFSBulkStats_val[i];
2808                 tstatus->errorCode = errorCode;
2809                 (void)PutVolumePackage(parentwhentargetnotdir, targetptr,
2810                                        (Vnode *) 0, volptr, &client);
2811                 parentwhentargetnotdir = (Vnode *) 0;
2812                 targetptr = (Vnode *) 0;
2813                 volptr = (Volume *) 0;
2814                 client = (struct client *)0;
2815                 continue;
2816             }
2817         }
2818
2819         /* set OutStatus From the Fid  */
2820         GetStatus(targetptr,
2821                   (struct AFSFetchStatus *)&OutStats->AFSBulkStats_val[i],
2822                   rights, anyrights, parentwhentargetnotdir);
2823
2824         /* If a r/w volume, also set the CallBack state */
2825         if (VolumeWriteable(volptr))
2826             SetCallBackStruct(AddBulkCallBack(client->host, tfid),
2827                               &CallBacks->AFSCBs_val[i]);
2828         else {
2829             struct AFSFid myFid;
2830             memset(&myFid, 0, sizeof(struct AFSFid));
2831             myFid.Volume = tfid->Volume;
2832             SetCallBackStruct(AddVolCallBack(client->host, &myFid),
2833                               &CallBacks->AFSCBs_val[i]);
2834         }
2835
2836         /* put back the file ID and volume */
2837         (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
2838                                volptr, &client);
2839         parentwhentargetnotdir = (Vnode *) 0;
2840         targetptr = (Vnode *) 0;
2841         volptr = (Volume *) 0;
2842         client = (struct client *)0;
2843     }
2844
2845   Bad_InlineBulkStatus:
2846     /* Update and store volume/vnode and parent vnodes back */
2847     (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
2848                            volptr, &client);
2849     errorCode = CallPostamble(tcon, errorCode, thost);
2850
2851     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
2852
2853 #if FS_STATS_DETAILED
2854     FT_GetTimeOfDay(&opStopTime, 0);
2855     if (errorCode == 0) {
2856         FS_LOCK;
2857         (opP->numSuccesses)++;
2858         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2859         fs_stats_AddTo((opP->sumTime), elapsedTime);
2860         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2861         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2862             fs_stats_TimeAssign((opP->minTime), elapsedTime);
2863         }
2864         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2865             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2866         }
2867         FS_UNLOCK;
2868     }
2869 #endif /* FS_STATS_DETAILED */
2870
2871   Audit_and_Return:
2872     ViceLog(2, ("SAFS_InlineBulkStatus  returns %d\n", errorCode));
2873     osi_auditU(acall, InlineBulkFetchStatusEvent, errorCode, 
2874                AUD_ID, t_client ? t_client->ViceId : 0,
2875                AUD_FIDS, Fids, AUD_END);
2876     return 0;
2877
2878 }                               /*SRXAFS_InlineBulkStatus */
2879
2880
2881 afs_int32
2882 SRXAFS_FetchStatus(struct rx_call * acall, struct AFSFid * Fid,
2883                    struct AFSFetchStatus * OutStatus,
2884                    struct AFSCallBack * CallBack, struct AFSVolSync * Sync)
2885 {
2886     afs_int32 code;
2887     struct rx_connection *tcon;
2888     struct host *thost;
2889     struct client *t_client = NULL;     /* tmp ptr to client data */
2890 #if FS_STATS_DETAILED
2891     struct fs_stats_opTimingData *opP;  /* Ptr to this op's timing struct */
2892     struct timeval opStartTime, opStopTime;     /* Start/stop times for RPC op */
2893     struct timeval elapsedTime; /* Transfer time */
2894
2895     /*
2896      * Set our stats pointer, remember when the RPC operation started, and
2897      * tally the operation.
2898      */
2899     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_FETCHSTATUS]);
2900     FS_LOCK;
2901     (opP->numOps)++;
2902     FS_UNLOCK;
2903     FT_GetTimeOfDay(&opStartTime, 0);
2904 #endif /* FS_STATS_DETAILED */
2905
2906     if ((code = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
2907         goto Bad_FetchStatus;
2908
2909     code = SAFSS_FetchStatus(acall, Fid, OutStatus, CallBack, Sync);
2910
2911   Bad_FetchStatus:
2912     code = CallPostamble(tcon, code, thost);
2913
2914     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
2915
2916 #if FS_STATS_DETAILED
2917     FT_GetTimeOfDay(&opStopTime, 0);
2918     if (code == 0) {
2919         FS_LOCK;
2920         (opP->numSuccesses)++;
2921         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2922         fs_stats_AddTo((opP->sumTime), elapsedTime);
2923         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2924         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2925             fs_stats_TimeAssign((opP->minTime), elapsedTime);
2926         }
2927         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2928             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2929         }
2930         FS_UNLOCK;
2931     }
2932 #endif /* FS_STATS_DETAILED */
2933
2934     osi_auditU(acall, FetchStatusEvent, code, 
2935                AUD_ID, t_client ? t_client->ViceId : 0,
2936                AUD_FID, Fid, AUD_END);
2937     return code;
2938
2939 }                               /*SRXAFS_FetchStatus */
2940
2941 static
2942   afs_int32
2943 common_StoreData64(struct rx_call *acall, struct AFSFid *Fid,
2944                    struct AFSStoreStatus *InStatus, afs_fsize_t Pos,
2945                    afs_fsize_t Length, afs_fsize_t FileLength,
2946                    struct AFSFetchStatus *OutStatus, struct AFSVolSync *Sync)
2947 {
2948     Vnode *targetptr = 0;       /* pointer to input fid */
2949     Vnode *parentwhentargetnotdir = 0;  /* parent of Fid to get ACL */
2950     Vnode tparentwhentargetnotdir;      /* parent vnode for GetStatus */
2951     int errorCode = 0;          /* return code for caller */
2952     int fileCode = 0;           /* return code from vol package */
2953     Volume *volptr = 0;         /* pointer to the volume header */
2954     struct client *client = 0;  /* pointer to client structure */
2955     afs_int32 rights, anyrights;        /* rights for this and any user */
2956     struct client *t_client = NULL;     /* tmp ptr to client data */
2957     struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
2958     struct rx_connection *tcon;
2959     struct host *thost;
2960 #if FS_STATS_DETAILED
2961     struct fs_stats_opTimingData *opP;  /* Ptr to this op's timing struct */
2962     struct fs_stats_xferData *xferP;    /* Ptr to this op's byte size struct */
2963     struct timeval opStartTime, opStopTime;     /* Start/stop times for RPC op */
2964     struct timeval xferStartTime, xferStopTime; /* Start/stop times for xfer portion */
2965     struct timeval elapsedTime; /* Transfer time */
2966     afs_sfsize_t bytesToXfer;   /* # bytes to xfer */
2967     afs_sfsize_t bytesXferred;  /* # bytes actually xfer */
2968     static afs_int32 tot_bytesXferred;  /* shared access protected by FS_LOCK */
2969
2970     /*
2971      * Set our stats pointers, remember when the RPC operation started, and
2972      * tally the operation.
2973      */
2974     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_STOREDATA]);
2975     xferP = &(afs_FullPerfStats.det.xferOpTimes[FS_STATS_XFERIDX_STOREDATA]);
2976     FS_LOCK;
2977     (opP->numOps)++;
2978     FS_UNLOCK;
2979     ViceLog(1,
2980             ("StoreData: Fid = %u.%u.%u\n", Fid->Volume, Fid->Vnode,
2981              Fid->Unique));
2982     FT_GetTimeOfDay(&opStartTime, 0);
2983 #endif /* FS_STATS_DETAILED */
2984
2985     FS_LOCK;
2986     AFSCallStats.StoreData++, AFSCallStats.TotalCalls++;
2987     FS_UNLOCK;
2988     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
2989         goto Bad_StoreData;
2990
2991     /* Get ptr to client data for user Id for logging */
2992     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
2993     logHostAddr.s_addr = rxr_HostOf(tcon);
2994     ViceLog(5,
2995             ("StoreData: Fid = %u.%u.%u, Host %s:%d, Id %d\n", Fid->Volume,
2996              Fid->Vnode, Fid->Unique, inet_ntoa(logHostAddr),
2997              ntohs(rxr_PortOf(tcon)), t_client->ViceId));
2998
2999     /*
3000      * Get associated volume/vnode for the stored file; caller's rights
3001      * are also returned
3002      */
3003     if ((errorCode =
3004          GetVolumePackage(tcon, Fid, &volptr, &targetptr, MustNOTBeDIR,
3005                           &parentwhentargetnotdir, &client, WRITE_LOCK,
3006                           &rights, &anyrights))) {
3007         goto Bad_StoreData;
3008     }
3009
3010     /* set volume synchronization information */
3011     SetVolumeSync(Sync, volptr);
3012
3013     if ((targetptr->disk.type == vSymlink)) {
3014         /* Should we return a better error code here??? */
3015         errorCode = EISDIR;
3016         goto Bad_StoreData;
3017     }
3018
3019     /* Check if we're allowed to store the data */
3020     if ((errorCode =
3021          Check_PermissionRights(targetptr, client, rights, CHK_STOREDATA,
3022                                 InStatus))) {
3023         goto Bad_StoreData;
3024     }
3025
3026     /*
3027      * Drop the read lock on the parent directory after saving the parent
3028      * vnode information we need to pass to GetStatus
3029      */
3030     if (parentwhentargetnotdir != NULL) {
3031         tparentwhentargetnotdir = *parentwhentargetnotdir;
3032         VPutVnode(&fileCode, parentwhentargetnotdir);
3033         assert(!fileCode || (fileCode == VSALVAGE));
3034         parentwhentargetnotdir = NULL;
3035     }
3036 #if FS_STATS_DETAILED
3037     /*
3038      * Remember when the data transfer started.
3039      */
3040     FT_GetTimeOfDay(&xferStartTime, 0);
3041 #endif /* FS_STATS_DETAILED */
3042
3043     /* Do the actual storing of the data */
3044 #if FS_STATS_DETAILED
3045     errorCode =
3046         StoreData_RXStyle(volptr, targetptr, Fid, client, acall, Pos, Length,
3047                           FileLength, (InStatus->Mask & AFS_FSYNC),
3048                           &bytesToXfer, &bytesXferred);
3049 #else
3050     errorCode =
3051         StoreData_RXStyle(volptr, targetptr, Fid, client, acall, Pos, Length,
3052                           FileLength, (InStatus->Mask & AFS_FSYNC));
3053     if (errorCode && (!targetptr->changed_newTime))
3054         goto Bad_StoreData;
3055 #endif /* FS_STATS_DETAILED */
3056 #if FS_STATS_DETAILED
3057     /*
3058      * At this point, the data transfer is done, for good or ill.  Remember
3059      * when the transfer ended, bump the number of successes/failures, and
3060      * integrate the transfer size and elapsed time into the stats.  If the
3061      * operation failed, we jump to the appropriate point.
3062      */
3063     FT_GetTimeOfDay(&xferStopTime, 0);
3064     FS_LOCK;
3065     (xferP->numXfers)++;
3066     if (!errorCode) {
3067         (xferP->numSuccesses)++;
3068
3069         /*
3070          * Bump the xfer sum by the number of bytes actually sent, NOT the
3071          * target number.
3072          */
3073         tot_bytesXferred += bytesXferred;
3074         (xferP->sumBytes) += (tot_bytesXferred >> 10);
3075         tot_bytesXferred &= 0x3FF;
3076         if (bytesXferred < xferP->minBytes)
3077             xferP->minBytes = bytesXferred;
3078         if (bytesXferred > xferP->maxBytes)
3079             xferP->maxBytes = bytesXferred;
3080
3081         /*
3082          * Tally the size of the object.  Note: we tally the actual size,
3083          * NOT the number of bytes that made it out over the wire.
3084          */
3085         if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET0)
3086             (xferP->count[0])++;
3087         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET1)
3088             (xferP->count[1])++;
3089         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET2)
3090             (xferP->count[2])++;
3091         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET3)
3092             (xferP->count[3])++;
3093         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET4)
3094             (xferP->count[4])++;
3095         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET5)
3096             (xferP->count[5])++;
3097         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET6)
3098             (xferP->count[6])++;
3099         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET7)
3100             (xferP->count[7])++;
3101         else
3102             (xferP->count[8])++;
3103
3104         fs_stats_GetDiff(elapsedTime, xferStartTime, xferStopTime);
3105         fs_stats_AddTo((xferP->sumTime), elapsedTime);
3106         fs_stats_SquareAddTo((xferP->sqrTime), elapsedTime);
3107         if (fs_stats_TimeLessThan(elapsedTime, (xferP->minTime))) {
3108             fs_stats_TimeAssign((xferP->minTime), elapsedTime);
3109         }
3110         if (fs_stats_TimeGreaterThan(elapsedTime, (xferP->maxTime))) {
3111             fs_stats_TimeAssign((xferP->maxTime), elapsedTime);
3112         }
3113     }
3114     FS_UNLOCK;
3115     /*
3116      * Finally, go off to tell our caller the bad news in case the
3117      * store failed.
3118      */
3119     if (errorCode && (!targetptr->changed_newTime))
3120         goto Bad_StoreData;
3121 #endif /* FS_STATS_DETAILED */
3122
3123     /* Update the status of the target's vnode */
3124     Update_TargetVnodeStatus(targetptr, TVS_SDATA, client, InStatus,
3125                              targetptr, volptr, 0);
3126
3127     /* Get the updated File's status back to the caller */
3128     GetStatus(targetptr, OutStatus, rights, anyrights,
3129               &tparentwhentargetnotdir);
3130
3131   Bad_StoreData:
3132     /* Update and store volume/vnode and parent vnodes back */
3133     (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
3134                            volptr, &client);
3135     ViceLog(2, ("SAFS_StoreData returns %d\n", errorCode));
3136
3137     errorCode = CallPostamble(tcon, errorCode, thost);
3138
3139 #if FS_STATS_DETAILED
3140     FT_GetTimeOfDay(&opStopTime, 0);
3141     if (errorCode == 0) {
3142         FS_LOCK;
3143         (opP->numSuccesses)++;
3144         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3145         fs_stats_AddTo((opP->sumTime), elapsedTime);
3146         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3147         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3148             fs_stats_TimeAssign((opP->minTime), elapsedTime);
3149         }
3150         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3151             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3152         }
3153         FS_UNLOCK;
3154     }
3155 #endif /* FS_STATS_DETAILED */
3156     osi_auditU(acall, StoreDataEvent, errorCode, 
3157                AUD_ID, t_client ? t_client->ViceId : 0,
3158                AUD_FID, Fid, AUD_END);
3159     return (errorCode);
3160 }                               /*common_StoreData64 */
3161
3162 afs_int32
3163 SRXAFS_StoreData(struct rx_call * acall, struct AFSFid * Fid,
3164                  struct AFSStoreStatus * InStatus, afs_uint32 Pos,
3165                  afs_uint32 Length, afs_uint32 FileLength,
3166                  struct AFSFetchStatus * OutStatus, struct AFSVolSync * Sync)
3167 {
3168     if (FileLength > 0x7fffffff || Pos > 0x7fffffff || 
3169         (0x7fffffff - Pos) < Length)
3170         return EFBIG;
3171
3172     return common_StoreData64(acall, Fid, InStatus, Pos, Length, FileLength,
3173                               OutStatus, Sync);
3174 }                               /*SRXAFS_StoreData */
3175
3176 afs_int32
3177 SRXAFS_StoreData64(struct rx_call * acall, struct AFSFid * Fid,
3178                    struct AFSStoreStatus * InStatus, afs_uint64 Pos,
3179                    afs_uint64 Length, afs_uint64 FileLength,
3180                    struct AFSFetchStatus * OutStatus,
3181                    struct AFSVolSync * Sync)
3182 {
3183     int code;
3184     afs_fsize_t tPos;
3185     afs_fsize_t tLength;
3186     afs_fsize_t tFileLength;
3187
3188 #ifdef AFS_64BIT_ENV
3189 #ifndef AFS_LARGEFILE_ENV
3190     if (FileLength > 0x7fffffff)
3191         return EFBIG;
3192 #endif /* !AFS_LARGEFILE_ENV */
3193     tPos = (afs_fsize_t) Pos;
3194     tLength = (afs_fsize_t) Length;
3195     tFileLength = (afs_fsize_t) FileLength;
3196 #else /* AFS_64BIT_ENV */
3197     if (FileLength.high)
3198         return EFBIG;
3199     tPos = Pos.low;
3200     tLength = Length.low;
3201     tFileLength = FileLength.low;
3202 #endif /* AFS_64BIT_ENV */
3203
3204     code =
3205         common_StoreData64(acall, Fid, InStatus, tPos, tLength, tFileLength,
3206                            OutStatus, Sync);
3207     return code;
3208 }
3209
3210 afs_int32
3211 SRXAFS_StoreACL(struct rx_call * acall, struct AFSFid * Fid,
3212                 struct AFSOpaque * AccessList,
3213                 struct AFSFetchStatus * OutStatus, struct AFSVolSync * Sync)
3214 {
3215     Vnode *targetptr = 0;       /* pointer to input fid */
3216     Vnode *parentwhentargetnotdir = 0;  /* parent of Fid to get ACL */
3217     int errorCode = 0;          /* return code for caller */
3218     struct AFSStoreStatus InStatus;     /* Input status for fid */
3219     Volume *volptr = 0;         /* pointer to the volume header */
3220     struct client *client = 0;  /* pointer to client structure */
3221     afs_int32 rights, anyrights;        /* rights for this and any user */
3222     struct rx_connection *tcon;
3223     struct host *thost;
3224     struct client *t_client = NULL;     /* tmp ptr to client data */
3225     struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
3226 #if FS_STATS_DETAILED
3227     struct fs_stats_opTimingData *opP;  /* Ptr to this op's timing struct */
3228     struct timeval opStartTime, opStopTime;     /* Start/stop times for RPC op */
3229     struct timeval elapsedTime; /* Transfer time */
3230
3231     /*
3232      * Set our stats pointer, remember when the RPC operation started, and
3233      * tally the operation.
3234      */
3235     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_STOREACL]);
3236     FS_LOCK;
3237     (opP->numOps)++;
3238     FS_UNLOCK;
3239     FT_GetTimeOfDay(&opStartTime, 0);
3240 #endif /* FS_STATS_DETAILED */
3241     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
3242         goto Bad_StoreACL;
3243
3244     /* Get ptr to client data for user Id for logging */
3245     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
3246     logHostAddr.s_addr = rxr_HostOf(tcon);
3247     ViceLog(1,
3248             ("SAFS_StoreACL, Fid = %u.%u.%u, ACL=%s, Host %s:%d, Id %d\n",
3249              Fid->Volume, Fid->Vnode, Fid->Unique, AccessList->AFSOpaque_val,
3250              inet_ntoa(logHostAddr), ntohs(rxr_PortOf(tcon)), t_client->ViceId));
3251     FS_LOCK;
3252     AFSCallStats.StoreACL++, AFSCallStats.TotalCalls++;
3253     FS_UNLOCK;
3254     InStatus.Mask = 0;          /* not storing any status */
3255
3256     /*
3257      * Get associated volume/vnode for the target dir; caller's rights
3258      * are also returned.
3259      */
3260     if ((errorCode =
3261          GetVolumePackage(tcon, Fid, &volptr, &targetptr, MustBeDIR,
3262                           &parentwhentargetnotdir, &client, WRITE_LOCK,
3263                           &rights, &anyrights))) {
3264         goto Bad_StoreACL;
3265     }
3266
3267     /* set volume synchronization information */
3268     SetVolumeSync(Sync, volptr);
3269
3270     /* Check if we have permission to change the dir's ACL */
3271     if ((errorCode =
3272          Check_PermissionRights(targetptr, client, rights, CHK_STOREACL,
3273                                 &InStatus))) {
3274         goto Bad_StoreACL;
3275     }
3276
3277     /* Build and store the new Access List for the dir */
3278     if ((errorCode = RXStore_AccessList(targetptr, AccessList))) {
3279         goto Bad_StoreACL;
3280     }
3281
3282     targetptr->changed_newTime = 1;     /* status change of directory */
3283
3284     /* convert the write lock to a read lock before breaking callbacks */
3285     VVnodeWriteToRead(&errorCode, targetptr);
3286     assert(!errorCode || errorCode == VSALVAGE);
3287
3288     /* break call backs on the directory  */
3289     BreakCallBack(client->host, Fid, 0);
3290
3291     /* Get the updated dir's status back to the caller */
3292     GetStatus(targetptr, OutStatus, rights, anyrights, 0);
3293
3294   Bad_StoreACL:
3295     /* Update and store volume/vnode and parent vnodes back */
3296     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, 
3297                      volptr, &client);
3298     ViceLog(2, ("SAFS_StoreACL returns %d\n", errorCode));
3299     errorCode = CallPostamble(tcon, errorCode, thost);
3300
3301 #if FS_STATS_DETAILED
3302     FT_GetTimeOfDay(&opStopTime, 0);
3303     if (errorCode == 0) {
3304         FS_LOCK;
3305         (opP->numSuccesses)++;
3306         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3307         fs_stats_AddTo((opP->sumTime), elapsedTime);
3308         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3309         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3310             fs_stats_TimeAssign((opP->minTime), elapsedTime);
3311         }
3312         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3313             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3314         }
3315         FS_UNLOCK;
3316     }
3317 #endif /* FS_STATS_DETAILED */
3318
3319     osi_auditU(acall, StoreACLEvent, errorCode, 
3320                AUD_ID, t_client ? t_client->ViceId : 0,
3321                AUD_FID, Fid, AUD_ACL, AccessList->AFSOpaque_val, AUD_END);
3322     return errorCode;
3323
3324 }                               /*SRXAFS_StoreACL */
3325
3326
3327 /*
3328  * Note: This routine is called exclusively from SRXAFS_StoreStatus(), and
3329  * should be merged when possible.
3330  */
3331 static afs_int32
3332 SAFSS_StoreStatus(struct rx_call *acall, struct AFSFid *Fid,
3333                   struct AFSStoreStatus *InStatus,
3334                   struct AFSFetchStatus *OutStatus, struct AFSVolSync *Sync)
3335 {
3336     Vnode *targetptr = 0;       /* pointer to input fid */
3337     Vnode *parentwhentargetnotdir = 0;  /* parent of Fid to get ACL */
3338     int errorCode = 0;          /* return code for caller */
3339     Volume *volptr = 0;         /* pointer to the volume header */
3340     struct client *client = 0;  /* pointer to client structure */
3341     afs_int32 rights, anyrights;        /* rights for this and any user */
3342     struct client *t_client = NULL;     /* tmp ptr to client data */
3343     struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
3344     struct rx_connection *tcon = rx_ConnectionOf(acall);
3345
3346     /* Get ptr to client data for user Id for logging */
3347     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
3348     logHostAddr.s_addr = rxr_HostOf(tcon);
3349     ViceLog(1,
3350             ("SAFS_StoreStatus,  Fid    = %u.%u.%u, Host %s:%d, Id %d\n",
3351              Fid->Volume, Fid->Vnode, Fid->Unique, inet_ntoa(logHostAddr),
3352              ntohs(rxr_PortOf(tcon)), t_client->ViceId));
3353     FS_LOCK;
3354     AFSCallStats.StoreStatus++, AFSCallStats.TotalCalls++;
3355     FS_UNLOCK;
3356     /*
3357      * Get volume/vnode for the target file; caller's rights to it are
3358      * also returned
3359      */
3360     if ((errorCode =
3361          GetVolumePackage(tcon, Fid, &volptr, &targetptr, DONTCHECK,
3362                           &parentwhentargetnotdir, &client, WRITE_LOCK,
3363                           &rights, &anyrights))) {
3364         goto Bad_StoreStatus;
3365     }
3366
3367     /* set volume synchronization information */
3368     SetVolumeSync(Sync, volptr);
3369
3370     /* Check if the caller has proper permissions to store status to Fid */
3371     if ((errorCode =
3372          Check_PermissionRights(targetptr, client, rights, CHK_STORESTATUS,
3373                                 InStatus))) {
3374         goto Bad_StoreStatus;
3375     }
3376     /*
3377      * Check for a symbolic link; we can't chmod these (otherwise could
3378      * change a symlink to a mt pt or vice versa)
3379      */
3380     if (targetptr->disk.type == vSymlink && (InStatus->Mask & AFS_SETMODE)) {
3381         errorCode = EINVAL;
3382         goto Bad_StoreStatus;
3383     }
3384
3385     /* Update the status of the target's vnode */
3386     Update_TargetVnodeStatus(targetptr, TVS_SSTATUS, client, InStatus,
3387                              (parentwhentargetnotdir ? parentwhentargetnotdir
3388                               : targetptr), volptr, 0);
3389
3390     /* convert the write lock to a read lock before breaking callbacks */
3391     VVnodeWriteToRead(&errorCode, targetptr);
3392     assert(!errorCode || errorCode == VSALVAGE);
3393
3394     /* Break call backs on Fid */
3395     BreakCallBack(client->host, Fid, 0);
3396
3397     /* Return the updated status back to caller */
3398     GetStatus(targetptr, OutStatus, rights, anyrights,
3399               parentwhentargetnotdir);
3400
3401   Bad_StoreStatus:
3402     /* Update and store volume/vnode and parent vnodes back */
3403     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, 
3404                      volptr, &client);
3405     ViceLog(2, ("SAFS_StoreStatus returns %d\n", errorCode));
3406     return errorCode;
3407
3408 }                               /*SAFSS_StoreStatus */
3409
3410
3411 afs_int32
3412 SRXAFS_StoreStatus(struct rx_call * acall, struct AFSFid * Fid,
3413                    struct AFSStoreStatus * InStatus,
3414                    struct AFSFetchStatus * OutStatus,
3415                    struct AFSVolSync * Sync)
3416 {
3417     afs_int32 code;
3418     struct rx_connection *tcon;
3419     struct host *thost;
3420     struct client *t_client = NULL;     /* tmp ptr to client data */
3421 #if FS_STATS_DETAILED
3422     struct fs_stats_opTimingData *opP;  /* Ptr to this op's timing struct */
3423     struct timeval opStartTime, opStopTime;     /* Start/stop times for RPC op */
3424     struct timeval elapsedTime; /* Transfer time */
3425
3426     /*
3427      * Set our stats pointer, remember when the RPC operation started, and
3428      * tally the operation.
3429      */
3430     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_STORESTATUS]);
3431     FS_LOCK;
3432     (opP->numOps)++;
3433     FS_UNLOCK;
3434     FT_GetTimeOfDay(&opStartTime, 0);
3435 #endif /* FS_STATS_DETAILED */
3436
3437     if ((code = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
3438         goto Bad_StoreStatus;
3439
3440     code = SAFSS_StoreStatus(acall, Fid, InStatus, OutStatus, Sync);
3441
3442   Bad_StoreStatus:
3443     code = CallPostamble(tcon, code, thost);
3444
3445     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
3446
3447 #if FS_STATS_DETAILED
3448     FT_GetTimeOfDay(&opStopTime, 0);
3449     if (code == 0) {
3450         FS_LOCK;
3451         (opP->numSuccesses)++;
3452         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3453         fs_stats_AddTo((opP->sumTime), elapsedTime);
3454         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3455         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3456             fs_stats_TimeAssign((opP->minTime), elapsedTime);
3457         }
3458         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3459             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3460         }
3461         FS_UNLOCK;
3462     }
3463 #endif /* FS_STATS_DETAILED */
3464
3465     osi_auditU(acall, StoreStatusEvent, code, 
3466                AUD_ID, t_client ? t_client->ViceId : 0,
3467                AUD_FID, Fid, AUD_END);
3468     return code;
3469
3470 }                  &nb