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