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