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