windows-64bit-printf-sanity-20090218
[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                     FT_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                     FT_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 %" AFS_INT64_FMT " 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
1761             if (targetptr->disk.lock.lockCount >= 0) {
1762                 ++(targetptr->disk.lock.lockCount);
1763                 targetptr->disk.lock.lockTime = Time;
1764             } else
1765                 return (EAGAIN);
1766         } else if (LockingType == LockWrite) {
1767             if ( !(rights & PRSFS_WRITE) && 
1768                  !(OWNSp(client, targetptr) && (rights & PRSFS_INSERT)) )
1769                 return(EACCES);
1770
1771             if (targetptr->disk.lock.lockCount == 0) {
1772                 targetptr->disk.lock.lockCount = -1;
1773                 targetptr->disk.lock.lockTime = Time;
1774             } else
1775                 return (EAGAIN);
1776         }
1777         break;
1778     case LockExtend:
1779         Time += AFS_LOCKWAIT;
1780         if (targetptr->disk.lock.lockCount != 0)
1781             targetptr->disk.lock.lockTime = Time;
1782         else
1783             return (EINVAL);
1784         break;
1785     case LockRelease:
1786         if ((--targetptr->disk.lock.lockCount) <= 0)
1787             targetptr->disk.lock.lockCount = targetptr->disk.lock.lockTime =
1788                 0;
1789         break;
1790     default:
1791         targetptr->changed_oldTime = writeVnode;        /* restore old status */
1792         ViceLog(0, ("Illegal Locking type %d\n", LockingType));
1793     }
1794     return (0);
1795 }                               /*HandleLocking */
1796
1797 /* 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. */
1798
1799 static afs_int32
1800 CheckWriteMode(Vnode * targetptr, afs_int32 rights, int Prfs_Mode)
1801 {
1802     if (readonlyServer)
1803         return (VREADONLY);
1804     if (!(rights & Prfs_Mode))
1805         return (EACCES);
1806     if ((targetptr->disk.type != vDirectory)
1807         && (!(targetptr->disk.modeBits & OWNERWRITE)))
1808         return (EACCES);
1809     return (0);
1810 }
1811
1812 /*
1813  * If some flags (i.e. min or max quota) are set, the volume's in disk
1814  * label is updated; Name, OfflineMsg, and Motd are also reflected in the
1815  * update, if applicable.
1816  */
1817 static afs_int32
1818 RXUpdate_VolumeStatus(Volume * volptr, AFSStoreVolumeStatus * StoreVolStatus,
1819                       char *Name, char *OfflineMsg, char *Motd)
1820 {
1821     Error errorCode = 0;
1822
1823     if (StoreVolStatus->Mask & AFS_SETMINQUOTA)
1824         V_minquota(volptr) = StoreVolStatus->MinQuota;
1825     if (StoreVolStatus->Mask & AFS_SETMAXQUOTA)
1826         V_maxquota(volptr) = StoreVolStatus->MaxQuota;
1827     if (strlen(OfflineMsg) > 0) {
1828         strcpy(V_offlineMessage(volptr), OfflineMsg);
1829     }
1830     if (strlen(Name) > 0) {
1831         strcpy(V_name(volptr), Name);
1832     }
1833 #if OPENAFS_VOL_STATS
1834     /*
1835      * We don't overwrite the motd field, since it's now being used
1836      * for stats
1837      */
1838 #else
1839     if (strlen(Motd) > 0) {
1840         strcpy(V_motd(volptr), Motd);
1841     }
1842 #endif /* FS_STATS_DETAILED */
1843     VUpdateVolume(&errorCode, volptr);
1844     return (errorCode);
1845
1846 }                               /*RXUpdate_VolumeStatus */
1847
1848
1849 static afs_int32
1850 RXGetVolumeStatus(AFSFetchVolumeStatus * status, char **name, char **offMsg,
1851                   char **motd, Volume * volptr)
1852 {
1853     int temp;
1854
1855     status->Vid = V_id(volptr);
1856     status->ParentId = V_parentId(volptr);
1857     status->Online = V_inUse(volptr);
1858     status->InService = V_inService(volptr);
1859     status->Blessed = V_blessed(volptr);
1860     status->NeedsSalvage = V_needsSalvaged(volptr);
1861     if (VolumeWriteable(volptr))
1862         status->Type = ReadWrite;
1863     else
1864         status->Type = ReadOnly;
1865     status->MinQuota = V_minquota(volptr);
1866     status->MaxQuota = V_maxquota(volptr);
1867     status->BlocksInUse = V_diskused(volptr);
1868     status->PartBlocksAvail = RoundInt64ToInt32(volptr->partition->free);
1869     status->PartMaxBlocks = RoundInt64ToInt32(volptr->partition->totalUsable);
1870
1871     /* now allocate and copy these things; they're freed by the RXGEN stub */
1872     temp = strlen(V_name(volptr)) + 1;
1873     *name = malloc(temp);
1874     if (!*name) {
1875         ViceLog(0, ("Failed malloc in RXGetVolumeStatus\n"));
1876         assert(0);
1877     }
1878     strcpy(*name, V_name(volptr));
1879     temp = strlen(V_offlineMessage(volptr)) + 1;
1880     *offMsg = malloc(temp);
1881     if (!*offMsg) {
1882         ViceLog(0, ("Failed malloc in RXGetVolumeStatus\n"));
1883         assert(0);
1884     }
1885     strcpy(*offMsg, V_offlineMessage(volptr));
1886 #if OPENAFS_VOL_STATS
1887     *motd = malloc(1);
1888     if (!*motd) {
1889         ViceLog(0, ("Failed malloc in RXGetVolumeStatus\n"));
1890         assert(0);
1891     }
1892     strcpy(*motd, nullString);
1893 #else
1894     temp = strlen(V_motd(volptr)) + 1;
1895     *motd = malloc(temp);
1896     if (!*motd) {
1897         ViceLog(0, ("Failed malloc in RXGetVolumeStatus\n"));
1898         assert(0);
1899     }
1900     strcpy(*motd, V_motd(volptr));
1901 #endif /* FS_STATS_DETAILED */
1902     return 0;
1903 }                               /*RXGetVolumeStatus */
1904
1905
1906 static afs_int32
1907 FileNameOK(register char *aname)
1908 {
1909     register afs_int32 i, tc;
1910     i = strlen(aname);
1911     if (i >= 4) {
1912         /* watch for @sys on the right */
1913         if (strcmp(aname + i - 4, "@sys") == 0)
1914             return 0;
1915     }
1916     while ((tc = *aname++)) {
1917         if (tc == '/')
1918             return 0;           /* very bad character to encounter */
1919     }
1920     return 1;                   /* file name is ok */
1921
1922 }                               /*FileNameOK */
1923
1924
1925 /*
1926  * This variant of symlink is expressly to support the AFS/DFS translator
1927  * and is not supported by the AFS fileserver. We just return EINVAL.
1928  * The cache manager should not generate this call to an AFS cache manager.
1929  */
1930 afs_int32
1931 SRXAFS_DFSSymlink(struct rx_call *acall, struct AFSFid *DirFid, char *Name,
1932                   char *LinkContents, struct AFSStoreStatus *InStatus,
1933                   struct AFSFid *OutFid, struct AFSFetchStatus *OutFidStatus,
1934                   struct AFSFetchStatus *OutDirStatus,
1935                   struct AFSCallBack *CallBack, struct AFSVolSync *Sync)
1936 {
1937     return EINVAL;
1938 }
1939
1940 afs_int32
1941 SRXAFS_ResidencyCmd(struct rx_call * acall, struct AFSFid * Fid,
1942                     struct ResidencyCmdInputs * Inputs,
1943                     struct ResidencyCmdOutputs * Outputs)
1944 {
1945     return EINVAL;
1946 }
1947
1948 #ifdef AFS_NT40_ENV
1949 static struct afs_buffer {
1950     struct afs_buffer *next;
1951 } *freeBufferList = 0;
1952 static int afs_buffersAlloced = 0;
1953
1954 static
1955 FreeSendBuffer(register struct afs_buffer *adata)
1956 {
1957     FS_LOCK;
1958     afs_buffersAlloced--;
1959     adata->next = freeBufferList;
1960     freeBufferList = adata;
1961     FS_UNLOCK;
1962     return 0;
1963
1964 }                               /*FreeSendBuffer */
1965
1966 /* allocate space for sender */
1967 static char *
1968 AllocSendBuffer()
1969 {
1970     register struct afs_buffer *tp;
1971
1972     FS_LOCK;
1973     afs_buffersAlloced++;
1974     if (!freeBufferList) {
1975         char *tmp;
1976         FS_UNLOCK;
1977         tmp = malloc(sendBufSize);
1978         if (!tmp) {
1979             ViceLog(0, ("Failed malloc in AllocSendBuffer\n"));
1980             assert(0);
1981         }
1982         return tmp;
1983     }
1984     tp = freeBufferList;
1985     freeBufferList = tp->next;
1986     FS_UNLOCK;
1987     return (char *)tp;
1988
1989 }                               /*AllocSendBuffer */
1990 #endif /* AFS_NT40_ENV */
1991
1992 /*
1993  * This routine returns the status info associated with the targetptr vnode
1994  * in the AFSFetchStatus structure.  Some of the newer fields, such as
1995  * SegSize and Group are not yet implemented
1996  */
1997 static
1998     void
1999 GetStatus(Vnode * targetptr, AFSFetchStatus * status, afs_int32 rights,
2000           afs_int32 anyrights, Vnode * parentptr)
2001 {
2002     /* initialize return status from a vnode  */
2003     status->InterfaceVersion = 1;
2004     status->SyncCounter = status->dataVersionHigh = status->lockCount =
2005         status->errorCode = 0;
2006     status->ResidencyMask = 1;  /* means for MR-AFS: file in /vicepr-partition */
2007     if (targetptr->disk.type == vFile)
2008         status->FileType = File;
2009     else if (targetptr->disk.type == vDirectory)
2010         status->FileType = Directory;
2011     else if (targetptr->disk.type == vSymlink)
2012         status->FileType = SymbolicLink;
2013     else
2014         status->FileType = Invalid;     /*invalid type field */
2015     status->LinkCount = targetptr->disk.linkCount;
2016     {
2017         afs_fsize_t targetLen;
2018         VN_GET_LEN(targetLen, targetptr);
2019         SplitOffsetOrSize(targetLen, status->Length_hi, status->Length);
2020     }
2021     status->DataVersion = targetptr->disk.dataVersion;
2022     status->Author = targetptr->disk.author;
2023     status->Owner = targetptr->disk.owner;
2024     status->CallerAccess = rights;
2025     status->AnonymousAccess = anyrights;
2026     status->UnixModeBits = targetptr->disk.modeBits;
2027     status->ClientModTime = targetptr->disk.unixModifyTime;     /* This might need rework */
2028     status->ParentVnode =
2029         (status->FileType ==
2030          Directory ? targetptr->vnodeNumber : parentptr->vnodeNumber);
2031     status->ParentUnique =
2032         (status->FileType ==
2033          Directory ? targetptr->disk.uniquifier : parentptr->disk.uniquifier);
2034     status->ServerModTime = targetptr->disk.serverModifyTime;
2035     status->Group = targetptr->disk.group;
2036     status->lockCount = targetptr->disk.lock.lockCount;
2037     status->errorCode = 0;
2038
2039 }                               /*GetStatus */
2040
2041 static
2042   afs_int32
2043 common_FetchData64(struct rx_call *acall, struct AFSFid *Fid,
2044                    afs_sfsize_t Pos, afs_sfsize_t Len,
2045                    struct AFSFetchStatus *OutStatus,
2046                    struct AFSCallBack *CallBack, struct AFSVolSync *Sync,
2047                    int type)
2048 {
2049     Vnode *targetptr = 0;       /* pointer to vnode to fetch */
2050     Vnode *parentwhentargetnotdir = 0;  /* parent vnode if vptr is a file */
2051     Vnode tparentwhentargetnotdir;      /* parent vnode for GetStatus */
2052     int errorCode = 0;          /* return code to caller */
2053     int fileCode = 0;           /* return code from vol package */
2054     Volume *volptr = 0;         /* pointer to the volume */
2055     struct client *client = 0;  /* pointer to the client data */
2056     struct rx_connection *tcon; /* the connection we're part of */
2057     struct host *thost;
2058     afs_int32 rights, anyrights;        /* rights for this and any user */
2059     struct client *t_client = NULL;     /* tmp ptr to client data */
2060     struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
2061 #if FS_STATS_DETAILED
2062     struct fs_stats_opTimingData *opP;  /* Ptr to this op's timing struct */
2063     struct fs_stats_xferData *xferP;    /* Ptr to this op's byte size struct */
2064     struct timeval opStartTime, opStopTime;     /* Start/stop times for RPC op */
2065     struct timeval xferStartTime, xferStopTime; /* Start/stop times for xfer portion */
2066     struct timeval elapsedTime; /* Transfer time */
2067     afs_sfsize_t bytesToXfer;   /* # bytes to xfer */
2068     afs_sfsize_t bytesXferred;  /* # bytes actually xferred */
2069     int readIdx;                /* Index of read stats array to bump */
2070     static afs_int32 tot_bytesXferred;  /* shared access protected by FS_LOCK */
2071
2072     /*
2073      * Set our stats pointers, remember when the RPC operation started, and
2074      * tally the operation.
2075      */
2076     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_FETCHDATA]);
2077     xferP = &(afs_FullPerfStats.det.xferOpTimes[FS_STATS_XFERIDX_FETCHDATA]);
2078     FS_LOCK;
2079     (opP->numOps)++;
2080     FS_UNLOCK;
2081     FT_GetTimeOfDay(&opStartTime, 0);
2082 #endif /* FS_STATS_DETAILED */
2083
2084     ViceLog(1,
2085             ("SRXAFS_FetchData, Fid = %u.%u.%u\n", Fid->Volume, Fid->Vnode,
2086              Fid->Unique));
2087     FS_LOCK;
2088     AFSCallStats.FetchData++, AFSCallStats.TotalCalls++;
2089     FS_UNLOCK;
2090     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
2091         goto Bad_FetchData;
2092
2093     /* Get ptr to client data for user Id for logging */
2094     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
2095     logHostAddr.s_addr = rxr_HostOf(tcon);
2096     ViceLog(5,
2097             ("SRXAFS_FetchData, Fid = %u.%u.%u, Host %s:%d, Id %d\n",
2098              Fid->Volume, Fid->Vnode, Fid->Unique, inet_ntoa(logHostAddr),
2099              ntohs(rxr_PortOf(tcon)), t_client->ViceId));
2100     /*
2101      * Get volume/vnode for the fetched file; caller's access rights to
2102      * it are also returned
2103      */
2104     if ((errorCode =
2105          GetVolumePackage(tcon, Fid, &volptr, &targetptr, DONTCHECK,
2106                           &parentwhentargetnotdir, &client, READ_LOCK,
2107                           &rights, &anyrights)))
2108         goto Bad_FetchData;
2109
2110     SetVolumeSync(Sync, volptr);
2111
2112 #if FS_STATS_DETAILED
2113     /*
2114      * Remember that another read operation was performed.
2115      */
2116     FS_LOCK;
2117     if (client->InSameNetwork)
2118         readIdx = VOL_STATS_SAME_NET;
2119     else
2120         readIdx = VOL_STATS_DIFF_NET;
2121     V_stat_reads(volptr, readIdx)++;
2122     if (client->ViceId != AnonymousID) {
2123         V_stat_reads(volptr, readIdx + 1)++;
2124     }
2125     FS_UNLOCK;
2126 #endif /* FS_STATS_DETAILED */
2127     /* Check whether the caller has permission access to fetch the data */
2128     if ((errorCode =
2129          Check_PermissionRights(targetptr, client, rights, CHK_FETCHDATA, 0)))
2130         goto Bad_FetchData;
2131
2132     /*
2133      * Drop the read lock on the parent directory after saving the parent
2134      * vnode information we need to pass to GetStatus
2135      */
2136     if (parentwhentargetnotdir != NULL) {
2137         tparentwhentargetnotdir = *parentwhentargetnotdir;
2138         VPutVnode(&fileCode, parentwhentargetnotdir);
2139         assert(!fileCode || (fileCode == VSALVAGE));
2140         parentwhentargetnotdir = NULL;
2141     }
2142 #if FS_STATS_DETAILED
2143     /*
2144      * Remember when the data transfer started.
2145      */
2146     FT_GetTimeOfDay(&xferStartTime, 0);
2147 #endif /* FS_STATS_DETAILED */
2148
2149     /* actually do the data transfer */
2150 #if FS_STATS_DETAILED
2151     errorCode =
2152         FetchData_RXStyle(volptr, targetptr, acall, Pos, Len, type,
2153                           &bytesToXfer, &bytesXferred);
2154 #else
2155     if ((errorCode =
2156          FetchData_RXStyle(volptr, targetptr, acall, Pos, Len, type)))
2157         goto Bad_FetchData;
2158 #endif /* FS_STATS_DETAILED */
2159
2160 #if FS_STATS_DETAILED
2161     /*
2162      * At this point, the data transfer is done, for good or ill.  Remember
2163      * when the transfer ended, bump the number of successes/failures, and
2164      * integrate the transfer size and elapsed time into the stats.  If the
2165      * operation failed, we jump to the appropriate point.
2166      */
2167     FT_GetTimeOfDay(&xferStopTime, 0);
2168     FS_LOCK;
2169     (xferP->numXfers)++;
2170     if (!errorCode) {
2171         (xferP->numSuccesses)++;
2172
2173         /*
2174          * Bump the xfer sum by the number of bytes actually sent, NOT the
2175          * target number.
2176          */
2177         tot_bytesXferred += bytesXferred;
2178         (xferP->sumBytes) += (tot_bytesXferred >> 10);
2179         tot_bytesXferred &= 0x3FF;
2180         if (bytesXferred < xferP->minBytes)
2181             xferP->minBytes = bytesXferred;
2182         if (bytesXferred > xferP->maxBytes)
2183             xferP->maxBytes = bytesXferred;
2184
2185         /*
2186          * Tally the size of the object.  Note: we tally the actual size,
2187          * NOT the number of bytes that made it out over the wire.
2188          */
2189         if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET0)
2190             (xferP->count[0])++;
2191         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET1)
2192             (xferP->count[1])++;
2193         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET2)
2194             (xferP->count[2])++;
2195         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET3)
2196             (xferP->count[3])++;
2197         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET4)
2198             (xferP->count[4])++;
2199         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET5)
2200             (xferP->count[5])++;
2201         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET6)
2202             (xferP->count[6])++;
2203         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET7)
2204             (xferP->count[7])++;
2205         else
2206             (xferP->count[8])++;
2207
2208         fs_stats_GetDiff(elapsedTime, xferStartTime, xferStopTime);
2209         fs_stats_AddTo((xferP->sumTime), elapsedTime);
2210         fs_stats_SquareAddTo((xferP->sqrTime), elapsedTime);
2211         if (fs_stats_TimeLessThan(elapsedTime, (xferP->minTime))) {
2212             fs_stats_TimeAssign((xferP->minTime), elapsedTime);
2213         }
2214         if (fs_stats_TimeGreaterThan(elapsedTime, (xferP->maxTime))) {
2215             fs_stats_TimeAssign((xferP->maxTime), elapsedTime);
2216         }
2217     }
2218     FS_UNLOCK;
2219     /*
2220      * Finally, go off to tell our caller the bad news in case the
2221      * fetch failed.
2222      */
2223     if (errorCode)
2224         goto Bad_FetchData;
2225 #endif /* FS_STATS_DETAILED */
2226
2227     /* write back  the OutStatus from the target vnode  */
2228     GetStatus(targetptr, OutStatus, rights, anyrights,
2229               &tparentwhentargetnotdir);
2230
2231     /* if a r/w volume, promise a callback to the caller */
2232     if (VolumeWriteable(volptr))
2233         SetCallBackStruct(AddCallBack(client->host, Fid), CallBack);
2234     else {
2235         struct AFSFid myFid;
2236         memset(&myFid, 0, sizeof(struct AFSFid));
2237         myFid.Volume = Fid->Volume;
2238         SetCallBackStruct(AddVolCallBack(client->host, &myFid), CallBack);
2239     }
2240
2241   Bad_FetchData:
2242     /* Update and store volume/vnode and parent vnodes back */
2243     (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
2244                            volptr, &client);
2245     ViceLog(2, ("SRXAFS_FetchData returns %d\n", errorCode));
2246     errorCode = CallPostamble(tcon, errorCode, thost);
2247
2248 #if FS_STATS_DETAILED
2249     FT_GetTimeOfDay(&opStopTime, 0);
2250     if (errorCode == 0) {
2251         FS_LOCK;
2252         (opP->numSuccesses)++;
2253         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2254         fs_stats_AddTo((opP->sumTime), elapsedTime);
2255         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2256         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2257             fs_stats_TimeAssign((opP->minTime), elapsedTime);
2258         }
2259         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2260             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2261         }
2262         FS_UNLOCK;
2263     }
2264 #endif /* FS_STATS_DETAILED */
2265
2266     osi_auditU(acall, FetchDataEvent, errorCode, 
2267                AUD_ID, t_client ? t_client->ViceId : 0,
2268                AUD_FID, Fid, AUD_END);
2269     return (errorCode);
2270
2271 }                               /*SRXAFS_FetchData */
2272
2273 afs_int32
2274 SRXAFS_FetchData(struct rx_call * acall, struct AFSFid * Fid, afs_int32 Pos,
2275                  afs_int32 Len, struct AFSFetchStatus * OutStatus,
2276                  struct AFSCallBack * CallBack, struct AFSVolSync * Sync)
2277 {
2278     return common_FetchData64(acall, Fid, Pos, Len, OutStatus, CallBack, 
2279                               Sync, 0);
2280 }
2281
2282 afs_int32
2283 SRXAFS_FetchData64(struct rx_call * acall, struct AFSFid * Fid, afs_int64 Pos,
2284                    afs_int64 Len, struct AFSFetchStatus * OutStatus,
2285                    struct AFSCallBack * CallBack, struct AFSVolSync * Sync)
2286 {
2287     int code;
2288     afs_sfsize_t tPos, tLen;
2289
2290 #ifdef AFS_64BIT_ENV
2291 #ifndef AFS_LARGEFILE_ENV
2292     if (Pos + Len > 0x7fffffff)
2293         return EFBIG;
2294 #endif /* !AFS_LARGEFILE_ENV */
2295     tPos = (afs_sfsize_t) Pos;
2296     tLen = (afs_sfsize_t) Len;
2297 #else /* AFS_64BIT_ENV */
2298     if (Pos.high || Len.high)
2299         return EFBIG;
2300     tPos = Pos.low;
2301     tLen = Len.low;
2302 #endif /* AFS_64BIT_ENV */
2303
2304     code =
2305         common_FetchData64(acall, Fid, tPos, tLen, OutStatus, CallBack, Sync,
2306                            1);
2307     return code;
2308 }
2309
2310 afs_int32
2311 SRXAFS_FetchACL(struct rx_call * acall, struct AFSFid * Fid,
2312                 struct AFSOpaque * AccessList,
2313                 struct AFSFetchStatus * OutStatus, struct AFSVolSync * Sync)
2314 {
2315     Vnode *targetptr = 0;       /* pointer to vnode to fetch */
2316     Vnode *parentwhentargetnotdir = 0;  /* parent vnode if targetptr is a file */
2317     int errorCode = 0;          /* return error code to caller */
2318     Volume *volptr = 0;         /* pointer to the volume */
2319     struct client *client = 0;  /* pointer to the client data */
2320     afs_int32 rights, anyrights;        /* rights for this and any user */
2321     struct rx_connection *tcon = rx_ConnectionOf(acall);
2322     struct host *thost;
2323     struct client *t_client = NULL;     /* tmp ptr to client data */
2324     struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
2325 #if FS_STATS_DETAILED
2326     struct fs_stats_opTimingData *opP;  /* Ptr to this op's timing struct */
2327     struct timeval opStartTime, opStopTime;     /* Start/stop times for RPC op */
2328     struct timeval elapsedTime; /* Transfer time */
2329
2330     /*
2331      * Set our stats pointer, remember when the RPC operation started, and
2332      * tally the operation.
2333      */
2334     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_FETCHACL]);
2335     FS_LOCK;
2336     (opP->numOps)++;
2337     FS_UNLOCK;
2338     FT_GetTimeOfDay(&opStartTime, 0);
2339 #endif /* FS_STATS_DETAILED */
2340
2341     ViceLog(1,
2342             ("SAFS_FetchACL, Fid = %u.%u.%u\n", Fid->Volume, Fid->Vnode,
2343              Fid->Unique));
2344     FS_LOCK;
2345     AFSCallStats.FetchACL++, AFSCallStats.TotalCalls++;
2346     FS_UNLOCK;
2347     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
2348         goto Bad_FetchACL;
2349
2350     /* Get ptr to client data for user Id for logging */
2351     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
2352     logHostAddr.s_addr = rxr_HostOf(tcon);
2353     ViceLog(5,
2354             ("SAFS_FetchACL, Fid = %u.%u.%u, Host %s:%d, Id %d\n", Fid->Volume,
2355              Fid->Vnode, Fid->Unique, inet_ntoa(logHostAddr),
2356              ntohs(rxr_PortOf(tcon)), t_client->ViceId));
2357
2358     AccessList->AFSOpaque_len = 0;
2359     AccessList->AFSOpaque_val = malloc(AFSOPAQUEMAX);
2360     if (!AccessList->AFSOpaque_val) {
2361         ViceLog(0, ("Failed malloc in SRXAFS_FetchACL\n"));
2362         assert(0);
2363     }
2364
2365     /*
2366      * Get volume/vnode for the fetched file; caller's access rights to it
2367      * are also returned
2368      */
2369     if ((errorCode =
2370          GetVolumePackage(tcon, Fid, &volptr, &targetptr, DONTCHECK,
2371                           &parentwhentargetnotdir, &client, READ_LOCK,
2372                           &rights, &anyrights)))
2373         goto Bad_FetchACL;
2374
2375     SetVolumeSync(Sync, volptr);
2376
2377     /* Check whether we have permission to fetch the ACL */
2378     if ((errorCode =
2379          Check_PermissionRights(targetptr, client, rights, CHK_FETCHACL, 0)))
2380         goto Bad_FetchACL;
2381
2382     /* Get the Access List from the dir's vnode */
2383     if ((errorCode =
2384          RXFetch_AccessList(targetptr, parentwhentargetnotdir, AccessList)))
2385         goto Bad_FetchACL;
2386
2387     /* Get OutStatus back From the target Vnode  */
2388     GetStatus(targetptr, OutStatus, rights, anyrights,
2389               parentwhentargetnotdir);
2390
2391   Bad_FetchACL:
2392     /* Update and store volume/vnode and parent vnodes back */
2393     (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
2394                            volptr, &client);
2395     ViceLog(2,
2396             ("SAFS_FetchACL returns %d (ACL=%s)\n", errorCode,
2397              AccessList->AFSOpaque_val));
2398     errorCode = CallPostamble(tcon, errorCode, thost);
2399
2400 #if FS_STATS_DETAILED
2401     FT_GetTimeOfDay(&opStopTime, 0);
2402     if (errorCode == 0) {
2403         FS_LOCK;
2404         (opP->numSuccesses)++;
2405         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2406         fs_stats_AddTo((opP->sumTime), elapsedTime);
2407         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2408         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2409             fs_stats_TimeAssign((opP->minTime), elapsedTime);
2410         }
2411         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2412             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2413         }
2414         FS_UNLOCK;
2415     }
2416 #endif /* FS_STATS_DETAILED */
2417
2418     osi_auditU(acall, FetchACLEvent, errorCode, 
2419                AUD_ID, t_client ? t_client->ViceId : 0,
2420                AUD_FID, Fid, 
2421                AUD_ACL, AccessList->AFSOpaque_val, AUD_END);
2422     return errorCode;
2423 }                               /*SRXAFS_FetchACL */
2424
2425
2426 /*
2427  * This routine is called exclusively by SRXAFS_FetchStatus(), and should be
2428  * merged into it when possible.
2429  */
2430 static
2431   afs_int32
2432 SAFSS_FetchStatus(struct rx_call *acall, struct AFSFid *Fid,
2433                   struct AFSFetchStatus *OutStatus,
2434                   struct AFSCallBack *CallBack, struct AFSVolSync *Sync)
2435 {
2436     Vnode *targetptr = 0;       /* pointer to vnode to fetch */
2437     Vnode *parentwhentargetnotdir = 0;  /* parent vnode if targetptr is a file */
2438     int errorCode = 0;          /* return code to caller */
2439     Volume *volptr = 0;         /* pointer to the volume */
2440     struct client *client = 0;  /* pointer to the client data */
2441     afs_int32 rights, anyrights;        /* rights for this and any user */
2442     struct client *t_client = NULL;     /* tmp ptr to client data */
2443     struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
2444     struct rx_connection *tcon = rx_ConnectionOf(acall);
2445
2446     /* Get ptr to client data for user Id for logging */
2447     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
2448     logHostAddr.s_addr = rxr_HostOf(tcon);
2449     ViceLog(1,
2450             ("SAFS_FetchStatus,  Fid = %u.%u.%u, Host %s:%d, Id %d\n",
2451              Fid->Volume, Fid->Vnode, Fid->Unique, inet_ntoa(logHostAddr),
2452              ntohs(rxr_PortOf(tcon)), t_client->ViceId));
2453     FS_LOCK;
2454     AFSCallStats.FetchStatus++, AFSCallStats.TotalCalls++;
2455     FS_UNLOCK;
2456     /*
2457      * Get volume/vnode for the fetched file; caller's rights to it are
2458      * also returned
2459      */
2460     if ((errorCode =
2461          GetVolumePackage(tcon, Fid, &volptr, &targetptr, DONTCHECK,
2462                           &parentwhentargetnotdir, &client, READ_LOCK,
2463                           &rights, &anyrights)))
2464         goto Bad_FetchStatus;
2465
2466     /* set volume synchronization information */
2467     SetVolumeSync(Sync, volptr);
2468
2469     /* Are we allowed to fetch Fid's status? */
2470     if (targetptr->disk.type != vDirectory) {
2471         if ((errorCode =
2472              Check_PermissionRights(targetptr, client, rights,
2473                                     CHK_FETCHSTATUS, 0))) {
2474             if (rx_GetCallAbortCode(acall) == errorCode)
2475                 rx_SetCallAbortCode(acall, 0);
2476             goto Bad_FetchStatus;
2477         }
2478     }
2479
2480     /* set OutStatus From the Fid  */
2481     GetStatus(targetptr, OutStatus, rights, anyrights,
2482               parentwhentargetnotdir);
2483
2484     /* If a r/w volume, also set the CallBack state */
2485     if (VolumeWriteable(volptr))
2486         SetCallBackStruct(AddCallBack(client->host, Fid), CallBack);
2487     else {
2488         struct AFSFid myFid;
2489         memset(&myFid, 0, sizeof(struct AFSFid));
2490         myFid.Volume = Fid->Volume;
2491         SetCallBackStruct(AddVolCallBack(client->host, &myFid), CallBack);
2492     }
2493
2494   Bad_FetchStatus:
2495     /* Update and store volume/vnode and parent vnodes back */
2496     (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
2497                            volptr, &client);
2498     ViceLog(2, ("SAFS_FetchStatus returns %d\n", errorCode));
2499     return errorCode;
2500
2501 }                               /*SAFSS_FetchStatus */
2502
2503
2504 afs_int32
2505 SRXAFS_BulkStatus(struct rx_call * acall, struct AFSCBFids * Fids,
2506                   struct AFSBulkStats * OutStats, struct AFSCBs * CallBacks,
2507                   struct AFSVolSync * Sync)
2508 {
2509     register int i;
2510     afs_int32 nfiles;
2511     Vnode *targetptr = 0;       /* pointer to vnode to fetch */
2512     Vnode *parentwhentargetnotdir = 0;  /* parent vnode if targetptr is a file */
2513     int errorCode = 0;          /* return code to caller */
2514     Volume *volptr = 0;         /* pointer to the volume */
2515     struct client *client = 0;  /* pointer to the client data */
2516     afs_int32 rights, anyrights;        /* rights for this and any user */
2517     register struct AFSFid *tfid;       /* file id we're dealing with now */
2518     struct rx_connection *tcon = rx_ConnectionOf(acall);
2519     struct host *thost;
2520     struct client *t_client = NULL;     /* tmp pointer to the client data */
2521 #if FS_STATS_DETAILED
2522     struct fs_stats_opTimingData *opP;  /* Ptr to this op's timing struct */
2523     struct timeval opStartTime, opStopTime;     /* Start/stop times for RPC op */
2524     struct timeval elapsedTime; /* Transfer time */
2525
2526     /*
2527      * Set our stats pointer, remember when the RPC operation started, and
2528      * tally the operation.
2529      */
2530     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_BULKSTATUS]);
2531     FS_LOCK;
2532     (opP->numOps)++;
2533     FS_UNLOCK;
2534     FT_GetTimeOfDay(&opStartTime, 0);
2535 #endif /* FS_STATS_DETAILED */
2536
2537     ViceLog(1, ("SAFS_BulkStatus\n"));
2538     FS_LOCK;
2539     AFSCallStats.TotalCalls++;
2540     FS_UNLOCK;
2541     nfiles = Fids->AFSCBFids_len;       /* # of files in here */
2542     if (nfiles <= 0) {          /* Sanity check */
2543         errorCode = EINVAL;
2544         goto Audit_and_Return;
2545     }
2546
2547     /* allocate space for return output parameters */
2548     OutStats->AFSBulkStats_val = (struct AFSFetchStatus *)
2549         malloc(nfiles * sizeof(struct AFSFetchStatus));
2550     if (!OutStats->AFSBulkStats_val) {
2551         ViceLog(0, ("Failed malloc in SRXAFS_BulkStatus\n"));
2552         assert(0);
2553     }
2554     OutStats->AFSBulkStats_len = nfiles;
2555     CallBacks->AFSCBs_val = (struct AFSCallBack *)
2556         malloc(nfiles * sizeof(struct AFSCallBack));
2557     if (!CallBacks->AFSCBs_val) {
2558         ViceLog(0, ("Failed malloc in SRXAFS_BulkStatus\n"));
2559         assert(0);
2560     }
2561     CallBacks->AFSCBs_len = nfiles;
2562
2563     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
2564         goto Bad_BulkStatus;
2565
2566     tfid = Fids->AFSCBFids_val;
2567     for (i = 0; i < nfiles; i++, tfid++) {
2568         /*
2569          * Get volume/vnode for the fetched file; caller's rights to it
2570          * are also returned
2571          */
2572         if ((errorCode =
2573              GetVolumePackage(tcon, tfid, &volptr, &targetptr, DONTCHECK,
2574                               &parentwhentargetnotdir, &client, READ_LOCK,
2575                               &rights, &anyrights)))
2576             goto Bad_BulkStatus;
2577         /* set volume synchronization information, but only once per call */
2578         if (i == nfiles)
2579             SetVolumeSync(Sync, volptr);
2580
2581         /* Are we allowed to fetch Fid's status? */
2582         if (targetptr->disk.type != vDirectory) {
2583             if ((errorCode =
2584                  Check_PermissionRights(targetptr, client, rights,
2585                                         CHK_FETCHSTATUS, 0))) {
2586                 if (rx_GetCallAbortCode(acall) == errorCode)
2587                     rx_SetCallAbortCode(acall, 0);
2588                 goto Bad_BulkStatus;
2589             }
2590         }
2591
2592         /* set OutStatus From the Fid  */
2593         GetStatus(targetptr, &OutStats->AFSBulkStats_val[i], rights,
2594                   anyrights, parentwhentargetnotdir);
2595
2596         /* If a r/w volume, also set the CallBack state */
2597         if (VolumeWriteable(volptr))
2598             SetCallBackStruct(AddBulkCallBack(client->host, tfid),
2599                               &CallBacks->AFSCBs_val[i]);
2600         else {
2601             struct AFSFid myFid;
2602             memset(&myFid, 0, sizeof(struct AFSFid));
2603             myFid.Volume = tfid->Volume;
2604             SetCallBackStruct(AddVolCallBack(client->host, &myFid),
2605                               &CallBacks->AFSCBs_val[i]);
2606         }
2607
2608         /* put back the file ID and volume */
2609         (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
2610                                volptr, &client);
2611         parentwhentargetnotdir = (Vnode *) 0;
2612         targetptr = (Vnode *) 0;
2613         volptr = (Volume *) 0;
2614         client = (struct client *)0;
2615     }
2616
2617   Bad_BulkStatus:
2618     /* Update and store volume/vnode and parent vnodes back */
2619     (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
2620                            volptr, &client);
2621     errorCode = CallPostamble(tcon, errorCode, thost);
2622
2623     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
2624
2625 #if FS_STATS_DETAILED
2626     FT_GetTimeOfDay(&opStopTime, 0);
2627     if (errorCode == 0) {
2628         FS_LOCK;
2629         (opP->numSuccesses)++;
2630         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2631         fs_stats_AddTo((opP->sumTime), elapsedTime);
2632         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2633         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2634             fs_stats_TimeAssign((opP->minTime), elapsedTime);
2635         }
2636         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2637             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2638         }
2639         FS_UNLOCK;
2640     }
2641 #endif /* FS_STATS_DETAILED */
2642
2643   Audit_and_Return:
2644     ViceLog(2, ("SAFS_BulkStatus        returns %d\n", errorCode));
2645     osi_auditU(acall, BulkFetchStatusEvent, errorCode, 
2646                AUD_ID, t_client ? t_client->ViceId : 0,
2647                AUD_FIDS, Fids, AUD_END);
2648     return errorCode;
2649
2650 }                               /*SRXAFS_BulkStatus */
2651
2652
2653 afs_int32
2654 SRXAFS_InlineBulkStatus(struct rx_call * acall, struct AFSCBFids * Fids,
2655                         struct AFSBulkStats * OutStats,
2656                         struct AFSCBs * CallBacks, struct AFSVolSync * Sync)
2657 {
2658     register int i;
2659     afs_int32 nfiles;
2660     Vnode *targetptr = 0;       /* pointer to vnode to fetch */
2661     Vnode *parentwhentargetnotdir = 0;  /* parent vnode if targetptr is a file */
2662     int errorCode = 0;          /* return code to caller */
2663     Volume *volptr = 0;         /* pointer to the volume */
2664     struct client *client = 0;  /* pointer to the client data */
2665     afs_int32 rights, anyrights;        /* rights for this and any user */
2666     register struct AFSFid *tfid;       /* file id we're dealing with now */
2667     struct rx_connection *tcon;
2668     struct host *thost;
2669     struct client *t_client = NULL;     /* tmp ptr to client data */
2670     AFSFetchStatus *tstatus;
2671 #if FS_STATS_DETAILED
2672     struct fs_stats_opTimingData *opP;  /* Ptr to this op's timing struct */
2673     struct timeval opStartTime, opStopTime;     /* Start/stop times for RPC op */
2674     struct timeval elapsedTime; /* Transfer time */
2675
2676     /*
2677      * Set our stats pointer, remember when the RPC operation started, and
2678      * tally the operation.
2679      */
2680     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_BULKSTATUS]);
2681     FS_LOCK;
2682     (opP->numOps)++;
2683     FS_UNLOCK;
2684     FT_GetTimeOfDay(&opStartTime, 0);
2685 #endif /* FS_STATS_DETAILED */
2686
2687     ViceLog(1, ("SAFS_InlineBulkStatus\n"));
2688     FS_LOCK;
2689     AFSCallStats.TotalCalls++;
2690     FS_UNLOCK;
2691     nfiles = Fids->AFSCBFids_len;       /* # of files in here */
2692     if (nfiles <= 0) {          /* Sanity check */
2693         errorCode = EINVAL;
2694         goto Audit_and_Return;
2695     }
2696
2697     /* allocate space for return output parameters */
2698     OutStats->AFSBulkStats_val = (struct AFSFetchStatus *)
2699         malloc(nfiles * sizeof(struct AFSFetchStatus));
2700     if (!OutStats->AFSBulkStats_val) {
2701         ViceLog(0, ("Failed malloc in SRXAFS_FetchStatus\n"));
2702         assert(0);
2703     }
2704     OutStats->AFSBulkStats_len = nfiles;
2705     CallBacks->AFSCBs_val = (struct AFSCallBack *)
2706         malloc(nfiles * sizeof(struct AFSCallBack));
2707     if (!CallBacks->AFSCBs_val) {
2708         ViceLog(0, ("Failed malloc in SRXAFS_FetchStatus\n"));
2709         assert(0);
2710     }
2711     CallBacks->AFSCBs_len = nfiles;
2712
2713     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon, &thost))) {
2714         goto Bad_InlineBulkStatus;
2715     }
2716
2717     tfid = Fids->AFSCBFids_val;
2718     for (i = 0; i < nfiles; i++, tfid++) {
2719         /*
2720          * Get volume/vnode for the fetched file; caller's rights to it
2721          * are also returned
2722          */
2723         if ((errorCode =
2724              GetVolumePackage(tcon, tfid, &volptr, &targetptr, DONTCHECK,
2725                               &parentwhentargetnotdir, &client, READ_LOCK,
2726                               &rights, &anyrights))) {
2727             tstatus = &OutStats->AFSBulkStats_val[i];
2728             tstatus->errorCode = errorCode;
2729             PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, 
2730                              volptr, &client);
2731             parentwhentargetnotdir = (Vnode *) 0;
2732             targetptr = (Vnode *) 0;
2733             volptr = (Volume *) 0;
2734             client = (struct client *)0;
2735             continue;
2736         }
2737
2738         /* set volume synchronization information, but only once per call */
2739         if (i == nfiles)
2740             SetVolumeSync(Sync, volptr);
2741
2742         /* Are we allowed to fetch Fid's status? */
2743         if (targetptr->disk.type != vDirectory) {
2744             if ((errorCode =
2745                  Check_PermissionRights(targetptr, client, rights,
2746                                         CHK_FETCHSTATUS, 0))) {
2747                 tstatus = &OutStats->AFSBulkStats_val[i];
2748                 tstatus->errorCode = errorCode;
2749                 (void)PutVolumePackage(parentwhentargetnotdir, targetptr,
2750                                        (Vnode *) 0, volptr, &client);
2751                 parentwhentargetnotdir = (Vnode *) 0;
2752                 targetptr = (Vnode *) 0;
2753                 volptr = (Volume *) 0;
2754                 client = (struct client *)0;
2755                 continue;
2756             }
2757         }
2758
2759         /* set OutStatus From the Fid  */
2760         GetStatus(targetptr,
2761                   (struct AFSFetchStatus *)&OutStats->AFSBulkStats_val[i],
2762                   rights, anyrights, parentwhentargetnotdir);
2763
2764         /* If a r/w volume, also set the CallBack state */
2765         if (VolumeWriteable(volptr))
2766             SetCallBackStruct(AddBulkCallBack(client->host, tfid),
2767                               &CallBacks->AFSCBs_val[i]);
2768         else {
2769             struct AFSFid myFid;
2770             memset(&myFid, 0, sizeof(struct AFSFid));
2771             myFid.Volume = tfid->Volume;
2772             SetCallBackStruct(AddVolCallBack(client->host, &myFid),
2773                               &CallBacks->AFSCBs_val[i]);
2774         }
2775
2776         /* put back the file ID and volume */
2777         (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
2778                                volptr, &client);
2779         parentwhentargetnotdir = (Vnode *) 0;
2780         targetptr = (Vnode *) 0;
2781         volptr = (Volume *) 0;
2782         client = (struct client *)0;
2783     }
2784
2785   Bad_InlineBulkStatus:
2786     /* Update and store volume/vnode and parent vnodes back */
2787     (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
2788                            volptr, &client);
2789     errorCode = CallPostamble(tcon, errorCode, thost);
2790
2791     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
2792
2793 #if FS_STATS_DETAILED
2794     FT_GetTimeOfDay(&opStopTime, 0);
2795     if (errorCode == 0) {
2796         FS_LOCK;
2797         (opP->numSuccesses)++;
2798         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2799         fs_stats_AddTo((opP->sumTime), elapsedTime);
2800         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2801         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2802             fs_stats_TimeAssign((opP->minTime), elapsedTime);
2803         }
2804         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2805             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2806         }
2807         FS_UNLOCK;
2808     }
2809 #endif /* FS_STATS_DETAILED */
2810
2811   Audit_and_Return:
2812     ViceLog(2, ("SAFS_InlineBulkStatus  returns %d\n", errorCode));
2813     osi_auditU(acall, InlineBulkFetchStatusEvent, errorCode, 
2814                AUD_ID, t_client ? t_client->ViceId : 0,
2815                AUD_FIDS, Fids, AUD_END);
2816     return 0;
2817
2818 }                               /*SRXAFS_InlineBulkStatus */
2819
2820
2821 afs_int32
2822 SRXAFS_FetchStatus(struct rx_call * acall, struct AFSFid * Fid,
2823                    struct AFSFetchStatus * OutStatus,
2824                    struct AFSCallBack * CallBack, struct AFSVolSync * Sync)
2825 {
2826     afs_int32 code;
2827     struct rx_connection *tcon;
2828     struct host *thost;
2829     struct client *t_client = NULL;     /* tmp ptr to client data */
2830 #if FS_STATS_DETAILED
2831     struct fs_stats_opTimingData *opP;  /* Ptr to this op's timing struct */
2832     struct timeval opStartTime, opStopTime;     /* Start/stop times for RPC op */
2833     struct timeval elapsedTime; /* Transfer time */
2834
2835     /*
2836      * Set our stats pointer, remember when the RPC operation started, and
2837      * tally the operation.
2838      */
2839     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_FETCHSTATUS]);
2840     FS_LOCK;
2841     (opP->numOps)++;
2842     FS_UNLOCK;
2843     FT_GetTimeOfDay(&opStartTime, 0);
2844 #endif /* FS_STATS_DETAILED */
2845
2846     if ((code = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
2847         goto Bad_FetchStatus;
2848
2849     code = SAFSS_FetchStatus(acall, Fid, OutStatus, CallBack, Sync);
2850
2851   Bad_FetchStatus:
2852     code = CallPostamble(tcon, code, thost);
2853
2854     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
2855
2856 #if FS_STATS_DETAILED
2857     FT_GetTimeOfDay(&opStopTime, 0);
2858     if (code == 0) {
2859         FS_LOCK;
2860         (opP->numSuccesses)++;
2861         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2862         fs_stats_AddTo((opP->sumTime), elapsedTime);
2863         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2864         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2865             fs_stats_TimeAssign((opP->minTime), elapsedTime);
2866         }
2867         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2868             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2869         }
2870         FS_UNLOCK;
2871     }
2872 #endif /* FS_STATS_DETAILED */
2873
2874     osi_auditU(acall, FetchStatusEvent, code, 
2875                AUD_ID, t_client ? t_client->ViceId : 0,
2876                AUD_FID, Fid, AUD_END);
2877     return code;
2878
2879 }                               /*SRXAFS_FetchStatus */
2880
2881 static
2882   afs_int32
2883 common_StoreData64(struct rx_call *acall, struct AFSFid *Fid,
2884                    struct AFSStoreStatus *InStatus, afs_fsize_t Pos,
2885                    afs_fsize_t Length, afs_fsize_t FileLength,
2886                    struct AFSFetchStatus *OutStatus, struct AFSVolSync *Sync)
2887 {
2888     Vnode *targetptr = 0;       /* pointer to input fid */
2889     Vnode *parentwhentargetnotdir = 0;  /* parent of Fid to get ACL */
2890     Vnode tparentwhentargetnotdir;      /* parent vnode for GetStatus */
2891     int errorCode = 0;          /* return code for caller */
2892     int fileCode = 0;           /* return code from vol package */
2893     Volume *volptr = 0;         /* pointer to the volume header */
2894     struct client *client = 0;  /* pointer to client structure */
2895     afs_int32 rights, anyrights;        /* rights for this and any user */
2896     struct client *t_client = NULL;     /* tmp ptr to client data */
2897     struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
2898     struct rx_connection *tcon;
2899     struct host *thost;
2900 #if FS_STATS_DETAILED
2901     struct fs_stats_opTimingData *opP;  /* Ptr to this op's timing struct */
2902     struct fs_stats_xferData *xferP;    /* Ptr to this op's byte size struct */
2903     struct timeval opStartTime, opStopTime;     /* Start/stop times for RPC op */
2904     struct timeval xferStartTime, xferStopTime; /* Start/stop times for xfer portion */
2905     struct timeval elapsedTime; /* Transfer time */
2906     afs_sfsize_t bytesToXfer;   /* # bytes to xfer */
2907     afs_sfsize_t bytesXferred;  /* # bytes actually xfer */
2908     static afs_int32 tot_bytesXferred;  /* shared access protected by FS_LOCK */
2909
2910     /*
2911      * Set our stats pointers, remember when the RPC operation started, and
2912      * tally the operation.
2913      */
2914     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_STOREDATA]);
2915     xferP = &(afs_FullPerfStats.det.xferOpTimes[FS_STATS_XFERIDX_STOREDATA]);
2916     FS_LOCK;
2917     (opP->numOps)++;
2918     FS_UNLOCK;
2919     ViceLog(1,
2920             ("StoreData: Fid = %u.%u.%u\n", Fid->Volume, Fid->Vnode,
2921              Fid->Unique));
2922     FT_GetTimeOfDay(&opStartTime, 0);
2923 #endif /* FS_STATS_DETAILED */
2924
2925     FS_LOCK;
2926     AFSCallStats.StoreData++, AFSCallStats.TotalCalls++;
2927     FS_UNLOCK;
2928     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
2929         goto Bad_StoreData;
2930
2931     /* Get ptr to client data for user Id for logging */
2932     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
2933     logHostAddr.s_addr = rxr_HostOf(tcon);
2934     ViceLog(5,
2935             ("StoreData: Fid = %u.%u.%u, Host %s:%d, Id %d\n", Fid->Volume,
2936              Fid->Vnode, Fid->Unique, inet_ntoa(logHostAddr),
2937              ntohs(rxr_PortOf(tcon)), t_client->ViceId));
2938
2939     /*
2940      * Get associated volume/vnode for the stored file; caller's rights
2941      * are also returned
2942      */
2943     if ((errorCode =
2944          GetVolumePackage(tcon, Fid, &volptr, &targetptr, MustNOTBeDIR,
2945                           &parentwhentargetnotdir, &client, WRITE_LOCK,
2946                           &rights, &anyrights))) {
2947         goto Bad_StoreData;
2948     }
2949
2950     /* set volume synchronization information */
2951     SetVolumeSync(Sync, volptr);
2952
2953     if ((targetptr->disk.type == vSymlink)) {
2954         /* Should we return a better error code here??? */
2955         errorCode = EISDIR;
2956         goto Bad_StoreData;
2957     }
2958
2959     /* Check if we're allowed to store the data */
2960     if ((errorCode =
2961          Check_PermissionRights(targetptr, client, rights, CHK_STOREDATA,
2962                                 InStatus))) {
2963         goto Bad_StoreData;
2964     }
2965
2966     /*
2967      * Drop the read lock on the parent directory after saving the parent
2968      * vnode information we need to pass to GetStatus
2969      */
2970     if (parentwhentargetnotdir != NULL) {
2971         tparentwhentargetnotdir = *parentwhentargetnotdir;
2972         VPutVnode(&fileCode, parentwhentargetnotdir);
2973         assert(!fileCode || (fileCode == VSALVAGE));
2974         parentwhentargetnotdir = NULL;
2975     }
2976 #if FS_STATS_DETAILED
2977     /*
2978      * Remember when the data transfer started.
2979      */
2980     FT_GetTimeOfDay(&xferStartTime, 0);
2981 #endif /* FS_STATS_DETAILED */
2982
2983     /* Do the actual storing of the data */
2984 #if FS_STATS_DETAILED
2985     errorCode =
2986         StoreData_RXStyle(volptr, targetptr, Fid, client, acall, Pos, Length,
2987                           FileLength, (InStatus->Mask & AFS_FSYNC),
2988                           &bytesToXfer, &bytesXferred);
2989 #else
2990     errorCode =
2991         StoreData_RXStyle(volptr, targetptr, Fid, client, acall, Pos, Length,
2992                           FileLength, (InStatus->Mask & AFS_FSYNC));
2993     if (errorCode && (!targetptr->changed_newTime))
2994         goto Bad_StoreData;
2995 #endif /* FS_STATS_DETAILED */
2996 #if FS_STATS_DETAILED
2997     /*
2998      * At this point, the data transfer is done, for good or ill.  Remember
2999      * when the transfer ended, bump the number of successes/failures, and
3000      * integrate the transfer size and elapsed time into the stats.  If the
3001      * operation failed, we jump to the appropriate point.
3002      */
3003     FT_GetTimeOfDay(&xferStopTime, 0);
3004     FS_LOCK;
3005     (xferP->numXfers)++;
3006     if (!errorCode) {
3007         (xferP->numSuccesses)++;
3008
3009         /*
3010          * Bump the xfer sum by the number of bytes actually sent, NOT the
3011          * target number.
3012          */
3013         tot_bytesXferred += bytesXferred;
3014         (xferP->sumBytes) += (tot_bytesXferred >> 10);
3015         tot_bytesXferred &= 0x3FF;
3016         if (bytesXferred < xferP->minBytes)
3017             xferP->minBytes = bytesXferred;
3018         if (bytesXferred > xferP->maxBytes)
3019             xferP->maxBytes = bytesXferred;
3020
3021         /*
3022          * Tally the size of the object.  Note: we tally the actual size,
3023          * NOT the number of bytes that made it out over the wire.
3024          */
3025         if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET0)
3026             (xferP->count[0])++;
3027         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET1)
3028             (xferP->count[1])++;
3029         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET2)
3030             (xferP->count[2])++;
3031         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET3)
3032             (xferP->count[3])++;
3033         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET4)
3034             (xferP->count[4])++;
3035         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET5)
3036             (xferP->count[5])++;
3037         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET6)
3038             (xferP->count[6])++;
3039         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET7)
3040             (xferP->count[7])++;
3041         else
3042             (xferP->count[8])++;
3043
3044         fs_stats_GetDiff(elapsedTime, xferStartTime, xferStopTime);
3045         fs_stats_AddTo((xferP->sumTime), elapsedTime);
3046         fs_stats_SquareAddTo((xferP->sqrTime), elapsedTime);
3047         if (fs_stats_TimeLessThan(elapsedTime, (xferP->minTime))) {
3048             fs_stats_TimeAssign((xferP->minTime), elapsedTime);
3049         }
3050         if (fs_stats_TimeGreaterThan(elapsedTime, (xferP->maxTime))) {
3051             fs_stats_TimeAssign((xferP->maxTime), elapsedTime);
3052         }
3053     }
3054     FS_UNLOCK;
3055     /*
3056      * Finally, go off to tell our caller the bad news in case the
3057      * store failed.
3058      */
3059     if (errorCode && (!targetptr->changed_newTime))
3060         goto Bad_StoreData;
3061 #endif /* FS_STATS_DETAILED */
3062
3063     /* Update the status of the target's vnode */
3064     Update_TargetVnodeStatus(targetptr, TVS_SDATA, client, InStatus,
3065                              targetptr, volptr, 0);
3066
3067     /* Get the updated File's status back to the caller */
3068     GetStatus(targetptr, OutStatus, rights, anyrights,
3069               &tparentwhentargetnotdir);
3070
3071   Bad_StoreData:
3072     /* Update and store volume/vnode and parent vnodes back */
3073     (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
3074                            volptr, &client);
3075     ViceLog(2, ("SAFS_StoreData returns %d\n", errorCode));
3076
3077     errorCode = CallPostamble(tcon, errorCode, thost);
3078
3079 #if FS_STATS_DETAILED
3080     FT_GetTimeOfDay(&opStopTime, 0);
3081     if (errorCode == 0) {
3082         FS_LOCK;
3083         (opP->numSuccesses)++;
3084         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3085         fs_stats_AddTo((opP->sumTime), elapsedTime);
3086         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3087         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3088             fs_stats_TimeAssign((opP->minTime), elapsedTime);
3089         }
3090         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3091             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3092         }
3093         FS_UNLOCK;
3094     }
3095 #endif /* FS_STATS_DETAILED */
3096     osi_auditU(acall, StoreDataEvent, errorCode, 
3097                AUD_ID, t_client ? t_client->ViceId : 0,
3098                AUD_FID, Fid, AUD_END);
3099     return (errorCode);
3100 }                               /*common_StoreData64 */
3101
3102 afs_int32
3103 SRXAFS_StoreData(struct rx_call * acall, struct AFSFid * Fid,
3104                  struct AFSStoreStatus * InStatus, afs_uint32 Pos,
3105                  afs_uint32 Length, afs_uint32 FileLength,
3106                  struct AFSFetchStatus * OutStatus, struct AFSVolSync * Sync)
3107 {
3108     if (FileLength > 0x7fffffff || Pos > 0x7fffffff || 
3109         (0x7fffffff - Pos) < Length)
3110         return EFBIG;
3111
3112     return common_StoreData64(acall, Fid, InStatus, Pos, Length, FileLength,
3113                               OutStatus, Sync);
3114 }                               /*SRXAFS_StoreData */
3115
3116 afs_int32
3117 SRXAFS_StoreData64(struct rx_call * acall, struct AFSFid * Fid,
3118                    struct AFSStoreStatus * InStatus, afs_uint64 Pos,
3119                    afs_uint64 Length, afs_uint64 FileLength,
3120                    struct AFSFetchStatus * OutStatus,
3121                    struct AFSVolSync * Sync)
3122 {
3123     int code;
3124     afs_fsize_t tPos;
3125     afs_fsize_t tLength;
3126     afs_fsize_t tFileLength;
3127
3128 #ifdef AFS_64BIT_ENV
3129 #ifndef AFS_LARGEFILE_ENV
3130     if (FileLength > 0x7fffffff)
3131         return EFBIG;
3132 #endif /* !AFS_LARGEFILE_ENV */
3133     tPos = (afs_fsize_t) Pos;
3134     tLength = (afs_fsize_t) Length;
3135     tFileLength = (afs_fsize_t) FileLength;
3136 #else /* AFS_64BIT_ENV */
3137     if (FileLength.high)
3138         return EFBIG;
3139     tPos = Pos.low;
3140     tLength = Length.low;
3141     tFileLength = FileLength.low;
3142 #endif /* AFS_64BIT_ENV */
3143
3144     code =
3145         common_StoreData64(acall, Fid, InStatus, tPos, tLength, tFileLength,
3146                            OutStatus, Sync);
3147     return code;
3148 }
3149
3150 afs_int32
3151 SRXAFS_StoreACL(struct rx_call * acall, struct AFSFid * Fid,
3152                 struct AFSOpaque * AccessList,
3153                 struct AFSFetchStatus * OutStatus, struct AFSVolSync * Sync)
3154 {
3155     Vnode *targetptr = 0;       /* pointer to input fid */
3156     Vnode *parentwhentargetnotdir = 0;  /* parent of Fid to get ACL */
3157     int errorCode = 0;          /* return code for caller */
3158     struct AFSStoreStatus InStatus;     /* Input status for fid */
3159     Volume *volptr = 0;         /* pointer to the volume header */
3160     struct client *client = 0;  /* pointer to client structure */
3161     afs_int32 rights, anyrights;        /* rights for this and any user */
3162     struct rx_connection *tcon;
3163     struct host *thost;
3164     struct client *t_client = NULL;     /* tmp ptr to client data */
3165     struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
3166 #if FS_STATS_DETAILED
3167     struct fs_stats_opTimingData *opP;  /* Ptr to this op's timing struct */
3168     struct timeval opStartTime, opStopTime;     /* Start/stop times for RPC op */
3169     struct timeval elapsedTime; /* Transfer time */
3170
3171     /*
3172      * Set our stats pointer, remember when the RPC operation started, and
3173      * tally the operation.
3174      */
3175     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_STOREACL]);
3176     FS_LOCK;
3177     (opP->numOps)++;
3178     FS_UNLOCK;
3179     FT_GetTimeOfDay(&opStartTime, 0);
3180 #endif /* FS_STATS_DETAILED */
3181     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
3182         goto Bad_StoreACL;
3183
3184     /* Get ptr to client data for user Id for logging */
3185     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
3186     logHostAddr.s_addr = rxr_HostOf(tcon);
3187     ViceLog(1,
3188             ("SAFS_StoreACL, Fid = %u.%u.%u, ACL=%s, Host %s:%d, Id %d\n",
3189              Fid->Volume, Fid->Vnode, Fid->Unique, AccessList->AFSOpaque_val,
3190              inet_ntoa(logHostAddr), ntohs(rxr_PortOf(tcon)), t_client->ViceId));
3191     FS_LOCK;
3192     AFSCallStats.StoreACL++, AFSCallStats.TotalCalls++;
3193     FS_UNLOCK;
3194     InStatus.Mask = 0;          /* not storing any status */
3195
3196     /*
3197      * Get associated volume/vnode for the target dir; caller's rights
3198      * are also returned.
3199      */
3200     if ((errorCode =
3201          GetVolumePackage(tcon, Fid, &volptr, &targetptr, MustBeDIR,
3202                           &parentwhentargetnotdir, &client, WRITE_LOCK,
3203                           &rights, &anyrights))) {
3204         goto Bad_StoreACL;
3205     }
3206
3207     /* set volume synchronization information */
3208     SetVolumeSync(Sync, volptr);
3209
3210     /* Check if we have permission to change the dir's ACL */
3211     if ((errorCode =
3212          Check_PermissionRights(targetptr, client, rights, CHK_STOREACL,
3213                                 &InStatus))) {
3214         goto Bad_StoreACL;
3215     }
3216
3217     /* Build and store the new Access List for the dir */
3218     if ((errorCode = RXStore_AccessList(targetptr, AccessList))) {
3219         goto Bad_StoreACL;
3220     }
3221
3222     targetptr->changed_newTime = 1;     /* status change of directory */
3223
3224     /* convert the write lock to a read lock before breaking callbacks */
3225     VVnodeWriteToRead(&errorCode, targetptr);
3226     assert(!errorCode || errorCode == VSALVAGE);
3227
3228     /* break call backs on the directory  */
3229     BreakCallBack(client->host, Fid, 0);
3230
3231     /* Get the updated dir's status back to the caller */
3232     GetStatus(targetptr, OutStatus, rights, anyrights, 0);
3233
3234   Bad_StoreACL:
3235     /* Update and store volume/vnode and parent vnodes back */
3236     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, 
3237                      volptr, &client);
3238     ViceLog(2, ("SAFS_StoreACL returns %d\n", errorCode));
3239     errorCode = CallPostamble(tcon, errorCode, thost);
3240
3241 #if FS_STATS_DETAILED
3242     FT_GetTimeOfDay(&opStopTime, 0);
3243     if (errorCode == 0) {
3244         FS_LOCK;
3245         (opP->numSuccesses)++;
3246         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3247         fs_stats_AddTo((opP->sumTime), elapsedTime);
3248         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3249         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3250             fs_stats_TimeAssign((opP->minTime), elapsedTime);
3251         }
3252         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3253             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3254         }
3255         FS_UNLOCK;
3256     }
3257 #endif /* FS_STATS_DETAILED */
3258
3259     osi_auditU(acall, StoreACLEvent, errorCode, 
3260                AUD_ID, t_client ? t_client->ViceId : 0,
3261                AUD_FID, Fid, AUD_ACL, AccessList->AFSOpaque_val, AUD_END);
3262     return errorCode;
3263
3264 }                               /*SRXAFS_StoreACL */
3265
3266
3267 /*
3268  * Note: This routine is called exclusively from SRXAFS_StoreStatus(), and
3269  * should be merged when possible.
3270  */
3271 static afs_int32
3272 SAFSS_StoreStatus(struct rx_call *acall, struct AFSFid *Fid,
3273                   struct AFSStoreStatus *InStatus,
3274                   struct AFSFetchStatus *OutStatus, struct AFSVolSync *Sync)
3275 {
3276     Vnode *targetptr = 0;       /* pointer to input fid */
3277     Vnode *parentwhentargetnotdir = 0;  /* parent of Fid to get ACL */
3278     int errorCode = 0;          /* return code for caller */
3279     Volume *volptr = 0;         /* pointer to the volume header */
3280     struct client *client = 0;  /* pointer to client structure */
3281     afs_int32 rights, anyrights;        /* rights for this and any user */
3282     struct client *t_client = NULL;     /* tmp ptr to client data */
3283     struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
3284     struct rx_connection *tcon = rx_ConnectionOf(acall);
3285
3286     /* Get ptr to client data for user Id for logging */
3287     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
3288     logHostAddr.s_addr = rxr_HostOf(tcon);
3289     ViceLog(1,
3290             ("SAFS_StoreStatus,  Fid    = %u.%u.%u, Host %s:%d, Id %d\n",
3291              Fid->Volume, Fid->Vnode, Fid->Unique, inet_ntoa(logHostAddr),
3292              ntohs(rxr_PortOf(tcon)), t_client->ViceId));
3293     FS_LOCK;
3294     AFSCallStats.StoreStatus++, AFSCallStats.TotalCalls++;
3295     FS_UNLOCK;
3296     /*
3297      * Get volume/vnode for the target file; caller's rights to it are
3298      * also returned
3299      */
3300     if ((errorCode =
3301          GetVolumePackage(tcon, Fid, &volptr, &targetptr, DONTCHECK,
3302                           &parentwhentargetnotdir, &client, WRITE_LOCK,
3303                           &rights, &anyrights))) {
3304         goto Bad_StoreStatus;
3305     }
3306
3307     /* set volume synchronization information */
3308     SetVolumeSync(Sync, volptr);
3309
3310     /* Check if the caller has proper permissions to store status to Fid */
3311     if ((errorCode =
3312          Check_PermissionRights(targetptr, client, rights, CHK_STORESTATUS,
3313                                 InStatus))) {
3314         goto Bad_StoreStatus;
3315     }
3316     /*
3317      * Check for a symbolic link; we can't chmod these (otherwise could
3318      * change a symlink to a mt pt or vice versa)
3319      */
3320     if (targetptr->disk.type == vSymlink && (InStatus->Mask & AFS_SETMODE)) {
3321         errorCode = EINVAL;
3322         goto Bad_StoreStatus;
3323     }
3324
3325     /* Update the status of the target's vnode */
3326     Update_TargetVnodeStatus(targetptr, TVS_SSTATUS, client, InStatus,
3327                              (parentwhentargetnotdir ? parentwhentargetnotdir
3328                               : targetptr), volptr, 0);
3329
3330     /* convert the write lock to a read lock before breaking callbacks */
3331     VVnodeWriteToRead(&errorCode, targetptr);
3332     assert(!errorCode || errorCode == VSALVAGE);
3333
3334     /* Break call backs on Fid */
3335     BreakCallBack(client->host, Fid, 0);
3336
3337     /* Return the updated status back to caller */
3338     GetStatus(targetptr, OutStatus, rights, anyrights,
3339               parentwhentargetnotdir);
3340
3341   Bad_StoreStatus:
3342     /* Update and store volume/vnode and parent vnodes back */
3343     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, 
3344                      volptr, &client);
3345     ViceLog(2, ("SAFS_StoreStatus returns %d\n", errorCode));
3346     return errorCode;
3347
3348 }                               /*SAFSS_StoreStatus */
3349
3350
3351 afs_int32
3352 SRXAFS_StoreStatus(struct rx_call * acall, struct AFSFid * Fid,
3353                    struct AFSStoreStatus * InStatus,
3354                    struct AFSFetchStatus * OutStatus,
3355                    struct AFSVolSync * Sync)
3356 {
3357     afs_int32 code;
3358     struct rx_connection *tcon;
3359     struct host *thost;
3360     struct client *t_client = NULL;     /* tmp ptr to client data */
3361 #if FS_STATS_DETAILED
3362     struct fs_stats_opTimingData *opP;  /* Ptr to this op's timing struct */
3363     struct timeval opStartTime, opStopTime;     /* Start/stop times for RPC op */
3364     struct timeval elapsedTime; /* Transfer time */
3365
3366     /*
3367      * Set our stats pointer, remember when the RPC operation started, and
3368      * tally the operation.
3369      */
3370     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_STORESTATUS]);
3371     FS_LOCK;
3372     (opP->numOps)++;
3373     FS_UNLOCK;
3374     FT_GetTimeOfDay(&opStartTime, 0);
3375 #endif /* FS_STATS_DETAILED */
3376
3377     if ((code = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
3378         goto Bad_StoreStatus;
3379
3380     code = SAFSS_StoreStatus(acall, Fid, InStatus, OutStatus, Sync);
3381
3382   Bad_StoreStatus:
3383     code = CallPostamble(tcon, code, thost);
3384
3385     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
3386
3387 #if FS_STATS_DETAILED
3388     FT_GetTimeOfDay(&opStopTime, 0);
3389     if (code == 0) {
3390         FS_LOCK;
3391         (opP->numSuccesses)++;
3392         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3393         fs_stats_AddTo((opP->sumTime), elapsedTime);
3394         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3395         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3396             fs_stats_TimeAssign((opP->minTime), elapsedTime);
3397         }
3398         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3399             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3400         }
3401         FS_UNLOCK;
3402     }
3403 #endif /* FS_STATS_DETAILED */
3404
3405     osi_auditU(acall, StoreStatusEvent, code, 
3406                AUD_ID, t_client ? t_client->ViceId : 0,
3407                AUD_FID, Fid, AUD_END);
3408     return code;
3409
3410 }                               /*SRXAFS_StoreStatus */
3411
3412
3413 /*
3414  * This routine is called exclusively by SRXAFS_RemoveFile(), and should be
3415  * merged in when possible.
3416  */
3417 static afs_int32
3418 SAFSS_RemoveFile(struct rx_call *acall, struct AFSFid *DirFid, char *Name,
3419                  struct AFSFetchStatus *OutDirStatus, struct AFSVolSync *Sync)
3420 {
3421     Vnode *parentptr = 0;       /* vnode of input Directory */
3422     Vnode *parentwhentargetnotdir = 0;  /* parent for use in SetAccessList */
3423     Vnode *targetptr = 0;       /* file to be deleted */
3424     Volume *volptr = 0;         /* pointer to the volume header */
3425     AFSFid fileFid;             /* area for Fid from the directory */
3426     int errorCode = 0;          /* error code */
3427     DirHandle dir;              /* Handle for dir package I/O */
3428     struct client *client = 0;  /* pointer to client structure */
3429     afs_int32 rights, anyrights;        /* rights for this and any user */
3430     struct client *t_client;    /* tmp ptr to client data */
3431     struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
3432     struct rx_connection *tcon = rx_ConnectionOf(acall);
3433
3434     FidZero(&dir);
3435     /* Get ptr to client data for user Id for logging */
3436     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
3437     logHostAddr.s_addr = rxr_HostOf(tcon);
3438     ViceLog(1,
3439             ("SAFS_RemoveFile %s,  Did = %u.%u.%u, Host %s:%d, Id %d\n", Name,
3440              DirFid->Volume, DirFid->Vnode, DirFid->Unique,
3441              inet_ntoa(logHostAddr), ntohs(rxr_PortOf(tcon)), t_client->ViceId));
3442     FS_LOCK;
3443     AFSCallStats.RemoveFile++, AFSCallStats.TotalCalls++;
3444     FS_UNLOCK;
3445     /*
3446      * Get volume/vnode for the parent dir; caller's access rights are
3447      * also returned
3448      */
3449     if ((errorCode =
3450          GetVolumePackage(tcon, DirFid, &volptr, &parentptr, MustBeDIR,
3451                           &parentwhentargetnotdir, &client, WRITE_LOCK,
3452                           &rights, &anyrights))) {
3453         goto Bad_RemoveFile;
3454     }
3455     /* set volume synchronization information */
3456     SetVolumeSync(Sync, volptr);
3457
3458     /* Does the caller has delete (& write) access to the parent directory? */
3459     if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_DELETE))) {
3460         goto Bad_RemoveFile;
3461     }
3462
3463     /* Actually delete the desired file */
3464     if ((errorCode =
3465          Del